X-Git-Url: http://git.rot13.org/?p=BackupPC.git;a=blobdiff_plain;f=lib%2FBackupPC%2FLib.pm;h=cef6d9c4046cb905b33f817197f10b20fb15f582;hp=d5438802ee514bd8cfc1ec82bfddcfa9a8d7d5bc;hb=a7e968ce327855f2ba2624ca8517069a936c9b5b;hpb=7dee89bfce659051d486cc66515bb7f22bbc4f09 diff --git a/lib/BackupPC/Lib.pm b/lib/BackupPC/Lib.pm index d543880..cef6d9c 100644 --- a/lib/BackupPC/Lib.pm +++ b/lib/BackupPC/Lib.pm @@ -11,7 +11,7 @@ # Craig Barratt # # COPYRIGHT -# Copyright (C) 2001 Craig Barratt +# Copyright (C) 2001-2003 Craig Barratt # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -29,7 +29,7 @@ # #======================================================================== # -# Version 2.0.0beta1, released 30 Mar 2003. +# Version 2.1.0_CVS, released 3 Jul 2003. # # See http://backuppc.sourceforge.net. # @@ -52,13 +52,13 @@ use Digest::MD5; sub new { my $class = shift; - my($topDir, $installDir) = @_; + my($topDir, $installDir, $noUserCheck) = @_; my $bpc = bless { TopDir => $topDir || '/data/BackupPC', BinDir => $installDir || '/usr/local/BackupPC', LibDir => $installDir || '/usr/local/BackupPC', - Version => '2.0.0beta1', + Version => '2.1.0_CVS', BackupFields => [qw( num type startTime endTime nFiles size nFilesExist sizeExist nFilesNew sizeNew @@ -70,6 +70,9 @@ sub new num startTime endTime result errorMsg nFiles size tarCreateErrs xferErrs )], + ArchiveFields => [qw( + num startTime endTime result errorMsg + )], }, $class; $bpc->{BinDir} .= "/bin"; $bpc->{LibDir} .= "/lib"; @@ -83,6 +86,16 @@ sub new print(STDERR $error, "\n"); return; } + # + # Verify we are running as the correct user + # + if ( !$noUserCheck + && $bpc->{Conf}{BackupPCUserVerify} + && $> != (my $uid = (getpwnam($bpc->{Conf}{BackupPCUser}))[2]) ) { + print("Wrong user: my userid is $>, instead of $uid" + . " ($bpc->{Conf}{BackupPCUser})\n"); + return; + } return $bpc; } @@ -141,32 +154,19 @@ sub verbose return $bpc->{verbose}; } -sub timeStamp -{ - my($bpc, $t, $noPad) = @_; - my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) - = localtime($t || time); - $year += 1900; - $mon++; - return "$year/$mon/$mday " . sprintf("%02d:%02d:%02d", $hour, $min, $sec) - . ($noPad ? "" : " "); -} - # -# An ISO 8601-compliant version of timeStamp. Needed by the -# --newer-mtime argument to GNU tar in BackupPC::Xfer::Tar. -# Also see http://www.w3.org/TR/NOTE-datetime. +# Generate an ISO 8601 format timeStamp (but without the "T"). +# See http://www.w3.org/TR/NOTE-datetime and +# http://www.cl.cam.ac.uk/~mgk25/iso-time.html # -sub timeStampISO +sub timeStamp { my($bpc, $t, $noPad) = @_; my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($t || time); - $year += 1900; - $mon++; - return sprintf("%04d-%02d-%02d ", $year, $mon, $mday) - . sprintf("%02d:%02d:%02d", $hour, $min, $sec) - . ($noPad ? "" : " "); + return sprintf("%04d-%02d-%02d %02d:%02d:%02d", + $year + 1900, $mon + 1, $mday, $hour, $min, $sec) + . ($noPad ? "" : " "); } sub BackupInfoRead @@ -177,9 +177,10 @@ sub BackupInfoRead flock(LOCK, LOCK_EX) if open(LOCK, "$bpc->{TopDir}/pc/$host/LOCK"); if ( open(BK_INFO, "$bpc->{TopDir}/pc/$host/backups") ) { + binmode(BK_INFO); while ( ) { s/[\n\r]+//; - next if ( !/^(\d+\t(incr|full)[\d\t]*$)/ ); + next if ( !/^(\d+\t(incr|full|partial)[\d\t]*$)/ ); $_ = $1; @{$Backups[@Backups]}{@{$bpc->{BackupFields}}} = split(/\t/); } @@ -202,6 +203,7 @@ sub BackupInfoWrite "$bpc->{TopDir}/pc/$host/backups.old") if ( -f "$bpc->{TopDir}/pc/$host/backups" ); if ( open(BK_INFO, ">$bpc->{TopDir}/pc/$host/backups") ) { + binmode(BK_INFO); for ( $i = 0 ; $i < @Backups ; $i++ ) { my %b = %{$Backups[$i]}; printf(BK_INFO "%s\n", join("\t", @b{@{$bpc->{BackupFields}}})); @@ -219,6 +221,7 @@ sub RestoreInfoRead flock(LOCK, LOCK_EX) if open(LOCK, "$bpc->{TopDir}/pc/$host/LOCK"); if ( open(RESTORE_INFO, "$bpc->{TopDir}/pc/$host/restores") ) { + binmode(RESTORE_INFO); while ( ) { s/[\n\r]+//; next if ( !/^(\d+.*)/ ); @@ -244,6 +247,7 @@ sub RestoreInfoWrite "$bpc->{TopDir}/pc/$host/restores.old") if ( -f "$bpc->{TopDir}/pc/$host/restores" ); if ( open(RESTORE_INFO, ">$bpc->{TopDir}/pc/$host/restores") ) { + binmode(RESTORE_INFO); for ( $i = 0 ; $i < @Restores ; $i++ ) { my %b = %{$Restores[$i]}; printf(RESTORE_INFO "%s\n", @@ -254,6 +258,51 @@ sub RestoreInfoWrite close(LOCK); } +sub ArchiveInfoRead +{ + my($bpc, $host) = @_; + local(*ARCHIVE_INFO, *LOCK); + my(@Archives); + + flock(LOCK, LOCK_EX) if open(LOCK, "$bpc->{TopDir}/pc/$host/LOCK"); + if ( open(ARCHIVE_INFO, "$bpc->{TopDir}/pc/$host/archives") ) { + binmode(ARCHIVE_INFO); + while ( ) { + s/[\n\r]+//; + next if ( !/^(\d+.*)/ ); + $_ = $1; + @{$Archives[@Archives]}{@{$bpc->{ArchiveFields}}} = split(/\t/); + } + close(ARCHIVE_INFO); + } + close(LOCK); + return @Archives; +} + +sub ArchiveInfoWrite +{ + my($bpc, $host, @Archives) = @_; + local(*ARCHIVE_INFO, *LOCK); + my($i); + + flock(LOCK, LOCK_EX) if open(LOCK, "$bpc->{TopDir}/pc/$host/LOCK"); + unlink("$bpc->{TopDir}/pc/$host/archives.old") + if ( -f "$bpc->{TopDir}/pc/$host/archives.old" ); + rename("$bpc->{TopDir}/pc/$host/archives", + "$bpc->{TopDir}/pc/$host/archives.old") + if ( -f "$bpc->{TopDir}/pc/$host/archives" ); + if ( open(ARCHIVE_INFO, ">$bpc->{TopDir}/pc/$host/archives") ) { + binmode(ARCHIVE_INFO); + for ( $i = 0 ; $i < @Archives ; $i++ ) { + my %b = %{$Archives[$i]}; + printf(ARCHIVE_INFO "%s\n", + join("\t", @b{@{$bpc->{ArchiveFields}}})); + } + close(ARCHIVE_INFO); + } + close(LOCK); +} + sub ConfigRead { my($bpc, $host) = @_; @@ -325,6 +374,7 @@ sub HostInfoRead "Can't open $bpc->{TopDir}/conf/hosts\n"); return {}; } + binmode(HOST_INFO); while ( ) { s/[\n\r]+//; s/#.*//; @@ -440,7 +490,8 @@ sub RmTreeDefer } # -# Empty the trash directory. Returns 0 if it did nothing. +# Empty the trash directory. Returns 0 if it did nothing, 1 if it +# did something, -1 if it failed to remove all the files. # sub RmTreeTrashEmpty { @@ -450,13 +501,15 @@ sub RmTreeTrashEmpty $cwd = $1 if ( $cwd =~ /(.*)/ ); return if ( !-d $trashDir ); - my $d = DirHandle->new($trashDir) - or carp "Can't read $trashDir: $!"; + my $d = DirHandle->new($trashDir) or carp "Can't read $trashDir: $!"; @files = $d->read; $d->close; @files = grep $_!~/^\.{1,2}$/, @files; return 0 if ( !@files ); $bpc->RmTreeQuiet($trashDir, \@files); + foreach my $f ( @files ) { + return -1 if ( -e $f ); + } chdir($cwd) if ( $cwd ); return 1; } @@ -593,6 +646,7 @@ sub File2MD5 $name = $1 if ( $name =~ /(.*)/ ); return ("", 0) if ( $fileSize == 0 ); return ("", -1) if ( !open(N, $name) ); + binmode(N); $md5->reset(); $md5->add($fileSize); if ( $fileSize > 262144 ) { @@ -712,8 +766,8 @@ sub CheckHostAlive # Return success if the ping cmd is undefined or empty. # if ( $bpc->{Conf}{PingCmd} eq "" ) { - print("CheckHostAlive: return ok because \$Conf{PingCmd} is empty\n") - if ( $bpc->{verbose} ); + print(STDERR "CheckHostAlive: return ok because \$Conf{PingCmd}" + . " is empty\n") if ( $bpc->{verbose} ); return 0; } @@ -728,7 +782,7 @@ sub CheckHostAlive # $s = $bpc->cmdSystemOrEval($pingCmd, undef, $args); if ( $? ) { - print("CheckHostAlive: first ping failed ($?, $!)\n") + print(STDERR "CheckHostAlive: first ping failed ($?, $!)\n") if ( $bpc->{verbose} ); return -1; } @@ -738,7 +792,7 @@ sub CheckHostAlive # $s = $bpc->cmdSystemOrEval($pingCmd, undef, $args); if ( $? ) { - print("CheckHostAlive: second ping failed ($?, $!)\n") + print(STDERR "CheckHostAlive: second ping failed ($?, $!)\n") if ( $bpc->{verbose} ); return -1; } @@ -747,11 +801,11 @@ sub CheckHostAlive } elsif ( $s =~ /time=([\d\.]+)\s*usec/i ) { $ret = $1/1000; } else { - print("CheckHostAlive: can't extract round-trip time (not fatal)\n") - if ( $bpc->{verbose} ); + print(STDERR "CheckHostAlive: can't extract round-trip time" + . " (not fatal)\n") if ( $bpc->{verbose} ); $ret = 0; } - print("CheckHostAlive: returning $ret\n") if ( $bpc->{verbose} ); + print(STDERR "CheckHostAlive: returning $ret\n") if ( $bpc->{verbose} ); return $ret; } @@ -786,9 +840,8 @@ sub NetBiosInfoGet # Skip NetBios check if NmbLookupCmd is emtpy # if ( $bpc->{Conf}{NmbLookupCmd} eq "" ) { - print("NetBiosInfoGet: return $host because \$Conf{NmbLookupCmd}" - . " is empty\n") - if ( $bpc->{verbose} ); + print(STDERR "NetBiosInfoGet: return $host because \$Conf{NmbLookupCmd}" + . " is empty\n") if ( $bpc->{verbose} ); return ($host, undef); } @@ -803,15 +856,14 @@ sub NetBiosInfoGet $netBiosUserName = $1 if ( $2 eq "03" ); # user is last 03 } if ( !defined($netBiosHostName) ) { - print("NetBiosInfoGet: failed: can't parse return string\n") + print(STDERR "NetBiosInfoGet: failed: can't parse return string\n") if ( $bpc->{verbose} ); return; } $netBiosHostName = lc($netBiosHostName); $netBiosUserName = lc($netBiosUserName); - print("NetBiosInfoGet: success, returning host $netBiosHostName," - . " user $netBiosUserName\n") - if ( $bpc->{verbose} ); + print(STDERR "NetBiosInfoGet: success, returning host $netBiosHostName," + . " user $netBiosUserName\n") if ( $bpc->{verbose} ); return ($netBiosHostName, $netBiosUserName); } @@ -832,7 +884,7 @@ sub NetBiosHostIPFind # Skip NetBios lookup if NmbLookupFindHostCmd is emtpy # if ( $bpc->{Conf}{NmbLookupFindHostCmd} eq "" ) { - print("NetBiosHostIPFind: return $host because" + print(STDERR "NetBiosHostIPFind: return $host because" . " \$Conf{NmbLookupFindHostCmd} is empty\n") if ( $bpc->{verbose} ); return $host; @@ -856,12 +908,12 @@ sub NetBiosHostIPFind } $ipAddr = $firstIpAddr if ( !defined($ipAddr) ); if ( defined($ipAddr) ) { - print("NetBiosHostIPFind: found IP address $ipAddr for host $host\n") - if ( $bpc->{verbose} ); + print(STDERR "NetBiosHostIPFind: found IP address $ipAddr for" + . " host $host\n") if ( $bpc->{verbose} ); return $ipAddr; } else { - print("NetBiosHostIPFind: couldn't find IP address for host $host\n") - if ( $bpc->{verbose} ); + print(STDERR "NetBiosHostIPFind: couldn't find IP address for" + . " host $host\n") if ( $bpc->{verbose} ); return; } } @@ -991,7 +1043,7 @@ sub cmdVarSubstitute $arg =~ s{\$(\w+)(\+?)}{ exists($vars->{$1}) && ref($vars->{$1}) ne "ARRAY" ? ($2 eq "+" ? $bpc->shellEscape($vars->{$1}) : $vars->{$1}) - : "\$$1" + : "\$$1$2" }eg; # # Now replicate any array arguments; this just works for just one @@ -1025,17 +1077,17 @@ sub cmdExecOrEval if ( (ref($cmd) eq "ARRAY" ? $cmd->[0] : $cmd) =~ /^\&/ ) { $cmd = join(" ", $cmd) if ( ref($cmd) eq "ARRAY" ); - print("cmdExecOrEval: about to eval perl code $cmd\n") + print(STDERR "cmdExecOrEval: about to eval perl code $cmd\n") if ( $bpc->{verbose} ); eval($cmd); print(STDERR "Perl code fragment for exec shouldn't return!!\n"); exit(1); } else { $cmd = [split(/\s+/, $cmd)] if ( ref($cmd) ne "ARRAY" ); - print("cmdExecOrEval: about to exec ", + print(STDERR "cmdExecOrEval: about to exec ", $bpc->execCmd2ShellCmd(@$cmd), "\n") if ( $bpc->{verbose} ); - exec(@$cmd); + exec(map { m/(.*)/ } @$cmd); # untaint print(STDERR "Exec failed for @$cmd\n"); exit(1); } @@ -1061,18 +1113,18 @@ sub cmdSystemOrEval if ( (ref($cmd) eq "ARRAY" ? $cmd->[0] : $cmd) =~ /^\&/ ) { $cmd = join(" ", $cmd) if ( ref($cmd) eq "ARRAY" ); - print("cmdSystemOrEval: about to eval perl code $cmd\n") + print(STDERR "cmdSystemOrEval: about to eval perl code $cmd\n") if ( $bpc->{verbose} ); $out = eval($cmd); $$stdoutCB .= $out if ( ref($stdoutCB) eq 'SCALAR' ); &$stdoutCB($out) if ( ref($stdoutCB) eq 'CODE' ); - print("cmdSystemOrEval: finished: got output $out\n") + print(STDERR "cmdSystemOrEval: finished: got output $out\n") if ( $bpc->{verbose} ); return $out if ( !defined($stdoutCB) ); return; } else { $cmd = [split(/\s+/, $cmd)] if ( ref($cmd) ne "ARRAY" ); - print("cmdSystemOrEval: about to system ", + print(STDERR "cmdSystemOrEval: about to system ", $bpc->execCmd2ShellCmd(@$cmd), "\n") if ( $bpc->{verbose} ); if ( !defined($pid = open(CHILD, "-|")) ) { @@ -1083,13 +1135,14 @@ sub cmdSystemOrEval return $err if ( !defined($stdoutCB) ); return; } + binmode(CHILD); if ( !$pid ) { # # This is the child # close(STDERR); open(STDERR, ">&STDOUT"); - exec(@$cmd); + exec(map { m/(.*)/ } @$cmd); # untaint print("Exec of @$cmd failed\n"); exit(1); } @@ -1105,7 +1158,7 @@ sub cmdSystemOrEval $? = 0; close(CHILD); } - print("cmdSystemOrEval: finished: got output $allOut\n") + print(STDERR "cmdSystemOrEval: finished: got output $allOut\n") if ( $bpc->{verbose} ); return $out; }