5 Bweb - A Bacula web interface
6 Bacula® - The Network Backup Solution
8 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
10 The main author of Bweb is Eric Bollengier.
11 The main author of Bacula is Kern Sibbald, with contributions from
12 many others, a complete list can be found in the file AUTHORS.
14 This program is Free Software; you can redistribute it and/or
15 modify it under the terms of version two of the GNU General Public
16 License as published by the Free Software Foundation plus additions
17 that are listed in the file LICENSE.
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
29 Bacula® is a registered trademark of Kern Sibbald.
30 The licensor of Bacula is the Free Software Foundation Europe
31 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
32 Switzerland, email:ftf@fsfeurope.org.
41 use POSIX qw/strftime/;
44 use Digest::MD5 qw(md5_hex);
45 use File::Basename qw/basename dirname/;
47 my $conf = new Bweb::Config(config_file => $Bweb::config_file);
49 my $bweb = new Bweb(info => $conf);
52 my $arg = $bweb->get_form('where', 'jobid', 'pathid', 'filenameid');
53 my $where = $arg->{where} || '/';
54 my $jobid = $arg->{jobid};
55 my $pathid = $arg->{pathid};
56 my $fnid = $arg->{filenameid};
57 my $jobid_url = "jobid=$jobid";
60 my $batch = CGI::param("mode") || '';
62 my $md5_rep = md5_hex("$where:$jobid:$pathid:$fnid") ;
63 my $base_url = '/bweb/fv' ;
64 my $base_fich = $conf->{fv_write_path};
66 if ($jobid and $batch eq 'batch') {
67 my $root = fv_get_root_pathid($where);
69 fv_compute_size($jobid, $root);
75 print CGI::header('text/html');
76 $bweb->display_begin();
77 $bweb->display_job_zoom($jobid);
80 $bweb->error("Can't get where or jobid");
85 unless ($base_fich and -w $base_fich) {
86 $bweb->error("fv_write_path ($base_fich) is not writable." .
87 " See Bweb configuration.");
92 if (-f "$base_fich/$md5_rep.png" and -f "$base_fich/$md5_rep.tpl")
94 $bweb->display({}, "$base_fich/$md5_rep.tpl");
99 my $r = $bweb->dbh_selectrow_hashref("SELECT PurgedFiles AS ok FROM Job WHERE JobId = $jobid");
100 if (!$r || $r->{ok}) {
101 $bweb->error("File information for job $jobid has been pruned from catalog");
102 $bweb->display_end();
106 $r = $bweb->dbh_selectrow_hashref("SELECT JobId AS ok FROM brestore_knownjobid WHERE JobId = $jobid");
107 if (!$r || !$r->{ok}) { # TODO: compute information
108 $bweb->error("Path information for job $jobid has not been updated in the catalog");
109 $bweb->display_end();
113 # if it's a file, display it
114 if ($fnid and $pathid)
116 my $attribs = fv_get_file_attribute_from_id($jobid, $pathid, $fnid);
117 if ($attribs->{found}) {
118 $bweb->display($attribs, 'fv_file_attribs.tpl');
119 $bweb->display_end();
123 } elsif ($where ne '/') {
125 my $attribs = fv_get_file_attribute($jobid, $where);
126 if ($attribs->{found}) {
127 $bweb->display($attribs, 'fv_file_attribs.tpl');
128 $bweb->display_end();
137 $where = fv_get_root_path($pathid);
140 if ($where !~ m!/$!) {
141 $where = $where . "/" ;
144 $root = fv_get_root_pathid($where);
148 $bweb->error("Can't find $where in catalog");
149 $bweb->display_end();
153 my $total = fv_compute_size($jobid, $root);
155 my $url_action = "bfileview.pl?opt_level=$opt_level" ;
156 my $top = new CCircle(
158 base_url => "$url_action;pathid=$root;$jobid_url;here=$where",
161 fv_display_rep($top, $total, $root, $opt_level) ;
163 $top->draw_labels() ;
164 $top->set_title(Bweb::human_size($total)) ;
166 open(OUT, ">$base_fich/$md5_rep.png") or die "$base_fich/$md5_rep.png $!";
167 # make sure we are writing to a binary stream
169 # Convert the image to PNG and print it on standard output
170 print OUT $CCircle::gd->png;
173 open(OUT, ">$base_fich/$md5_rep.tpl") or die "$base_fich/$md5_rep.tpl $!";
175 <form action='$url_action' method='get'>
177 <input title='jobids' type='hidden' name='jobid' value='$jobid'>
178 <input title='directory' type='text' name='where' value='$where'/>
179 <input type='submit' size='256' name='go' value='go'/>
185 print OUT $top->get_imagemap($where, "$base_url/$md5_rep.png") ;
188 $bweb->display({}, "$base_fich/$md5_rep.tpl");
189 $bweb->display_end();
193 my ($ccircle, $max, $rep, $level) = @_ ;
194 return if ($max < 1);
197 my $dirs = fv_list_dirs($jobid, $rep); # 0: pathid, 1: pathname
199 foreach my $dir (@{$dirs})
201 my $size = fv_compute_size($jobid, $dir->[0]);
204 my $per = $size * 100 / $max;
205 # can't use pathname when using utf or accent
207 $ccircle->{base_url} =~ s/pathid=\d+;/pathid=$dir->[0];/;
209 my $chld = $ccircle->add_part($per,
210 basename($dir->[1]) . '/',
212 . sprintf(' %.0f%% ', $per)
213 . Bweb::human_size($size)
216 if ($chld && $level > 0) {
217 fv_display_rep($chld, $size, $dir->[0], $level - 1) ;
221 # 0: filenameid, 1: filename, 2: size
222 my $files = fv_get_big_files($jobid, $rep, 3*100/$max, $max_file/($level+1));
223 foreach my $f (@{$files}) {
224 $ccircle->{base_url} =~ s/pathid=\d+;(filenameid=\d+)?/pathid=$rep;filenameid=$f->[0];/;
226 $ccircle->add_part($f->[2] * 100 / $max,
228 $f->[1] . "\n" . Bweb::human_size($f->[2]));
233 $ccircle->add_part(($max - $sum) * 100 / $max,
235 "other\n" . Bweb::human_size($max - $sum));
238 $ccircle->finalize() ;
243 my ($jobid, $rep) = @_;
245 my $size = fv_get_size($jobid, $rep);
250 $size = fv_get_files_size($jobid, $rep);
252 my $dirs = fv_list_dirs($jobid, $rep);
253 foreach my $dir (@{$dirs}) {
254 $size += fv_compute_size($jobid, $dir->[0]);
257 fv_update_size($jobid, $rep, $size);
263 my ($jobid, $rep) = @_;
265 my $ret = $bweb->dbh_selectall_arrayref("
267 ( SELECT Path FROM Path WHERE PathId = P.PathId) AS Path
270 FROM brestore_pathvisibility
271 INNER JOIN brestore_pathhierarchy USING (PathId)
280 sub fv_get_file_attribute
282 my ($jobid, $full_name) = @_;
284 if ($full_name eq '/') {
288 my $filename = $bweb->dbh_quote(basename($full_name));
289 my $path = $bweb->dbh_quote(dirname($full_name) . "/");
291 my $attr = $bweb->dbh_selectrow_hashref("
294 base64_decode_lstat(8, LStat) AS size,
295 base64_decode_lstat(11, LStat) AS atime,
296 base64_decode_lstat(12, LStat) AS mtime,
297 base64_decode_lstat(13, LStat) AS ctime
299 FROM File JOIN Filename USING (FilenameId)
300 JOIN Path USING (PathId)
301 WHERE Name = $filename
306 $attr->{filename} = $full_name;
307 $attr->{size} = Bweb::human_size($attr->{size});
308 foreach my $d (qw/atime ctime mtime/) {
309 $attr->{$d} = strftime('%F %H:%M', localtime($attr->{$d}));
315 sub fv_get_file_attribute_from_id
317 my ($jobid, $pathid, $filenameid) = @_;
319 my $attr = $bweb->dbh_selectrow_hashref("
322 base64_decode_lstat(8, LStat) AS size,
323 base64_decode_lstat(11, LStat) AS atime,
324 base64_decode_lstat(12, LStat) AS mtime,
325 base64_decode_lstat(13, LStat) AS ctime,
326 Path.Path || Filename.Name AS filename
328 FROM File INNER JOIN Filename USING (FilenameId)
329 INNER JOIN Path USING (PathId)
330 WHERE FilenameId = $filenameid
335 $attr->{size} = Bweb::human_size($attr->{size});
336 foreach my $d (qw/atime ctime mtime/) {
337 $attr->{$d} = strftime('%F %H:%M', localtime($attr->{$d}));
344 my ($jobid, $rep) = @_;
346 my $ret = $bweb->dbh_selectrow_hashref("
348 FROM brestore_pathvisibility
356 sub fv_get_files_size
358 my ($jobid, $rep) = @_;
360 my $ret = $bweb->dbh_selectrow_hashref("
361 SELECT sum(base64_decode_lstat(8,LStat)) AS size
373 my ($jobid, $rep, $min, $limit) = @_;
374 $limit = int($limit);
376 my $ret = $bweb->dbh_selectall_arrayref("
377 SELECT FilenameId AS filenameid, Name AS name, size
379 SELECT FilenameId, base64_decode_lstat(8,LStat) AS size
384 ) AS S INNER JOIN Filename USING (FilenameId)
395 my ($jobid, $rep, $size) = @_;
397 my $nb = $bweb->dbh_do("
398 UPDATE brestore_pathvisibility SET Size = $size
406 sub fv_get_root_pathid
409 $path = $bweb->dbh_quote($path);
410 my $ret = $bweb->dbh_selectrow_hashref("SELECT PathId FROM Path WHERE Path = $path");
411 return $ret->{pathid};
417 my $ret = $bweb->dbh_selectrow_hashref("SELECT Path FROM Path WHERE PathId = $pathid");
424 CREATE OR REPLACE FUNCTION base64_decode_lstat(int4, varchar) RETURNS int8 AS $$
431 size := split_part($2, ' ', $1);
432 b64 := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
434 FOR i IN 1..length(size) LOOP
435 val := val + (strpos(b64, substr(size, i, 1))-1) * (64^(length(size)-i));
439 $$ language 'plpgsql';
441 ALTER TABLE brestore_pathvisibility ADD Size int8;
445 ALTER TABLE brestore_pathvisibility ADD Files int4;