* Commit for 2.1.0.
[BackupPC.git] / lib / BackupPC / Lib.pm
index fe31429..5ad2770 100644 (file)
@@ -29,7 +29,7 @@
 #
 #========================================================================
 #
-# Version 2.1.0_CVS, released 3 Jul 2003.
+# Version 2.1.0, released 20 Jun 2004.
 #
 # See http://backuppc.sourceforge.net.
 #
@@ -48,6 +48,7 @@ use File::Compare;
 use Socket;
 use Cwd;
 use Digest::MD5;
+use Config;
 
 sub new
 {
@@ -58,7 +59,7 @@ sub new
         TopDir  => $topDir || '/data/BackupPC',
         BinDir  => $installDir || '/usr/local/BackupPC',
         LibDir  => $installDir || '/usr/local/BackupPC',
-        Version => '2.1.0_CVS',
+        Version => '2.1.0',
         BackupFields => [qw(
                     num type startTime endTime
                     nFiles size nFilesExist sizeExist nFilesNew sizeNew
@@ -92,7 +93,7 @@ sub new
     if ( !$noUserCheck
            && $bpc->{Conf}{BackupPCUserVerify}
            && $> != (my $uid = (getpwnam($bpc->{Conf}{BackupPCUser}))[2]) ) {
-       print("Wrong user: my userid is $>, instead of $uid"
+       print(STDERR "Wrong user: my userid is $>, instead of $uid"
            . " ($bpc->{Conf}{BackupPCUser})\n");
        return;
     }
@@ -131,7 +132,15 @@ sub Lang
 
 sub adminJob
 {
-    return " admin ";
+    my($bpc, $num) = @_;
+    return " admin " if ( !$num );
+    return " admin$num ";
+}
+
+sub isAdminJob
+{
+    my($bpc, $str) = @_;
+    return $str =~ /^ admin/;
 }
 
 sub trashJob
@@ -154,6 +163,20 @@ sub verbose
     return $bpc->{verbose};
 }
 
+sub sigName2num
+{
+    my($bpc, $sig) = @_;
+
+    if ( !defined($bpc->{SigName2Num}) ) {
+       my $i = 0;
+       foreach my $name ( split(' ', $Config{sig_name}) ) {
+           $bpc->{SigName2Num}{$name} = $i;
+           $i++;
+       }
+    }
+    return $bpc->{SigName2Num}{$sig};
+}
+
 #
 # Generate an ISO 8601 format timeStamp (but without the "T").
 # See http://www.w3.org/TR/NOTE-datetime and
@@ -197,11 +220,13 @@ sub BackupInfoWrite
     my($i);
 
     flock(LOCK, LOCK_EX) if open(LOCK, "$bpc->{TopDir}/pc/$host/LOCK");
-    unlink("$bpc->{TopDir}/pc/$host/backups.old")
-                if ( -f "$bpc->{TopDir}/pc/$host/backups.old" );
-    rename("$bpc->{TopDir}/pc/$host/backups",
-           "$bpc->{TopDir}/pc/$host/backups.old")
-                if ( -f "$bpc->{TopDir}/pc/$host/backups" );
+    if ( -s "$bpc->{TopDir}/pc/$host/backups" ) {
+       unlink("$bpc->{TopDir}/pc/$host/backups.old")
+                   if ( -f "$bpc->{TopDir}/pc/$host/backups.old" );
+       rename("$bpc->{TopDir}/pc/$host/backups",
+              "$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++ ) {
@@ -241,11 +266,13 @@ sub RestoreInfoWrite
     my($i);
 
     flock(LOCK, LOCK_EX) if open(LOCK, "$bpc->{TopDir}/pc/$host/LOCK");
-    unlink("$bpc->{TopDir}/pc/$host/restores.old")
-                if ( -f "$bpc->{TopDir}/pc/$host/restores.old" );
-    rename("$bpc->{TopDir}/pc/$host/restores",
-           "$bpc->{TopDir}/pc/$host/restores.old")
-                if ( -f "$bpc->{TopDir}/pc/$host/restores" );
+    if ( -s "$bpc->{TopDir}/pc/$host/restores" ) {
+       unlink("$bpc->{TopDir}/pc/$host/restores.old")
+                   if ( -f "$bpc->{TopDir}/pc/$host/restores.old" );
+       rename("$bpc->{TopDir}/pc/$host/restores",
+              "$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++ ) {
@@ -286,11 +313,13 @@ sub ArchiveInfoWrite
     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 ( -s "$bpc->{TopDir}/pc/$host/archives" ) {
+       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++ ) {
@@ -434,7 +463,7 @@ sub RmTreeQuiet
     if ( defined($roots) && length($roots) ) {
       $roots = [$roots] unless ref $roots;
     } else {
-      print "RmTreeQuiet: No root path(s) specified\n";
+      print(STDERR "RmTreeQuiet: No root path(s) specified\n");
     }
     chdir($pwd);
     foreach $root (@{$roots}) {
@@ -447,14 +476,17 @@ sub RmTreeQuiet
        #
        if ( !unlink($root) ) {
             if ( -d $root ) {
-                my $d = DirHandle->new($root)
-                  or print "Can't read $pwd/$root: $!";
-                @files = $d->read;
-                $d->close;
-                @files = grep $_!~/^\.{1,2}$/, @files;
-                $bpc->RmTreeQuiet("$pwd/$root", \@files);
-                chdir($pwd);
-                rmdir($root) || rmdir($root);
+                my $d = DirHandle->new($root);
+               if ( !defined($d) ) {
+                   print(STDERR "Can't read $pwd/$root: $!\n");
+               } else {
+                   @files = $d->read;
+                   $d->close;
+                   @files = grep $_!~/^\.{1,2}$/, @files;
+                   $bpc->RmTreeQuiet("$pwd/$root", \@files);
+                   chdir($pwd);
+                   rmdir($root) || rmdir($root);
+               }
             } else {
                 unlink($root) || unlink($root);
             }
@@ -1088,7 +1120,12 @@ sub cmdExecOrEval
        print(STDERR "cmdExecOrEval: about to exec ",
              $bpc->execCmd2ShellCmd(@$cmd), "\n")
                        if ( $bpc->{verbose} );
-        exec(map { m/(.*)/ } @$cmd);           # untaint
+       alarm(0);
+       $cmd = [map { m/(.*)/ } @$cmd];         # untaint
+       #
+       # force list-form of exec(), ie: no shell even for 1 arg
+       #
+        exec { $cmd->[0] } @$cmd;
         print(STDERR "Exec failed for @$cmd\n");
         exit(1);
     }
@@ -1106,9 +1143,9 @@ sub cmdExecOrEval
 #
 # Also, $? should be set when the CHILD pipe is closed.
 #
-sub cmdSystemOrEval
+sub cmdSystemOrEvalLong
 {
-    my($bpc, $cmd, $stdoutCB, @args) = @_;
+    my($bpc, $cmd, $stdoutCB, $ignoreStderr, $pidHandlerCB, @args) = @_;
     my($pid, $out, $allOut);
     local(*CHILD);
     
@@ -1142,11 +1179,26 @@ sub cmdSystemOrEval
            # This is the child
            #
             close(STDERR);
-           open(STDERR, ">&STDOUT");
-           exec(map { m/(.*)/ } @$cmd);                # untaint
-            print("Exec of @$cmd failed\n");
+           if ( $ignoreStderr ) {
+               open(STDERR, ">", "/dev/null");
+           } else {
+               open(STDERR, ">&STDOUT");
+           }
+           alarm(0);
+           $cmd = [map { m/(.*)/ } @$cmd];             # untaint
+           #
+           # force list-form of exec(), ie: no shell even for 1 arg
+           #
+           exec { $cmd->[0] } @$cmd;
+            print(STDERR "Exec of @$cmd failed\n");
             exit(1);
        }
+
+       #
+       # Notify caller of child's pid
+       #
+       &$pidHandlerCB($pid) if ( ref($pidHandlerCB) eq "CODE" );
+
        #
        # The parent gathers the output from the child
        #
@@ -1164,4 +1216,34 @@ sub cmdSystemOrEval
     return $out;
 }
 
+#
+# The shorter version that sets $ignoreStderr = 0, ie: merges stdout
+# and stderr together.
+#
+sub cmdSystemOrEval
+{
+    my($bpc, $cmd, $stdoutCB, @args) = @_;
+
+    return $bpc->cmdSystemOrEvalLong($cmd, $stdoutCB, 0, undef, @args);
+}
+
+
+#
+# Promotes $conf->{BackupFilesOnly}, $conf->{BackupFilesExclude}
+# to hashes and $conf->{$shareName} to an array
+#
+sub backupFileConfFix
+{
+    my($bpc, $conf, $shareName) = @_;
+
+    $conf->{$shareName} = [ $conf->{$shareName} ]
+                    if ( ref($conf->{$shareName}) ne "ARRAY" );
+    foreach my $param qw(BackupFilesOnly BackupFilesExclude) {
+        next if ( !defined($conf->{$param}) || ref($conf->{$param}) eq "HASH" );
+        $conf->{$param} = [ $conf->{$param} ]
+                               if ( ref($conf->{$param}) ne "ARRAY" );
+        $conf->{$param} = { map { $_ => $conf->{$param} }                                                       @{$conf->{$shareName}} };
+    }
+}
+
 1;