Merge tag 'upstream/3.3.3'
[debian/amanda] / server-src / amoverview.pl
index 0dc5fc1ef98841073401f97e4a31df0497deaefc..eb53a3f1475f5676a075bb65f491c01a5d18e90c 100644 (file)
@@ -1,62 +1,53 @@
 #!@PERL@
 #!@PERL@
-
-# Catch for sh/csh on systems without #! ability.
-eval '(exit $?0)' && eval 'exec @PERL@ -S $0 ${1+"$@"}'
-       & eval 'exec @PERL@ -S $0 $argv:q'
-               if 0;
-
-require 5.001;
-
+# Copyright (c) 2010-2012 Zmanda Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
+# Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
+
+use lib '@amperldir@';
+use strict;
+use warnings;
+
+use Amanda::Config qw( :init :getconf );
+use Amanda::Disklist;
+use Amanda::DB::Catalog;
 use FileHandle;
 use Getopt::Long;
 use FileHandle;
 use Getopt::Long;
-use Text::ParseWords;
 use Carp;
 use POSIX;
 
 use Carp;
 use POSIX;
 
-delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV', 'PATH'};
-$ENV{'PATH'} = "/usr/bin:/usr/sbin:/sbin:/bin";
-
 sub Usage {
     print STDERR <<END;
 sub Usage {
     print STDERR <<END;
-Usage: $0 [[-config] CONFIG] [-hostwidth width] [-diskwidth width] [-skipmissed] [-last] [-num0] [-togo0] [-verbose]
+Usage: $0 [--hostwidth width] [--diskwidth width] [--skipmissed]
+         [--last] [--num0] [--togo0] [--verbose] [--config] <config>
 
 This script generates to standard output an overview of the filesystems
 dumped over time and the type of dump done on a particular day, such as
 a full dump, or an incremental, or if the dump failed.
 
 
 This script generates to standard output an overview of the filesystems
 dumped over time and the type of dump done on a particular day, such as
 a full dump, or an incremental, or if the dump failed.
 
-You may override the default configuration `@DEFAULT_CONFIG@' by using
-the -config command line option.  On larger installations, this script
-will take a while to run.  In this case, run it with --verbose to see
-how far along it is.
+On larger installations, this script will take a while to run.  In this case,
+run it with --verbose to see how far along it is.
 END
     exit 1;
 }
 
 END
     exit 1;
 }
 
-# Default paths for this installation of Amanda.
-my $prefix='@prefix@';
-$prefix=$prefix;               # avoid warnings about possible typo
-my $exec_prefix="@exec_prefix@";
-$exec_prefix=$exec_prefix;     # ditto
-my $amlibexecdir="@amlibexecdir@";
-my $sbindir="@sbindir@";
-# The directory where configurations can be found.
-my $confdir="@CONFIG_DIR@";
-
-# The default configuration.
-my $config="@DEFAULT_CONFIG@";
-
-# Get the version suffix.
-my $USE_VERSION_SUFFIXES = '@USE_VERSION_SUFFIXES@';
-my $suf = '';
-if ( $USE_VERSION_SUFFIXES =~ /^yes$/i ) {
-       $suf='-@VERSION@';
-}
-
-my $amadmin    = "$sbindir/amadmin$suf";
-
 # overrideable defaults
 # overrideable defaults
-my $opt_config         = "$config";
+my $opt_version;
+my $opt_config         = undef;
 my $opt_hostwidth      = 8;
 my $opt_diskwidth      = 20;
 my $opt_skipmissed     = 0;
 my $opt_hostwidth      = 8;
 my $opt_diskwidth      = 20;
 my $opt_skipmissed     = 0;
@@ -65,7 +56,8 @@ my $opt_num0          = 0;
 my $opt_togo0          = 0;
 my $opt_verbose                = 0;
 
 my $opt_togo0          = 0;
 my $opt_verbose                = 0;
 
-GetOptions('config=s'          => \$opt_config,
+GetOptions('version'            => \$opt_version,
+          'config=s'           => \$opt_config,
           'hostwidth=i'        => \$opt_hostwidth,
           'diskwidth=i'        => \$opt_diskwidth,
           'skipmissed'         => \$opt_skipmissed,
           'hostwidth=i'        => \$opt_hostwidth,
           'diskwidth=i'        => \$opt_diskwidth,
           'skipmissed'         => \$opt_skipmissed,
@@ -75,105 +67,69 @@ GetOptions('config=s'              => \$opt_config,
           'verbose'            => \$opt_verbose)
 or Usage();
 
           'verbose'            => \$opt_verbose)
 or Usage();
 
-if($#ARGV == 0) {
-  $opt_config = $ARGV[0];
-}
-elsif($#ARGV > 0) {
-  Usage();
+if (defined $opt_version) {
+    print "amoverview-" . $Amanda::Constants::VERSION , "\n";
+    exit 0;
 }
 
 }
 
-#untaint user input $ARGV[0]
-
-if ($opt_config =~ /^([\w.-]+)$/) {          # $1 is untainted
-   $opt_config = $1;
-} else {
-    die "filename '$opt_config' has invalid characters.\n";
+unless(defined($opt_config)) {
+    if (@ARGV == 1) {
+       $opt_config = $ARGV[0];
+    } else {
+       Usage();
+    }
 }
 
 }
 
-
--d "$confdir/$opt_config" or
-       die "$0: directory `$confdir/$opt_config' does not exist.\n";
+#Initialize configuration
+config_init($CONFIG_INIT_EXPLICIT_NAME, $opt_config);
+my ($cfgerr_level, @cfgerr_errors) = config_errors();
+if ($cfgerr_level >= $CFGERR_WARNINGS) {
+    config_print_errors();
+    if ($cfgerr_level >= $CFGERR_ERRORS) {
+        die("errors processing config file");
+    }
+}
 
 # read disklist
 
 # read disklist
+$cfgerr_level = Amanda::Disklist::read_disklist();
+die("Config errors") if ($cfgerr_level >= $CFGERR_WARNINGS);
+
 my %disks = ();
 my %disks = ();
-$::host = '';
-$::disk = '';
-$opt_verbose and
-    print STDERR "Running $amadmin $opt_config disklist\n";
-my $dlfh = new FileHandle "$amadmin $opt_config disklist|" or
-    die "$0: error in opening `$amadmin $opt_config disklist' pipe: $!\n";
-$/ = "";
-while (<$dlfh>) {
-    ($host, $disk) = m/    host (.*?):\n.*    disk (.*?):\n.*strategy (STANDARD|NOFULL|NOINC|HANOI|INCRONLY).*ignore NO/ms;
-    next unless $host;
-    $disks{$host}{$disk}++;
+foreach my $dle (Amanda::Disklist::all_disks()) {
+    $disks{$dle->{"host"}->{"hostname"}}{$dle->{"name"}}++;
 }
 
 }
 
-$/ = "\n";
-$dlfh->close or
-    die "$0: error in closing `$amadmin $opt_config disklist|' pipe: $!\n";
-
-# Get backup dates
-%::dates = ();
-%::level = ();
-$::level = '';
-my ($date, $tape, $file, $status);
+# Get dumps
+my %dates = ();
+my %level = ();
+my ($date, $host, $disk);
 $opt_verbose and
 $opt_verbose and
-    print STDERR "Running $amadmin $opt_config find\n";
-my $fh = new FileHandle "$amadmin $opt_config find|" or
-    die "$0: error in opening `$amadmin $opt_config find' pipe: $!\n";
-<$fh>;
-while (<$fh>) {
-    chomp;
-    next if /found Amanda directory/;
-    next if /skipping cruft directory/;
-    next if /skip-incr/;
-
-    ($date, $time, $host, $disk, $level, $tape, $file, $part, $status) = shellwords($_);
-
-    next if $date eq 'date';
-    next if $date eq 'Warning:';
-    next if $date eq 'Scanning';
-    next if $date eq "";
-
-    if($time !~/^\d\d:\d\d:\d\d$/) {
-       $status = $part;
-       $part = $file;
-       $file = $tape;
-       $tape = $level;
-       $level = $disk;
-       $disk = $host;
-       $host = $time;
-    }
-
-    if ($date =~ /^\d\d\d\d-\d\d-\d\d$/) {
-       if(defined $disks{$host}{$disk}) {
-           defined($level{$host}{$disk}{$date}) or
-               $level{$host}{$disk}{$date} = '';
-           $level{$host}{$disk}{$date} .= ($status eq 'OK') ? $level : 'E';
-           $dates{$date}++;
-       }
-    }
-    else {
-       print "bad date $date in $_\n";
+    print STDERR "Processing $opt_config dumps\n";
+foreach my $dump (Amanda::DB::Catalog::sort_dumps(['hostname','diskname','write_timestamp'],Amanda::DB::Catalog::get_dumps())) {
+    $host = $dump->{"hostname"};
+    $disk = $dump->{"diskname"};
+    $date = substr($dump->{"dump_timestamp"},0,8);
+
+    if (defined $disks{$host}{$disk}) {
+        defined($level{$host}{$disk}{$date}) or
+            $level{$host}{$disk}{$date} = '';
+        $level{$host}{$disk}{$date} .= ($dump->{"status"} eq 'OK') ? $dump->{"level"} : 'E';
+        $dates{$date}++;
     }
 }
     }
 }
-$fh->close or
-    die "$0: error in closing `$amadmin $opt_config find|' pipe: $!\n";
 
 # Process the status to arrive at a "last" status
 if ($opt_last) {
     for $host (sort keys %disks) {
         for $disk (sort keys %{$disks{$host}}) {
 
 # Process the status to arrive at a "last" status
 if ($opt_last) {
     for $host (sort keys %disks) {
         for $disk (sort keys %{$disks{$host}}) {
-           $level{$host}{$disk}{"0000-LA-ST"} = '';
+           $level{$host}{$disk}{"0000LAST"} = '';
            for $date (sort keys %dates) {
            for $date (sort keys %dates) {
+               next unless defined($level{$host}{$disk}{$date});
                if ($level{$host}{$disk}{$date} eq "E"
                if ($level{$host}{$disk}{$date} eq "E"
-                    && $level{$host}{$disk}{"0000-LA-ST"} =~ /^\d/ ) {
-                   $level{$host}{$disk}{"0000-LA-ST"} .= $level{$host}{$disk}{$date};
-               } elsif ($level{$host}{$disk}{$date} eq "") {
-                   $level{$host}{$disk}{"0000-LA-ST"} =~ s/E//;
+                    && $level{$host}{$disk}{"0000LAST"} =~ /^\d/ ) {
+                   $level{$host}{$disk}{"0000LAST"} .= $level{$host}{$disk}{$date};
                } else {
                } else {
-                   $level{$host}{$disk}{"0000-LA-ST"} = $level{$host}{$disk}{$date};
+                   $level{$host}{$disk}{"0000LAST"} = $level{$host}{$disk}{$date};
                }
            }
         }
                }
            }
         }
@@ -184,10 +140,11 @@ if ($opt_last) {
 if ($opt_num0) {
     for $host (sort keys %disks) {
         for $disk (sort keys %{$disks{$host}}) {
 if ($opt_num0) {
     for $host (sort keys %disks) {
         for $disk (sort keys %{$disks{$host}}) {
-            $level{$host}{$disk}{'0000-NM-L0'} = 0;
+            $level{$host}{$disk}{'0000NML0'} = 0;
             for $date (sort keys %dates) {
             for $date (sort keys %dates) {
-                if ($level{$host}{$disk}{$date} =~ /0/) {
-                    $level{$host}{$disk}{'0000-NM-L0'} += 1;
+                if (defined($level{$host}{$disk}{$date})
+                       && $level{$host}{$disk}{$date} =~ /0/) {
+                    $level{$host}{$disk}{'0000NML0'} += 1;
                 }
             }
         }
                 }
             }
         }
@@ -198,11 +155,12 @@ if ($opt_num0) {
 if ($opt_togo0) {
     for $host (sort keys %disks) {
         for $disk (sort keys %{$disks{$host}}) {
 if ($opt_togo0) {
     for $host (sort keys %disks) {
         for $disk (sort keys %{$disks{$host}}) {
-            $level{$host}{$disk}{'0000-TO-GO'} = 0;
+            $level{$host}{$disk}{'0000TOGO'} = 0;
             my $togo=0;
             for $date (sort keys %dates) {
             my $togo=0;
             for $date (sort keys %dates) {
-                if ($level{$host}{$disk}{$date} =~ /0/) {
-                    $level{$host}{$disk}{'0000-TO-GO'} = $togo;
+                if (defined($level{$host}{$disk}{$date})
+                       && $level{$host}{$disk}{$date} =~ /0/) {
+                    $level{$host}{$disk}{'0000TOGO'} = $togo;
                 }
                 $togo++;
             }
                 }
                 $togo++;
             }
@@ -215,51 +173,59 @@ unless ($opt_skipmissed)
 {
     my ($start, $finish) = 
        map {
 {
     my ($start, $finish) = 
        map {
-           my($y,$m,$d) = split /-/, $_;
+           my($y,$m,$d) = /(....)(..)(..)/;
            POSIX::mktime(0,0,0,$d,$m-1,$y-1900);
        } (sort keys %dates)[0,-1];
 
            POSIX::mktime(0,0,0,$d,$m-1,$y-1900);
        } (sort keys %dates)[0,-1];
 
-    while ($start < $finish) {
-       my @l = localtime $start;
-       $dates{sprintf("%d-%02d-%02d", 1900+$l[5], $l[4]+1, $l[3])}++;
-       $start += 86400;
+    # Special case of only one date
+    if (defined($finish)) {
+       while ($start < $finish) {
+           my @l = localtime $start;
+           $dates{sprintf("%d%02d%02d", 1900+$l[5], $l[4]+1, $l[3])}++;
+           $start += 86400;
+       }
     }
 }
 
 #Add the "last" entry    
     }
 }
 
 #Add the "last" entry    
-$dates{"0000-LA-ST"}=1 if ($opt_last);
+$dates{"0000LAST"}=1 if ($opt_last);
 
 #Add the "Number of Level 0s" entry
 
 #Add the "Number of Level 0s" entry
-$dates{"0000-NM-L0"}=1 if ($opt_num0);
+$dates{"0000NML0"}=1 if ($opt_num0);
 
 #Add the "Runs to go" entry
 
 #Add the "Runs to go" entry
-$dates{"0000-TO-GO"}=1 if ($opt_togo0);
+$dates{"0000TOGO"}=1 if ($opt_togo0);
 
 # make formats
 
 
 # make formats
 
-my $top_format = "format TOP =\n\n" .
-    sprintf("%-0${opt_hostwidth}s %-0${opt_diskwidth}s ", '', 'date') .
-    join(' ', map((split(/-/, $_))[1], sort keys %dates)) . "\n" .
-    sprintf("%-0${opt_hostwidth}s %-0${opt_diskwidth}s ", 'host', 'disk') .
-    join(' ', map((split(/-/, $_))[2], sort keys %dates)) . "\n" .
-    "\n.\n";
+sub row {
+    my ($host, $disk, @cols) = @_;
+    $host = substr($host, 0, $opt_hostwidth);
+    $disk = substr($disk, 0, $opt_diskwidth);
+    print
+       sprintf("%-0${opt_hostwidth}s %-0${opt_diskwidth}s ", $host, $disk) .
+       join(" ", map(sprintf("%-2s ", $_), @cols)) .
+       "\n";
+}
 
 
-my $out_format = "format STDOUT =\n" .
-    "@" . "<" x ($opt_hostwidth - 1) . ' ' .
-    "@" . "<" x ($opt_diskwidth - 1) . ' ' .
-    '@> ' x scalar(keys %dates) . "\n" .
-    join(', ', '$host', '$disk', 
-        map("substr(\$level{\$host}{\$disk}{'$_'},-2)", sort keys %dates)) . "\n" .
-    ".\n";
+sub fmt_levels {
+    my ($host, $disk, $date) = @_;
+    my $levels = $level{$host}{$disk}{$date};
+
+    # no dumps on this date
+    $levels = '-' unless defined($levels);
+
+    return substr($levels, -2);
+}
 
 
-eval $top_format;
-die $@ if $@;
-$^ = 'TOP';
-eval $out_format;
-die $@ if $@;
+# header
+row('',     'date', map((/....(..) .. /x)[0], sort keys %dates));
+row('host', 'disk', map((/.... .. (..)/x)[0], sort keys %dates));
 
 
+# body
 for $host (sort keys %disks) {
     for $disk (sort keys %{$disks{$host}}) {
 for $host (sort keys %disks) {
     for $disk (sort keys %{$disks{$host}}) {
-       write;
+       row($host, $disk,
+           map(fmt_levels($host, $disk, $_), sort keys %dates));
     }
 }
     }
 }