Changes for 2.1.3:
[BackupPC.git] / bin / BackupPC
index 585eec1..b031e65 100755 (executable)
@@ -47,7 +47,7 @@
 #
 #========================================================================
 #
-# Version 2.1.0beta1, released 9 Apr 2004.
+# Version 2.1.3, released 21 Jan 2007.
 #
 # See http://backuppc.sourceforge.net.
 #
@@ -56,7 +56,7 @@
 use strict;
 no  utf8;
 use vars qw(%Status %Info $Hosts);
-use lib "/usr/local/BackupPC/lib";
+use lib "/usr/local/BackupPC2.1.0/lib";
 use BackupPC::Lib;
 use BackupPC::FileZIO;
 
@@ -66,6 +66,7 @@ use Getopt::Std;
 use Socket;
 use Carp;
 use Digest::MD5;
+use POSIX qw(setsid);
 
 ###########################################################################
 # Handle command line options
@@ -260,10 +261,22 @@ sub Main_Initialize
 
     if ( $opts{d} ) {
         #
-        # daemonize by forking
+        # daemonize by forking; more robust method per:
+        #       http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=301057
         #
-        defined(my $pid = fork) or die "Can't fork: $!";
+        my $pid;
+        defined($pid = fork) or die("Can't fork: $!");
+        exit if( $pid );   # parent exits
+
+        POSIX::setsid();
+        defined($pid = fork) or die("Can't fork: $!");
         exit if $pid;   # parent exits
+
+        chdir ("/") or die("Cannot chdir to /: $!\n");
+        close(STDIN);
+        open(STDIN , ">/dev/null") or die("Cannot open /dev/null as stdin\n");
+        # STDOUT and STDERR are handled in LogFileOpen() right below,
+        # otherwise we would have to reopen them too.
     }
 
     #
@@ -546,9 +559,11 @@ sub Main_TryToRun_CmdQueue
 sub Main_TryToRun_Bg_or_User_Queue
 {
     my($req, $host);
+    my(@deferUserQueue, @deferBgQueue);
+
     while ( $RunNightlyWhenIdle == 0 ) {
         local(*FH);
-        my(@args, @deferUserQueue, @deferBgQueue, $progName, $type);
+        my(@args, $progName, $type);
         my $nJobs = keys(%Jobs);
         #
         # CmdJob and trashClean don't count towards MaxBackups / MaxUserBackups
@@ -596,7 +611,7 @@ sub Main_TryToRun_Bg_or_User_Queue
             if ( $du > $Conf{DfMaxUsagePct} ) {
                 my $nSkip = @BgQueue + @deferBgQueue;
                 print(LOG $bpc->timeStamp,
-                           "Disk too full ($du%%); skipping $nSkip hosts\n");
+                           "Disk too full ($du%); skipping $nSkip hosts\n");
                $Info{DUDailySkipHostCnt} += $nSkip;
                 @BgQueue = ();
                 @deferBgQueue = ();
@@ -782,6 +797,8 @@ sub Main_Check_Timeout
         }
         print(LOG $bpc->timeStamp, "Aging LOG files, LOG -> LOG.0 -> "
                    . "LOG.1 -> ... -> LOG.$lastLog\n");
+       close(STDERR);          # dup of LOG
+       close(STDOUT);          # dup of LOG
         close(LOG);
         for ( my $i = $lastLog - 1 ; $i >= 0 ; $i-- ) {
             my $j = $i + 1;
@@ -920,6 +937,7 @@ sub Main_Check_Job_Messages
                 delete($Status{$host}{error});
                 delete($Status{$host}{errorTime});
                 $Status{$host}{endTime}   = time;
+                $Status{$host}{lastGoodBackupTime} = time;
             } elsif ( $mesg =~ /^backups disabled/ ) {
                 print(LOG $bpc->timeStamp,
                            "Ignoring old backup error on $host\n");
@@ -1531,6 +1549,37 @@ sub StatusWrite
     }
 }
 
+#
+# Compare function for host sort.  Hosts with errors go first,
+# sorted with the oldest errors first.  The remaining hosts
+# are sorted so that those with the oldest backups go first.
+#
+sub HostSortCompare
+{
+    #
+    # Hosts with errors go before hosts without errors
+    #
+    return -1 if ( $Status{$a}{error} ne "" && $Status{$b}{error} eq "" );
+
+    #
+    # Hosts with no errors go after hosts with errors
+    #
+
+    return  1 if ( $Status{$a}{error} eq "" && $Status{$b}{error} ne "" );
+
+    #
+    # hosts with the older last good backups sort earlier
+    #
+    my $r = $Status{$a}{lastGoodBackupTime} <=> $Status{$b}{lastGoodBackupTime};
+    return $r if ( $r );
+
+    #
+    # Finally, just sort based on host name
+    #
+    return $a cmp $b;
+}
+
+
 #
 # Queue all the hosts for backup.  This means queuing all the fixed
 # ip hosts and all the dhcp address ranges.  We also additionally
@@ -1538,7 +1587,7 @@ sub StatusWrite
 #
 sub QueueAllPCs
 {
-    foreach my $host ( sort(keys(%$Hosts)) ) {
+    foreach my $host ( sort(HostSortCompare keys(%$Hosts)) ) {
         delete($Status{$host}{backoffTime})
                 if ( defined($Status{$host}{backoffTime})
                   && $Status{$host}{backoffTime} < time );
@@ -1792,6 +1841,7 @@ sub ServerShutdown
         }
         %Jobs = ();
     }
+    delete($Info{pid});
     StatusWrite();
     unlink("$TopDir/log/BackupPC.pid");
     exit(1);