Imported Upstream version 3.3.3
[debian/amanda] / perl / Amanda / Report / postscript.pm
1 # Copyright (c) 2010-2012 Zmanda, Inc.  All Rights Reserved.
2 #
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11 # for more details.
12 #
13 # You should have received a copy of the GNU General Public License along
14 # with this program; if not, write to the Free Software Foundation, Inc.,
15 # 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 #
17 # Contact information: Zmanda Inc., 465 S Mathlida Ave, Suite 300
18 # Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
19
20 package Amanda::Report::postscript;
21
22 =head1 NAME
23
24 Amanda::Report::postscript -- postscript output for amreport
25
26 =head1 DESCRIPTION
27
28 This package implements the postscript output for amreport.  See amreport(8)
29 for more information.
30
31 =cut
32
33 use strict;
34 use warnings;
35
36 use Amanda::Constants;
37 use Amanda::Config qw( :getconf config_dir_relative );
38 use Amanda::Debug qw( debug );
39 use Amanda::Util;
40
41 sub new
42 {
43     my $class = shift;
44     my ($report, $config_name, $logfname) = @_;
45
46     my $self = bless {
47         report => $report,
48         config_name => $config_name,
49         logfname => $logfname,
50     }, $class;
51
52     # get some other parameters we'll need
53     my $ttyp = getconf($CNF_TAPETYPE);
54     my $tt = lookup_tapetype($ttyp) if $ttyp;
55     my ($tapelen, $marksize, $template_filename);
56
57     if ($ttyp && $tt) {
58
59         # append null string to get the right context
60         $tapelen = "" . tapetype_getconf($tt, $TAPETYPE_LENGTH);
61         $marksize = "" . tapetype_getconf($tt, $TAPETYPE_FILEMARK);
62         $template_filename = "" . tapetype_getconf($tt, $TAPETYPE_LBL_TEMPL);
63     }
64
65     # these values should never be zero, so assign defaults
66     $self->{'tapelen'} = $tapelen || 100 * 1024 * 1024;
67     $self->{'marksize'} = $marksize || 1 * 1024 * 1024;
68
69     # TODO: this should be a shared method somewhere
70     my $timestamp = $report->get_timestamp();
71     my ($year, $month, $day) = ($timestamp =~ m/^(\d\d\d\d)(\d\d)(\d\d)/);
72     my $date  = POSIX::strftime('%B %e, %Y', 0, 0, 0, $day, $month - 1, $year - 1900);
73     $date =~ s/  / /g; # get rid of intervening space
74     $self->{'datestr'} = $date;
75
76     # get the template
77     $self->{'template'} = $self->_get_template($template_filename);
78
79     return $self;
80 }
81
82 sub write_report
83 {
84     my $self = shift;
85     my ($fh) = @_;
86
87     my $tape_labels = $self->{'report'}->get_program_info("taper", "tape_labels", []);
88     my $tapes = $self->{'report'}->get_program_info("taper", "tapes", {});
89
90     for my $label (@$tape_labels) {
91         my $tape = $tapes->{$label};
92         $self->_write_report_tape($fh, $label, $tape);
93     }
94 }
95
96 sub _write_report_tape
97 {
98     my $self = shift;
99     my ($fh, $label, $tape) = @_;
100
101     # function to quote string literals
102     sub psstr {
103         my ($str) = @_;
104         $str =~ s/([()\\])/\\$1/g;
105         return "($str)";
106     }
107
108     ## include the template once for each tape (might be overkill, but oh well)
109     print $fh $self->{'template'};
110
111     ## header stuff
112     print $fh psstr($self->{'datestr'}), " DrawDate\n\n";
113     print $fh psstr("Amanda Version $Amanda::Constants::VERSION"), " DrawVers\n";
114     print $fh psstr($label), " DrawTitle\n";
115
116     ## pre-calculate everything
117
118     # make a list of the first part in each dumpfile, and at the same
119     # time count the origsize and outsize of every file beginning on this
120     # tape, and separate sums only of the compressed dumps
121     my @first_parts;
122     my $total_outsize = 0;
123     my $total_origsize = 0;
124     my $comp_outsize = 0;
125     my $comp_origsize = 0;
126     foreach my $dle ($self->{'report'}->get_dles()) {
127         my ($host, $disk) = @$dle;
128         my $dle_info = $self->{'report'}->get_dle_info($host, $disk);
129
130         my $alldumps = $dle_info->{'dumps'};
131
132         while( my ($timestamp, $tries) = each %$alldumps ) {
133             # run once for each try for this DLE
134             foreach my $try (@$tries) {
135
136                 next unless exists $try->{taper};
137                 my $taper = $try->{taper};
138
139                 my $parts = $taper->{parts};
140                 next unless @$parts > 0;
141
142                 my $first_part = $parts->[0];
143                 my $dlename = undef;
144                 if ($first_part->{label} eq $label) {
145                     $dlename = $disk;
146                 } else { #find if one part is on the volume
147                     foreach $parts (@$parts) {
148                         if ($parts->{label} eq $label) {
149                             $dlename = '- ' . $disk;
150                             last;
151                         }
152                     }
153                     next if !defined $dlename;
154                 }
155
156                 my $filenum = $first_part->{file};
157
158                 # sum the part sizes on this label to get the outsize.  Note that
159                 # the postscript output does not contain a row for each part, but
160                 # for each part..
161                 my $outsize = 0;
162                 for my $part (@$parts) {
163                     next unless $part->{'label'} eq $label;
164                     $outsize += $part->{'kb'};
165                 }
166
167                 # Get origsize for this try.
168                 my $origsize = 0;
169                 my $level = -1;
170
171                 # TODO: this is complex and should probably be in a parent-class method
172                 if (exists $try->{dumper} and ($try->{dumper}{status} ne 'fail')) {
173                     my $try_dumper = $try->{dumper};
174                     $level    = $try_dumper->{level};
175                     $origsize = $try_dumper->{orig_kb};
176                 } else {    # we already know a taper run exists in this try
177                     $level = $taper->{level};
178                     $origsize = $taper->{orig_kb} if $taper->{orig_kb};
179                 }
180
181                 $total_outsize += $outsize;
182                 $total_origsize += $origsize;
183
184                 if ($outsize != $origsize) {
185                     $comp_outsize += $outsize;
186                     $comp_origsize += $origsize;
187                 }
188
189                 push @first_parts, [$host, $dlename, $level, $filenum, $origsize, $outsize];
190             }
191         }
192     }
193     # count filemarks in the tapeused assessment
194     my $tapeused = $tape->{'kb'};
195     $tapeused += $self->{'marksize'} * (1 + $tape->{'files'});
196
197     # sort @first_parts by filenum
198     @first_parts = sort { $a->[3] <=> $b->[3] } @first_parts;
199
200     ## output
201
202     print $fh psstr(sprintf('Total Size:        %6.1f MB', $tape->{kb} / 1024)),
203             " DrawStat\n";
204     print $fh psstr(sprintf('Tape Used (%%)       %4s %%',
205                                 $self->divzero($tapeused * 100, $self->{'tapelen'}))),
206             " DrawStat\n";
207     print $fh psstr(sprintf('Number of files:  %5s', $tape->{'files'})),
208             " DrawStat\n";
209     print $fh psstr(sprintf('Filesystems Taped: %4d', $tape->{dle})),
210             " DrawStat\n";
211
212     my $header = ["-", $label, "-", 0, 32, 32];
213     for my $ff ($header, @first_parts) {
214         my ($host, $name, $level, $filenum, $origsize, $outsize) = @$ff;
215         print $fh join(" ",
216                 psstr($host),
217                 psstr($name),
218                 psstr($level),
219                 psstr(sprintf("%3d", $filenum)),
220                 psstr(sprintf("%8s", $origsize || "")),
221                 psstr(sprintf("%8s", $outsize || "")),
222                 "DrawHost\n");
223     }
224
225     print $fh "\nshowpage\n";
226 }
227
228
229 # copy the user's configured template file into $fh
230 sub _get_template {
231     my $self = shift;
232     my ($filename) = @_;
233
234     $filename = config_dir_relative($filename) if $filename;
235
236     if (!$filename || !-r $filename) {
237         debug("could not open template file '$filename'");
238         return undef;
239     }
240
241     return Amanda::Util::slurp($filename);
242 }
243
244 # TODO: this should be a common function somewhere
245 sub divzero
246 {
247     my $self = shift;
248     my ( $a, $b ) = @_;
249     my $q;
250     return
251         ( $b == 0 )              ? "-- "
252       : ( ($q = $a / $b) > 99999.95 ) ? "#####"
253       : ( $q > 999.95 ) ? sprintf( "%5.0f", $q )
254       :                   sprintf( "%5.1f", $q );
255 }
256
257 1;