35 use constant NO => 'NO'; |
35 use constant NO => 'NO'; |
36 use constant DUMPDATES => '/var/lib/dumpdates'; |
36 use constant DUMPDATES => '/var/lib/dumpdates'; |
37 use constant FD3 => 3; |
37 use constant FD3 => 3; |
38 use constant FD4 => 4; |
38 use constant FD4 => 4; |
39 |
39 |
|
40 my $BS = 64 * 2**20; # 64 MB read size |
|
41 |
40 $SIG{__DIE__} = sub { die $^S ? '' : "$ME: ", @_ }; |
42 $SIG{__DIE__} = sub { die $^S ? '' : "$ME: ", @_ }; |
41 |
43 |
42 my %SUPPORT = ( |
44 my %SUPPORT = ( |
43 CONFIG => YES, # --config … (default) |
45 CONFIG => YES, # --config … (default) |
44 DISK => NO, # --disk … |
46 DISK => NO, # --disk … |
90 'host=s' => sub { }, # ignore |
93 'host=s' => sub { }, # ignore |
91 'disk=s' => sub { }, # ignore |
94 'disk=s' => sub { }, # ignore |
92 ) or pod2usage; |
95 ) or pod2usage; |
93 |
96 |
94 given ($command) { |
97 given ($command) { |
95 when ("support") { exec_support } |
98 when ('support') { exec_support } |
96 when ("selfcheck") { |
99 when ('selfcheck') { |
97 pod2usage if undef ~~ $opt_device; |
100 pod2usage if undef ~~ $opt_device; |
98 exec_selfcheck |
101 exec_selfcheck |
99 } |
102 } |
100 when ("estimate") { |
103 when ('estimate') { |
101 pod2usage if undef ~~ [$opt_device, $opt_level[0]]; |
104 pod2usage if undef ~~ [$opt_device, $opt_level[0]]; |
102 exec_estimate |
105 exec_estimate |
103 } |
106 } |
104 when ("backup") { |
107 when ('backup') { |
105 pod2usage if undef ~~ [$opt_device, $opt_level[0]]; |
108 pod2usage if undef ~~ [$opt_device, $opt_level[0]]; |
106 exec_backup |
109 exec_backup |
107 } |
110 } |
|
111 when ('validate') { |
|
112 exec_validate |
|
113 } |
|
114 |
108 default { pod2usage } |
115 default { pod2usage } |
109 } |
116 } |
110 } |
117 } |
111 |
118 |
112 # output a list of supported options |
119 # output a list of supported options |
131 my (undef, @gids) = split ' ', $); |
138 my (undef, @gids) = split ' ', $); |
132 my @groups = map { '' . getgrgid $_ } @gids; |
139 my @groups = map { '' . getgrgid $_ } @gids; |
133 "@gids (@groups)"; |
140 "@gids (@groups)"; |
134 }; |
141 }; |
135 |
142 |
136 foreach my $tool (qw(dump restore)) { |
143 foreach my $tool (qw(dump restore cat)) { |
137 if ($_ = (grep { -x ($_ .= "/$tool") } split /:/ => $ENV{PATH})[0]) { |
144 if (my $path = |
138 my ($version, undef) = `$_ 2>&1`; |
145 (grep { -x ($_ .= "/$tool") } split /:/ => $ENV{PATH})[0]) |
139 chomp $version; |
146 { |
140 OK "$tool is $version"; |
147 |
|
148 # not all tools understand --version, but fortunately they |
|
149 # all output a line starting with the name of the tool and |
|
150 # the version information |
|
151 my ($version, undef) = |
|
152 map { /^.*?\s+(.*)/ } |
|
153 grep { /\A(?:$path|$tool)\s/ } `$path --version 2>&1`; |
|
154 chomp $version; |
|
155 OK "$tool is $path $version"; |
141 } |
156 } |
142 else { |
157 else { |
143 ERROR "$tool not found in $ENV{PATH}"; |
158 ERROR "$tool not found in $ENV{PATH}"; |
144 } |
159 } |
145 } |
160 } |
255 }; |
270 }; |
256 exec 'restore', -tvf => '-'; |
271 exec 'restore', -tvf => '-'; |
257 die "Can't exec `restore -tvf -`: $!"; |
272 die "Can't exec `restore -tvf -`: $!"; |
258 }; |
273 }; |
259 |
274 |
260 # the restore may close it's input, we'll get |
275 # The restore may close it's input, we'll get |
261 # a SIG{PIPE} because of this |
276 # a SIG{PIPE} because of this. |
|
277 # But how can we be sure that it was the restore |
|
278 # that just sent us the signal? Currently we write |
|
279 # to two processes only, writing to STDOUT (the data |
|
280 # stream up down to the server). If this fails we die. |
|
281 # The other stream we write to is the 'restore'. |
|
282 # If we got this SIGPIPE, we 'switch' to cat, since |
|
283 # it's faster then our perl script. |
262 local $SIG{PIPE} = sub { |
284 local $SIG{PIPE} = sub { |
263 close $restore; |
285 close $restore; |
264 $restore = undef; |
286 $restore = undef; |
265 $SIG{PIPE} = 'default'; |
287 $SIG{PIPE} = 'default'; |
|
288 exec 'cat'; |
|
289 die "Can't exec `cat': $!\n"; |
266 }; |
290 }; |
267 |
291 |
268 local $/ = \(my $x = 64 * 1024); |
292 local $/ = \$BS; |
269 while (<STDIN>) { |
293 while (<STDIN>) { |
270 print $_; |
294 print $_ or die "Can't send data to `dump': $!\n"; |
271 print $restore $_ if $restore; |
295 print $restore $_; |
272 } |
296 } |
273 close($restore) if $restore; |
297 close($restore) if $restore; |
274 exit 0; |
298 exit 0; |
275 }; |
299 }; |
276 |
300 |
395 |
419 |
396 } |
420 } |
397 |
421 |
398 } |
422 } |
399 |
423 |
|
424 sub exec_validate { |
|
425 |
|
426 my $pid = fork // die "Can't fork: $!\n"; |
|
427 |
|
428 # the first part goes into restore |
|
429 # but restore stops reading after the directory |
|
430 if (not $pid) { |
|
431 exec 'restore', '-tf', '-'; |
|
432 die "Can't exec restore: $!\n"; |
|
433 } |
|
434 waitpid($pid, 0); |
|
435 die $? if $?; |
|
436 |
|
437 # read the remaining dump via cat, I think, |
|
438 # nobody is fast than cat |
|
439 open(STDOUT, '>', '/dev/null') |
|
440 or die "Can't redirect STDOUT to >/dev/null: $!\n"; |
|
441 exec 'cat'; |
|
442 die "Can't exec `cat': $!\n"; |
|
443 } |
|
444 |
400 sub device { |
445 sub device { |
401 my $_ = shift; |
446 my $_ = shift; |
402 return $_ if /^\//; |
447 return $_ if /^\//; |
403 return "/dev/$_"; |
448 return "/dev/$_"; |
404 } |
449 } |
417 amdumpext - the amanda dump application |
462 amdumpext - the amanda dump application |
418 |
463 |
419 =head1 SYNOPSIS |
464 =head1 SYNOPSIS |
420 |
465 |
421 amdumpext support |
466 amdumpext support |
422 amdumpext selfcheck [options] [--level <level>] --device <device> |
467 amdumpext selfcheck [options] [--level <level>] --device <device> |
423 amdumpext estimate [options] [--level <level>]... --device <device> |
468 amdumpext backup [options] [--level <level>] --device <device> |
|
469 amdumpext estimate [options] [--level <level>]... --device <device> |
|
470 amdumpext validate |
424 |
471 |
425 =head1 DESCRIPTION |
472 =head1 DESCRIPTION |
426 |
473 |
427 The B<amdumpext> is an application plugin for amanda. It drives the |
474 The B<amdumpext> is an application plugin for amanda. It drives the |
428 native ext2/3/4 dump/restore programs found on most Linux systems. See L<dump(8)> |
475 native ext2/3/4 dump/restore programs found on most Linux systems. See L<dump(8)> |
486 |
533 |
487 Create an estimate about the amount of data we may expect for the |
534 Create an estimate about the amount of data we may expect for the |
488 backup. Multi-Level estimates are supported. |
535 backup. Multi-Level estimates are supported. |
489 |
536 |
490 mandatory options: device, level, ... |
537 mandatory options: device, level, ... |
|
538 |
|
539 =head2 validate |
|
540 |
|
541 This checks if the data stream is readable and looks like a dump. |
|
542 Actually it does not try to completly validate the stream, as B<restore> |
|
543 does not have such an option. |
491 |
544 |
492 =head1 PROPERTIES |
545 =head1 PROPERTIES |
493 |
546 |
494 The properties may be set on the server side to tune the behaviour |
547 The properties may be set on the server side to tune the behaviour |
495 of the application. Currently property setting on the client side is |
548 of the application. Currently property setting on the client side is |