# Craig Barratt <cbarratt@users.sourceforge.net>
#
# COPYRIGHT
-# Copyright (C) 2001-2003 Craig Barratt
+# Copyright (C) 2001-2007 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
#
#========================================================================
#
-# Version 3.0.0, released 28 Jan 2007.
+# Version 3.2.0beta0, released 17 Jan 2009.
#
# See http://backuppc.sourceforge.net.
#
use lib "/usr/local/BackupPC/lib";
use BackupPC::Lib;
use BackupPC::FileZIO;
-use Encode;
+use Encode qw/decode_utf8/;
use File::Path;
use Data::Dumper;
umask($Conf{UmaskMode});
#
- # Check for another running process, check that PASSWD is set and
- # verify executables are configured correctly.
+ # Check for another running process, verify executables are configured
+ # correctly and make sure $TopDir is on a file system that supports
+ # hardlinks.
#
if ( $Info{pid} ne "" && kill(0, $Info{pid}) ) {
print(STDERR $bpc->timeStamp,
"Another BackupPC is running (pid $Info{pid}); quitting...\n");
exit(1);
}
+
foreach my $progName ( qw(SmbClientPath NmbLookupPath PingPath DfPath
SendmailPath SshPath) ) {
next if ( $Conf{$progName} eq "" || -x $Conf{$progName} );
exit(1);
}
+ if ( !$bpc->HardlinkTest("$TopDir/pc", "$TopDir/cpool") ) {
+ print(STDERR $bpc->timeStamp, "Can't create a test hardlink between a file"
+ . " in $TopDir/pc and $TopDir/cpool. Either these are different"
+ . " file systems, or this file system doesn't support hardlinks,"
+ . " or these directories don't exist, or there is a permissions"
+ . " problem, or the file system is out of inodes or full. Use"
+ . " df, df -i, and ls -ld to check each of these possibilities."
+ . " Quitting...\n");
+ exit(1);
+ }
+
if ( $opts{d} ) {
#
# daemonize by forking; more robust method per:
$CmdQueueOn{$bpc->trashJob} = 1;
}
if ( $RunNightlyWhenIdle == 1 ) {
-
#
# Queue multiple nightly jobs based on the configuration
#
$start = $start0 + int(($end - $start0)
* ($i + 1) / $Conf{MaxBackupPCNightlyJobs});
push(@$cmd, $start - 1);
-
my $job = $bpc->adminJob($i);
unshift(@CmdQueue, {
host => $job,
}
if ( !$pid ) {
setpgrp 0,0;
+ $ENV{BPC_REQUSER} = $req->{user};
+ POSIX::nice($Conf{CmdQueueNice}) if ( $Conf{CmdQueueNice} );
exec(@$cmd);
print(LOG $bpc->timeStamp, "can't exec @$cmd for $host\n");
exit(0);
# 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
if ( $Status{$host}{dhcpCheckCnt} > 0 );
} elsif ( $mesg =~ /^xferPids (.*)/ ) {
$Jobs{$host}{xferPid} = $1;
+ } elsif ( $mesg =~ /^completionPercent (.*)/ ) {
+ $Jobs{$host}{completionPercent} = $1;
} elsif ( $mesg =~ /^started_restore/ ) {
$Jobs{$host}{type} = "restore";
print(LOG $bpc->timeStamp,
QueueAllPCs();
} elsif ( $cmd =~ /^BackupPC_nightly run$/ ) {
$RunNightlyWhenIdle = 1;
+ } elsif ( $cmd =~ /^queue (\S+)$/ ) {
+ $host = $1;
+ $host = $bpc->uriUnesc($host);
+ if ( !defined($Hosts->{$host}) ) {
+ print(LOG $bpc->timeStamp,
+ "User requested backup of unknown host $host\n");
+ $reply = "error: unknown host $host";
+ } else {
+ if ( QueueOnePC($host) ) {
+ print(LOG $bpc->timeStamp,
+ "Disk too full ($Info{DUlastValue}%); skipped 1 host\n");
+ $Info{DUDailySkipHostCnt}++;
+ $reply = "error: disk too full to queue $host";
+ } else {
+ print(LOG $bpc->timeStamp, "Host $host queued by user.\n");
+ $reply = "ok: $host queued";
+ }
+ }
} elsif ( $cmd =~ /^backup (\S+)\s+(\S+)\s+(\S+)\s+(\S+)/ ) {
my $hostIP = $1;
$host = $2;
my $doFull = $4;
$host = $bpc->uriUnesc($host);
$hostIP = $bpc->uriUnesc($hostIP);
- if ( !defined($Status{$host}) ) {
+ if ( !defined($Hosts->{$host}) ) {
print(LOG $bpc->timeStamp,
"User $user requested backup of unknown host"
. " $host\n");
my $reqFileName = $4;
$host = $bpc->uriUnesc($host);
$hostIP = $bpc->uriUnesc($hostIP);
- if ( !defined($Status{$host}) ) {
+ if ( !defined($Hosts->{$host}) ) {
print(LOG $bpc->timeStamp,
"User $user requested restore to unknown host"
. " $host");
[ \%Info, \%Status],
[qw(*Info *Status)]);
$dump->Indent(1);
- if ( open(STATUS, ">", "$LogDir/status.pl") ) {
- print(STATUS $dump->Dump);
- close(STATUS);
- }
+ my $text = $dump->Dump;
+ $bpc->{storage}->TextFileWrite("$LogDir/status.pl", $text);
}
#
#
# Hosts with no errors go after hosts with errors
#
-
return 1 if ( $Status{$a}{error} eq "" && $Status{$b}{error} ne "" );
#
return $a cmp $b;
}
+sub QueueOnePC
+{
+ my($host) = @_;
+ my $skipped = 0;
+
+ delete($Status{$host}{backoffTime})
+ if ( defined($Status{$host}{backoffTime})
+ && $Status{$host}{backoffTime} < time );
+ return if ( defined($Jobs{$host})
+ || $BgQueueOn{$host}
+ || $UserQueueOn{$host}
+ || $CmdQueueOn{$host} );
+ if ( $Hosts->{$host}{dhcp} ) {
+ $Status{$host}{dhcpCheckCnt}++;
+ if ( $RunNightlyWhenIdle ) {
+ #
+ # Once per night queue a check for DHCP hosts that just
+ # checks for expired dumps. We need to do this to handle
+ # the case when a DHCP host has not been on the network for
+ # a long time, and some of the old dumps need to be expired.
+ # Normally expiry checks are done by BackupPC_dump only
+ # after the DHCP hosts has been detected on the network.
+ #
+ unshift(@BgQueue,
+ {host => $host, user => "BackupPC", reqTime => time,
+ dhcp => 0, dumpExpire => 1});
+ $BgQueueOn{$host} = 1;
+ }
+ } else {
+ #
+ # this is a fixed ip host: queue it
+ #
+ if ( $Info{DUlastValue} > $Conf{DfMaxUsagePct} ) {
+ #
+ # Since we are out of disk space, instead of queuing
+ # a regular job, queue an expire check instead. That
+ # way if the admin reduces the number of backups to
+ # keep then we will actually delete them. Otherwise
+ # BackupPC_dump will never run since we have exceeded
+ # the limit.
+ #
+ $skipped = 1;
+ unshift(@BgQueue,
+ {host => $host, user => "BackupPC", reqTime => time,
+ dhcp => $Hosts->{$host}{dhcp}, dumpExpire => 1});
+ } else {
+ #
+ # Queue regular background backup
+ #
+ unshift(@BgQueue,
+ {host => $host, user => "BackupPC", reqTime => time,
+ dhcp => $Hosts->{$host}{dhcp}});
+ }
+ $BgQueueOn{$host} = 1;
+ }
+
+ return $skipped;
+}
+
#
# Queue all the hosts for backup. This means queuing all the fixed
# ip hosts and all the dhcp address ranges. We also additionally
sub QueueAllPCs
{
my $nSkip = 0;
+
foreach my $host ( sort(HostSortCompare keys(%$Hosts)) ) {
- delete($Status{$host}{backoffTime})
- if ( defined($Status{$host}{backoffTime})
- && $Status{$host}{backoffTime} < time );
- next if ( defined($Jobs{$host})
- || $BgQueueOn{$host}
- || $UserQueueOn{$host}
- || $CmdQueueOn{$host} );
- if ( $Hosts->{$host}{dhcp} ) {
- $Status{$host}{dhcpCheckCnt}++;
- if ( $RunNightlyWhenIdle ) {
- #
- # Once per night queue a check for DHCP hosts that just
- # checks for expired dumps. We need to do this to handle
- # the case when a DHCP host has not been on the network for
- # a long time, and some of the old dumps need to be expired.
- # Normally expiry checks are done by BackupPC_dump only
- # after the DHCP hosts has been detected on the network.
- #
- unshift(@BgQueue,
- {host => $host, user => "BackupPC", reqTime => time,
- dhcp => 0, dumpExpire => 1});
- $BgQueueOn{$host} = 1;
- }
- } else {
- #
- # this is a fixed ip host: queue it
- #
- if ( $Info{DUlastValue} > $Conf{DfMaxUsagePct} ) {
- #
- # Since we are out of disk space, instead of queuing
- # a regular job, queue an expire check instead. That
- # way if the admin reduces the number of backups to
- # keep then we will actually delete them. Otherwise
- # BackupPC_dump will never run since we have exceeded
- # the limit.
- #
- $nSkip++;
- unshift(@BgQueue,
- {host => $host, user => "BackupPC", reqTime => time,
- dhcp => $Hosts->{$host}{dhcp}, dumpExpire => 1});
- } else {
- #
- # Queue regular background backup
- #
- unshift(@BgQueue,
- {host => $host, user => "BackupPC", reqTime => time,
- dhcp => $Hosts->{$host}{dhcp}});
- }
- $BgQueueOn{$host} = 1;
- }
+ $nSkip += QueueOnePC($host);
}
if ( $nSkip ) {
print(LOG $bpc->timeStamp,