"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "bin/BackupPC_dump" between
BackupPC-4.3.2.tar.gz and BackupPC-4.4.0.tar.gz

About: BackupPC is a high-performance, enterprise-grade system for backing up Linux and WinXX PCs and laptops to a server’s disk (http/cgi user interface).

BackupPC_dump  (BackupPC-4.3.2):BackupPC_dump  (BackupPC-4.4.0)
skipping to change at line 93 skipping to change at line 93
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
#======================================================================== #========================================================================
# #
# Version 4.3.2, released 17 Feb 2020. # Version 4.4.0, released 20 Jun 2020.
# #
# See http://backuppc.sourceforge.net. # See http://backuppc.sourceforge.net.
# #
#======================================================================== #========================================================================
use strict; use strict;
no utf8; no utf8;
use lib "__INSTALLDIR__/lib"; use lib "__INSTALLDIR__/lib";
use BackupPC::DirOps; use BackupPC::DirOps;
use BackupPC::Lib; use BackupPC::Lib;
use BackupPC::Storage; use BackupPC::Storage;
use BackupPC::Xfer; use BackupPC::Xfer;
use BackupPC::XS; use BackupPC::XS;
use Data::Dumper; use Data::Dumper;
use Encode; use Encode;
use Errno qw(EINTR); use Errno qw(EINTR);
use Socket; use Socket;
use File::Path; use File::Path;
use File::Find; use File::Find;
use Getopt::Std; use Getopt::Std;
########################################################################### ###########################################################################
# Initialize # Initialize
########################################################################### ###########################################################################
die("BackupPC::Lib->new failed\n") if ( !(my $bpc = BackupPC::Lib->new) ); die("BackupPC::Lib->new failed\n") if ( !(my $bpc = BackupPC::Lib->new) );
my $TopDir = $bpc->TopDir(); my $TopDir = $bpc->TopDir();
my $BinDir = $bpc->BinDir(); my $BinDir = $bpc->BinDir();
my %Conf = $bpc->Conf(); my %Conf = $bpc->Conf();
my $NeedPostCmd; my $NeedPostCmd;
my $Hosts; my $Hosts;
my $SigName; my $SigName;
my $Abort = 0; my $Abort = 0;
my $LockFd; my $LockFd;
$bpc->ChildInit(); $bpc->ChildInit();
skipping to change at line 168 skipping to change at line 170
} }
if ( $ARGV[0] !~ /^([\w\.\s-]+)$/ ) { if ( $ARGV[0] !~ /^([\w\.\s-]+)$/ ) {
print("$0: bad client name '$ARGV[0]'\n"); print("$0: bad client name '$ARGV[0]'\n");
exit(1); exit(1);
} }
if ( (defined($opts{f}) + defined($opts{i}) + defined($opts{F}) + defined($opts{ I})) > 1 ) { if ( (defined($opts{f}) + defined($opts{i}) + defined($opts{F}) + defined($opts{ I})) > 1 ) {
print("$0: exiting because you can only use one of -f, -i, -F, and -I\n"); print("$0: exiting because you can only use one of -f, -i, -F, and -I\n");
exit(1); exit(1);
} }
my $client = $1; # BackupPC's client name (might not be real host name) my $client = $1; # BackupPC's client name (might not be real host name)
my $hostIP; # this is the IP address my $hostIP; # this is the IP address
my $host; # this is the real host name my $host; # this is the real host name
my($clientURI, $user); my($clientURI, $user);
$bpc->verbose(1) if ( $opts{v} ); $bpc->verbose(1) if ( $opts{v} );
if ( $opts{d} ) { if ( $opts{d} ) {
# #
# The client name $client is simply a DHCP address. We need to check # The client name $client is simply a DHCP address. We need to check
# if there is any machine at this address, and if so, get the actual # if there is any machine at this address, and if so, get the actual
# host name via NetBios using nmblookup. # host name via NetBios using nmblookup.
# #
$hostIP = $client; $hostIP = $client;
if ( $bpc->CheckHostAlive($hostIP) < 0 ) { if ( $bpc->CheckHostAlive($hostIP) < 0 ) {
print("Exiting because CheckHostAlive($hostIP) failed\n") print("Exiting because CheckHostAlive($hostIP) failed\n")
if ( $opts{v} ); if ( $opts{v} );
exit(1); exit(1);
} }
if ( $Conf{NmbLookupCmd} eq "" ) { if ( $Conf{NmbLookupCmd} eq "" ) {
print("Exiting because \$Conf{NmbLookupCmd} is empty\n") print("Exiting because \$Conf{NmbLookupCmd} is empty\n")
if ( $opts{v} ); if ( $opts{v} );
exit(1); exit(1);
} }
($client, $user) = $bpc->NetBiosInfoGet($hostIP); ($client, $user) = $bpc->NetBiosInfoGet($hostIP);
if ( $client !~ /^([\w\.\s-]+)$/ ) { if ( $client !~ /^([\w\.\s-]+)$/ ) {
print("Exiting because NetBiosInfoGet($hostIP) returned" print("Exiting because NetBiosInfoGet($hostIP) returned '$client', an in
. " '$client', an invalid host name\n") if ( $opts{v} ); valid host name\n")
exit(1) if ( $opts{v} );
exit(1);
} }
$Hosts = $bpc->HostInfoRead($client); $Hosts = $bpc->HostInfoRead($client);
$host = $client; $host = $client;
} else { } else {
$Hosts = $bpc->HostInfoRead($client); $Hosts = $bpc->HostInfoRead($client);
} }
if ( !defined($Hosts->{$client}) ) { if ( !defined($Hosts->{$client}) ) {
print("Exiting because host $client does not exist in the" print("Exiting because host $client does not exist in the hosts file\n") if
. " hosts file\n") if ( $opts{v} ); ( $opts{v} );
exit(1) exit(1);
} }
my $Dir = "$TopDir/pc/$client"; my $Dir = "$TopDir/pc/$client";
my @xferPid = (); my @xferPid = ();
my $tarPid = -1; my $tarPid = -1;
# #
# Re-read config file, so we can include the PC-specific config # Re-read config file, so we can include the PC-specific config
# #
$clientURI = $bpc->uriEsc($client); $clientURI = $bpc->uriEsc($client);
skipping to change at line 265 skipping to change at line 266
# For the -e option we just expire backups and quit # For the -e option we just expire backups and quit
# #
if ( $opts{e} ) { if ( $opts{e} ) {
BackupExpire($client); BackupExpire($client);
exit(0); exit(0);
} }
# #
# For archive hosts we don't bother any further # For archive hosts we don't bother any further
# #
if ($Conf{XferMethod} eq "archive" ) { if ( $Conf{XferMethod} eq "archive" ) {
print("Exiting because the XferMethod is set to archive\n") print("Exiting because the XferMethod is set to archive\n")
if ( $opts{v} ); if ( $opts{v} );
exit(0); exit(0);
} }
########################################################################### ###########################################################################
# Figure out what to do and do it # Figure out what to do and do it
########################################################################### ###########################################################################
# #
# See if we should skip this host during a certain range # See if we should skip this host during a certain range
# of times. # of times.
skipping to change at line 289 skipping to change at line 290
my $err = $bpc->ServerConnect($Conf{ServerHost}, $Conf{ServerPort}); my $err = $bpc->ServerConnect($Conf{ServerHost}, $Conf{ServerPort});
if ( $err ne "" ) { if ( $err ne "" ) {
print("Can't connect to server ($err)\n"); print("Can't connect to server ($err)\n");
print($LogFd $bpc->timeStamp, "Can't connect to server ($err)\n"); print($LogFd $bpc->timeStamp, "Can't connect to server ($err)\n");
exit(1); exit(1);
} }
my $reply = $bpc->ServerMesg("status host($clientURI)"); my $reply = $bpc->ServerMesg("status host($clientURI)");
$reply = $1 if ( $reply =~ /(.*)/s ); $reply = $1 if ( $reply =~ /(.*)/s );
my(%StatusHost); my(%StatusHost);
eval($reply); eval($reply);
if ( !$opts{m} && (my $status = $bpc->ServerMesg("hostMutex $client -1 BackupPC_
dump")) =~ /fail/ ) {
print(STDERR "$0: $status (use -m option to force running)\n");
exit(1);
}
# #
# For DHCP tell BackupPC which host this is # For DHCP tell BackupPC which host this is
# #
if ( $opts{d} ) { if ( $opts{d} ) {
if ( $StatusHost{activeJob} ) { if ( $StatusHost{activeJob} ) {
# oops, something is already running for this host print(STDERR "$0: exiting because backup is already running for $client\
print("Exiting because backup is already running for $client\n") n");
if ( $opts{v} ); exit(1);
exit(0);
} }
print("DHCP $hostIP $clientURI\n"); if ( (my $status = $bpc->ServerMesg("DHCP $hostIP $clientURI")) =~ /fail/ )
{
print(STDERR "$0: $status; exiting\n");
exit(1);
}
}
if ( !$opts{m} && (my $status = $bpc->ServerMesg("hostMutex $client -1 BackupPC_
dump")) =~ /fail/ ) {
print(STDERR "$0: $status (use -m option to force running)\n");
exit(1);
} }
my(@Backups, $type); my(@Backups, $type);
my $lastFullTime = 0; my $lastFullTime = 0;
my $lastIncrTime = 0; my $lastIncrTime = 0;
my($incrBaseTime, $incrBaseBkupNum); my($incrBaseTime, $incrBaseBkupNum);
my($lastBkupIdx, $lastBkupNum, $lastBkupType, $lastBkupCompressLevel, $prevBkupI dx); my($lastBkupIdx, $lastBkupNum, $lastBkupType, $lastBkupCompressLevel, $prevBkupI dx);
my($newBkupNum, $newBkupIdx, $preV4, $noFillCnt); my($newBkupNum, $newBkupIdx, $preV4, $noFillCnt);
my $inodeLast = 1; my $inodeLast = 1;
# #
# Maintain backward compatibility with $Conf{FullPeriod} == -1 or -2 # Maintain backward compatibility with $Conf{FullPeriod} == -1 or -2
# meaning disable backups # meaning disable backups
# #
$Conf{BackupsDisable} = -$Conf{FullPeriod} $Conf{BackupsDisable} = -$Conf{FullPeriod}
if ( !$Conf{BackupsDisable} && $Conf{FullPeriod} < 0 ); if ( !$Conf{BackupsDisable} && $Conf{FullPeriod} < 0 );
if ( $Conf{BackupsDisable} == 1 && !$opts{f} && !$opts{i} if ( $Conf{BackupsDisable} == 1 && !$opts{f} && !$opts{i}
|| $Conf{BackupsDisable} == 2 ) { || $Conf{BackupsDisable} == 2 ) {
print("Exiting because backups are disabled with" print("Exiting because backups are disabled with \$Conf{BackupsDisable} = $C
. " \$Conf{BackupsDisable} = $Conf{BackupsDisable}\n") if ( $opts{v} ); onf{BackupsDisable}\n")
if ( $opts{v} );
# #
# Tell BackupPC to ignore old failed backups on hosts that # Tell BackupPC to ignore old failed backups on hosts that
# have backups disabled. # have backups disabled.
# #
print("backups disabled\n") print("backups disabled\n")
if ( defined($StatusHost{errorTime}) if ( defined($StatusHost{errorTime})
&& $StatusHost{reason} ne "Reason_backup_done" && $StatusHost{reason} ne "Reason_backup_done"
&& time - $StatusHost{errorTime} > 4 * 24 * 3600 ); && time - $StatusHost{errorTime} > 4 * 24 * 3600 );
NothingToDo(); NothingToDo();
} }
if ( !$opts{i} && !$opts{f} && $Conf{BlackoutGoodCnt} >= 0 if ( !$opts{i}
&& $StatusHost{aliveCnt} >= $Conf{BlackoutGoodCnt} ) { && !$opts{f}
my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); && $Conf{BlackoutGoodCnt} >= 0
&& $StatusHost{aliveCnt} >= $Conf{BlackoutGoodCnt} ) {
my($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(
time);
my($currHours) = $hour + $min / 60 + $sec / 3600; my($currHours) = $hour + $min / 60 + $sec / 3600;
my $blackout; my $blackout;
foreach my $p ( @{$Conf{BlackoutPeriods}} ) { foreach my $p ( @{$Conf{BlackoutPeriods}} ) {
# #
# Allow blackout to span midnight (specified by hourBegin # Allow blackout to span midnight (specified by hourBegin
# being greater than hourEnd) # being greater than hourEnd)
# #
next if ( ref($p->{weekDays}) ne "ARRAY" next if ( ref($p->{weekDays}) ne "ARRAY" || !defined($p->{hourBegin}) ||
|| !defined($p->{hourBegin}) !defined($p->{hourEnd}) );
|| !defined($p->{hourEnd})
);
my $matchWday = $wday; my $matchWday = $wday;
if ( $p->{hourBegin} > $p->{hourEnd} ) { if ( $p->{hourBegin} > $p->{hourEnd} ) {
$blackout = $p->{hourBegin} <= $currHours $blackout = $p->{hourBegin} <= $currHours
|| $currHours <= $p->{hourEnd}; || $currHours <= $p->{hourEnd};
if ( $currHours <= $p->{hourEnd} ) { if ( $currHours <= $p->{hourEnd} ) {
# #
# This is after midnight, so decrement the weekday for the # This is after midnight, so decrement the weekday for the
# weekday check (eg: Monday 11pm-1am means Monday 2300 to # weekday check (eg: Monday 11pm-1am means Monday 2300 to
# Tuesday 0100, not Monday 2300-2400 plus Monday 0000-0100). # Tuesday 0100, not Monday 2300-2400 plus Monday 0000-0100).
# #
$matchWday--; $matchWday--;
$matchWday += 7 if ( $matchWday < 0 ); $matchWday += 7 if ( $matchWday < 0 );
} }
} else { } else {
$blackout = $p->{hourBegin} <= $currHours $blackout = $p->{hourBegin} <= $currHours
&& $currHours <= $p->{hourEnd}; && $currHours <= $p->{hourEnd};
} }
if ( $blackout && grep($_ == $matchWday, @{$p->{weekDays}}) ) { if ( $blackout && grep($_ == $matchWday, @{$p->{weekDays}}) ) {
# print($LogFd $bpc->timeStamp, "skipping because of blackout"
# . " (alive $StatusHost{aliveCnt} times)\n"); # print($LogFd $bpc->timeStamp, "skipping because of black
out"
# . " (alive $StatusHost{aliveCnt} times)\n");
print("Skipping $client because of blackout\n") print("Skipping $client because of blackout\n")
if ( $opts{v} ); if ( $opts{v} );
NothingToDo(); NothingToDo();
} }
} }
} }
if ( !$opts{i} && !$opts{f} && $StatusHost{backoffTime} > time ) { if ( !$opts{i} && !$opts{f} && $StatusHost{backoffTime} > time ) {
printf($LogFd "%sskipping because of user requested delay (%.1f hours left)\ n", printf($LogFd "%sskipping because of user requested delay (%.1f hours left)\ n",
$bpc->timeStamp, ($StatusHost{backoffTime} - time) / 3600); $bpc->timeStamp, ($StatusHost{backoffTime} - time) / 3600);
NothingToDo(); NothingToDo();
} }
# #
# Now see if there are any old backups we should delete # Now see if there are any old backups we should delete
# #
BackupExpire($client); BackupExpire($client);
# #
# Read Backup information, and if the most recent backup is v4, check # Read Backup information, and if the most recent backup is v4, check
# that it is filled and it exists. # that it is filled and it exists.
# #
@Backups = $bpc->BackupInfoRead($client); @Backups = $bpc->BackupInfoRead($client);
if ( @Backups if ( @Backups
&& ($Backups[-1]{version} ne "" && $Backups[-1]{version} !~ /^[23]\./) && ($Backups[-1]{version} ne "" && $Backups[-1]{version} !~ /^[23]\./)
&& ($Backups[-1]{noFill} || !-d "$Dir/$Backups[-1]{num}") ) { && ($Backups[-1]{noFill} || !-d "$Dir/$Backups[-1]{num}") ) {
my $i; my $i;
if ( $Backups[-1]{noFill} ) { if ( $Backups[-1]{noFill} ) {
printf($LogFd "%sSerious error: last backup %d is not filled! Need to r emove back to last filled backup\n", printf($LogFd "%sSerious error: last backup %d is not filled! Need to r emove back to last filled backup\n",
$bpc->timeStamp, $Backups[-1]{num}); $bpc->timeStamp, $Backups[-1]{num});
printf(STDERR "Serious error: last backup %d is not filled! Need to rem printf("Serious error: last backup %d is not filled! Need to remove bac
ove back to last filled backup\n", k to last filled backup\n",
$Backups[-1]{num}) if ( $opts{v} ); $Backups[-1]{num})
if ( $opts{v} );
} else { } else {
printf($LogFd "%sSerious error: last backup %s directory doesn't exist!! printf($LogFd
! Need to remove back to last filled backup\n", "%sSerious error: last backup %s directory doesn't exist!!! Need
$bpc->timeStamp, "$Dir/$Backups[-1]{num}"); to remove back to last filled backup\n",
printf(STDERR "%sSerious error: last backup %s directory doesn't exist!! $bpc->timeStamp, "$Dir/$Backups[-1]{num}");
! Need to remove back to last filled backup\n", printf(
$bpc->timeStamp, "$Dir/$Backups[-1]{num}") if ( $opts{v} ); "%sSerious error: last backup %s directory doesn't exist!!! Need to
remove back to last filled backup\n",
$bpc->timeStamp, "$Dir/$Backups[-1]{num}")
if ( $opts{v} );
} }
for ( $i = @Backups - 1 ; $i >= 0 ; $i-- ) { for ( $i = @Backups - 1 ; $i >= 0 ; $i-- ) {
last if ( $Backups[$i]{version} eq "" || $Backups[$i]{version} =~ /^[23] \./ ); last if ( $Backups[$i]{version} eq "" || $Backups[$i]{version} =~ /^[23] \./ );
last if ( !$Backups[$i]{noFill} && -d "$Dir/$Backups[$i]{num}"); last if ( !$Backups[$i]{noFill} && -d "$Dir/$Backups[$i]{num}" );
} }
$i++; $i++;
while ( $i < @Backups ) { while ( $i < @Backups ) {
printf($LogFd "%sDeleting backup %d\n", $bpc->timeStamp, $Backups[$i]{nu m}); printf($LogFd "%sDeleting backup %d\n", $bpc->timeStamp, $Backups[$i]{nu m});
printf(STDERR "%sDeleting backup %d\n", $bpc->timeStamp, $Backups[$i]{nu m}) if ( $opts{v} ); printf("%sDeleting backup %d\n", $bpc->timeStamp, $Backups[$i]{nu m}) if ( $opts{v} );
BackupRemove($client, $i, 1); BackupRemove($client, $i, 1);
$bpc->BackupInfoWrite($client, @Backups); $bpc->BackupInfoWrite($client, @Backups);
} }
exit(0); exit(0);
} }
# #
# Find the most recent backup, times of the most recent full and incremental bac kups, # Find the most recent backup, times of the most recent full and incremental bac kups,
# and check if the most recent backup is V4+ or prior to V4 (ie: preV4). # and check if the most recent backup is V4+ or prior to V4 (ie: preV4).
# #
skipping to change at line 446 skipping to change at line 453
$lastBkupIdx = $i; $lastBkupIdx = $i;
$incrBaseBkupNum = $Backups[$i]{num}; $incrBaseBkupNum = $Backups[$i]{num};
$incrBaseTime = $Backups[$i]{startTime}; $incrBaseTime = $Backups[$i]{startTime};
$lastBkupType = $Backups[$i]{type}; $lastBkupType = $Backups[$i]{type};
$lastBkupCompressLevel = $Backups[$i]{compress}; $lastBkupCompressLevel = $Backups[$i]{compress};
$preV4 = $Backups[$i]{preV4}; $preV4 = $Backups[$i]{preV4};
$noFillCnt = $thisNoFillCnt; $noFillCnt = $thisNoFillCnt;
} }
$thisNoFillCnt = 0 if ( !$Backups[$i]{noFill} ); $thisNoFillCnt = 0 if ( !$Backups[$i]{noFill} );
if ( $Backups[$i]{type} eq "full" ) { if ( $Backups[$i]{type} eq "full" ) {
if ( $lastFullTime < $Backups[$i]{startTime} ) { if ( $lastFullTime < $Backups[$i]{startTime} ) {
$lastFullTime = $Backups[$i]{startTime}; $lastFullTime = $Backups[$i]{startTime};
} }
} elsif ( $Backups[$i]{type} eq "incr" ) { } elsif ( $Backups[$i]{type} eq "incr" ) {
$lastIncrTime = $Backups[$i]{startTime} $lastIncrTime = $Backups[$i]{startTime}
if ( $lastIncrTime < $Backups[$i]{startTime} ); if ( $lastIncrTime < $Backups[$i]{startTime} );
} }
} }
# #
# Decide whether we do nothing, or a full or incremental backup. # Decide whether we do nothing, or a full or incremental backup.
# #
my $needs_full = (time - $lastFullTime > $Conf{FullPeriod} * 24 * 3600 my $needs_full =
&& time - $lastIncrTime > $Conf{IncrPeriod} * 24 * 3600); (time - $lastFullTime > $Conf{FullPeriod} * 24 * 3600 && time - $lastIncrTime
my $needs_incr = (time - $lastIncrTime > $Conf{IncrPeriod} * 24 * 3600 > $Conf{IncrPeriod} * 24 * 3600);
&& time - $lastFullTime > $Conf{IncrPeriod} * 24 * 3600); my $needs_incr =
(time - $lastIncrTime > $Conf{IncrPeriod} * 24 * 3600 && time - $lastFullTime
> $Conf{IncrPeriod} * 24 * 3600);
$needs_full = 0 if ( $Conf{FullPeriod} == 0 ); $needs_full = 0 if ( $Conf{FullPeriod} == 0 );
if ( $opts{f} if ( $opts{f} || (!$opts{i} && !$opts{I} && $needs_full) || ($opts{F} && $needs_
|| (!$opts{i} && !$opts{I} && $needs_full) incr) ) {
|| ( $opts{F} && $needs_incr) ) {
$type = "full"; $type = "full";
} elsif ( $opts{i} } elsif ( $opts{i} || $needs_incr || ($opts{I} && $needs_full) ) {
|| $needs_incr
|| ($opts{I} && $needs_full) ) {
$type = "incr"; $type = "incr";
} else { } else {
NothingToDo(); NothingToDo();
} }
print("Backup type: type = $type, needs_full = $needs_full, needs_incr = $needs_ print( "Backup type: type = $type, needs_full = $needs_full, needs_incr = $need
incr, lastFullTime = $lastFullTime," s_incr, lastFullTime = $lastFullTime,"
. " opts{f} = $opts{f}, opts{i} = $opts{i}, opts{F} = $opts{F}\n") if ( $opt . " opts{f} = $opts{f}, opts{i} = $opts{i}, opts{F} = $opts{F}\n")
s{v} ); if ( $opts{v} );
# #
# Create top-level directories if they don't exist # Create top-level directories if they don't exist
# #
foreach my $dir ( ( foreach my $dir ( ("$Conf{TopDir}/pool", "$Conf{TopDir}/cpool", $Dir, "$Dir/refC
"$Conf{TopDir}/pool", nt") ) {
"$Conf{TopDir}/cpool",
$Dir,
"$Dir/refCnt",
) ) {
next if ( -d $dir ); next if ( -d $dir );
mkpath($dir, 0, 0777); mkpath($dir, 0, 0777);
if ( !-d $dir ) { if ( !-d $dir ) {
print("Failed to create $dir\n"); print("Failed to create $dir\n");
printf($LogFd "%sFailed to create directory %s\n", $bpc->timeStamp, $dir ); printf($LogFd "%sFailed to create directory %s\n", $bpc->timeStamp, $dir );
exit(1); exit(1);
} else { } else {
printf($LogFd "%sCreated directory %s\n", $bpc->timeStamp, $dir); printf($LogFd "%sCreated directory %s\n", $bpc->timeStamp, $dir);
} }
} }
skipping to change at line 523 skipping to change at line 522
} elsif ( $Conf{ClientNameAlias} ne "" ) { } elsif ( $Conf{ClientNameAlias} ne "" ) {
push(@hostsToCheck, $Conf{ClientNameAlias}); push(@hostsToCheck, $Conf{ClientNameAlias});
} else { } else {
push(@hostsToCheck, $client); push(@hostsToCheck, $client);
} }
foreach my $hostToCheck ( @hostsToCheck ) { foreach my $hostToCheck ( @hostsToCheck ) {
$hostIP = HostLookupCheck($hostToCheck); $hostIP = HostLookupCheck($hostToCheck);
push(@validHosts, [$hostToCheck, $hostIP]) if ( defined($hostIP) ); push(@validHosts, [$hostToCheck, $hostIP]) if ( defined($hostIP) );
} }
} else { } else {
# In DHCP case we've already found $hostIP # In DHCP case we've already found $hostIP
push(@validHosts, [$host, $hostIP]); push(@validHosts, [$host, $hostIP]);
} }
# #
# Find the first entry in @validHosts that we can ping # Find the first entry in @validHosts that we can ping
# #
foreach my $h ( @validHosts ) { foreach my $h ( @validHosts ) {
($host, $hostIP) = @$h; ($host, $hostIP) = @$h;
my $delay = $bpc->CheckHostAlive($hostIP); my $delay = $bpc->CheckHostAlive($hostIP);
if ( $delay < 0 ) { if ( $delay < 0 ) {
print($LogFd $bpc->timeStamp, "no ping response from $hostIP\n"); print($LogFd $bpc->timeStamp, "no ping response from $hostIP\n");
print("no ping response from $hostIP\n"); print("no ping response from $hostIP\n");
$hostIP = undef; $hostIP = undef;
next; next;
} elsif ( $delay > $Conf{PingMaxMsec} ) { } elsif ( $delay > $Conf{PingMaxMsec} ) {
printf($LogFd "%sping too slow on $hostIP %.4gmsec\n", $bpc->timeStamp, printf($LogFd "%sping too slow on $hostIP %.4gmsec\n", $bpc
$delay); ->timeStamp, $delay);
printf("ping too slow on $hostIP %.4gmsec (threshold is %gmsec)\n", printf("ping too slow on $hostIP %.4gmsec (threshold is %gmsec)\n", $del
$delay, $Conf{PingMaxMsec}); ay, $Conf{PingMaxMsec});
$hostIP = undef; $hostIP = undef;
next; next;
} }
last; last;
} }
if ( !defined($hostIP) ) { if ( !defined($hostIP) ) {
print($LogFd $bpc->timeStamp, "can't ping $host (client = $client); exiting\ n"); print($LogFd $bpc->timeStamp, "can't ping $host (client = $client); exiting\ n");
print("can't ping $host (client = $client); exiting\n"); print("can't ping $host (client = $client); exiting\n") if ( $opts{v} );
exit(1); exit(1);
} }
# #
# Make sure it is really the machine we expect (only for fixed addresses, # Make sure it is really the machine we expect (only for fixed addresses,
# since we got the DHCP address above). # since we got the DHCP address above).
# #
if ( !$opts{d} && (my $errMsg = CorrectHostCheck($hostIP, $host)) ) { if ( !$opts{d} && (my $errMsg = CorrectHostCheck($hostIP, $host)) ) {
print($LogFd $bpc->timeStamp, "dump failed: $errMsg\n"); print($LogFd $bpc->timeStamp, "dump failed: $errMsg\n");
print("dump failed: $errMsg\n"); print("dump failed: $errMsg\n");
skipping to change at line 603 skipping to change at line 602
# up on a failed backup. # up on a failed backup.
# #
# Note: $Conf{FillCycle} == 0, then the V4 fill cycle matches the # Note: $Conf{FillCycle} == 0, then the V4 fill cycle matches the
# full/incr cycle. # full/incr cycle.
# #
# #
# $inPlace means the Xfer method makes all the changes in place, without # $inPlace means the Xfer method makes all the changes in place, without
# stored any reverse deltas in a prior backup tree. # stored any reverse deltas in a prior backup tree.
# #
my $inPlace = 0; my $inPlace = 0;
# #
# doDuplicate means we run BackupPC_backupDuplicate, which duplicates the # doDuplicate means we run BackupPC_backupDuplicate, which duplicates the
# most recent v3 and v4 backup. # most recent v3 and v4 backup.
# #
my $doDuplicate = 0; my $doDuplicate = 0;
my $copyXferLOG; my $copyXferLOG;
# #
# Remember which case, so we can figure out what to clean up on a failed backup. # Remember which case, so we can figure out what to clean up on a failed backup.
skipping to change at line 653 skipping to change at line 652
# #
$BackupCase = 2; $BackupCase = 2;
$inPlace = 1; $inPlace = 1;
$doDuplicate = 1; $doDuplicate = 1;
$newBkupNum = $lastBkupNum + 1; # will exist after BackupPC_backupDuplic ate $newBkupNum = $lastBkupNum + 1; # will exist after BackupPC_backupDuplic ate
$newBkupIdx = @Backups; $newBkupIdx = @Backups;
$lastBkupNum = undef; $lastBkupNum = undef;
$lastBkupIdx = undef; $lastBkupIdx = undef;
$type = "full"; $type = "full";
} else { } else {
if ( ($lastBkupType eq "partial" || $lastBkupType eq "active") if ( ($lastBkupType eq "partial" || $lastBkupType eq "active")
&& (!defined($prevBkupIdx) || $Backups[$prevBkupIdx]{preV4} || !$Backu && (!defined($prevBkupIdx) || $Backups[$prevBkupIdx]{preV4} || !$Backups
ps[$prevBkupIdx]{noFill}) ) { [$prevBkupIdx]{noFill}) ) {
# #
# case 6: partial, and either no previous, V3 previous, or filled previo us: simply update in place, # case 6: partial, and either no previous, V3 previous, or filled previo us: simply update in place,
# with no prior deltas. # with no prior deltas.
# #
$BackupCase = 6; $BackupCase = 6;
$inPlace = 1; $inPlace = 1;
$doDuplicate = 0; $doDuplicate = 0;
# #
# We need to append the current XferLOG file. Rename it and copy it bel ow. # We need to append the current XferLOG file. Rename it and copy it bel ow.
# #
my $fileExt = $lastBkupCompressLevel > 0 ? ".z" : ""; my $fileExt = $lastBkupCompressLevel > 0 ? ".z" : "";
if ( -f "$Dir/XferLOG.$lastBkupNum$fileExt" ) { if ( -f "$Dir/XferLOG.$lastBkupNum$fileExt" ) {
print($LogFd $bpc->timeStamp, "Renaming $Dir/XferLOG.$lastBkupNum$fi print($LogFd $bpc->timeStamp,
leExt -> $Dir/XferLOG.$lastBkupNum$fileExt.tmp\n"); "Renaming $Dir/XferLOG.$lastBkupNum$fileExt -> $Dir/XferLOG.$las
tBkupNum$fileExt.tmp\n");
rename("$Dir/XferLOG.$lastBkupNum$fileExt", "$Dir/XferLOG.$lastBkupN um$fileExt.tmp"); rename("$Dir/XferLOG.$lastBkupNum$fileExt", "$Dir/XferLOG.$lastBkupN um$fileExt.tmp");
$copyXferLOG = ["$Dir/XferLOG.$lastBkupNum$fileExt.tmp", $lastBkupCo mpressLevel, 1]; $copyXferLOG = ["$Dir/XferLOG.$lastBkupNum$fileExt.tmp", $lastBkupCo mpressLevel, 1];
} }
$newBkupNum = $lastBkupNum; $newBkupNum = $lastBkupNum;
$newBkupIdx = $lastBkupIdx; $newBkupIdx = $lastBkupIdx;
$lastBkupNum = undef; $lastBkupNum = undef;
$lastBkupIdx = undef; $lastBkupIdx = undef;
} elsif ( $lastBkupType eq "full" || ($Conf{FillCycle} > 0 && $noFillCnt >= $Conf{FillCycle} - 1) ) { } elsif ( $lastBkupType eq "full" || ($Conf{FillCycle} > 0 && $noFillCnt >= $Conf{FillCycle} - 1) ) {
# #
# case 3: V4; last is filled, so duplicate and do in place # case 3: V4; last is filled, so duplicate and do in place
skipping to change at line 701 skipping to change at line 701
$inPlace = 0; $inPlace = 0;
$doDuplicate = 0; $doDuplicate = 0;
$newBkupNum = $lastBkupNum; $newBkupNum = $lastBkupNum;
$newBkupIdx = @Backups; $newBkupIdx = @Backups;
do { do {
$newBkupNum++; $newBkupNum++;
} while ( -d "$Dir/$newBkupNum" ); } while ( -d "$Dir/$newBkupNum" );
if ( !rename("$Dir/$lastBkupNum", "$Dir/$newBkupNum") ) { if ( !rename("$Dir/$lastBkupNum", "$Dir/$newBkupNum") ) {
print($LogFd $bpc->timeStamp, "Can't rename $Dir/$lastBkupNum to $Di r/$newBkupNum\n"); print($LogFd $bpc->timeStamp, "Can't rename $Dir/$lastBkupNum to $Di r/$newBkupNum\n");
print("Exiting because rename $Dir/$lastBkupNum to $Dir/$newBkupNum failed\n") print("Exiting because rename $Dir/$lastBkupNum to $Dir/$newBkupNum failed\n")
if ( $opts{v} ); if ( $opts{v} );
exit(1); exit(1);
} }
$Backups[$lastBkupIdx]{noFill} = 1; $Backups[$lastBkupIdx]{noFill} = 1;
# #
# Create the lastBkupNum and refCnt directory and flag it needing an fsc k # Create the lastBkupNum and refCnt directory and flag it needing an fsc k
# in case we exit without cleanup. Also add a flag that it's ok not # in case we exit without cleanup. Also add a flag that it's ok not
# having any current poolCnt files. # having any current poolCnt files.
# #
eval { mkpath("$Dir/$lastBkupNum/refCnt", 0, 0777) }; eval { mkpath("$Dir/$lastBkupNum/refCnt", 0, 0777) };
if ( $@ ) { if ( $@ ) {
print($LogFd $bpc->timeStamp, "Can't create $Dir/$lastBkupNum/refCnt \n"); print($LogFd $bpc->timeStamp, "Can't create $Dir/$lastBkupNum/refCnt \n");
print("Can't create backup directory $Dir/$lastBkupNum/refCnt") print("Can't create backup directory $Dir/$lastBkupNum/refCnt")
if ( $opts{v} ); if ( $opts{v} );
exit(1); exit(1);
} }
my $newFH; my $newFH;
if ( !(open($newFH, ">", "$Dir/$lastBkupNum/refCnt/needFsck.newDir") && close($newFH)) ) { if ( !(open($newFH, ">", "$Dir/$lastBkupNum/refCnt/needFsck.newDir") && close($newFH)) ) {
print($LogFd $bpc->timeStamp, "Can't create $Dir/$lastBkupNum/refCnt /needFsck.newDir ($?)\n"); print($LogFd $bpc->timeStamp, "Can't create $Dir/$lastBkupNum/refCnt /needFsck.newDir ($?)\n");
print("Can't create $Dir/$lastBkupNum/refCnt/needFsck.newDir ($?)\n" ); print("Can't create $Dir/$lastBkupNum/refCnt/needFsck.newDir ($?)\n" );
} }
if ( !(open($newFH, ">", "$Dir/$lastBkupNum/refCnt/noPoolCntOk") && clos e($newFH)) ) { if ( !(open($newFH, ">", "$Dir/$lastBkupNum/refCnt/noPoolCntOk") && clos e($newFH)) ) {
print($LogFd $bpc->timeStamp, "Can't create $Dir/$lastBkupNum/refCnt /noPoolCntOk ($?)\n"); print($LogFd $bpc->timeStamp, "Can't create $Dir/$lastBkupNum/refCnt /noPoolCntOk ($?)\n");
print("Can't create $Dir/$lastBkupNum/refCnt/noPoolCntOk ($?)\n"); print("Can't create $Dir/$lastBkupNum/refCnt/noPoolCntOk ($?)\n");
skipping to change at line 755 skipping to change at line 755
} }
} }
# #
# Setup file extension for compression and open XferLOG output file # Setup file extension for compression and open XferLOG output file
# #
my $fileExt = $Conf{CompressLevel} > 0 ? ".z" : ""; my $fileExt = $Conf{CompressLevel} > 0 ? ".z" : "";
unlink("$Dir/XferLOG.$newBkupNum$fileExt") if ( -e "$Dir/XferLOG.$newBkupNum$fil eExt" ); unlink("$Dir/XferLOG.$newBkupNum$fileExt") if ( -e "$Dir/XferLOG.$newBkupNum$fil eExt" );
my $XferLOG = BackupPC::XS::FileZIO::open("$Dir/XferLOG.$newBkupNum$fileExt", 1, $Conf{CompressLevel}); my $XferLOG = BackupPC::XS::FileZIO::open("$Dir/XferLOG.$newBkupNum$fileExt", 1, $Conf{CompressLevel});
if ( !defined($XferLOG) ) { if ( !defined($XferLOG) ) {
print($LogFd $bpc->timeStamp, "dump failed: unable to open/create" print($LogFd $bpc->timeStamp, "dump failed: unable to open/create $Dir/XferL
. " $Dir/XferLOG.$newBkupNum$fileExt\n"); OG.$newBkupNum$fileExt\n");
print("dump failed: unable to open/create $Dir/XferLOG.$newBkupNum$fileExt\n "); print("dump failed: unable to open/create $Dir/XferLOG.$newBkupNum$fileExt\n ");
exit(1); exit(1);
} }
xferLOGCopyFile(@$copyXferLOG) if ( defined($copyXferLOG) ); xferLOGCopyFile(@$copyXferLOG) if ( defined($copyXferLOG) );
$XferLOG->writeTeeStderr(1) if ( $opts{v} ); $XferLOG->writeTeeStderr(1) if ( $opts{v} );
my $str = "XferLOG file $Dir/XferLOG.$newBkupNum$fileExt created " . $bpc->timeS tamp . "\n"; my $str = "XferLOG file $Dir/XferLOG.$newBkupNum$fileExt created " . $bpc->timeS tamp . "\n";
$XferLOG->write(\$str); $XferLOG->write(\$str);
if ( $Conf{XferLogLevel} >= 1 || $opts{v} ) { if ( $Conf{XferLogLevel} >= 1 || $opts{v} ) {
$str = "Backup prep: type = $type, case = $BackupCase, inPlace = $inPlace, d $str =
oDuplicate = $doDuplicate," "Backup prep: type = $type, case = $BackupCase, inPlace = $inPlace, doDu
. " newBkupNum = $newBkupNum, newBkupIdx = $newBkupIdx, lastBkupNum = $ plicate = $doDuplicate,"
lastBkupNum, lastBkupIdx = $lastBkupIdx" . " newBkupNum = $newBkupNum, newBkupIdx = $newBkupIdx, lastBkupNum = $las
. " (FillCycle = $Conf{FillCycle}, noFillCnt = $noFillCnt)\n"; tBkupNum, lastBkupIdx = $lastBkupIdx"
. " (FillCycle = $Conf{FillCycle}, noFillCnt = $noFillCnt)\n";
$XferLOG->write(\$str); $XferLOG->write(\$str);
} }
# #
# See if this client needs an fsck. # See if this client needs an fsck.
# #
my $needFsck = 0; my $needFsck = 0;
my $refCntFiles = BackupPC::DirOps::dirRead($bpc, "$Dir/$newBkupNum/refCnt"); my $refCntFiles = BackupPC::DirOps::dirRead($bpc, "$Dir/$newBkupNum/refCnt");
foreach my $file ( @$refCntFiles ) { foreach my $file ( @$refCntFiles ) {
next if ( $file !~ /^needFsck/ ); next if ( $file !~ /^needFsck/ );
$needFsck = 1; $needFsck = 1;
last; last;
} }
RefCountUpdate(1, 0) if ( $needFsck ); RefCountUpdate(1, 0) if ( $needFsck );
# #
# Duplicate the most recent backup, if required # Duplicate the most recent backup, if required
# #
if ( $doDuplicate ) { if ( $doDuplicate ) {
my $t = time; my $t = time;
my $pids = {}; my $pids = {};
# #
# Run BackupPC_backupDuplicate, then re-read the backups file. # Run BackupPC_backupDuplicate, then re-read the backups file.
# #
my $cmd = ["$BinDir/BackupPC_backupDuplicate", "-m", "-h", $client]; my $cmd = ["$BinDir/BackupPC_backupDuplicate", "-m", "-h", $client];
push(@$cmd, "-p") if ( $opts{p} ); push(@$cmd, "-p") if ( $opts{p} );
$XferLOG->write(\"Executing @$cmd\n"); $XferLOG->write(\"Executing @$cmd\n");
$bpc->cmdSystemOrEval($cmd, $bpc->cmdSystemOrEval(
sub { $cmd,
if ( $_[0] =~ /^__bpc_progress_/ ) { sub {
print($_[0]); if ( $_[0] =~ /^__bpc_progress_/ ) {
} elsif ( $_[0] =~ /^__bpc_pidStart__ (\d+)/ ) { print($_[0]);
$pids->{$1} = 1; } elsif ( $_[0] =~ /^__bpc_pidStart__ (\d+)/ ) {
pidHandler(keys(%$pids)); $pids->{$1} = 1;
} elsif ( $_[0] =~ /^__bpc_pidEnd__ (\d+)/ ) { pidHandler(keys(%$pids));
delete($pids->{$1}); } elsif ( $_[0] =~ /^__bpc_pidEnd__ (\d+)/ ) {
pidHandler(keys(%$pids)); delete($pids->{$1});
pidHandler(keys(%$pids));
} else {
if ( defined($XferLOG) ) {
$XferLOG->write(\$_[0]);
} else { } else {
if ( defined($XferLOG) ) { print($LogFd $bpc->timeStamp, $_[0]);
$XferLOG->write(\$_[0]);
} else {
print($LogFd $bpc->timeStamp, $_[0]);
}
} }
}); }
}
);
$t = time - $t; $t = time - $t;
$XferLOG->write(\"Finished BackupPC_backupDuplicate (running time: $t sec)\n "); $XferLOG->write(\"Finished BackupPC_backupDuplicate (running time: $t sec)\n ");
@Backups = $bpc->BackupInfoRead($client); @Backups = $bpc->BackupInfoRead($client);
pidHandler(); pidHandler();
} }
# #
# Create a placeholder backups entry if needed # Create a placeholder backups entry if needed
# #
if ( $newBkupIdx >= @Backups ) { if ( $newBkupIdx >= @Backups ) {
$Backups[$newBkupIdx]{num} = $newBkupNum; $Backups[$newBkupIdx]{num} = $newBkupNum;
$Backups[$newBkupIdx]{level} = $type eq "incr" ? 1 : 0; $Backups[$newBkupIdx]{level} = $type eq "incr" ? 1 : 0;
$Backups[$newBkupIdx]{noFill} = 0; $Backups[$newBkupIdx]{noFill} = 0;
$Backups[$newBkupIdx]{mangle} = 1; # name mangling always on for v1. 04+ $Backups[$newBkupIdx]{mangle} = 1; # name mangli ng always on for v1.04+
$Backups[$newBkupIdx]{xferMethod} = $Conf{XferMethod}; $Backups[$newBkupIdx]{xferMethod} = $Conf{XferMethod};
$Backups[$newBkupIdx]{charset} = $Conf{ClientCharset}; $Backups[$newBkupIdx]{charset} = $Conf{ClientCharset};
$Backups[$newBkupIdx]{version} = $bpc->Version(); $Backups[$newBkupIdx]{version} = $bpc->Version();
$Backups[$newBkupIdx]{compress} = $Conf{CompressLevel}; $Backups[$newBkupIdx]{compress} = $Conf{CompressLevel};
$Backups[$newBkupIdx]{keep} = 0;
} }
# #
# New backup shows as "active" while running # New backup shows as "active" while running
# #
$Backups[$newBkupIdx]{type} = "active"; $Backups[$newBkupIdx]{type} = "active";
$Backups[$newBkupIdx]{startTime} = time(); $Backups[$newBkupIdx]{startTime} = time();
# #
# Create new directory # Create new directory
# #
if ( defined($newBkupNum) && !-d "$Dir/$newBkupNum" ) { if ( defined($newBkupNum) && !-d "$Dir/$newBkupNum" ) {
# #
# Create the new backup directory # Create the new backup directory
# #
eval { mkpath("$Dir/$newBkupNum", 0, 0777) }; eval { mkpath("$Dir/$newBkupNum", 0, 0777) };
if ( $@ ) { if ( $@ ) {
print($LogFd $bpc->timeStamp, "Can't create $Dir/$newBkupNum\n"); print($LogFd $bpc->timeStamp, "Can't create $Dir/$newBkupNum\n");
print("Can't create backup directory $Dir/$newBkupNum") print("Can't create backup directory $Dir/$newBkupNum")
if ( $opts{v} ); if ( $opts{v} );
exit(1); exit(1);
} }
} }
if ( defined($newBkupNum) && !-d "$Dir/$newBkupNum/refCnt" ) { if ( defined($newBkupNum) && !-d "$Dir/$newBkupNum/refCnt" ) {
# #
# Create the new refCnt directory and flag it needing an fsck # Create the new refCnt directory and flag it needing an fsck
# in case we exit without cleanup. # in case we exit without cleanup.
# #
eval { mkpath("$Dir/$newBkupNum/refCnt", 0, 0777) }; eval { mkpath("$Dir/$newBkupNum/refCnt", 0, 0777) };
if ( $@ ) { if ( $@ ) {
print($LogFd $bpc->timeStamp, "Can't create $Dir/$newBkupNum/refCnt\n"); print($LogFd $bpc->timeStamp, "Can't create $Dir/$newBkupNum/refCnt\n");
print("Can't create backup directory $Dir/$newBkupNum/refCnt") print("Can't create backup directory $Dir/$newBkupNum/refCnt")
if ( $opts{v} ); if ( $opts{v} );
exit(1); exit(1);
} }
my $needFsckFH; my $needFsckFH;
if ( !(open($needFsckFH, ">", "$Dir/$newBkupNum/refCnt/needFsck.newDir") && close($needFsckFH)) ) { if ( !(open($needFsckFH, ">", "$Dir/$newBkupNum/refCnt/needFsck.newDir") && close($needFsckFH)) ) {
$XferLOG->write(\"Can't create $Dir/$newBkupNum/refCnt/needFsck.newDir ( $?)\n"); $XferLOG->write(\"Can't create $Dir/$newBkupNum/refCnt/needFsck.newDir ( $?)\n");
} }
} }
# #
# Save backupInfo and backups # Save backupInfo and backups
skipping to change at line 897 skipping to change at line 900
my $sizeTotal = 0; my $sizeTotal = 0;
my($logMsg, %stat, $xfer, $ShareNames, $noFilesErr); my($logMsg, %stat, $xfer, $ShareNames, $noFilesErr);
$ShareNames = BackupPC::Xfer::getShareNames(\%Conf); $ShareNames = BackupPC::Xfer::getShareNames(\%Conf);
# #
# Run an optional pre-dump command # Run an optional pre-dump command
# #
UserCommandRun("DumpPreUserCmd"); UserCommandRun("DumpPreUserCmd");
if ( $? && $Conf{UserCmdCheckStatus} ) { if ( $? && $Conf{UserCmdCheckStatus} ) {
print($LogFd $bpc->timeStamp, print($LogFd $bpc->timeStamp, "DumpPreUserCmd returned error status $?... ex
"DumpPreUserCmd returned error status $?... exiting\n"); iting\n");
$XferLOG->write(\"DumpPreUserCmd returned error status $?... exiting\n"); $XferLOG->write(\"DumpPreUserCmd returned error status $?... exiting\n");
$stat{hostError} = "DumpPreUserCmd returned error status $?"; $stat{hostError} = "DumpPreUserCmd returned error status $?";
BackupFailCleanup(); BackupFailCleanup();
} }
$NeedPostCmd = 1; $NeedPostCmd = 1;
# #
# Now backup each of the shares # Now backup each of the shares
# #
my $shareDuplicate = {}; my $shareDuplicate = {};
skipping to change at line 922 skipping to change at line 924
# the data transport program. # the data transport program.
# #
alarm($Conf{ClientTimeout}); alarm($Conf{ClientTimeout});
local(*RH, *WH); local(*RH, *WH);
# #
# Convert $shareName to utf8 octets # Convert $shareName to utf8 octets
# #
$shareName = encode("utf8", $shareName); $shareName = encode("utf8", $shareName);
$stat{xferOK} = $stat{hostAbort} = undef; $stat{xferOK} = $stat{hostAbort} = undef;
$stat{hostError} = $stat{lastOutputLine} = undef; $stat{hostError} = $stat{lastOutputLine} = undef;
if ( $shareName eq "" ) { if ( $shareName eq "" ) {
print($LogFd $bpc->timeStamp, "unexpected empty share name skipped\n"); print($LogFd $bpc->timeStamp, "unexpected empty share name skipped\n");
next; next;
} }
if ( $shareDuplicate->{$shareName} ) { if ( $shareDuplicate->{$shareName} ) {
print($LogFd $bpc->timeStamp, "unexpected repeated share name $shareName skipped\n"); print($LogFd $bpc->timeStamp, "unexpected repeated share name $shareName skipped\n");
next; next;
} }
$shareDuplicate->{$shareName} = 1; $shareDuplicate->{$shareName} = 1;
skipping to change at line 958 skipping to change at line 960
@Backups = $bpc->BackupInfoRead($client); @Backups = $bpc->BackupInfoRead($client);
$Backups[$newBkupIdx]{inodeLast} = $inodeLast; $Backups[$newBkupIdx]{inodeLast} = $inodeLast;
BackupPC::Storage->backupInfoWrite($Dir, $newBkupNum, $Backups[$newBkupIdx], 1); BackupPC::Storage->backupInfoWrite($Dir, $newBkupNum, $Backups[$newBkupIdx], 1);
$bpc->BackupInfoWrite($client, @Backups); $bpc->BackupInfoWrite($client, @Backups);
$xfer = BackupPC::Xfer::create($Conf{XferMethod}, $bpc); $xfer = BackupPC::Xfer::create($Conf{XferMethod}, $bpc);
if ( !defined($xfer) ) { if ( !defined($xfer) ) {
my $errStr = BackupPC::Xfer::errStr(); my $errStr = BackupPC::Xfer::errStr();
print($LogFd $bpc->timeStamp, "dump failed: $errStr\n"); print($LogFd $bpc->timeStamp, "dump failed: $errStr\n");
UserCommandRun("DumpPostShareCmd", $shareName) if ( $NeedPostCmd ); UserCommandRun("DumpPostShareCmd", $shareName) if ( $NeedPostCmd );
UserCommandRun("DumpPostUserCmd") if ( $NeedPostCmd ); UserCommandRun("DumpPostUserCmd") if ( $NeedPostCmd );
$XferLOG->write(\"BackupPC::Xfer::create failed: $errStr\n"); $XferLOG->write(\"BackupPC::Xfer::create failed: $errStr\n");
$stat{hostError} = $errStr; $stat{hostError} = $errStr;
BackupFailCleanup(); BackupFailCleanup();
} }
my $useTar = $xfer->useTar; my $useTar = $xfer->useTar;
if ( $useTar ) { if ( $useTar ) {
# #
# This xfer method outputs a tar format file, so we start a # This xfer method outputs a tar format file, so we start a
# BackupPC_tarExtract to extract the data. # BackupPC_tarExtract to extract the data.
# #
# Create a socketpair to connect the Xfer method to BackupPC_tarExtract # Create a socketpair to connect the Xfer method to BackupPC_tarExtract
# WH is the write handle for writing, provided to the transport # WH is the write handle for writing, provided to the transport
# program, and RH is the other end of the socket for reading, # program, and RH is the other end of the socket for reading,
# provided to BackupPC_tarExtract. # provided to BackupPC_tarExtract.
# #
if ( socketpair(RH, WH, AF_UNIX, SOCK_STREAM, PF_UNSPEC) ) { if ( socketpair(RH, WH, AF_UNIX, SOCK_STREAM, PF_UNSPEC) ) {
shutdown(RH, 1); # no writing to this socket shutdown(RH, 1); # no writing to this socket
shutdown(WH, 0); # no reading from this socket shutdown(WH, 0); # no reading from this socket
setsockopt(RH, SOL_SOCKET, SO_RCVBUF, 8 * 65536); setsockopt(RH, SOL_SOCKET, SO_RCVBUF, 8 * 65536);
setsockopt(WH, SOL_SOCKET, SO_SNDBUF, 8 * 65536); setsockopt(WH, SOL_SOCKET, SO_SNDBUF, 8 * 65536);
} else { } else {
# #
# Default to pipe() if socketpair() doesn't work. # Default to pipe() if socketpair() doesn't work.
# #
pipe(RH, WH); pipe(RH, WH);
} }
# #
# fork a child for BackupPC_tarExtract. TAR is a file handle # fork a child for BackupPC_tarExtract. TAR is a file handle
# on which we (the parent) read the stdout & stderr from # on which we (the parent) read the stdout & stderr from
# BackupPC_tarExtract. # BackupPC_tarExtract.
# #
if ( !defined($tarPid = open(TAR, "-|")) ) { if ( !defined($tarPid = open(TAR, "-|")) ) {
print($LogFd $bpc->timeStamp, "can't fork to run tar\n"); print($LogFd $bpc->timeStamp, "can't fork to run tar\n");
print("can't fork to run tar\n"); print("can't fork to run tar\n");
close(RH); close(RH);
close(WH); close(WH);
last; last;
} }
binmode(TAR); binmode(TAR);
if ( !$tarPid ) { if ( !$tarPid ) {
# #
# This is the tar child. Close the write end of the pipe, # This is the tar child. Close the write end of the pipe,
# clone STDERR to STDOUT, clone STDIN from RH, and then # clone STDERR to STDOUT, clone STDIN from RH, and then
# exec BackupPC_tarExtract. # exec BackupPC_tarExtract.
# #
setpgrp 0,0; setpgrp 0, 0;
close(WH); close(WH);
close(STDERR); close(STDERR);
open(STDERR, ">&STDOUT"); open(STDERR, ">&STDOUT");
close(STDIN); close(STDIN);
open(STDIN, "<&RH"); open(STDIN, "<&RH");
alarm(0); alarm(0);
my @tarOpts = ("-h", $client, "-s", $shareName); my @tarOpts = ("-h", $client, "-s", $shareName);
push(@tarOpts, "-f") if ( $type eq "full" ); push(@tarOpts, "-f") if ( $type eq "full" );
push(@tarOpts, "-P") if ( $inPlace ); push(@tarOpts, "-P") if ( $inPlace );
push(@tarOpts, "-p") if ( $opts{p} ); push(@tarOpts, "-p") if ( $opts{p} );
exec("$BinDir/BackupPC_tarExtract", @tarOpts); exec("$BinDir/BackupPC_tarExtract", @tarOpts);
print($LogFd $bpc->timeStamp, "can't exec $BinDir/BackupPC_tarExtract print($LogFd $bpc->timeStamp, "can't exec $BinDir/BackupPC_tarExtrac
\n"); t\n");
exit(0); exit(0);
} }
} }
# #
# Run the transport program # Run the transport program
# #
$xfer->args({ $xfer->args({
host => $host, host => $host,
client => $client, client => $client,
hostIP => $hostIP, hostIP => $hostIP,
shareName => $shareName, shareName => $shareName,
pipeRH => *RH, pipeRH => *RH,
pipeWH => *WH, pipeWH => *WH,
XferLOG => $XferLOG, XferLOG => $XferLOG,
outDir => $Dir, outDir => $Dir,
type => $type, type => $type,
backups => \@Backups, backups => \@Backups,
compress => $Conf{CompressLevel}, compress => $Conf{CompressLevel},
XferMethod => $Conf{XferMethod}, XferMethod => $Conf{XferMethod},
logLevel => $Conf{XferLogLevel}, logLevel => $Conf{XferLogLevel},
inPlace => $inPlace, inPlace => $inPlace,
newBkupIdx => $newBkupIdx, newBkupIdx => $newBkupIdx,
lastBkupIdx => $lastBkupIdx, lastBkupIdx => $lastBkupIdx,
incrBaseBkupNum => $incrBaseBkupNum, incrBaseBkupNum => $incrBaseBkupNum,
incrBaseTime => $incrBaseTime, incrBaseTime => $incrBaseTime,
pidHandler => \&pidHandler, pidHandler => \&pidHandler,
noProgressPrint => $opts{p}, noProgressPrint => $opts{p},
}); });
if ( !defined($logMsg = $xfer->start()) ) { if ( !defined($logMsg = $xfer->start()) ) {
my $errStr = "xfer start failed: " . $xfer->errStr . "\n"; my $errStr = "xfer start failed: " . $xfer->errStr . "\n";
print($LogFd $bpc->timeStamp, $errStr); print($LogFd $bpc->timeStamp, $errStr);
# #
# kill off the tar process, first nicely then forcefully # kill off the tar process, first nicely then forcefully
# #
if ( $tarPid > 0 ) { if ( $tarPid > 0 ) {
kill($bpc->sigName2num("INT"), $tarPid); kill($bpc->sigName2num("INT"), $tarPid);
sleep(1); sleep(1);
kill($bpc->sigName2num("KILL"), $tarPid); kill($bpc->sigName2num("KILL"), $tarPid);
} }
if ( @xferPid ) { if ( @xferPid ) {
sleep(1); sleep(1);
kill($bpc->sigName2num("INT"), @xferPid); kill($bpc->sigName2num("INT"), @xferPid);
sleep(1); sleep(1);
kill($bpc->sigName2num("KILL"), @xferPid); kill($bpc->sigName2num("KILL"), @xferPid);
} }
UserCommandRun("DumpPostShareCmd", $shareName) if ( $NeedPostCmd ); UserCommandRun("DumpPostShareCmd", $shareName) if ( $NeedPostCmd );
UserCommandRun("DumpPostUserCmd") if ( $NeedPostCmd ); UserCommandRun("DumpPostUserCmd") if ( $NeedPostCmd );
$XferLOG->write(\$errStr); $XferLOG->write(\$errStr);
$stat{hostError} = $errStr; $stat{hostError} = $errStr;
BackupFailCleanup(); BackupFailCleanup();
} }
# #
# Create a needFsck file, so if we are killed and can't recover, we can # Create a needFsck file, so if we are killed and can't recover, we can
# make sure an fsck is run next time. # make sure an fsck is run next time.
# #
my $needFsckFH; my $needFsckFH;
skipping to change at line 1092 skipping to change at line 1094
# #
# Also grab a lock file, so we can serialize any fsck that might be # Also grab a lock file, so we can serialize any fsck that might be
# running. # running.
# #
$LockFd = BackupPC::XS::DirOps::lockRangeFile("$Dir/refCnt/LOCK", 0, 1, 1); $LockFd = BackupPC::XS::DirOps::lockRangeFile("$Dir/refCnt/LOCK", 0, 1, 1);
@xferPid = $xfer->xferPid; @xferPid = $xfer->xferPid;
if ( $useTar ) { if ( $useTar ) {
# #
# The parent must close both handles on the pipe since the children # The parent must close both handles on the pipe since the children
# are using these handles now. # are using these handles now.
# #
close(RH); close(RH);
close(WH); close(WH);
} }
print($LogFd $bpc->timeStamp, $logMsg, "\n"); print($LogFd $bpc->timeStamp, $logMsg, "\n");
$XferLOG->write(\"$logMsg\n"); $XferLOG->write(\"$logMsg\n");
print("started $type dump, share=$shareName\n"); print("started $type dump, share=$shareName\n");
pidHandler(@xferPid); pidHandler(@xferPid);
if ( $useTar ) { if ( $useTar ) {
# #
# Parse the output of the transfer program and BackupPC_tarExtract # Parse the output of the transfer program and BackupPC_tarExtract
# while they run. Since we might be reading from two or more children # while they run. Since we might be reading from two or more children
# we use a select. # we use a select.
# #
my($FDread, $tarOut, $mesg); my($FDread, $tarOut, $mesg);
vec($FDread, fileno(TAR), 1) = 1; vec($FDread, fileno(TAR), 1) = 1;
$xfer->setSelectMask(\$FDread); $xfer->setSelectMask(\$FDread);
SCAN: while ( 1 ) { SCAN: while ( 1 ) {
my $ein = $FDread; my $ein = $FDread;
last if ( $FDread =~ /^\0*$/ ); last if ( $FDread =~ /^\0*$/ );
select(my $rout = $FDread, undef, $ein, undef); select(my $rout = $FDread, undef, $ein, undef);
if ( vec($rout, fileno(TAR), 1) ) { if ( vec($rout, fileno(TAR), 1) ) {
if ( sysread(TAR, $mesg, 8192) <= 0 ) { if ( sysread(TAR, $mesg, 8192) <= 0 ) {
next if ( $!{EINTR} ); next if ( $!{EINTR} );
vec($FDread, fileno(TAR), 1) = 0; vec($FDread, fileno(TAR), 1) = 0;
close(TAR); close(TAR);
if ( $? ) { if ( $? ) {
$XferLOG->write(\"BackupPC_tarExtract exited with fail s tatus $?\n"); $XferLOG->write(\"BackupPC_tarExtract exited with fail s tatus $?\n");
$stat{hostError} = "BackupPC_tarExtract exited with fail status $?"; $stat{hostError} = "BackupPC_tarExtract exited with fail status $?";
} }
} else { } else {
$tarOut .= $mesg; $tarOut .= $mesg;
} }
} }
while ( $tarOut =~ /(.*?)[\n\r]+(.*)/s ) { while ( $tarOut =~ /(.*?)[\n\r]+(.*)/s ) {
$_ = $1; $_ = $1;
$tarOut = $2; $tarOut = $2;
if ( /^ / ) { if ( /^ / ) {
$XferLOG->write(\"$_\n"); $XferLOG->write(\"$_\n");
} elsif ( /^__bpc_progress_fileCnt__/ ) { } elsif ( /^__bpc_progress_fileCnt__/ ) {
print("$_\n"); print("$_\n");
} else { } else {
$XferLOG->write(\"tarExtract: $_\n"); $XferLOG->write(\"tarExtract: $_\n");
} }
if ( /^BackupPC_tarExtact aborting \((.*)\)/ ) { if ( /^BackupPC_tarExtact aborting \((.*)\)/ ) {
$stat{hostError} = $1; $stat{hostError} = $1;
} }
if ( /^Done: (\d+) errors, (\d+) filesExist, (\d+) sizeExist, (\ if (
d+) sizeExistComp, (\d+) filesTotal, (\d+) sizeTotal, (\d+) filesNew, (\d+) size /^Done: (\d+) errors, (\d+) filesExist, (\d+) sizeExist, (\d
New, (\d+) sizeNewComp, (\d+) inodeLast/ ) { +) sizeExistComp, (\d+) filesTotal, (\d+) sizeTotal, (\d+) filesNew, (\d+) sizeN
ew, (\d+) sizeNewComp, (\d+) inodeLast/
) {
$tarErrs += $1; $tarErrs += $1;
$nFilesExist += $2; $nFilesExist += $2;
$sizeExist += $3; $sizeExist += $3;
$sizeExistComp += $4; $sizeExistComp += $4;
$nFilesTotal += $5; $nFilesTotal += $5;
$sizeTotal += $6; $sizeTotal += $6;
$nFilesNew += $7; $nFilesNew += $7;
$sizeNew += $8; $sizeNew += $8;
$sizeNewComp += $9; $sizeNewComp += $9;
$inodeLast = $10; $inodeLast = $10;
} }
} }
last if ( !$xfer->readOutput(\$FDread, $rout) ); last if ( !$xfer->readOutput(\$FDread, $rout) );
while ( my $str = $xfer->logMsgGet ) { while ( my $str = $xfer->logMsgGet ) {
print($LogFd $bpc->timeStamp, "xfer: $str\n"); print($LogFd $bpc->timeStamp, "xfer: $str\n");
} }
if ( $xfer->getStats->{fileCnt} == 1 ) { if ( $xfer->getStats->{fileCnt} == 1 ) {
# #
# Make sure it is still the machine we expect. We do this while # Make sure it is still the machine we expect. We do this while
# the transfer is running to avoid a potential race condition if # the transfer is running to avoid a potential race condition if
# the ip address was reassigned by dhcp just before we started # the ip address was reassigned by dhcp just before we started
# the transfer. # the transfer.
# #
if ( my $errMsg = CorrectHostCheck($hostIP, $host) ) { if ( my $errMsg = CorrectHostCheck($hostIP, $host) ) {
$stat{hostError} = $errMsg if ( $stat{hostError} eq "" ); $stat{hostError} = $errMsg if ( $stat{hostError} eq "" );
last SCAN; last SCAN;
} }
} }
} }
} else { } else {
# #
# otherwise the xfer module does everything for us # otherwise the xfer module does everything for us
# #
my @results = $xfer->run(); my @results = $xfer->run();
$tarErrs += $results[0]; $tarErrs += $results[0];
$nFilesExist += $results[1]; $nFilesExist += $results[1];
$sizeExist += $results[2]; $sizeExist += $results[2];
$sizeExistComp += $results[3]; $sizeExistComp += $results[3];
$nFilesTotal += $results[4]; $nFilesTotal += $results[4];
$sizeTotal += $results[5]; $sizeTotal += $results[5];
$nFilesNew += $results[6]; $nFilesNew += $results[6];
$sizeNew += $results[7]; $sizeNew += $results[7];
$sizeNewComp += $results[8]; $sizeNewComp += $results[8];
$inodeLast = $results[9]; $inodeLast = $results[9];
} }
alarm(0); alarm(0);
# #
# Merge the xfer status (need to accumulate counts) # Merge the xfer status (need to accumulate counts)
# #
my $newStat = $xfer->getStats; my $newStat = $xfer->getStats;
# MAKSYM 14082016: forcing the right file count if some bytes were transferr ed; ensures compatibility with at least Samba-4.3 # MAKSYM 14082016: forcing the right file count if some bytes were transferr ed; ensures compatibility with at least Samba-4.3
$newStat->{fileCnt} = $nFilesTotal if ( $useTar && $newStat->{fileCnt} == 0 && $xfer->getStats->{byteCnt} > 0 ); $newStat->{fileCnt} = $nFilesTotal if ( $useTar && $newStat->{fileCnt} == 0 && $xfer->getStats->{byteCnt} > 0 );
if ( $newStat->{fileCnt} == 0 ) { if ( $newStat->{fileCnt} == 0 ) {
$noFilesErr ||= "No files dumped for share $shareName"; $noFilesErr ||= "No files dumped for share $shareName";
} }
foreach my $k ( (keys(%stat), keys(%$newStat)) ) { foreach my $k ( (keys(%stat), keys(%$newStat)) ) {
next if ( !defined($newStat->{$k}) ); next if ( !defined($newStat->{$k}) );
if ( $k =~ /Cnt$/ ) { if ( $k =~ /Cnt$/ ) {
$stat{$k} += $newStat->{$k}; $stat{$k} += $newStat->{$k};
delete($newStat->{$k}); delete($newStat->{$k});
next; next;
} }
if ( !defined($stat{$k}) ) { if ( !defined($stat{$k}) ) {
$stat{$k} = $newStat->{$k}; $stat{$k} = $newStat->{$k};
delete($newStat->{$k}); delete($newStat->{$k});
next; next;
} }
} }
if ( $NeedPostCmd ) { if ( $NeedPostCmd ) {
UserCommandRun("DumpPostShareCmd", $shareName); UserCommandRun("DumpPostShareCmd", $shareName);
if ( $? && $Conf{UserCmdCheckStatus} ) { if ( $? && $Conf{UserCmdCheckStatus} ) {
print($LogFd $bpc->timeStamp, print($LogFd $bpc->timeStamp, "DumpPostShareCmd returned error statu
"DumpPostShareCmd returned error status $?... exiting\n"); s $?... exiting\n");
$stat{hostError} = "DumpPostShareCmd returned error status $?"; $stat{hostError} = "DumpPostShareCmd returned error status $?";
} }
} }
$stat{xferOK} = 0 if ( $stat{hostError} || $stat{hostAbort} ); $stat{xferOK} = 0 if ( $stat{hostError} || $stat{hostAbort} );
if ( !$stat{xferOK} ) { if ( !$stat{xferOK} ) {
# #
# kill off the transfer program, first nicely then forcefully # kill off the transfer program, first nicely then forcefully
# #
if ( @xferPid ) { if ( @xferPid ) {
kill($bpc->sigName2num("INT"), @xferPid); kill($bpc->sigName2num("INT"), @xferPid);
sleep(1); sleep(1);
kill($bpc->sigName2num("KILL"), @xferPid); kill($bpc->sigName2num("KILL"), @xferPid);
} }
# #
# kill off the tar process, first nicely then forcefully # kill off the tar process, first nicely then forcefully
# #
if ( $tarPid > 0 ) { if ( $tarPid > 0 ) {
sleep(1); sleep(1);
kill($bpc->sigName2num("INT"), $tarPid); kill($bpc->sigName2num("INT"), $tarPid);
sleep(1); sleep(1);
kill($bpc->sigName2num("KILL"), $tarPid); kill($bpc->sigName2num("KILL"), $tarPid);
} }
# #
# don't do any more shares on this host # don't do any more shares on this host
# #
BackupPC::XS::DirOps::unlockRangeFile($LockFd); BackupPC::XS::DirOps::unlockRangeFile($LockFd);
$LockFd = undef; $LockFd = undef;
last; last;
} }
# #
# Wait for any child processes to exit # Wait for any child processes to exit
# #
skipping to change at line 1266 skipping to change at line 1270
unlink("$Dir/$newBkupNum/refCnt/needFsck.dump"); unlink("$Dir/$newBkupNum/refCnt/needFsck.dump");
BackupPC::XS::DirOps::unlockRangeFile($LockFd); BackupPC::XS::DirOps::unlockRangeFile($LockFd);
$LockFd = undef; $LockFd = undef;
} }
$tarPid = 0; $tarPid = 0;
pidHandler(); pidHandler();
# #
# If this is a full, and any share had zero files then consider the dump bad # If this is a full, and any share had zero files then consider the dump bad
# #
if ( $type eq "full" && $stat{hostError} eq "" if ( $type eq "full"
&& length($noFilesErr) && $Conf{BackupZeroFilesIsFatal} ) { && $stat{hostError} eq ""
&& length($noFilesErr)
&& $Conf{BackupZeroFilesIsFatal} ) {
$stat{hostError} = $noFilesErr; $stat{hostError} = $noFilesErr;
$stat{xferOK} = 0; $stat{xferOK} = 0;
} }
$stat{xferOK} = 0 if ( $Abort ); $stat{xferOK} = 0 if ( $Abort );
# #
# Do one last check to make sure it is still the machine we expect. # Do one last check to make sure it is still the machine we expect.
# #
if ( $stat{xferOK} && (my $errMsg = CorrectHostCheck($hostIP, $host)) ) { if ( $stat{xferOK} && (my $errMsg = CorrectHostCheck($hostIP, $host)) ) {
$stat{hostError} = $errMsg; $stat{hostError} = $errMsg;
$stat{xferOK} = 0; $stat{xferOK} = 0;
} }
# #
# Remove any shares that exist in the backup, but aren't in $ShareNames # Remove any shares that exist in the backup, but aren't in $ShareNames
# #
if ( $stat{xferOK} ) { if ( $stat{xferOK} ) {
OrphanShareNameClean("$Dir/$newBkupNum", $ShareNames, $Backups[$newBkupIdx]{ compress}); OrphanShareNameClean("$Dir/$newBkupNum", $ShareNames, $Backups[$newBkupIdx]{ compress});
} }
UserCommandRun("DumpPostUserCmd") if ( $NeedPostCmd ); UserCommandRun("DumpPostUserCmd") if ( $NeedPostCmd );
if ( $? && $Conf{UserCmdCheckStatus} ) { if ( $? && $Conf{UserCmdCheckStatus} ) {
print($LogFd $bpc->timeStamp, print($LogFd $bpc->timeStamp, "DumpPostUserCmd returned error status $?... e
"DumpPostUserCmd returned error status $?... exiting\n"); xiting\n");
$stat{hostError} = "DumpPostUserCmd returned error status $?"; $stat{hostError} = "DumpPostUserCmd returned error status $?";
$stat{xferOK} = 0; $stat{xferOK} = 0;
} }
my $endTime = time(); my $endTime = time();
# #
# If the dump failed, clean up # If the dump failed, clean up
# #
if ( !$stat{xferOK} ) { if ( !$stat{xferOK} ) {
$stat{hostError} = $stat{lastOutputLine} if ( $stat{hostError} eq "" ); $stat{hostError} = $stat{lastOutputLine} if ( $stat{hostError} eq "" );
if ( $stat{hostError} ) { if ( $stat{hostError} ) {
print($LogFd $bpc->timeStamp, print($LogFd $bpc->timeStamp, "Got fatal error during xfer ($stat{hostEr
"Got fatal error during xfer ($stat{hostError})\n"); ror})\n");
$XferLOG->write(\"Got fatal error during xfer ($stat{hostError})\n"); $XferLOG->write(\"Got fatal error during xfer ($stat{hostError})\n");
} }
if ( !$Abort ) { if ( !$Abort ) {
# #
# wait a short while and see if the system is still alive # wait a short while and see if the system is still alive
# #
sleep(5); sleep(5);
if ( $bpc->CheckHostAlive($hostIP) < 0 ) { if ( $bpc->CheckHostAlive($hostIP) < 0 ) {
$stat{hostAbort} = 1; $stat{hostAbort} = 1;
} }
if ( $stat{hostAbort} ) { if ( $stat{hostAbort} ) {
$stat{hostError} = "lost network connection during backup"; $stat{hostError} = "lost network connection during backup";
} }
print($LogFd $bpc->timeStamp, "Backup aborted ($stat{hostError})\n"); print($LogFd $bpc->timeStamp, "Backup aborted ($stat{hostError})\n");
$XferLOG->write(\"Backup aborted ($stat{hostError})\n"); $XferLOG->write(\"Backup aborted ($stat{hostError})\n");
} else { } else {
$XferLOG->write(\"Backup aborted by user signal\n"); if ( $XferLOG ) {
$XferLOG->write(\"Backup aborted by user signal\n");
} elsif ( $opts{v} ) {
print("Backup aborted by user signal\n");
}
} }
# #
# Close the log file and call BackupFailCleanup, which exits. # Close the log file and call BackupFailCleanup, which exits.
# #
BackupFailCleanup(); BackupFailCleanup();
} }
if ( $BackupCase == 4 && ($lastBkupType eq "partial" || $lastBkupType eq "active ") ) { if ( $BackupCase == 4 && ($lastBkupType eq "partial" || $lastBkupType eq "active ") ) {
# #
# Delete the prior backup #n, so that its deltas are merged into #n-1 # Delete the prior backup #n, so that its deltas are merged into #n-1
# #
print($LogFd $bpc->timeStamp, "Removing prior partial backup #$lastBkupNum\n "); print($LogFd $bpc->timeStamp, "Removing prior partial backup #$lastBkupNum\n ");
$XferLOG->write(\"Removing prior partial backup #$lastBkupNum\n"); $XferLOG->write(\"Removing prior partial backup #$lastBkupNum\n");
BackupRemove($client, $lastBkupIdx, 1); BackupRemove($client, $lastBkupIdx, 1);
} }
my $newNum = BackupSave(); my $newNum = BackupSave();
my $otherCount = $stat{xferErrCnt} - $stat{xferBadFileCnt} my $otherCount = $stat{xferErrCnt} - $stat{xferBadFileCnt} - $stat{xferBadShareC
- $stat{xferBadShareCnt}; nt};
$stat{fileCnt} ||= 0; $stat{fileCnt} ||= 0;
$stat{byteCnt} ||= 0; $stat{byteCnt} ||= 0;
$stat{xferErrCnt} ||= 0; $stat{xferErrCnt} ||= 0;
$stat{xferBadFileCnt} ||= 0; $stat{xferBadFileCnt} ||= 0;
$stat{xferBadShareCnt} ||= 0; $stat{xferBadShareCnt} ||= 0;
print($LogFd $bpc->timeStamp, my $logStr =
"$type backup $newNum complete, $stat{fileCnt} files," "$type backup $newNum complete, $stat{fileCnt} files, $stat{byteCnt} bytes,"
. " $stat{byteCnt} bytes," . " $stat{xferErrCnt} xferErrs ($stat{xferBadFileCnt} bad files,"
. " $stat{xferErrCnt} xferErrs ($stat{xferBadFileCnt} bad files," . " $stat{xferBadShareCnt} bad shares, $otherCount other)\n";
. " $stat{xferBadShareCnt} bad shares, $otherCount other)\n"); print($LogFd $bpc->timeStamp, $logStr);
$XferLOG->write(\"$type backup $newNum complete, $stat{fileCnt} files," $XferLOG->write(\$logStr) if ( $XferLOG && $Conf{XferLogLevel} >= 1 );
. " $stat{byteCnt} bytes,"
. " $stat{xferErrCnt} xferErrs ($stat{xferBadFileCnt} bad files,"
. " $stat{xferBadShareCnt} bad shares, $otherCount other)\n")
if ( $XferLOG && $Conf{XferLogLevel} >= 1 );
if ( $stat{xferOK} && $BackupCase == 4 && -f "$Dir/$lastBkupNum/refCnt/needFsck. newDir" ) { if ( $stat{xferOK} && $BackupCase == 4 && -f "$Dir/$lastBkupNum/refCnt/needFsck. newDir" ) {
# #
# remove temporary needFsck file on previous backup since backup succeeded o k # remove temporary needFsck file on previous backup since backup succeeded o k
# #
unlink("$Dir/$lastBkupNum/refCnt/needFsck.newDir"); unlink("$Dir/$lastBkupNum/refCnt/needFsck.newDir");
} }
BackupExpire($client); BackupExpire($client);
skipping to change at line 1411 skipping to change at line 1414
{ {
my $sigName = shift; my $sigName = shift;
# #
# The first time we receive a signal we try to gracefully # The first time we receive a signal we try to gracefully
# abort the backup. This allows us to keep a partial dump # abort the backup. This allows us to keep a partial dump
# with the in-progress file deleted and attribute caches # with the in-progress file deleted and attribute caches
# flushed to disk etc. # flushed to disk etc.
# #
if ( !length($SigName) ) { if ( !length($SigName) ) {
my $reason; my $reason;
if ( $sigName eq "INT" ) { if ( $sigName eq "INT" ) {
$reason = "aborted by user (signal=$sigName)"; $reason = "aborted by user (signal=$sigName)";
} else { } else {
$reason = "aborted by signal=$sigName"; $reason = "aborted by signal=$sigName";
} }
$stat{hostError} = $reason; $stat{hostError} = $reason;
if ( $Pid == $$ ) { print("Received signal: $reason\n") if ( $opts{v} );
# if ( $Pid == $$ ) {
# Parent logs a message #
# # Parent logs a message
print($LogFd $bpc->timeStamp, #
"Aborting backup up after signal $sigName\n"); print($LogFd $bpc->timeStamp, "Aborting backup up after signal $sigN
ame\n");
# print("Aborting backup up after signal $sigName\n") if ( $opts{v} );
# Tell xfer to abort, but only if we actually started one
# #
$xfer->abort($reason) if ( defined($xfer) ); # Tell xfer to abort, but only if we actually started one
#
# $xfer->abort($reason) if ( defined($xfer) );
# Send ALRMs to BackupPC_tarExtract if we are using it
# #
if ( $tarPid > 0 ) { # Send ALRMs to BackupPC_tarExtract if we are using it
kill($bpc->sigName2num("ARLM"), $tarPid); #
} if ( $tarPid > 0 ) {
kill($bpc->sigName2num("ALRM"), $tarPid);
} else { }
#
# Children ignore anything other than ALRM and INT } else {
# #
if ( $sigName ne "ALRM" && $sigName ne "INT" ) { # Children ignore anything other than ALRM and INT
return; #
} if ( $sigName ne "ALRM" && $sigName ne "INT" ) {
return;
# }
# The child also tells xfer to abort
# #
$xfer->abort($reason); # The child also tells xfer to abort
#
} $xfer->abort($reason);
$SigName = $sigName;
$Abort = 1; }
return; $SigName = $sigName;
$Abort = 1;
return;
} }
# #
# This is a second signal: time to clean up. # This is a second signal: time to clean up.
# #
if ( $Pid != $$ && ($sigName eq "ALRM" || $sigName eq "INT") ) { if ( $Pid != $$ && ($sigName eq "ALRM" || $sigName eq "INT") ) {
# #
# Children quit quietly on ALRM or INT # Children quit quietly on ALRM or INT
# #
exit(1) exit(1);
} }
# #
# Ignore other signals in children # Ignore other signals in children
# #
return if ( $Pid != $$ ); return if ( $Pid != $$ );
$SIG{$sigName} = 'IGNORE'; $SIG{$sigName} = 'IGNORE';
UserCommandRun("DumpPostUserCmd") if ( $NeedPostCmd ); UserCommandRun("DumpPostUserCmd") if ( $NeedPostCmd );
$XferLOG->write(\"exiting after signal $sigName\n"); if ( $XferLOG ) {
$XferLOG->write(\"exiting after signal $sigName\n");
} elsif ( $opts{v} ) {
print("exiting after signal $sigName\n");
}
if ( @xferPid ) { if ( @xferPid ) {
printf("killing xfer pids %s\n", join(",", @xferPid)) if ( $opts{v} );
kill($bpc->sigName2num("INT"), @xferPid); kill($bpc->sigName2num("INT"), @xferPid);
sleep(1); sleep(1);
kill($bpc->sigName2num("KILL"), @xferPid); kill($bpc->sigName2num("KILL"), @xferPid);
} }
if ( $tarPid > 0 ) { if ( $tarPid > 0 ) {
sleep(1); printf("killing tar pid $tarPid\n") if ( $opts{v} );
sleep(1);
kill($bpc->sigName2num("INT"), $tarPid); kill($bpc->sigName2num("INT"), $tarPid);
sleep(1); sleep(1);
kill($bpc->sigName2num("KILL"), $tarPid); kill($bpc->sigName2num("KILL"), $tarPid);
} }
if ( $sigName eq "INT" ) { if ( $sigName eq "INT" ) {
$stat{hostError} = "aborted by user (signal=$sigName)"; $stat{hostError} = "aborted by user (signal=$sigName)";
} else { } else {
$stat{hostError} = "received signal=$sigName"; $stat{hostError} = "received signal=$sigName";
} }
BackupFailCleanup(); BackupFailCleanup();
} }
sub CheckForAnyFiles sub CheckForAnyFiles
skipping to change at line 1571 skipping to change at line 1581
$compress = $Backups[$newBkupIdx]{compress}; $compress = $Backups[$newBkupIdx]{compress};
$removeIdx = $newBkupIdx; $removeIdx = $newBkupIdx;
$removeNum = $newBkupNum; $removeNum = $newBkupNum;
} elsif ( $BackupCase == 4 && $lastBkupType ne "partial" ) { } elsif ( $BackupCase == 4 && $lastBkupType ne "partial" ) {
$checkDir = "$Dir/$lastBkupNum"; $checkDir = "$Dir/$lastBkupNum";
$compress = $Backups[$lastBkupIdx]{compress}; $compress = $Backups[$lastBkupIdx]{compress};
$removeIdx = $lastBkupIdx; $removeIdx = $lastBkupIdx;
$removeNum = $lastBkupNum; $removeNum = $lastBkupNum;
} }
if ( $nFilesTotal == 0 && $checkDir ne "" ) { if ( $nFilesTotal == 0 && $checkDir ne "" ) {
BackupPC::DirOps::find($bpc, {wanted => BackupPC::DirOps::find(
sub { $bpc,
{
wanted => sub {
CheckForAnyFiles(@_, $compress); CheckForAnyFiles(@_, $compress);
}}, $checkDir); }
},
$checkDir
);
} }
$XferLOG->write(\"BackupFailCleanup: nFilesTotal = $nFilesTotal, type = $typ $XferLOG->write(
e, BackupCase = $BackupCase, inPlace = $inPlace, lastBkupNum = $lastBkupNum\n"); \"BackupFailCleanup: nFilesTotal = $nFilesTotal, type = $type, BackupCas
e = $BackupCase, inPlace = $inPlace, lastBkupNum = $lastBkupNum\n"
);
if ( $BackupCase == 4 && ($lastBkupType eq "partial" || $lastBkupType eq "ac tive") ) { if ( $BackupCase == 4 && ($lastBkupType eq "partial" || $lastBkupType eq "ac tive") ) {
# #
# Delete the prior backup #n, so that its deltas are merged into #n-1 # Delete the prior backup #n, so that its deltas are merged into #n-1
# #
print($LogFd $bpc->timeStamp, "Removing prior partial backup #$lastBkupN um\n"); print($LogFd $bpc->timeStamp, "Removing prior partial backup #$lastBkupN um\n");
$XferLOG->write(\"Removing prior partial backup #$lastBkupNum\n"); $XferLOG->write(\"Removing prior partial backup #$lastBkupNum\n");
BackupRemove($client, $lastBkupIdx, 1); BackupRemove($client, $lastBkupIdx, 1);
$Backups[-1]{type} = "partial" if ( @Backups ); $Backups[-1]{type} = "partial" if ( @Backups );
} elsif ( $BackupCase == 4 ) { } elsif ( $BackupCase == 4 ) {
if ( $nFilesTotal == 0 ) { if ( $nFilesTotal == 0 ) {
# #
# Remove the empty backup directory. The new XferLOG file gets rena med # Remove the empty backup directory. The new XferLOG file gets rena med
# to bad. # to bad.
# #
$Backups[$newBkupIdx] = {%{$Backups[$lastBkupIdx]}}; $Backups[$newBkupIdx] = {%{$Backups[$lastBkupIdx]}};
$Backups[$newBkupIdx]{num} = $newBkupNum; $Backups[$newBkupIdx]{num} = $newBkupNum;
$Backups[$newBkupIdx]{noFill} = 0; $Backups[$newBkupIdx]{noFill} = 0;
$Backups[$newBkupIdx]{keep} = 0;
print($LogFd $bpc->timeStamp, "Removing empty backup #$removeNum\n") ; print($LogFd $bpc->timeStamp, "Removing empty backup #$removeNum\n") ;
$XferLOG->write(\"Removing empty backup #$removeNum\n"); $XferLOG->write(\"Removing empty backup #$removeNum\n");
BackupRemove($client, $removeIdx, 0); BackupRemove($client, $removeIdx, 0);
push(@logRenames, push(@logRenames,
{from => "$Dir/XferLOG.$newBkupNum$fileExt", to => "$Dir/XferLO G.bad$fileExt"}, {from => "$Dir/XferLOG.$newBkupNum$fileExt", to => "$Dir/XferLO G.bad$fileExt"},
{from => "$Dir/XferLOG.$lastBkupNum$fileExt", to => "$Dir/XferLO {from => "$Dir/XferLOG.$lastBkupNum$fileExt", to => "$Dir/XferLO
G.$newBkupNum$fileExt"} G.$newBkupNum$fileExt"});
);
} else { } else {
$XferLOG->write(\"Keeping non-empty backup #$removeNum ($checkDir)\n "); $XferLOG->write(\"Keeping non-empty backup #$removeNum ($checkDir)\n ");
$Backups[-1]{type} = "partial" if ( @Backups ); $Backups[-1]{type} = "partial" if ( @Backups );
} }
} elsif ( $BackupCase == 1 || $BackupCase == 5 ) { } elsif ( $BackupCase == 1 || $BackupCase == 5 ) {
if ( $nFilesTotal == 0 ) { if ( $nFilesTotal == 0 ) {
# #
# Remove the empty backup directory. The new XferLOG file gets rena med # Remove the empty backup directory. The new XferLOG file gets rena med
# to bad. # to bad.
# #
print($LogFd $bpc->timeStamp, "Removing empty backup #$removeNum\n") ; print($LogFd $bpc->timeStamp, "Removing empty backup #$removeNum\n") ;
$XferLOG->write(\"Removing empty backup #$removeNum\n"); $XferLOG->write(\"Removing empty backup #$removeNum\n");
push(@logRenames, push(@logRenames, {from => "$Dir/XferLOG.$newBkupNum$fileExt", to =>
{from => "$Dir/XferLOG.$newBkupNum$fileExt", to => "$Dir/XferLO "$Dir/XferLOG.bad$fileExt"});
G.bad$fileExt"},
);
BackupRemove($client, $removeIdx, 0); BackupRemove($client, $removeIdx, 0);
} else { } else {
$XferLOG->write(\"Keeping non-empty backup #$removeNum ($checkDir)\n "); $XferLOG->write(\"Keeping non-empty backup #$removeNum ($checkDir)\n ");
$Backups[-1]{type} = "partial" if ( @Backups ); $Backups[-1]{type} = "partial" if ( @Backups );
} }
} else { } else {
if ( $nFilesTotal == 0 ) { if ( $nFilesTotal == 0 ) {
$XferLOG->write(\"BackupFailCleanup: inPlace with no new files... no cleanup\n"); $XferLOG->write(\"BackupFailCleanup: inPlace with no new files... no cleanup\n");
if ( $BackupCase == 6 || $BackupCase == 2 || $BackupCase == 3 ) { if ( $BackupCase == 6 || $BackupCase == 2 || $BackupCase == 3 ) {
$Backups[-1]{type} = "partial" if ( @Backups ); $Backups[-1]{type} = "partial" if ( @Backups );
skipping to change at line 1672 skipping to change at line 1687
print("dump failed: $stat{hostError}\n"); print("dump failed: $stat{hostError}\n");
exit(1); exit(1);
} }
# #
# Decide which old backups should be expired. # Decide which old backups should be expired.
# #
sub BackupExpire sub BackupExpire
{ {
my($client) = @_; my($client) = @_;
my($Dir) = "$TopDir/pc/$client"; my($Dir) = "$TopDir/pc/$client";
my($cntFull, $cntIncr, $firstFull, $firstIncr, $oldestIncr, my($cntFull, $cntIncr, $firstFull, $firstIncr, $oldestIncr, $oldestFull, $ch
$oldestFull, $changes); anges);
@Backups = $bpc->BackupInfoRead($client); @Backups = $bpc->BackupInfoRead($client);
if ( (ref($Conf{FullKeepCnt}) eq "ARRAY" ? @{$Conf{FullKeepCnt}} : $Conf{Ful lKeepCnt}) <= 0 ) { if ( (ref($Conf{FullKeepCnt}) eq "ARRAY" ? @{$Conf{FullKeepCnt}} : $Conf{Ful lKeepCnt}) <= 0 ) {
print($LogFd $bpc->timeStamp, print($LogFd $bpc->timeStamp,
"Invalid value for \$Conf{FullKeepCnt}=$Conf{FullKeepCnt}; not "Invalid value for \$Conf{FullKeepCnt}=$Conf{FullKeepCnt}; not expir
expiring any backups\n"); ing any backups\n");
print("Invalid value for \$Conf{FullKeepCnt}=$Conf{FullKeepCnt}; not expi print("Invalid value for \$Conf{FullKeepCnt}=$Conf{FullKeepCnt}; not exp
ring any backups\n") iring any backups\n")
if ( $opts{v} ); if ( $opts{v} );
return; return;
} }
while ( 1 ) { while ( 1 ) {
$cntFull = $cntIncr = 0; $cntFull = $cntIncr = 0;
$oldestIncr = $oldestFull = 0; $oldestIncr = $oldestFull = 0;
for ( my $i = 0 ; $i < @Backups ; $i++ ) { for ( my $i = 0 ; $i < @Backups ; $i++ ) {
#
# don't consider any backups marked keep
#
next if ( $Backups[$i]{keep} );
$Backups[$i]{preV4} = ($Backups[$i]{version} eq "" || $Backups[$i]{v ersion} =~ /^[23]\./) ? 1 : 0; $Backups[$i]{preV4} = ($Backups[$i]{version} eq "" || $Backups[$i]{v ersion} =~ /^[23]\./) ? 1 : 0;
if ( $Backups[$i]{preV4} ) { if ( $Backups[$i]{preV4} ) {
if ( $Backups[$i]{type} eq "full" ) { if ( $Backups[$i]{type} eq "full" ) {
$firstFull = $i if ( $cntFull == 0 ); $firstFull = $i if ( $cntFull == 0 );
$cntFull++; $cntFull++;
} elsif ( $Backups[$i]{type} eq "incr" ) { } elsif ( $Backups[$i]{type} eq "incr" ) {
$firstIncr = $i if ( $cntIncr == 0 ); $firstIncr = $i if ( $cntIncr == 0 );
$cntIncr++; $cntIncr++;
} }
} else { } else {
if ( !$Backups[$i]{noFill} ) { if ( !$Backups[$i]{noFill} ) {
$firstFull = $i if ( $cntFull == 0 ); $firstFull = $i if ( $cntFull == 0 );
$cntFull++; $cntFull++;
} else { } else {
$firstIncr = $i if ( $cntIncr == 0 ); $firstIncr = $i if ( $cntIncr == 0 );
$cntIncr++; $cntIncr++;
} }
} }
} }
$oldestIncr = (time - $Backups[$firstIncr]{startTime}) / (24 * 3600) $oldestIncr = (time - $Backups[$firstIncr]{startTime}) / (24 * 3600)
if ( $cntIncr > 0 ); if ( $cntIncr > 0 );
$oldestFull = (time - $Backups[$firstFull]{startTime}) / (24 * 3600) $oldestFull = (time - $Backups[$firstFull]{startTime}) / (24 * 3600)
if ( $cntFull > 0 ); if ( $cntFull > 0 );
$XferLOG->write(\"BackupExpire: cntFull = $cntFull, cntIncr = $cntIncr, if ( $XferLOG ) {
firstFull = $firstFull," my $logStr = "BackupExpire: cntFull = $cntFull, cntIncr = $cntIncr,
. " firstIncr = $firstIncr, oldestIncr = $oldestIncr, oldestF firstFull = $firstFull,"
ull = $oldestFull\n") . " firstIncr = $firstIncr, oldestIncr = $oldestIncr, oldestFull =
if ( $XferLOG ); $oldestFull\n";
$XferLOG->write(\$logStr);
}
# #
# In <= 3.x, with multi-level incrementals, several of the # In <= 3.x, with multi-level incrementals, several of the
# following incrementals might depend upon this one, so we # following incrementals might depend upon this one, so we
# have to delete all of the them. Figure out if that is # have to delete all of the them. Figure out if that is
# possible by counting the number of consecutive incrementals # possible by counting the number of consecutive incrementals
# that are unfilled and have a level higher than this one. # that are unfilled and have a level higher than this one.
# #
# In >= 4.x any backup can be deleted since the changes get # In >= 4.x any backup can be deleted since the changes get
# merged with the next older deltas, so we just do one at # merged with the next older deltas, so we just do one at
# a time. # a time.
# #
my $cntIncrDel = 1; my $cntIncrDel = 1;
my $earliestIncr = $oldestIncr; my $earliestIncr = $oldestIncr;
if ( defined($firstIncr) ) { if ( defined($firstIncr) ) {
for ( my $i = $firstIncr + 1 ; $i < @Backups ; $i++ ) { for ( my $i = $firstIncr + 1 ; $i < @Backups ; $i++ ) {
last if ( !$Backups[$i]{preV4} || $Backups[$i]{level} <= $Backup last
s[$firstIncr]{level} if ( !$Backups[$i]{preV4}
|| !$Backups[$i]{noFill} ); || $Backups[$i]{level} <= $Backups[$firstIncr]{level}
|| !$Backups[$i]{noFill} );
$cntIncrDel++; $cntIncrDel++;
$earliestIncr = (time - $Backups[$i]{startTime}) / (24 * 3600); $earliestIncr = (time - $Backups[$i]{startTime}) / (24 * 3600);
} }
} }
if ( $cntIncr >= $Conf{IncrKeepCnt} + $cntIncrDel if (
|| ($cntIncr >= $Conf{IncrKeepCntMin} + $cntIncrDel $cntIncr >= $Conf{IncrKeepCnt} + $cntIncrDel
&& $earliestIncr > $Conf{IncrAgeMax}) ) { || ( $cntIncr >= $Conf{IncrKeepCntMin} + $cntIncrDel
&& $earliestIncr > $Conf{IncrAgeMax})
) {
# #
# Only delete an incr backup if the Conf settings are satisfied # Only delete an incr backup if the Conf settings are satisfied
# for all $cntIncrDel incrementals. Since BackupRemove() updates # for all $cntIncrDel incrementals. Since BackupRemove() updates
# the @Backups array we need to do the deletes in the reverse order. # the @Backups array we need to do the deletes in the reverse order.
# #
for ( my $i = $firstIncr + $cntIncrDel - 1 ; for ( my $i = $firstIncr + $cntIncrDel - 1 ; $i >= $firstIncr ; $i--
$i >= $firstIncr ; $i-- ) { ) {
print($LogFd $bpc->timeStamp, "Removing unfilled backup $Backups [$i]{num}\n"); print($LogFd $bpc->timeStamp, "Removing unfilled backup $Backups [$i]{num}\n");
$XferLOG->write(\"Removing unfilled backup $Backups[$i]{num}\n") if ( $XferLOG ); $XferLOG->write(\"Removing unfilled backup $Backups[$i]{num}\n") if ( $XferLOG );
last if ( BackupRemove($client, $i, 1) ); last if ( BackupRemove($client, $i, 1) );
$changes++; $changes++;
} }
next; next;
} }
# #
# Delete any old full backups, according to $Conf{FullKeepCntMin} # Delete any old full backups, according to $Conf{FullKeepCntMin}
# and $Conf{FullAgeMax}. # and $Conf{FullAgeMax}.
# #
# First make sure that $Conf{FullAgeMax} is at least bigger # First make sure that $Conf{FullAgeMax} is at least bigger
# than $Conf{FullPeriod} * $Conf{FullKeepCnt}, including # than $Conf{FullPeriod} * $Conf{FullKeepCnt}, including
# the exponential array case. # the exponential array case.
# #
my $fullKeepCnt = $Conf{FullKeepCnt}; my $fullKeepCnt = $Conf{FullKeepCnt};
$fullKeepCnt = [$fullKeepCnt] if ( ref($fullKeepCnt) ne "ARRAY" ); $fullKeepCnt = [$fullKeepCnt] if ( ref($fullKeepCnt) ne "ARRAY" );
# #
# Always save one more than what the user configured to account for the most # Always save one more than what the user configured to account for the most
# recent backup which is always filled (whether incr or full); also copy the # recent backup which is always filled (whether incr or full); also copy the
# array so we don't update $Conf{FullKeepCnt}. # array so we don't update $Conf{FullKeepCnt}.
# #
$fullKeepCnt = [@$fullKeepCnt]; $fullKeepCnt = [@$fullKeepCnt];
$fullKeepCnt->[0]++; $fullKeepCnt->[0]++;
my $fullAgeMax; my $fullAgeMax;
my $fullPeriod = int(0.5 + $Conf{FullPeriod}); my $fullPeriod = int(0.5 + $Conf{FullPeriod});
$fullPeriod = 7 if ( $fullPeriod <= 0 ); $fullPeriod = 7 if ( $fullPeriod <= 0 );
for ( my $i = 0 ; $i < @$fullKeepCnt ; $i++ ) { for ( my $i = 0 ; $i < @$fullKeepCnt ; $i++ ) {
$fullAgeMax += $fullKeepCnt->[$i] * $fullPeriod; $fullAgeMax += $fullKeepCnt->[$i] * $fullPeriod;
$fullPeriod *= 2; $fullPeriod *= 2;
} }
$fullAgeMax += $fullPeriod; # add some buffer $fullAgeMax += $fullPeriod; # add some buffer
if ( $cntFull > $Conf{FullKeepCntMin} + 1 if ( $cntFull > $Conf{FullKeepCntMin} + 1
&& $oldestFull > $Conf{FullAgeMax} && $oldestFull > $Conf{FullAgeMax}
&& $oldestFull > $fullAgeMax && $oldestFull > $fullAgeMax
&& $Conf{FullKeepCntMin} >= 0 && $Conf{FullKeepCntMin} >= 0
&& $Conf{FullAgeMax} > 0 ) { && $Conf{FullAgeMax} > 0 ) {
# #
# Only delete a full backup if the Conf settings are satisfied. # Only delete a full backup if the Conf settings are satisfied.
# #
# For pre-V4 we also must make sure that either this backup is the # For pre-V4 we also must make sure that either this backup is the
# most recent one, or the next backup is filled. # most recent one, or the next backup is filled.
# (In pre-V4 we can't deleted a full backup if the next backup is no t # (In pre-V4 we can't deleted a full backup if the next backup is no t
# filled.) # filled.)
# #
if ( !$Backups[$firstFull]{preV4} || (@Backups <= $firstFull + 1 if (
|| !$Backups[$firstFull + 1]{noFill}) ) { !$Backups[$firstFull]{preV4}
|| (@Backups <= $firstFull + 1
|| !$Backups[$firstFull + 1]{noFill})
) {
print($LogFd $bpc->timeStamp, "Removing filled backup $Backups[$ firstFull]{num}\n"); print($LogFd $bpc->timeStamp, "Removing filled backup $Backups[$ firstFull]{num}\n");
$XferLOG->write(\"Removing filled backup $Backups[$firstFull]{nu m}\n") if ( $XferLOG ); $XferLOG->write(\"Removing filled backup $Backups[$firstFull]{nu m}\n") if ( $XferLOG );
last if ( BackupRemove($client, $firstFull, 1) ); last if ( BackupRemove($client, $firstFull, 1) );
$changes++; $changes++;
next; next;
} }
} }
# #
# Do new-style full backup expiry, which includes the the case # Do new-style full backup expiry, which includes the the case
# where $Conf{FullKeepCnt} is an array. # where $Conf{FullKeepCnt} is an array.
# #
last if ( !BackupFullExpire($client, \@Backups) ); last if ( !BackupFullExpire($client, \@Backups) );
$changes++; $changes++;
} }
$bpc->BackupInfoWrite($client, @Backups) if ( $changes ); $bpc->BackupInfoWrite($client, @Backups) if ( $changes );
} }
# #
# Handle full backup expiry, using exponential periods. # Handle full backup expiry, using exponential periods.
# #
sub BackupFullExpire sub BackupFullExpire
{ {
my($client, $Backups) = @_; my($client, $Backups) = @_;
my $fullCnt = 0; my $fullCnt = 0;
my $fullPeriod = $Conf{FillCycle} <= 0 ? $Conf{FullPeriod} : $Conf{FillCycle }; my $fullPeriod = $Conf{FillCycle} <= 0 ? $Conf{FullPeriod} : $Conf{FillCycle };
my $nextFull; my $nextFull;
my $fullKeepCnt = $Conf{FullKeepCnt}; my $fullKeepCnt = $Conf{FullKeepCnt};
my $fullKeepIdx = 0; my $fullKeepIdx = 0;
my(@delete, @fullList); my(@delete, @fullList);
# #
# Don't delete anything if $Conf{FillCycle}, $Conf{FullPeriod} or $Conf{Full KeepCnt} # Don't delete anything if $Conf{FillCycle}, $Conf{FullPeriod} or $Conf{Full KeepCnt}
# are not defined - possibly a corrupted config.pl file. # are not defined - possibly a corrupted config.pl file.
# #
return if ( !defined($Conf{FillCycle}) || !defined($Conf{FullPeriod}) return if ( !defined($Conf{FillCycle})
|| !defined($Conf{FullKeepCnt}) ); || !defined($Conf{FullPeriod})
|| !defined($Conf{FullKeepCnt}) );
# #
# Always save one more than what the user configured to account for the most # Always save one more than what the user configured to account for the most
# recent backup which is always filled (whether incr or full); also copy the # recent backup which is always filled (whether incr or full); also copy the
# array so we don't update $Conf{FullKeepCnt}. # array so we don't update $Conf{FullKeepCnt}.
# #
$fullKeepCnt = [$fullKeepCnt] if ( ref($fullKeepCnt) ne "ARRAY" ); $fullKeepCnt = [$fullKeepCnt] if ( ref($fullKeepCnt) ne "ARRAY" );
$fullKeepCnt = [@$fullKeepCnt]; $fullKeepCnt = [@$fullKeepCnt];
$fullKeepCnt->[0]++; $fullKeepCnt->[0]++;
# #
# If regular backups are still disabled with $Conf{FullPeriod} < 0, # If regular backups are still disabled with $Conf{FullPeriod} < 0,
# we still expire backups based on a safe FullPeriod value - daily. # we still expire backups based on a safe FullPeriod value - daily.
# #
$fullPeriod = 1 if ( $fullPeriod <= 0 ); $fullPeriod = 1 if ( $fullPeriod <= 0 );
my $startTimeDeviation = $fullPeriod < 1 ? $fullPeriod / 2 : 0.5; my $startTimeDeviation = $fullPeriod < 1 ? $fullPeriod / 2 : 0.5;
my $keepPeriod = ($fullPeriod * ($fullKeepCnt->[0] - 1) - $startTimeDeviatio n) * 24 * 3600; my $keepPeriod = ($fullPeriod * ($fullKeepCnt->[0] - 1) - $startTime Deviation) * 24 * 3600;
for ( my $i = 0 ; $i < @$Backups ; $i++ ) { for ( my $i = 0 ; $i < @$Backups ; $i++ ) {
#
# don't consider any backups marked keep
#
next if ( $Backups[$i]{keep} );
if ( $Backups[$i]{preV4} ) { if ( $Backups[$i]{preV4} ) {
next if ( $Backups->[$i]{type} ne "full" ); next if ( $Backups->[$i]{type} ne "full" );
} else { } else {
next if ( $Backups->[$i]{noFill} ); next if ( $Backups->[$i]{noFill} );
} }
push(@fullList, $i); push(@fullList, $i);
} }
for ( my $k = @fullList - 1 ; $k >= 0 ; $k-- ) { for ( my $k = @fullList - 1 ; $k >= 0 ; $k-- ) {
my $i = $fullList[$k]; my $i = $fullList[$k];
my $prevFull = $fullList[$k-1] if ( $k > 0 ); my $prevFull = $fullList[$k - 1] if ( $k > 0 );
# #
# For pre-V4 don't delete any full that is followed by an unfilled backu p, # For pre-V4 don't delete any full that is followed by an unfilled backu p,
# since it is needed for restore. # since it is needed for restore.
# #
my $noDelete = $i + 1 < @$Backups ? $Backups->[$i+1]{noFill} : 0; my $noDelete = $i + 1 < @$Backups ? $Backups->[$i + 1]{noFill} : 0;
$noDelete = 0 if ( !$Backups[$i]{preV4} ); $noDelete = 0 if ( !$Backups[$i]{preV4} );
if ( !$noDelete && if (
($fullKeepIdx >= @$fullKeepCnt !$noDelete
|| $k > 0 && ( $fullKeepIdx >= @$fullKeepCnt
&& $fullKeepIdx > 0 || $k > 0
&& defined($nextFull) && $fullKeepIdx > 0
&& $Backups->[$nextFull]{startTime} - $Backups->[$prevFull]{sta && defined($nextFull)
rtTime} && $Backups->[$nextFull]{startTime} - $Backups->[$prevFull]{star
< ($fullPeriod + $startTimeDeviation) * 24 * 3600 tTime} <
) ($fullPeriod + $startTimeDeviation) * 24 * 3600)
) { ) {
# #
# Delete the full backup # Delete the full backup
# #
#print("Deleting backup $Backups->[$i]{num} (i = $i, k = $k, nextFul l = $nextFull, prevFull = $prevFull, fullKeepIdx = $fullKeepIdx, fullCnt = $full Cnt)\n"); #print("Deleting backup $Backups->[$i]{num} (i = $i, k = $k, nextFul l = $nextFull, prevFull = $prevFull, fullKeepIdx = $fullKeepIdx, fullCnt = $full Cnt)\n");
unshift(@delete, $i); unshift(@delete, $i);
} else { } else {
#printf("Keeping backup $Backups->[$i]{num} (i = $i, k = $k, nextFul l = $nextFull, prevFull = $prevFull, fullKeepIdx = $fullKeepIdx, fullCnt = $full Cnt, keepPeriod = %.3g, delta = %.3g)\n", $keepPeriod / (24 * 3600), (time - $Ba ckups->[$i]{startTime}) / (24 * 3600)); #printf("Keeping backup $Backups->[$i]{num} (i = $i, k = $k, nextFul l = $nextFull, prevFull = $prevFull, fullKeepIdx = $fullKeepIdx, fullCnt = $full Cnt, keepPeriod = %.3g, delta = %.3g)\n", $keepPeriod / (24 * 3600), (time - $Ba ckups->[$i]{startTime}) / (24 * 3600));
$fullCnt++; $fullCnt++;
$nextFull = $i; $nextFull = $i;
while ( $fullKeepIdx < @$fullKeepCnt while ( $fullKeepIdx < @$fullKeepCnt
&& $k > 0 && $k > 0
&& time - $Backups->[$prevFull]{startTime} > $keepPeriod && time - $Backups->[$prevFull]{startTime} > $keepPeriod
&& $fullCnt >= $fullKeepCnt->[$fullKeepIdx] ) { && $fullCnt >= $fullKeepCnt->[$fullKeepIdx] ) {
$fullKeepIdx++; $fullKeepIdx++;
$fullCnt = 0; $fullCnt = 0;
$fullPeriod = 2 * $fullPeriod; $fullPeriod = 2 * $fullPeriod;
} }
#print(" (now nextFull = $nextFull, prevFull = $prevFull, fullKee pIdx = $fullKeepIdx, fullCnt = $fullCnt, fullPeriod = $fullPeriod, fullKeepCnt[i dx] = $fullKeepCnt->[$fullKeepIdx])\n"); #print(" (now nextFull = $nextFull, prevFull = $prevFull, fullKee pIdx = $fullKeepIdx, fullCnt = $fullCnt, fullPeriod = $fullPeriod, fullKeepCnt[i dx] = $fullKeepCnt->[$fullKeepIdx])\n");
} }
} }
# #
# Now actually delete the backups # Now actually delete the backups
# #
for ( my $i = @delete - 1 ; $i >= 0 ; $i-- ) { for ( my $i = @delete - 1 ; $i >= 0 ; $i-- ) {
print($LogFd $bpc->timeStamp, "Removing filled backup $Backups->[$delete [$i]]{num}\n"); print($LogFd $bpc->timeStamp, "Removing filled backup $Backups->[$delete [$i]]{num}\n");
skipping to change at line 1924 skipping to change at line 1955
sub BackupSave sub BackupSave
{ {
my($noWrite) = @_; my($noWrite) = @_;
# #
# Update the new backup information to the backup file. # Update the new backup information to the backup file.
# A new entry in @Backups was created at the start of the backup, # A new entry in @Backups was created at the start of the backup,
# so we update the last entry of @Backups. # so we update the last entry of @Backups.
# #
@Backups = $bpc->BackupInfoRead($client); @Backups = $bpc->BackupInfoRead($client);
my $i = @Backups - 1; my $i = @Backups - 1;
$i = 0 if ( $i < 0 ); $i = 0 if ( $i < 0 );
$Backups[$i]{num} = $newBkupNum if ( !defined($Backups[$i]{num}) ); $Backups[$i]{num} = $newBkupNum if ( !defined($Backups[$i]{num}) );
my $num = $Backups[$i]{num}; my $num = $Backups[$i]{num};
$Backups[$i]{type} = $type; $Backups[$i]{type} = $type;
$Backups[$i]{level} = $type eq "incr" ? 1 : 0; $Backups[$i]{level} = $type eq "incr" ? 1 : 0;
$Backups[$i]{startTime} = $startTime; $Backups[$i]{startTime} = $startTime;
$Backups[$i]{endTime} = $endTime; $Backups[$i]{endTime} = $endTime;
$Backups[$i]{size} = $sizeTotal; $Backups[$i]{size} = $sizeTotal;
$Backups[$i]{nFiles} = $nFilesTotal; $Backups[$i]{nFiles} = $nFilesTotal;
$Backups[$i]{xferErrs} = $stat{xferErrCnt} || 0; $Backups[$i]{xferErrs} = $stat{xferErrCnt} || 0;
$Backups[$i]{xferBadFile} = $stat{xferBadFileCnt} || 0; $Backups[$i]{xferBadFile} = $stat{xferBadFileCnt} || 0;
$Backups[$i]{xferBadShare} = $stat{xferBadShareCnt} || 0; $Backups[$i]{xferBadShare} = $stat{xferBadShareCnt} || 0;
$Backups[$i]{nFilesExist} = $nFilesExist; $Backups[$i]{nFilesExist} = $nFilesExist;
$Backups[$i]{sizeExist} = $sizeExist; $Backups[$i]{sizeExist} = $sizeExist;
$Backups[$i]{sizeExistComp} = $sizeExistComp; $Backups[$i]{sizeExistComp} = $sizeExistComp;
$Backups[$i]{nFilesNew} = $nFilesNew; $Backups[$i]{nFilesNew} = $nFilesNew;
$Backups[$i]{sizeNew} = $sizeNew; $Backups[$i]{sizeNew} = $sizeNew;
$Backups[$i]{sizeNewComp} = $sizeNewComp; $Backups[$i]{sizeNewComp} = $sizeNewComp;
$Backups[$i]{tarErrs} = $tarErrs; $Backups[$i]{tarErrs} = $tarErrs;
$Backups[$i]{compress} = $Conf{CompressLevel}; $Backups[$i]{compress} = $Conf{CompressLevel};
$Backups[$i]{noFill} = 0; $Backups[$i]{noFill} = 0;
$Backups[$i]{mangle} = 1; # name mangling always on for v1.04+ $Backups[$i]{mangle} = 1; # name mangling always on for v1.04+
$Backups[$i]{xferMethod} = $Conf{XferMethod}; $Backups[$i]{xferMethod} = $Conf{XferMethod};
$Backups[$i]{charset} = $Conf{ClientCharset}; $Backups[$i]{charset} = $Conf{ClientCharset};
$Backups[$i]{version} = $bpc->Version(); $Backups[$i]{version} = $bpc->Version();
$Backups[$i]{inodeLast} = $inodeLast; $Backups[$i]{inodeLast} = $inodeLast;
$Backups[$i]{keep} = 0;
$Backups[$i]{share2path} = $Conf{ClientShareName2Path};
$Backups[$i]{comment} = "";
return if ( $noWrite ); return if ( $noWrite );
# #
# Save the main backups file # Save the main backups file
# #
$bpc->BackupInfoWrite($client, @Backups); $bpc->BackupInfoWrite($client, @Backups);
# #
# Save just this backup's info in case the main backups file # Save just this backup's info in case the main backups file
# gets corrupted # gets corrupted
# #
BackupPC::Storage->backupInfoWrite($Dir, $Backups[$i]{num}, BackupPC::Storage->backupInfoWrite($Dir, $Backups[$i]{num}, $Backups[$i], 1)
$Backups[$i], 1); ;
unlink("$Dir/timeStamp.level0") if ( -f "$Dir/timeStamp.level0" ); unlink("$Dir/timeStamp.level0") if ( -f "$Dir/timeStamp.level0" );
foreach my $ext ( qw(bad bad.z) ) { foreach my $ext ( qw(bad bad.z) ) {
next if ( !-f "$Dir/XferLOG.$ext" ); next if ( !-f "$Dir/XferLOG.$ext" );
unlink("$Dir/XferLOG.$ext.old") if ( -f "$Dir/XferLOG.$ext" ); unlink("$Dir/XferLOG.$ext.old") if ( -f "$Dir/XferLOG.$ext" );
rename("$Dir/XferLOG.$ext", "$Dir/XferLOG.$ext.old"); rename("$Dir/XferLOG.$ext", "$Dir/XferLOG.$ext.old");
} }
return $num; return $num;
} }
# #
# Removes a specific backup, or a sharename within a backup # Removes a specific backup, or a sharename within a backup
# #
sub BackupRemove sub BackupRemove
{ {
my($client, $idx, $removeXferLOG, $shareName) = @_; my($client, $idx, $removeXferLOG, $shareName) = @_;
my $t = time; my $t = time;
my $pids = {}; my $pids = {};
my $fileExt = $Backups[$idx]{compress} > 0 ? ".z" : ""; my $fileExt = $Backups[$idx]{compress} > 0 ? ".z" : "";
my $bkupNum = $Backups[$idx]{num}; my $bkupNum = $Backups[$idx]{num};
my @args = ("-h", $client, "-n", $Backups[$idx]{num}, "-l", "-m"); my @args = ("-h", $client, "-n", $Backups[$idx]{num}, "-l", "-m");
if ( $Backups[$idx]{keep} ) {
#
# this shouldn't happen, but report an error if it does
#
$XferLOG->write(\"BackupRemove(num = $bkupNum) -> skipping because keep
is set\n")
if ( defined($XferLOG) );
return 1;
}
if ( defined($shareName) ) { if ( defined($shareName) ) {
push(@args, "-s", $shareName, "/"); push(@args, "-s", $shareName, "/");
print("__bpc_progress_state__ delete share #$bkupNum/$shareName\n") if ( !$opts{p} ); print("__bpc_progress_state__ delete share #$bkupNum/$shareName\n") if ( !$opts{p} );
} else { } else {
print("__bpc_progress_state__ delete #$bkupNum\n") if ( !$opts{p} ); print("__bpc_progress_state__ delete #$bkupNum\n") if ( !$opts{p} );
} }
push(@args, "-p") if ( $opts{p} ); push(@args, "-p") if ( $opts{p} );
unlink("$Dir/XferLOG.$bkupNum$fileExt") if ( !defined($shareName) && $remove XferLOG ); unlink("$Dir/XferLOG.$bkupNum$fileExt") if ( !defined($shareName) && $remove XferLOG );
skipping to change at line 2011 skipping to change at line 2053
} elsif ( $_[0] =~ /^__bpc_pidStart__ (\d+)/ ) { } elsif ( $_[0] =~ /^__bpc_pidStart__ (\d+)/ ) {
$pids->{$1} = 1; $pids->{$1} = 1;
pidHandler(keys(%$pids)); pidHandler(keys(%$pids));
} elsif ( $_[0] =~ /^__bpc_pidEnd__ (\d+)/ ) { } elsif ( $_[0] =~ /^__bpc_pidEnd__ (\d+)/ ) {
delete($pids->{$1}); delete($pids->{$1});
pidHandler(keys(%$pids)); pidHandler(keys(%$pids));
} else { } else {
print($LogFd $bpc->timeStamp, $_[0]); print($LogFd $bpc->timeStamp, $_[0]);
$XferLOG->write(\$_[0]) if ( defined($XferLOG) ); $XferLOG->write(\$_[0]) if ( defined($XferLOG) );
} }
}); }
);
my $ret = $?; my $ret = $?;
$t = time - $t; $t = time - $t;
print($LogFd $bpc->timeStamp, "Finished BackupPC_backupDelete, status = $ret (running time: $t sec)\n"); print($LogFd $bpc->timeStamp, "Finished BackupPC_backupDelete, status = $ret (running time: $t sec)\n");
$XferLOG->write(\"Finished BackupPC_backupDelete, status = $ret (running tim e: $t sec)\n") $XferLOG->write(\"Finished BackupPC_backupDelete, status = $ret (running tim e: $t sec)\n")
if ( defined($XferLOG) ); if ( defined($XferLOG) );
pidHandler(); pidHandler();
if ( !defined($shareName) ) { if ( !defined($shareName) ) {
splice(@Backups, $idx, 1); splice(@Backups, $idx, 1);
} }
return $ret; return $ret;
} }
sub CorrectHostCheck sub CorrectHostCheck
{ {
my($hostIP, $host) = @_; my($hostIP, $host) = @_;
return if ( $hostIP eq $host || !$Conf{FixedIPNetBiosNameCheck} return if ( $hostIP eq $host || !$Conf{FixedIPNetBiosNameCheck} || $Conf{Nmb
|| $Conf{NmbLookupCmd} eq "" ); LookupCmd} eq "" );
if (ref($Conf{ClientNameAlias}) eq "ARRAY") { if ( ref($Conf{ClientNameAlias}) eq "ARRAY" ) {
return if ( grep /^$hostIP$/, @{ $Conf{ClientNameAlias} } ); return if ( grep /^$hostIP$/, @{$Conf{ClientNameAlias}} );
} }
my($netBiosHost, $netBiosUser) = $bpc->NetBiosInfoGet($hostIP); my($netBiosHost, $netBiosUser) = $bpc->NetBiosInfoGet($hostIP);
return "host $host has mismatching netbios name $netBiosHost" return "host $host has mismatching netbios name $netBiosHost"
if ( lc($netBiosHost) ne lc(substr($host, 0, 15)) ); if ( lc($netBiosHost) ne lc(substr($host, 0, 15)) );
return; return;
} }
# #
# Returns $host if $bpc->getHostAddrInfo() knows about it. # Returns $host if $bpc->getHostAddrInfo() knows about it.
# Otherwise tries to find the hostIP via NetBios, and returns # Otherwise tries to find the hostIP via NetBios, and returns
# the hostIP if successful. # the hostIP if successful.
# #
# Returns undef if both $bpc->getHostAddrInfo() and NetBios fail # Returns undef if both $bpc->getHostAddrInfo() and NetBios fail
# #
skipping to change at line 2106 skipping to change at line 2148
# #
# With $doFsck = 1 and $doCheck = 0, the pool count files are rebuilt, # With $doFsck = 1 and $doCheck = 0, the pool count files are rebuilt,
# without checking the old one. # without checking the old one.
# #
# With $doFsck = 1 and $doCheck = 1, the pool count files are rebuilt, # With $doFsck = 1 and $doCheck = 1, the pool count files are rebuilt,
# and differences to the current ones are listed. # and differences to the current ones are listed.
# #
sub RefCountUpdate sub RefCountUpdate
{ {
my($doFsck, $doCheck) = @_; my($doFsck, $doCheck) = @_;
my $t = time; my $t = time;
my $pids = {}; my $pids = {};
my $args = ["-h", $client]; my $args = ["-h", $client];
push(@$args, "-f") if ( $doFsck ); push(@$args, "-f") if ( $doFsck );
push(@$args, "-c") if ( $doCheck ); push(@$args, "-c") if ( $doCheck );
push(@$args, "-p") if ( $opts{p} ); push(@$args, "-p") if ( $opts{p} );
print("__bpc_progress_state__ fsck\n") if ( !$opts{p} ); print("__bpc_progress_state__ fsck\n") if ( !$opts{p} );
$XferLOG->write(\"Running BackupPC_refCountUpdate @$args on $client\n"); $XferLOG->write(\"Running BackupPC_refCountUpdate @$args on $client\n");
$bpc->cmdSystemOrEval(["$BinDir/BackupPC_refCountUpdate", @$args], $bpc->cmdSystemOrEval(
sub { ["$BinDir/BackupPC_refCountUpdate", @$args],
if ( $_[0] =~ /^__bpc_progress_/ ) { sub {
print($_[0]); if ( $_[0] =~ /^__bpc_progress_/ ) {
} elsif ( $_[0] =~ /^__bpc_pidStart__ (\d+)/ ) { print($_[0]);
$pids->{$1} = 1; } elsif ( $_[0] =~ /^__bpc_pidStart__ (\d+)/ ) {
pidHandler(keys(%$pids)); $pids->{$1} = 1;
} elsif ( $_[0] =~ /^__bpc_pidEnd__ (\d+)/ ) { pidHandler(keys(%$pids));
delete($pids->{$1}); } elsif ( $_[0] =~ /^__bpc_pidEnd__ (\d+)/ ) {
pidHandler(keys(%$pids)); delete($pids->{$1});
} else { pidHandler(keys(%$pids));
$XferLOG->write(\$_[0]); } else {
} $XferLOG->write(\$_[0]);
}); }
}
);
$t = time - $t; $t = time - $t;
$XferLOG->write(\"Finished BackupPC_refCountUpdate (running time: $t sec)\n" ); $XferLOG->write(\"Finished BackupPC_refCountUpdate (running time: $t sec)\n" );
pidHandler(); pidHandler();
} }
# #
# The Xfer method might tell us from time to time about processes # The Xfer method might tell us from time to time about processes
# it forks. We tell BackupPC about this (for status displays) and # it forks. We tell BackupPC about this (for status displays) and
# keep track of the pids in case we cancel the backup # keep track of the pids in case we cancel the backup
# #
skipping to change at line 2165 skipping to change at line 2209
{ {
my($cmdType, $sharename) = @_; my($cmdType, $sharename) = @_;
$? = 0; $? = 0;
return if ( !defined($Conf{$cmdType}) ); return if ( !defined($Conf{$cmdType}) );
my $vars = { my $vars = {
xfer => $xfer, xfer => $xfer,
client => $client, client => $client,
host => $host, host => $host,
hostIP => $hostIP, hostIP => $hostIP,
user => $Hosts->{$client}{user}, user => $Hosts->{$client}{user},
moreUsers => $Hosts->{$client}{moreUsers}, moreUsers => $Hosts->{$client}{moreUsers},
share => $ShareNames->[0], share => $ShareNames->[0],
shares => $ShareNames, shares => $ShareNames,
XferMethod => $Conf{XferMethod}, XferMethod => $Conf{XferMethod},
sshPath => $Conf{SshPath}, sshPath => $Conf{SshPath},
LOG => $LogFd, LOG => $LogFd,
XferLOG => $XferLOG, XferLOG => $XferLOG,
stat => \%stat, stat => \%stat,
xferOK => $stat{xferOK} || 0, xferOK => $stat{xferOK} || 0,
hostError => $stat{hostError}, hostError => $stat{hostError},
type => $type, type => $type,
cmdType => $cmdType, cmdType => $cmdType,
}; };
if ($cmdType eq 'DumpPreShareCmd' || $cmdType eq 'DumpPostShareCmd') { if ( $cmdType eq 'DumpPreShareCmd' || $cmdType eq 'DumpPostShareCmd' ) {
$vars->{share} = $sharename; $vars->{share} = $sharename;
if ( $cmdType =~ /Post/ ) { if ( $cmdType =~ /Post/ ) {
print("__bpc_progress_state__ post-cmd $sharename\n") if ( !$opts{p} ); print("__bpc_progress_state__ post-cmd $sharename\n") if ( !$opts{p} );
} else { } else {
print("__bpc_progress_state__ pre-cmd $sharename\n") if ( !$opts{p} ); print("__bpc_progress_state__ pre-cmd $sharename\n") if ( !$opts{p} );
} }
} else { } else {
if ( $cmdType =~ /Post/ ) { if ( $cmdType =~ /Post/ ) {
print("__bpc_progress_state__ post-cmd\n") if ( !$opts{p} ); print("__bpc_progress_state__ post-cmd\n") if ( !$opts{p} );
} else { } else {
print("__bpc_progress_state__ pre-cmd\n") if ( !$opts{p} ); print("__bpc_progress_state__ pre-cmd\n") if ( !$opts{p} );
} }
} }
my $cmd = $bpc->cmdVarSubstitute($Conf{$cmdType}, $vars); my $cmd = $bpc->cmdVarSubstitute($Conf{$cmdType}, $vars);
$XferLOG->write(\"Executing $cmdType: @$cmd\n"); if ( $XferLOG ) {
$XferLOG->write(\"Executing $cmdType: @$cmd\n");
} elsif ( $opts{v} ) {
print("Executing $cmdType: @$cmd\n");
}
# #
# Run the user's command, dumping the stdout/stderr into the # Run the user's command, dumping the stdout/stderr into the
# Xfer log file. Also supply the optional $vars and %Conf in # Xfer log file. Also supply the optional $vars and %Conf in
# case the command is really perl code instead of a shell # case the command is really perl code instead of a shell
# command. # command.
# #
$bpc->cmdSystemOrEval($cmd, $bpc->cmdSystemOrEval(
sub { $cmd,
if ( $XferLOG && length($_[0]) ) { sub {
$XferLOG->write(\$_[0]); if ( $XferLOG && length($_[0]) ) {
} elsif ( $LogFd && length($_[0]) ) { $XferLOG->write(\$_[0]);
print($LogFd $bpc->timeStamp, "Output from $cmdType: ", $_[0 } elsif ( $LogFd && length($_[0]) ) {
]); print($LogFd $bpc->timeStamp, "Output from $cmdType: ", $_[0]);
} }
}, },
$vars, \%Conf $vars,
); \%Conf
);
} }
sub flushLibMessages() sub flushLibMessages()
{ {
my $msg = BackupPC::XS::Lib::logMsgGet(); my $msg = BackupPC::XS::Lib::logMsgGet();
return if ( !defined($msg) ); return if ( !defined($msg) );
if ( $XferLOG ) { if ( $XferLOG ) {
foreach my $m ( @$msg ) { foreach my $m ( @$msg ) {
$XferLOG->write(\$m); $XferLOG->write(\$m);
} }
 End of changes. 144 change blocks. 
513 lines changed or deleted 585 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)