- config and host editing pretty much done
[BackupPC.git] / bin / BackupPC_fixupBackupSummary
1 #!/bin/perl
2 #============================================================= -*-perl-*-
3 #
4 # BackupPC_fixupBackupSummary: recreate backups file in case
5 # it was lost.
6 #
7 # DESCRIPTION
8 #  
9 #   Usage: BackupPC_fixupBackupSummary [clients...]
10 #
11 # AUTHOR
12 #   Craig Barratt  <cbarratt@users.sourceforge.net>
13 #
14 # COPYRIGHT
15 #   Copyright (C) 2005  Craig Barratt
16 #
17 #   This program is free software; you can redistribute it and/or modify
18 #   it under the terms of the GNU General Public License as published by
19 #   the Free Software Foundation; either version 2 of the License, or
20 #   (at your option) any later version.
21 #
22 #   This program is distributed in the hope that it will be useful,
23 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
24 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25 #   GNU General Public License for more details.
26 #
27 #   You should have received a copy of the GNU General Public License
28 #   along with this program; if not, write to the Free Software
29 #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30 #
31 #========================================================================
32 #
33 # Version 2.1.0, released 20 Jun 2004.
34 #
35 # See http://backuppc.sourceforge.net.
36 #
37 #========================================================================
38
39 use strict;
40 no  utf8;
41 use lib "/usr/local/BackupPC/lib";
42 use Getopt::Std;
43 use Data::Dumper;
44 use Time::ParseDate;
45
46 use BackupPC::Lib;
47 use BackupPC::Attrib qw(:all);
48 use BackupPC::FileZIO;
49 use BackupPC::Storage;
50
51 die("BackupPC::Lib->new failed\n") if ( !(my $bpc = BackupPC::Lib->new) );
52 my $TopDir = $bpc->TopDir();
53 my $BinDir = $bpc->BinDir();
54 my %Conf   = $bpc->Conf();
55 my $Hosts  = $bpc->HostInfoRead();
56 my @hostList;
57
58 our(%backupInfo);
59
60 if ( !@ARGV ) {
61     @hostList = sort(keys(%$Hosts));
62 } else {
63     @hostList = @ARGV;
64 }
65
66 foreach my $host ( @hostList ) {
67     my(@Backups, $BkupFromLOG, $BkupFromInfo, $BkupNums, @LogFiles);
68
69     $BkupFromInfo = {};
70     $BkupFromLOG  = {};
71     if ( !defined($Hosts->{$host}) ) {
72         print("$host doesn't exist in BackupPC's host file... skipping\n");
73         next;
74     }
75
76     my $dir = "$TopDir/pc/$host";
77     print("Doing host $host\n");
78
79     if ( !opendir(DIR, $dir) ) {
80         print("$host: Can't open $dir... skipping $host\n");
81         next;
82     }
83
84     #
85     # Read the backups file
86     #
87     @Backups = $bpc->BackupInfoRead($host);
88
89     #
90     # Temporary: create backupInfo files in each backup
91     # directory
92     #
93     foreach ( my $i = 0 ; $i < @Backups ; $i++ ) {
94         BackupPC::Storage->backupInfoWrite($dir, $Backups[$i]{num},
95                                            $Backups[$i]);
96         if ( 0 ) {
97             my $bkupNum = $Backups[$i]{num};
98             if ( !-f "$dir/$bkupNum/backupInfo" ) {
99                 my($dump) = Data::Dumper->new(
100                          [   $Backups[$i]],
101                          [qw(*backupInfo)]);
102                 $dump->Indent(1);
103                 if ( open(BKUPINFO, ">", "$dir/$bkupNum/backupInfo") ) {
104                     print(BKUPINFO $dump->Dump);
105                     close(BKUPINFO);
106                 }
107             }
108         }
109     }
110
111     #
112     # Look through the LOG files to get information about
113     # completed backups.  The data from the LOG file is
114     # incomplete, but enough to get some useful info.
115     #
116     # Also, try to pick up the new-style of information
117     # that is kept in each backup tree.  This info is
118     # complete.  This data is only saved after version
119     # 2.1.2.
120     #
121     my @files = readdir(DIR);
122     closedir(DIR);
123     foreach my $file ( @files ) {
124         if ( $file =~ /^LOG(.\d+\.z)?/ ) {
125             push(@LogFiles, $file);
126         } elsif ( $file =~ /^(\d+)$/ ) {
127             my $bkupNum = $1;
128             $BkupNums->{$bkupNum} = 1;
129
130             next if ( !-f "$dir/$bkupNum/backupInfo" );
131
132             #
133             # Read backup info
134             #
135             %backupInfo = ();
136             print("    Reading $dir/$bkupNum/backupInfo\n");
137             if ( !(my $ret = do "$dir/$bkupNum/backupInfo") ) {
138                 print("    couldn't parse $dir/$bkupNum/backupInfo: $@\n") if $@;
139                 print("    couldn't do $dir/$bkupNum/backupInfo: $!\n")
140                                                         unless defined $ret;
141                 print("    couldn't run $dir/$bkupNum/backupInfo\n");
142                 next;
143             }
144             if ( !keys(%backupInfo) || !defined($backupInfo{num}) ) {
145                 print("    $dir/$bkupNum/backupInfo is empty\n");
146                 next;
147             }
148             %{$BkupFromInfo->{$backupInfo{num}}} = %backupInfo;
149         }
150     }
151
152     #
153     # Read through LOG files from oldest to newest
154     #
155     @LogFiles = sort({-M "$dir/$a" <=> -M "$dir/$b"} @LogFiles);
156     my $startTime;
157     foreach my $file ( @LogFiles ) {
158         my $f = BackupPC::FileZIO->open("$dir/$file", 0, $file =~ /\.z/);
159
160         if ( !defined($f) ) {
161             print("$host: unable to open file $dir/$file\n");
162             next;
163         }
164         print("    Reading $file\n");
165         while ( (my $str = $f->readLine()) ne "" ) {
166             if ( $str =~ /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) (full|incr|partial) backup started for directory / ) {
167                 $startTime = $str;
168                 next;
169             }
170             next if ( $str !~ /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) (full|incr|partial) backup (\d+) complete, (\d+) files, (\d+) bytes, (\d+) xferErrs \((\d+) bad files, (\d+) bad shares, (\d+) other\)/ );
171
172             my $endTime     = $1;
173             my $type        = $2;
174             my $bkupNum     = $3;
175             my $nFilesTotal = $4;
176             my $sizeTotal   = $5;
177             my $xferErrs    = $6;
178             my $badFiles    = $7;
179             my $badShare    = $8;
180             print("    Got $type backup $bkupNum at $endTime\n");
181             next if ( !-d "$dir/$2" );
182             $BkupFromLOG->{$bkupNum} = {
183                 num            => $bkupNum,
184                 type           => $type,
185                 startTime      => parsedate($startTime),
186                 endTime        => parsedate($endTime),
187                 size           => $sizeTotal,
188                 nFiles         => $nFilesTotal,
189                 xferErrs       => $xferErrs,
190                 xferBadFile    => $badFiles,
191                 xferBadShare   => $badShare,
192                 nFilesExist    => 0,
193                 sizeExist      => 0,
194                 sizeExistComp  => 0,
195                 tarErrs        => 0,
196                 compress       => $Conf{CompressLevel},
197                 noFill         => $type eq "incr" ? 1 : 0,
198                 level          => $type eq "incr" ? 1 : 0,
199                 mangle         => 1,
200                 noFill         => $noFill;
201                 fillFromNum    => $fillFromNum;
202             };
203         }
204     }
205
206     splice(@Backups, 2, 1);
207     
208     #
209     # Now merge any info from $BkupFromInfo and $BkupFromLOG
210     # that is missing from @Backups.
211     #
212     # First, anything in @Backups overrides the other data
213     #
214     #
215     foreach ( my $i = 0 ; $i < @Backups ; $i++ ) {
216         my $bkupNum = $Backups[$i]{num};
217         delete($BkupFromLOG->{$bkupNum});
218         delete($BkupFromInfo->{$bkupNum});
219         delete($BkupNums->{$bkupNum});
220     }
221
222     #
223     # Now merge in data from the LOG and backupInfo files.
224     # backupInfo files override LOG files.
225     #
226     my $changes;
227
228     foreach my $bkupNum ( keys(%$BkupFromLOG) ) {
229         next if ( defined($BkupFromInfo->{$bkupNum}) );
230         print("    Adding info for backup $bkupNum from LOG file\n");
231         push(@Backups, $BkupFromLOG->{$bkupNum});
232         delete($BkupNums->{$bkupNum});
233         $changes++;
234     }
235     foreach my $bkupNum ( keys(%$BkupFromInfo) ) {
236         print("    Adding info for backup $bkupNum from backupInfo file\n");
237         push(@Backups, $BkupFromInfo->{$bkupNum});
238         delete($BkupNums->{$bkupNum});
239         $changes++;
240     }
241     foreach my $bkupNum ( keys(%$BkupNums) ) {
242         print("    *** No info for backup number $bkupNum\n");
243     }
244
245     if ( $changes ) {
246         @Backups = sort({$a->{num} <=> $b->{num}} @Backups);
247         print Dumper \@Backups;
248     } else {
249         print("    No changes for host $host\n");
250     }
251 }