2 #============================================================= -*-perl-*-
4 # BackupPC_fixupBackupSummary: recreate backups file in case
9 # Usage: BackupPC_fixupBackupSummary [clients...]
12 # Craig Barratt <cbarratt@users.sourceforge.net>
15 # Copyright (C) 2005 Craig Barratt
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.
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.
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
31 #========================================================================
33 # Version 3.0.0alpha, released 23 Jan 2006.
35 # See http://backuppc.sourceforge.net.
37 #========================================================================
41 use lib "/usr/local/BackupPC/lib";
47 use BackupPC::Attrib qw(:all);
48 use BackupPC::FileZIO;
49 use BackupPC::Storage;
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();
61 @hostList = sort(keys(%$Hosts));
66 foreach my $host ( @hostList ) {
67 my(@Backups, $BkupFromLOG, $BkupFromInfo, $BkupNums, @LogFiles);
71 if ( !defined($Hosts->{$host}) ) {
72 print("$host doesn't exist in BackupPC's host file... skipping\n");
76 my $dir = "$TopDir/pc/$host";
77 print("Doing host $host\n");
79 if ( !opendir(DIR, $dir) ) {
80 print("$host: Can't open $dir... skipping $host\n");
85 # Read the backups file
87 @Backups = $bpc->BackupInfoRead($host);
90 # Temporary: create backupInfo files in each backup
93 foreach ( my $i = 0 ; $i < @Backups ; $i++ ) {
94 BackupPC::Storage->backupInfoWrite($dir, $Backups[$i]{num},
97 my $bkupNum = $Backups[$i]{num};
98 if ( !-f "$dir/$bkupNum/backupInfo" ) {
99 my($dump) = Data::Dumper->new(
103 if ( open(BKUPINFO, ">", "$dir/$bkupNum/backupInfo") ) {
104 print(BKUPINFO $dump->Dump);
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.
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
121 my @files = readdir(DIR);
123 foreach my $file ( @files ) {
124 if ( $file =~ /^LOG(.\d+\.z)?/ ) {
125 push(@LogFiles, $file);
126 } elsif ( $file =~ /^(\d+)$/ ) {
128 $BkupNums->{$bkupNum} = 1;
130 next if ( !-f "$dir/$bkupNum/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")
141 print(" couldn't run $dir/$bkupNum/backupInfo\n");
144 if ( !keys(%backupInfo) || !defined($backupInfo{num}) ) {
145 print(" $dir/$bkupNum/backupInfo is empty\n");
148 %{$BkupFromInfo->{$backupInfo{num}}} = %backupInfo;
153 # Read through LOG files from oldest to newest
155 @LogFiles = sort({-M "$dir/$a" <=> -M "$dir/$b"} @LogFiles);
157 foreach my $file ( @LogFiles ) {
158 my $f = BackupPC::FileZIO->open("$dir/$file", 0, $file =~ /\.z/);
160 if ( !defined($f) ) {
161 print("$host: unable to open file $dir/$file\n");
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 / ) {
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\)/ );
175 my $nFilesTotal = $4;
180 print(" Got $type backup $bkupNum at $endTime\n");
181 next if ( !-d "$dir/$2" );
182 $BkupFromLOG->{$bkupNum} = {
185 startTime => parsedate($startTime),
186 endTime => parsedate($endTime),
188 nFiles => $nFilesTotal,
189 xferErrs => $xferErrs,
190 xferBadFile => $badFiles,
191 xferBadShare => $badShare,
196 compress => $Conf{CompressLevel},
197 noFill => $type eq "incr" ? 1 : 0,
198 level => $type eq "incr" ? 1 : 0,
201 fillFromNum => $fillFromNum;
206 splice(@Backups, 2, 1);
209 # Now merge any info from $BkupFromInfo and $BkupFromLOG
210 # that is missing from @Backups.
212 # First, anything in @Backups overrides the other data
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});
223 # Now merge in data from the LOG and backupInfo files.
224 # backupInfo files override LOG files.
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});
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});
241 foreach my $bkupNum ( keys(%$BkupNums) ) {
242 print(" *** No info for backup number $bkupNum\n");
246 @Backups = sort({$a->{num} <=> $b->{num}} @Backups);
247 print Dumper \@Backups;
249 print(" No changes for host $host\n");