root/zetaback_agent.in

Revision 7cea9ab1a636f9c76cf5f6af6502e308b246c646, 6.1 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

fixes #21

  • Property mode set to 100755
Line 
1 #!/usr/bin/perl
2
3 # Copyright (c) 2007 OmniTI Computer Consulting, Inc. All rights reserved.
4 # For information on licensing see:
5 #   https://labs.omniti.com/zetaback/trunk/LICENSE
6
7 use strict;
8 use Getopt::Long;
9 use POSIX qw/mkfifo/;
10 use Data::Dumper;
11
12 use vars qw/%conf $version_string
13             $PREFIX $CONF $LIST $FULL $SNAP $ZFS $BASE $RESTORE $VERSION
14             $BUG_6343779 $NEEDSFD/;
15 $version_string = '0.1';
16 $PREFIX = q^__PREFIX__^;
17 $CONF = qq^$PREFIX/etc/zetaback_agent.conf^;
18 $NEEDSFD = ($^O eq 'darwin') ? 1 : 0;
19
20 =pod
21
22 =head1 NAME
23
24 zetaback_agent - client-side component of zetaback.
25
26 =head1 SYNOPSIS
27
28   zetaback_agent -v
29
30   zetaback_agent -l [-c conf]
31
32   zetaback_agent -r [-b <timestamp>] [-c conf] [-z zfs]
33
34   zetaback -f <timestamp> [-c conf] [-z zfs]
35
36   zetaback -i <timestamp> [-c conf] [-z zfs]
37
38   zetaback -d <snap> -z <zfs> [-c conf]
39
40 =cut
41
42 GetOptions(
43   "c=s" => \$CONF,
44   "l"   => \$LIST,
45   "r"   => \$RESTORE,
46   "z=s" => \$ZFS,
47   "d=s" => \$SNAP,
48   "f=s" => \$FULL,
49   "i=s" => \$BASE,
50   "b=s" => \$BUG_6343779,
51   "v"   => \$VERSION,
52 );
53
54 =pod
55
56 =head1 DESCRIPTION
57
58 B<zetaback_agent> handles requests from zetaback and performs the requested
59 operations on a host.  Normally B<zetaback_agent> is only called by
60 zetaback and should never need to be invoked directly.
61
62 =head1 OPTIONS
63
64 The following options are available:
65
66 =over
67
68 =item -c <conf>
69
70 Use the specified file as the configuration file.  The default file, if
71 none is specified is /etc/zetaback_agent.conf.  The prefix of this file
72 may also be specified in the Makefile.
73
74 =item -d <snap>
75
76 Delete the specified snapshot.  Requires the use of -z to specify the
77 ZFS filesystem.
78
79 =item -f <timestamp>
80
81 Perform a full backup.  The name of the backup will include <timestamp>,
82 which is provided by the backup server.
83
84 =item -i <timestamp>
85
86 Perform an incremental backup.  The name of the backup will include
87 <timestamp>, which is provided by the backup server.
88
89 =item -l
90
91 List ZFS filesystems.
92
93 =item -r
94
95 Perform a restore.
96
97 =item -b
98
99 When performing a restore, if -b is specified, it informs the agent that
100 the receive command is an incremental based of the full snapshot with the
101 timestamp specified.  The agent will unmount and rollback the filesystem
102 prior to applying the incremental in order to work around bug 6343779.
103
104 =item -v
105
106 Print the version number and exit.
107
108 =item -z
109
110 Specify a ZFS filesystem to backup, restore, or delete.
111
112 =cut
113
114 if($VERSION) {
115   print "zetaback_agent: $version_string\n";
116   exit 0;
117 }
118
119 =pod
120
121 =head1 CONFIGURATION
122
123 The zetaback_agent configuration file contains a pattern list of ZFS
124 filesystems to be backed up.  The pattern list is a Perl-compatible
125 regular expression (PCRE).  Only one 'pattern=' line is permitted.
126
127 =head1 CONFIGURATION EXAMPLES
128
129 =head2 All ZFS filesystems
130
131 This pattern matches all ZFS filesystems.
132
133   pattern=.
134
135 =head2 Substring match
136
137 This will match anywhere in the name of the ZFS filesystem.  This is
138 helpful for catching all ZFS filesystems in a particular zpool, while
139 excluding any others.
140
141   pattern=zones
142
143 =head2 Left-anchored names
144
145 This pattern matches all ZFS filesystems whose names begin with 'www'.
146
147   pattern=^www
148
149 =head2 Specific ZFS filesystems
150
151 This pattern matches specific ZFS filesystems.
152
153   pattern=(?:data|mirrors|www)
154
155 =cut
156
157 # Read our config in
158 $conf{pattern} = '.';
159 open(CONF, "<$CONF");
160 while(<CONF>) { /^\s*([^#](?:\S*)?)\s*=\s*(\S+)/ && ($conf{lc($1)} = $2); }
161 close(CONF);
162
163 sub zfs_agent_remove_snap {
164   my $target = $ZFS . '@';
165   die "zfs_agent_remove_snap: insufficient args\n" unless($ZFS && $SNAP);
166   if($SNAP eq '__zb_incr' or
167      $SNAP =~ /__zb_full_\d+/) {
168     $target .= $SNAP;
169   }
170   else {
171     die "zfs_agent_remove_snap: illegal snap: $SNAP\n";
172   }
173   `__ZFS__ destroy $target`;
174 }
175
176 sub zfs_agent_perform_full {
177   my $target = $ZFS . '@__zb_full_' . $FULL;
178   unless($ZFS && $FULL =~ /^\d+$/) {
179     die "zfs_agent_perform_full: bad fs or snap name\n"
180   }
181   `__ZFS__ snapshot $target`;
182   my @cmd = ("__ZFS__", "send", $target);
183   if($NEEDSFD) {
184     fifo_exec(@cmd);
185   } else {
186     exec { $cmd[0] } @cmd;
187   }
188   exit;
189 }
190
191 sub zfs_agent_perform_incremental {
192   my $target = $ZFS . '@__zb_incr';
193   my $base = $ZFS . '@__zb_full_' . $BASE;
194   unless($ZFS && $BASE) {
195     die "zfs_agent_perform_incremental: bad args\n"
196   }
197   `__ZFS__ snapshot $target`;
198   my @cmd = ("__ZFS__", "send", "-i", $base, $target);
199   if($NEEDSFD) {
200     fifo_exec(@cmd);
201   } else {
202     exec { $cmd[0] } @cmd;
203   }
204   exit;
205 }
206
207 sub zfs_agent_list {
208   my %zfs;
209   open(ZFSLIST, "__ZFS__ list -H |");
210   while(<ZFSLIST>) {
211     chomp;
212     my @line = split /\t/;
213     (my $fs = $line[0]) =~ s/\@.+//;
214     if($fs =~ /$conf{pattern}/) {
215       if($line[0] =~ /(\S+)\@([^\@]+)$/) {
216         $zfs{$1} ||= [];
217         push @{$zfs{$1}}, $2;
218       }
219       else {
220         $zfs{$line[0]} ||= [];
221       }
222     }
223   }
224   close(ZFSLIST);
225
226   foreach my $fs (sort keys %zfs) {
227     print "$fs [".join(',',@{$zfs{$fs}})."]\n";
228   }
229 }
230
231 sub zfs_agent_perform_restore {
232   unless($ZFS && $RESTORE) {
233     die "zfs_agent_perform_restore: bad state\n";
234   }
235   if($BUG_6343779) {
236     # Optionally work around Solaris bug: 6343779
237     my $base = $ZFS . '@__zb_full_' . $BUG_6343779;
238     `__ZFS__ unmount $ZFS`;
239     `__ZFS__ rollback $base`;
240   }
241   my @cmd = ("__ZFS__", "recv", $ZFS);
242   exec { $cmd[0] } @cmd;
243   exit;
244 }
245
246 sub fifo_exec {
247   my @cmd = @_;
248   my $rv = -1;
249   my $fifo = "zetaback_${$}_${FULL}${BASE}.fifo";
250   mkfifo($fifo, 0600) || die "Could not create fifo: $!";
251   my $pid = fork();
252   if($pid == 0) {
253     close(STDOUT);
254     open(STDOUT, ">$fifo") || die "Could not open fifo: $!";
255     exec { $cmd[0] } @cmd;
256     exit;
257   }
258   open(FIFO, "<$fifo");
259   unlink($fifo);
260   my $buf;
261   while(my $len = sysread(FIFO, $buf, 1024*64)) {
262     syswrite(STDOUT, $buf, $len);
263   }
264   waitpid($pid, 0);
265 }
266
267 if($LIST) { zfs_agent_list(); exit; }
268 if($ZFS && $SNAP) { zfs_agent_remove_snap(); exit; }
269 if($ZFS && $RESTORE) { zfs_agent_perform_restore(); exit; }
270 if($ZFS && $FULL) { zfs_agent_perform_full(); exit; }
271 if($ZFS && $BASE) { zfs_agent_perform_incremental(); exit; }
272
273 =pod
274
275 =head1 FILES
276
277 =over
278
279 =item /etc/zetaback_agent.conf
280
281 The zetaback_agent configuration file.  The location of the file can be
282 specified on the command line with the -c flag.
283
284 =back
285
286 =head1 SEE ALSO
287
288 zetaback(1)
289
290 =cut
Note: See TracBrowser for help on using the browser.