From: cbarratt Date: Sat, 17 Jan 2009 19:26:46 +0000 (+0000) Subject: * Modified bin/BackupPC_dump to fix the case of a single partial X-Git-Tag: v3_2_0beta1~10 X-Git-Url: http://git.rot13.org/?p=BackupPC.git;a=commitdiff_plain;h=3d15da9b2c6de8018c02677549678d6d769234b5 * Modified bin/BackupPC_dump to fix the case of a single partial backup followed by a successful incremental resulting in a full backup of level 1, rather than level 0. Reported by Jeff Kosowsky. * Fixed BackupPC::PoolWrite to always create the parent directory. This fixed a case with rsync/rsyncd where a file like "-i" in the top-level directory sorts before ".", which meant the directory creation is after the file creation. Also PoolWrite errors now increment xferError count. Reported by Jeff Kosowsky. * BackupPC now gives a more useful error message if BackupPC_nightly takes more than 24 hours (ie: when the next one is meant to start). Reported by Tony Schreiner. --- diff --git a/ChangeLog b/ChangeLog index 3fca576..c114378 100644 --- a/ChangeLog +++ b/ChangeLog @@ -43,6 +43,21 @@ charset to utf-8. Also changed bin/BackupPC_sendEmail to not send any per-client email if $Conf{BackupsDisable} is set. +* Modified bin/BackupPC_dump to fix the case of a single partial + backup followed by a successful incremental resulting in a full + backup of level 1, rather than level 0. Reported by Jeff + Kosowsky. + +* Fixed BackupPC::PoolWrite to always create the parent directory. + This fixed a case with rsync/rsyncd where a file like "-i" in the + top-level directory sorts before ".", which meant the directory + creation is after the file creation. Also PoolWrite errors now + increment xferError count. Reported by Jeff Kosowsky. + +* BackupPC now gives a more useful error message if BackupPC_nightly + takes more than 24 hours (ie: when the next one is meant to + start). Reported by Tony Schreiner. + * Added server message for queuing a single host based on patch submitted by Joe Digilio. diff --git a/bin/BackupPC b/bin/BackupPC index f3df54a..2edf36d 100755 --- a/bin/BackupPC +++ b/bin/BackupPC @@ -409,7 +409,6 @@ sub Main_TryToRun_nightly $CmdQueueOn{$bpc->trashJob} = 1; } if ( $RunNightlyWhenIdle == 1 ) { - # # Queue multiple nightly jobs based on the configuration # @@ -477,7 +476,6 @@ sub Main_TryToRun_nightly $start = $start0 + int(($end - $start0) * ($i + 1) / $Conf{MaxBackupPCNightlyJobs}); push(@$cmd, $start - 1); - my $job = $bpc->adminJob($i); unshift(@CmdQueue, { host => $job, @@ -868,7 +866,12 @@ sub Main_Check_Timeout # Remember to run the nightly script when the next CmdQueue # job is done. # - $RunNightlyWhenIdle = 1; + if ( $RunNightlyWhenIdle == 2 ) { + print(LOG $bpc->timeStamp, "BackupPC_nightly is still running after 24 hours!!" + . " You should adjust the config settings; Skipping this run\n"); + } else { + $RunNightlyWhenIdle = 1; + } } # # Write out the current status and then queue all the PCs diff --git a/bin/BackupPC_dump b/bin/BackupPC_dump index 0971f9e..288ee85 100755 --- a/bin/BackupPC_dump +++ b/bin/BackupPC_dump @@ -413,7 +413,7 @@ for ( my $i = 0 ; $i < @Backups ; $i++ ) { # # Decide whether we do nothing, or a full or incremental backup. # -if ( @Backups == 0 +if ( $lastFullTime == 0 || $opts{f} || (!$opts{i} && (time - $lastFullTime > $Conf{FullPeriod} * 24*3600 && time - $lastIncrTime > $Conf{IncrPeriod} * 24*3600)) ) { diff --git a/conf/config.pl b/conf/config.pl index c7e17bb..feed6bf 100644 --- a/conf/config.pl +++ b/conf/config.pl @@ -2058,7 +2058,7 @@ $Conf{CgiHeaders} = ''; # used by configure.pl when you upgrade BackupPC. # # Example: -# $Conf{CgiImageDir} = '/usr/local/apache/htdocs/BackupPC'; +# $Conf{CgiImageDir} = '/var/www/htdocs/BackupPC'; # $Conf{CgiImageDir} = ''; diff --git a/configure.pl b/configure.pl index 4b97fa7..a879807 100755 --- a/configure.pl +++ b/configure.pl @@ -472,12 +472,12 @@ if ( $Conf{CgiDir} ne "" ) { print < diff --git a/lib/BackupPC/Attrib.pm b/lib/BackupPC/Attrib.pm index e19d85c..fc245d7 100644 --- a/lib/BackupPC/Attrib.pm +++ b/lib/BackupPC/Attrib.pm @@ -304,7 +304,13 @@ sub write my($data) = $a->writeData; $file = $a->fileName($dir, $file); - mkpath($dir, 0, 0777) if ( !-d $dir ); + if ( !-d $dir ) { + eval { mkpath($dir, 0, 0777) }; + if ( $@ ) { + $a->{_errStr} = "Can't create directory $dir"; + return; + } + } my $fd = BackupPC::FileZIO->open($file, 1, $a->{compress}); if ( !$fd ) { $a->{_errStr} = "Can't open/write to $file"; diff --git a/lib/BackupPC/CGI/Restore.pm b/lib/BackupPC/CGI/Restore.pm index 6b8755c..1892a95 100644 --- a/lib/BackupPC/CGI/Restore.pm +++ b/lib/BackupPC/CGI/Restore.pm @@ -28,7 +28,7 @@ # #======================================================================== # -# Version 3.1.0, released 25 Nov 2007. +# Version 3.2.0, released 31 Dec 2008. # # See http://backuppc.sourceforge.net. # @@ -337,7 +337,7 @@ EOF [ \%restoreReq], [qw(*RestoreReq)]); $dump->Indent(1); - mkpath("$TopDir/pc/$hostDest", 0, 0777) + eval { mkpath("$TopDir/pc/$hostDest", 0, 0777) } if ( !-d "$TopDir/pc/$hostDest" ); my $openPath = "$TopDir/pc/$hostDest/$reqFileName"; if ( open(REQ, ">", $openPath) ) { diff --git a/lib/BackupPC/Lib.pm b/lib/BackupPC/Lib.pm index e5cb98a..7e63431 100644 --- a/lib/BackupPC/Lib.pm +++ b/lib/BackupPC/Lib.pm @@ -624,7 +624,15 @@ sub RmTreeDefer my($i, $f); return if ( !-e $file ); - mkpath($trashDir, 0, 0777) if ( !-d $trashDir ); + if ( !-d $trashDir ) { + eval { mkpath($trashDir, 0, 0777) }; + if ( $@ ) { + # + # There's no good place to send this error - use stderr + # + print(STDERR "RmTreeDefer: can't create directory $trashDir"); + } + } for ( $i = 0 ; $i < 1000 ; $i++ ) { $f = sprintf("%s/%d_%d_%d", $trashDir, time, $$, $i); next if ( -e $f ); @@ -903,7 +911,10 @@ sub MakeFileLink } elsif ( $newFile && -f $name && (stat($name))[3] == 1 ) { my($newDir); ($newDir = $rawFile) =~ s{(.*)/.*}{$1}; - mkpath($newDir, 0, 0777) if ( !-d $newDir ); + if ( !-d $newDir ) { + eval { mkpath($newDir, 0, 0777) }; + return -5 if ( $@ ); + } return -4 if ( !link($name, $rawFile) ); return 2; } else { diff --git a/lib/BackupPC/PoolWrite.pm b/lib/BackupPC/PoolWrite.pm index 415c67f..3934827 100644 --- a/lib/BackupPC/PoolWrite.pm +++ b/lib/BackupPC/PoolWrite.pm @@ -56,7 +56,7 @@ # #======================================================================== # -# Version 3.1.0, released 25 Nov 2007. +# Version 3.2.0, released 31 Dec 2008. # # See http://backuppc.sourceforge.net. # @@ -95,6 +95,12 @@ sub new # Always unlink any current file in case it is already linked # unlink($fileName) if ( -f $fileName ); + if ( $fileName =~ m{(.*)/.+} && !-d $1 ) { + eval { mkpath($1, 0, 0777) }; + if ( $@ ) { + push(@{$self->{errors}}, "Unable to create directory $1 for $self->{fileName}"); + } + } return $self; } @@ -135,7 +141,7 @@ sub write if ( !defined($a->{base} = $a->{bpc}->MD52Path($a->{digest}, $a->{compress})) ) { push(@{$a->{errors}}, "Unable to get path from '$a->{digest}'" - . " for $a->{fileName}\n"); + . " for $a->{fileName}"); } else { while ( @{$a->{files}} < $MaxFiles ) { my $fh; @@ -176,7 +182,7 @@ sub write 1, $a->{compress}); if ( !defined($a->{fhOut}) ) { push(@{$a->{errors}}, "Unable to open $a->{fileName}" - . " for writing\n"); + . " for writing"); } } } @@ -220,7 +226,7 @@ sub write if ( !$a->{files}[$i]->{fh}->rewind() ) { push(@{$a->{errors}}, "Unable to rewind $a->{files}[$i]->{name}" - . " for compare\n"); + . " for compare"); } $match = $a->filePartialCompare($a->{files}[$i]->{fh}, $fh, $a->{nWrite}, $dataLen, \$a->{data}); @@ -249,12 +255,12 @@ sub write if ( !defined($a->{fhOut}) ) { push(@{$a->{errors}}, "Unable to open $a->{fileName}" - . " for writing\n"); + . " for writing"); } else { if ( !$a->{files}[$i]->{fh}->rewind() ) { push(@{$a->{errors}}, "Unable to rewind" - . " $a->{files}[$i]->{name} for copy\n"); + . " $a->{files}[$i]->{name} for copy"); } $a->filePartialCopy($a->{files}[$i]->{fh}, $a->{fhOut}, $a->{nWrite}); @@ -273,7 +279,7 @@ sub write my $n = $a->{fhOut}->write(\$a->{data}); if ( $n != $dataLen ) { push(@{$a->{errors}}, "Unable to write $dataLen bytes to" - . " $a->{fileName} (got $n)\n"); + . " $a->{fileName} (got $n)"); } } $a->{nWrite} += $dataLen; @@ -322,7 +328,7 @@ sub write || !defined($fh = BackupPC::FileZIO->open($fileName, 0, $a->{compress})) ) { push(@{$a->{errors}}, "Can't rename $a->{fileName} -> $fileName" - . " or open during size fixup\n"); + . " or open during size fixup"); } #print("Using temporary name $fileName\n"); } elsif ( defined($a->{files}) && defined($a->{files}[0]) ) { @@ -347,7 +353,7 @@ sub write if ( $n != $thisRead ) { push(@{$a->{errors}}, "Unable to read $thisRead bytes during resize" - . " from temp $fileName (got $n)\n"); + . " from temp $fileName (got $n)"); last; } $poolWrite->write(\$data); @@ -371,7 +377,7 @@ sub write local(*OUT); if ( !open(OUT, ">", $a->{fileName}) ) { push(@{$a->{errors}}, "Can't open $a->{fileName} for empty" - . " output\n"); + . " output"); } else { close(OUT); } @@ -394,7 +400,7 @@ sub write } else { if ( @{$a->{files}} == 0 ) { push(@{$a->{errors}}, "Botch, no matches on $a->{fileName}" - . " ($a->{digest})\n"); + . " ($a->{digest})"); } elsif ( @{$a->{files}} > 1 ) { # # This is no longer a real error because $Conf{HardLinkMax} @@ -429,7 +435,7 @@ sub write if ( !$a->{files}[$i]->{fh}->rewind() ) { push(@{$a->{errors}}, "Unable to rewind $a->{files}[$i]->{name}" - . " for copy after link fail\n"); + . " for copy after link fail"); next; } $a->{fhOut} = BackupPC::FileZIO->open($a->{fileName}, @@ -437,7 +443,7 @@ sub write if ( !defined($a->{fhOut}) ) { push(@{$a->{errors}}, "Unable to open $a->{fileName}" - . " for writing after link fail\n"); + . " for writing after link fail"); } else { $a->filePartialCopy($a->{files}[$i]->{fh}, $a->{fhOut}, $a->{nWrite}); @@ -501,14 +507,14 @@ sub filePartialCopy if ( $n != $thisRead ) { push(@{$a->{errors}}, "Unable to read $thisRead bytes from " - . $fhIn->name . " (got $n)\n"); + . $fhIn->name . " (got $n)"); return; } $n = $fhOut->write(\$data, $thisRead); if ( $n != $thisRead ) { push(@{$a->{errors}}, "Unable to write $thisRead bytes to " - . $fhOut->name . " (got $n)\n"); + . $fhOut->name . " (got $n)"); return; } $nRead += $thisRead; @@ -531,7 +537,7 @@ sub filePartialCompare $n = $fh0->read(\$data0, $thisRead); if ( $n != $thisRead ) { push(@{$a->{errors}}, "Unable to read $thisRead bytes from " - . $fh0->name . " (got $n)\n"); + . $fh0->name . " (got $n)"); return; } $n = $fh1->read(\$data1, $thisRead); diff --git a/lib/BackupPC/Storage/Text.pm b/lib/BackupPC/Storage/Text.pm index 5c60cf6..09140fe 100644 --- a/lib/BackupPC/Storage/Text.pm +++ b/lib/BackupPC/Storage/Text.pm @@ -30,7 +30,7 @@ # #======================================================================== # -# Version 3.1.0, released 25 Nov 2007. +# Version 3.2.0, released 31 Dec 2008. # # See http://backuppc.sourceforge.net. # @@ -214,7 +214,10 @@ sub TextFileWrite (my $dir = $file) =~ s{(.+)/(.+)}{$1}; - mkpath($dir, 0, 0775) if ( !-d $dir ); + if ( !-d $dir ) { + eval { mkpath($dir, 0, 0775) }; + return "TextFileWrite: can't create directory $dir" if ( $@ ); + } if ( open(FD, ">", "$file.new") ) { binmode(FD); print FD $contents; diff --git a/lib/BackupPC/Xfer/Rsync.pm b/lib/BackupPC/Xfer/Rsync.pm index ff24cd5..f92e667 100644 --- a/lib/BackupPC/Xfer/Rsync.pm +++ b/lib/BackupPC/Xfer/Rsync.pm @@ -29,7 +29,7 @@ # #======================================================================== # -# Version 3.1.0, released 25 Nov 2007. +# Version 3.2.0, released 31 Dec 2008. # # See http://backuppc.sourceforge.net. # @@ -376,7 +376,26 @@ sub run $t->{hostError} = $err; return; } + + # + # This is a hack. To avoid wide chars we encode the arguments + # to utf8 byte streams, then to the client's local charset. + # The second conversion should really go in File::RsyncP, since + # it shouldn't be applied to in-line include/exclude arguments. + # + for ( my $i = 0 ; $i < @{$rs->{rsyncArgs}} ; $i++ ) { + $rs->{rsyncArgs}[$i] = encode('utf8', $rs->{rsyncArgs}[$i]); + from_to($rs->{rsyncArgs}[$i], 'utf8', $conf->{ClientCharset}) + if ( $conf->{ClientCharset} ne "" ); + } + + my $str = "RsyncArgsBefore: " . join(" ", @{$rs->{rsyncArgs}}) . "\n"; + $t->{XferLOG}->write(\$str); + $rs->serverStart($remoteSend, $remoteDirDaemon); + + my $str = "RsyncArgsAfter: " . join(" ", @{$rs->{rsyncArgs}}) . "\n"; + $t->{XferLOG}->write(\$str); } my $shareNameSlash = $t->{shareNameSlash}; from_to($shareNameSlash, "utf8", $conf->{ClientCharset}) diff --git a/lib/BackupPC/Xfer/RsyncFileIO.pm b/lib/BackupPC/Xfer/RsyncFileIO.pm index 16f5fbb..bf52653 100644 --- a/lib/BackupPC/Xfer/RsyncFileIO.pm +++ b/lib/BackupPC/Xfer/RsyncFileIO.pm @@ -602,7 +602,10 @@ sub processClose my($exists, $digest, $outSize, $errs) = $poolWrite->close; $fileName =~ s{^/+}{}; - $fio->log(@$errs) if ( defined($errs) && @$errs ); + if ( defined($errs) && @$errs ) { + $fio->log(@$errs); + $fio->{stats}{errorCnt} += @$errs; + } if ( $doStats ) { $fio->{stats}{TotalFileCnt}++; $fio->{stats}{TotalFileSize} += $origSize; @@ -644,7 +647,7 @@ sub makePath $fio->logFileAction("create", $f) if ( $fio->{logLevel} >= 1 ); $fio->log("makePath($path, 0777)") if ( $fio->{logLevel} >= 5 ); $path = $1 if ( $path =~ /(.*)/s ); - File::Path::mkpath($path, 0, 0777) if ( !-d $path ); + eval { File::Path::mkpath($path, 0, 0777) } if ( !-d $path ); return $fio->attribSet($f) if ( -d $path ); $fio->log("Can't create directory $path"); $fio->{stats}{errorCnt}++;