3 # Catch for sh/csh on systems without #! ability.
4 eval '(exit $?0)' && eval 'exec @PERL@ -S $0 ${1+"$@"}'
5 & eval 'exec @PERL@ -S $0 $argv:q'
16 delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV', 'PATH'};
17 $ENV{'PATH'} = "/usr/bin:/usr/sbin:/sbin:/bin";
21 Usage: $0 [[-config] CONFIG] [-hostwidth width] [-diskwidth width] [-skipmissed] [-last] [-num0] [-togo0] [-verbose]
23 This script generates to standard output an overview of the filesystems
24 dumped over time and the type of dump done on a particular day, such as
25 a full dump, or an incremental, or if the dump failed.
27 You may override the default configuration `@DEFAULT_CONFIG@' by using
28 the -config command line option. On larger installations, this script
29 will take a while to run. In this case, run it with --verbose to see
35 # Default paths for this installation of Amanda.
36 my $prefix='@prefix@';
37 $prefix=$prefix; # avoid warnings about possible typo
38 my $exec_prefix="@exec_prefix@";
39 $exec_prefix=$exec_prefix; # ditto
40 my $libexecdir="@libexecdir@";
41 my $sbindir="@sbindir@";
43 # The directory where configurations can be found.
44 my $confdir="@CONFIG_DIR@";
46 # The default configuration.
47 my $config="@DEFAULT_CONFIG@";
49 # Get the version suffix.
50 my $USE_VERSION_SUFFIXES = '@USE_VERSION_SUFFIXES@';
52 if ( $USE_VERSION_SUFFIXES =~ /^yes$/i ) {
56 my $amadmin = "$sbindir/amadmin$suf";
58 # overrideable defaults
59 my $opt_config = "$config";
60 my $opt_hostwidth = 8;
61 my $opt_diskwidth = 20;
62 my $opt_skipmissed = 0;
68 GetOptions('config=s' => \$opt_config,
69 'hostwidth=i' => \$opt_hostwidth,
70 'diskwidth=i' => \$opt_diskwidth,
71 'skipmissed' => \$opt_skipmissed,
74 'togo0' => \$opt_togo0,
75 'verbose' => \$opt_verbose)
79 $opt_config = $ARGV[0];
85 #untaint user input $ARGV[0]
87 if ($opt_config =~ /^([\w.-]+)$/) { # $1 is untainted
90 die "filename '$opt_config' has invalid characters.\n";
94 -d "$confdir/$opt_config" or
95 die "$0: directory `$confdir/$opt_config' does not exist.\n";
102 print STDERR "Running $amadmin $opt_config disklist\n";
103 my $dlfh = new FileHandle "$amadmin $opt_config disklist|" or
104 die "$0: error in opening `$amadmin $opt_config disklist' pipe: $!\n";
107 ($host, $disk) = m/ host (.*?):.* disk (.*?):.*strategy (STANDARD|NOFULL|NOINC|HANOI|INCRONLY).*ignore NO/s;
109 $disks{$host}{$disk}++;
114 die "$0: error in closing `$amadmin $opt_config disklist|' pipe: $!\n";
120 my ($date, $tape, $file, $status);
122 print STDERR "Running $amadmin $opt_config find\n";
123 my $fh = new FileHandle "$amadmin $opt_config find|" or
124 die "$0: error in opening `$amadmin $opt_config find' pipe: $!\n";
128 next if /found Amanda directory/;
129 next if /skipping cruft directory/;
132 ($date, $time, $host, $disk, $level, $tape, $file, $part, $status) = shellwords($_);
134 next if $date eq 'date';
135 next if $date eq 'Warning:';
136 next if $date eq 'Scanning';
139 if($time !~/^\d\d:\d\d:\d\d$/) {
149 if ($date =~ /^\d\d\d\d-\d\d-\d\d$/) {
150 if(defined $disks{$host}{$disk}) {
151 defined($level{$host}{$disk}{$date}) or
152 $level{$host}{$disk}{$date} = '';
153 $level{$host}{$disk}{$date} .= ($status eq 'OK') ? $level : 'E';
158 print "bad date $date in $_\n";
162 die "$0: error in closing `$amadmin $opt_config find|' pipe: $!\n";
164 # Process the status to arrive at a "last" status
166 for $host (sort keys %disks) {
167 for $disk (sort keys %{$disks{$host}}) {
168 $level{$host}{$disk}{"0000-LA-ST"} = '';
169 for $date (sort keys %dates) {
170 if ($level{$host}{$disk}{$date} eq "E"
171 && $level{$host}{$disk}{"0000-LA-ST"} =~ /^\d/ ) {
172 $level{$host}{$disk}{"0000-LA-ST"} .= $level{$host}{$disk}{$date};
173 } elsif ($level{$host}{$disk}{$date} eq "") {
174 $level{$host}{$disk}{"0000-LA-ST"} =~ s/E//;
176 $level{$host}{$disk}{"0000-LA-ST"} = $level{$host}{$disk}{$date};
183 # Number of level 0 backups
185 for $host (sort keys %disks) {
186 for $disk (sort keys %{$disks{$host}}) {
187 $level{$host}{$disk}{'0000-NM-L0'} = 0;
188 for $date (sort keys %dates) {
189 if ($level{$host}{$disk}{$date} =~ /0/) {
190 $level{$host}{$disk}{'0000-NM-L0'} += 1;
197 # Runs to the last level 0
199 for $host (sort keys %disks) {
200 for $disk (sort keys %{$disks{$host}}) {
201 $level{$host}{$disk}{'0000-TO-GO'} = 0;
203 for $date (sort keys %dates) {
204 if ($level{$host}{$disk}{$date} =~ /0/) {
205 $level{$host}{$disk}{'0000-TO-GO'} = $togo;
213 unless ($opt_skipmissed)
214 # touch all the dates just in case whole days were missed.
216 my ($start, $finish) =
218 my($y,$m,$d) = split /-/, $_;
219 POSIX::mktime(0,0,0,$d,$m-1,$y-1900);
220 } (sort keys %dates)[0,-1];
222 while ($start < $finish) {
223 my @l = localtime $start;
224 $dates{sprintf("%d-%02d-%02d", 1900+$l[5], $l[4]+1, $l[3])}++;
229 #Add the "last" entry
230 $dates{"0000-LA-ST"}=1 if ($opt_last);
232 #Add the "Number of Level 0s" entry
233 $dates{"0000-NM-L0"}=1 if ($opt_num0);
235 #Add the "Runs to go" entry
236 $dates{"0000-TO-GO"}=1 if ($opt_togo0);
240 my $top_format = "format TOP =\n\n" .
241 sprintf("%-0${opt_hostwidth}s %-0${opt_diskwidth}s ", '', 'date') .
242 join(' ', map((split(/-/, $_))[1], sort keys %dates)) . "\n" .
243 sprintf("%-0${opt_hostwidth}s %-0${opt_diskwidth}s ", 'host', 'disk') .
244 join(' ', map((split(/-/, $_))[2], sort keys %dates)) . "\n" .
247 my $out_format = "format STDOUT =\n" .
248 "@" . "<" x ($opt_hostwidth - 1) . ' ' .
249 "@" . "<" x ($opt_diskwidth - 1) . ' ' .
250 '@> ' x scalar(keys %dates) . "\n" .
251 join(', ', '$host', '$disk',
252 map("substr(\$level{\$host}{\$disk}{'$_'},-2)", sort keys %dates)) . "\n" .
261 for $host (sort keys %disks) {
262 for $disk (sort keys %{$disks{$host}}) {