Rsync.pm (BackupPC-4.3.2) | : | Rsync.pm (BackupPC-4.4.0) | ||
---|---|---|---|---|
skipping to change at line 33 | skipping to change at line 33 | |||
# 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. | |||
# | # | |||
#======================================================================== | #======================================================================== | |||
package BackupPC::Xfer::Rsync; | package BackupPC::Xfer::Rsync; | |||
use strict; | use strict; | |||
use BackupPC::View; | use BackupPC::View; | |||
use Encode qw/from_to encode/; | use Encode qw/from_to encode/; | |||
skipping to change at line 60 | skipping to change at line 60 | |||
my $t = BackupPC::Xfer::Protocol->new($bpc, $args); | my $t = BackupPC::Xfer::Protocol->new($bpc, $args); | |||
$t->{logSave} = []; | $t->{logSave} = []; | |||
$t->{logInfo} = {}; | $t->{logInfo} = {}; | |||
return bless($t, $class); | return bless($t, $class); | |||
} | } | |||
sub start | sub start | |||
{ | { | |||
my($t) = @_; | my($t) = @_; | |||
my $bpc = $t->{bpc}; | my $bpc = $t->{bpc}; | |||
my $conf = $t->{conf}; | my $conf = $t->{conf}; | |||
my(@fileList, $rsyncArgs, $logMsg, $rsyncCmd); | my(@fileList, $rsyncArgs, $logMsg, $rsyncCmd); | |||
my $binDir = $t->{bpc}->BinDir(); | my $binDir = $t->{bpc}->BinDir(); | |||
my $shareNamePath = $t->shareName2Path($t->{shareName}); | my $shareNamePath = $t->shareName2Path($t->{shareName}); | |||
alarm(0); | alarm(0); | |||
# | # | |||
# We add a slash to the share name we pass to rsync | # We add a slash to the share name we pass to rsync | |||
# | # | |||
($t->{shareNameSlash} = "$shareNamePath/") =~ s{//+$}{/}; | ($t->{shareNameSlash} = "$shareNamePath/") =~ s{//+$}{/}; | |||
if ( $t->{type} eq "restore" ) { | if ( $t->{type} eq "restore" ) { | |||
my $remoteDir = "$shareNamePath/$t->{pathHdrDest}"; | my $remoteDir = "$shareNamePath/$t->{pathHdrDest}"; | |||
$remoteDir =~ s{//+}{/}g; | $remoteDir =~ s{//+}{/}g; | |||
my $filesFd; | my $filesFd; | |||
my $srcList; | my $srcList; | |||
my $srcDir = "/"; | my $srcDir = "/"; | |||
#from_to($remoteDir, "utf8", $conf->{ClientCharset}) | #from_to($remoteDir, "utf8", $conf->{ClientCharset}) | |||
# if ( $conf->{ClientCharset} ne "" ); | # if ( $conf->{ClientCharset} ne "" ); | |||
$rsyncArgs = [@{$conf->{RsyncRestoreArgs}}]; | $rsyncArgs = [@{$conf->{RsyncRestoreArgs}}]; | |||
if ( ref($conf->{RsyncRestoreArgsExtra}) eq 'ARRAY' ) { | ||||
push(@$rsyncArgs, @{$conf->{RsyncRestoreArgsExtra}}); | ||||
} | ||||
# | # | |||
# Each name in the fileList starts with $t->{pathHdrSrc}. The | # Each name in the fileList starts with $t->{pathHdrSrc}. The | |||
# default $t->{pathHdrDest} also ends in $t->{pathHdrSrc}, although | # default $t->{pathHdrDest} also ends in $t->{pathHdrSrc}, although | |||
# the user might have changed that. So we have $t->{pathHdrSrc} | # the user might have changed that. So we have $t->{pathHdrSrc} | |||
# appearing twice: in the fileList and in the target directory. | # appearing twice: in the fileList and in the target directory. | |||
# We have to remove one or the other. | # We have to remove one or the other. | |||
# | # | |||
# Since the client rsync only tries to create the last directory | # Since the client rsync only tries to create the last directory | |||
# in $t->{pathHdrDest} (rather than the full path), it will fail | # in $t->{pathHdrDest} (rather than the full path), it will fail | |||
skipping to change at line 108 | skipping to change at line 111 | |||
# | # | |||
if ( $remoteDir =~ m{(.*)\Q$t->{pathHdrSrc}\E(/*)$} ) { | if ( $remoteDir =~ m{(.*)\Q$t->{pathHdrSrc}\E(/*)$} ) { | |||
$remoteDir = "$1$2"; | $remoteDir = "$1$2"; | |||
$remoteDir = "/" if ( $remoteDir eq "" ); | $remoteDir = "/" if ( $remoteDir eq "" ); | |||
$t->{XferLOG}->write(\"Trimming $t->{pathHdrSrc} from remoteDir -> $ remoteDir\n"); | $t->{XferLOG}->write(\"Trimming $t->{pathHdrSrc} from remoteDir -> $ remoteDir\n"); | |||
} else { | } else { | |||
for ( my $i = 0 ; $i < @{$t->{fileList}} ; $i++ ) { | for ( my $i = 0 ; $i < @{$t->{fileList}} ; $i++ ) { | |||
$t->{fileList}[$i] = substr($t->{fileList}[$i], length($t->{path HdrSrc})); | $t->{fileList}[$i] = substr($t->{fileList}[$i], length($t->{path HdrSrc})); | |||
$t->{fileList}[$i] = "." if ( $t->{fileList}[$i] eq "" ); | $t->{fileList}[$i] = "." if ( $t->{fileList}[$i] eq "" ); | |||
} | } | |||
$srcDir = $t->{pathHdrSrc} if ($t->{pathHdrSrc}); | $srcDir = $t->{pathHdrSrc} if ( $t->{pathHdrSrc} ); | |||
$t->{XferLOG}->write(\"Trimming $t->{pathHdrSrc} from filesList\n"); | $t->{XferLOG}->write(\"Trimming $t->{pathHdrSrc} from filesList\n"); | |||
} | } | |||
$t->{filesFrom} = "$conf->{TopDir}/pc/$t->{client}/.rsyncFilesFrom$$"; | $t->{filesFrom} = "$conf->{TopDir}/pc/$t->{client}/.rsyncFilesFrom$$"; | |||
if ( open($filesFd, ">", $t->{filesFrom}) ) { | if ( open($filesFd, ">", $t->{filesFrom}) ) { | |||
syswrite($filesFd, join("\n", @{$t->{fileList}})); | syswrite($filesFd, join("\n", @{$t->{fileList}})); | |||
close($filesFd); | close($filesFd); | |||
$t->{XferLOG}->write(\"Wrote source file list to $t->{filesFrom}: @{ $t->{fileList}}\n"); | $t->{XferLOG}->write(\"Wrote source file list to $t->{filesFrom}: @{ $t->{fileList}}\n"); | |||
$srcList = ["--files-from=$t->{filesFrom}", $srcDir]; | $srcList = ["--files-from=$t->{filesFrom}", $srcDir]; | |||
} else { | } else { | |||
$t->{XferLOG}->write(\"Failed to open/create file list $t->{filesFro m}\n"); | $t->{XferLOG}->write(\"Failed to open/create file list $t->{filesFro m}\n"); | |||
$t->{_errStr} = "Failed to open/create file list $t->{filesFrom}"; | $t->{_errStr} = "Failed to open/create file list $t->{filesFrom}"; | |||
return; | return; | |||
} | } | |||
if ( $t->{XferMethod} eq "rsync" ) { | if ( $t->{XferMethod} eq "rsync" ) { | |||
unshift(@$rsyncArgs, "--rsync-path=$conf->{RsyncClientPath}") | unshift(@$rsyncArgs, "--rsync-path=$conf->{RsyncClientPath}") | |||
if ( $conf->{RsyncClientPath} ne "" ); | if ( $conf->{RsyncClientPath} ne "" ); | |||
unshift(@$rsyncArgs, @{$conf->{RsyncSshArgs}}) | unshift(@$rsyncArgs, @{$conf->{RsyncSshArgs}}) | |||
if ( ref($conf->{RsyncSshArgs}) eq 'ARRAY' ); | if ( ref($conf->{RsyncSshArgs}) eq 'ARRAY' ); | |||
push(@$rsyncArgs, @$srcList, "$t->{hostIP}:$remoteDir"); | push(@$rsyncArgs, @$srcList, "$t->{hostIP}:$remoteDir"); | |||
} else { | } else { | |||
if ( length($conf->{RsyncdPasswd}) ) { | if ( length($conf->{RsyncdPasswd}) ) { | |||
my($pwFd, $ok); | my($pwFd, $ok); | |||
$t->{pwFile} = "$conf->{TopDir}/pc/$t->{client}/.rsyncdpw$$"; | $t->{pwFile} = "$conf->{TopDir}/pc/$t->{client}/.rsyncdpw$$"; | |||
if ( open($pwFd, ">", $t->{pwFile}) ) { | if ( open($pwFd, ">", $t->{pwFile}) ) { | |||
$ok = 1; | $ok = 1; | |||
$ok = 0 if ( $ok && chmod(0400, $t->{pwFile}) != 1 ); | $ok = 0 if ( $ok && chmod(0400, $t->{pwFile}) != 1 ); | |||
$ok = 0 if ( $ok && !binmode($pwFd) ); | $ok = 0 if ( $ok && !binmode($pwFd) ); | |||
$ok = 0 if ( $ok && syswrite($pwFd, $conf->{RsyncdPasswd}) ! = length($conf->{RsyncdPasswd}) ); | $ok = 0 if ( $ok && syswrite($pwFd, $conf->{RsyncdPasswd}) ! = length($conf->{RsyncdPasswd}) ); | |||
$ok = 0 if ( $ok && !close($pwFd) ); | $ok = 0 if ( $ok && !close($pwFd) ); | |||
push(@$rsyncArgs, "--password-file=$t->{pwFile}"); | push(@$rsyncArgs, "--password-file=$t->{pwFile}"); | |||
} | } | |||
if ( !$ok ) { | if ( !$ok ) { | |||
$t->{XferLOG}->write(\"Failed to open/create rsynd pw file $ t->{pwFile} ($!)\n"); | $t->{XferLOG}->write(\"Failed to open/create rsynd pw file $ t->{pwFile} ($!)\n"); | |||
$t->{_errStr} = "Failed to open/create rsynd pw file $t->{pw File} ($!)"; | $t->{_errStr} = "Failed to open/create rsynd pw file $t->{pw File} ($!)"; | |||
return; | return; | |||
} | } | |||
} | } | |||
#my $shareName = $t->{shareName}; | #my $shareName = $t->{shareName}; | |||
#from_to($shareName, "utf8", $conf->{ClientCharset}) | #from_to($shareName, "utf8", $conf->{ClientCharset}) | |||
# if ( $conf->{ClientCharset} ne "" ); | # if ( $conf->{ClientCharset} ne "" ); | |||
if ( $conf->{RsyncdClientPort} != 873 ) { | if ( $conf->{RsyncdClientPort} != 873 ) { | |||
push(@$rsyncArgs, "--port=$conf->{RsyncdClientPort}"); | push(@$rsyncArgs, "--port=$conf->{RsyncdClientPort}"); | |||
} | } | |||
if ( $conf->{ClientCharset} ne "" ) { | if ( $conf->{ClientCharset} ne "" && $conf->{ClientCharset} ne "utf8 " ) { | |||
push(@$rsyncArgs, "--iconv=utf8,$conf->{ClientCharset}"); | push(@$rsyncArgs, "--iconv=utf8,$conf->{ClientCharset}"); | |||
} | } | |||
push(@$rsyncArgs, | push(@$rsyncArgs, @$srcList, "$conf->{RsyncdUserName}\@$t->{hostIP}: | |||
@$srcList, | :$remoteDir"); | |||
"$conf->{RsyncdUserName}\@$t->{hostIP}::$remoteDir"); | ||||
} | } | |||
# | # | |||
# Merge variables into $rsyncArgs | # Merge variables into $rsyncArgs | |||
# | # | |||
$rsyncArgs = $bpc->cmdVarSubstitute($rsyncArgs, { | $rsyncArgs = $bpc->cmdVarSubstitute( | |||
host => $t->{host}, | $rsyncArgs, | |||
hostIP => $t->{hostIP}, | { | |||
client => $t->{client}, | host => $t->{host}, | |||
shareNameOrig => $t->{shareName}, | hostIP => $t->{hostIP}, | |||
shareName => $shareNamePath, | client => $t->{client}, | |||
confDir => $conf->{ConfDir}, | shareNameOrig => $t->{shareName}, | |||
sshPath => $conf->{SshPath}, | shareName => $shareNamePath, | |||
}); | confDir => $conf->{ConfDir}, | |||
sshPath => $conf->{SshPath}, | ||||
} | ||||
); | ||||
# | # | |||
# create --bpc-bkup-merge list. This is the list of backups that have t o | # create --bpc-bkup-merge list. This is the list of backups that have t o | |||
# be merged to create the correct "view" of the backup being restore. | # be merged to create the correct "view" of the backup being restore. | |||
# | # | |||
my($srcIdx, $i, $mergeInfo); | my($srcIdx, $i, $mergeInfo); | |||
my $mergeIdxList = []; | my $mergeIdxList = []; | |||
for ( $i = 0 ; $i < @{$t->{backups}} ; $i++ ) { | for ( $i = 0 ; $i < @{$t->{backups}} ; $i++ ) { | |||
if ( $t->{backups}[$i]{num} == $t->{bkupSrcNum} ) { | if ( $t->{backups}[$i]{num} == $t->{bkupSrcNum} ) { | |||
$srcIdx = $i; | $srcIdx = $i; | |||
skipping to change at line 212 | skipping to change at line 217 | |||
# | # | |||
# For V4+ backups, we merge backward from the following filled backu p. | # For V4+ backups, we merge backward from the following filled backu p. | |||
# | # | |||
for ( $i = $srcIdx ; $i < @{$t->{backups}} ; $i++ ) { | for ( $i = $srcIdx ; $i < @{$t->{backups}} ; $i++ ) { | |||
unshift(@$mergeIdxList, $i); | unshift(@$mergeIdxList, $i); | |||
last if ( !$t->{backups}[$i]{noFill} ); | last if ( !$t->{backups}[$i]{noFill} ); | |||
} | } | |||
} | } | |||
foreach my $i ( @$mergeIdxList ) { | foreach my $i ( @$mergeIdxList ) { | |||
$mergeInfo .= "," if ( length($mergeInfo) ); | $mergeInfo .= "," if ( length($mergeInfo) ); | |||
$mergeInfo .= sprintf("%d/%d/%d", $t->{backups}[$i]{num}, $t->{backu | $mergeInfo .= | |||
ps}[$i]{compress}, int($t->{backups}[$i]{version})); | sprintf("%d/%d/%d", $t->{backups}[$i]{num}, $t->{backups}[$i]{comp | |||
ress}, int($t->{backups}[$i]{version})); | ||||
} | } | |||
unshift(@$rsyncArgs, | unshift( | |||
'--bpc-top-dir', $conf->{TopDir}, | @$rsyncArgs, | |||
'--bpc-host-name', $t->{bkupSrcHost}, | '--bpc-top-dir', $conf->{TopDir}, # perltidy p | |||
'--bpc-share-name', $t->{bkupSrcShare}, | rotect | |||
'--bpc-bkup-num', $t->{backups}[$srcIdx]{num}, | '--bpc-host-name', $t->{bkupSrcHost}, | |||
'--bpc-bkup-comp', $t->{backups}[$srcIdx]{compress}, | '--bpc-share-name', $t->{bkupSrcShare}, | |||
'--bpc-bkup-merge', $mergeInfo, | '--bpc-bkup-num', $t->{backups}[$srcIdx]{num}, | |||
'--bpc-bkup-comp', $t->{backups}[$srcIdx]{compress}, | ||||
'--bpc-bkup-merge', $mergeInfo, | ||||
'--bpc-log-level', $conf->{XferLogLevel}, | ||||
'--bpc-attrib-new', | '--bpc-attrib-new', | |||
'--bpc-log-level', $conf->{XferLogLevel}, | ||||
); | ); | |||
$logMsg = "restore started below directory $t->{shareName}" | $logMsg = "restore started below directory $t->{shareName} to host $t->{ | |||
. " to host $t->{host}"; | host}"; | |||
} else { | } else { | |||
# | # | |||
# Turn $conf->{BackupFilesOnly} and $conf->{BackupFilesExclude} | # Turn $conf->{BackupFilesOnly} and $conf->{BackupFilesExclude} | |||
# into a hash of arrays of files, and $conf->{RsyncShareName} | # into a hash of arrays of files, and $conf->{RsyncShareName} | |||
# to an array | # to an array | |||
# | # | |||
$bpc->backupFileConfFix($conf, "RsyncShareName"); | $bpc->backupFileConfFix($conf, "RsyncShareName"); | |||
if ( defined($conf->{BackupFilesOnly}{$t->{shareName}}) ) { | if ( defined($conf->{BackupFilesOnly}{$t->{shareName}}) ) { | |||
my(@inc, @exc, %incDone, %excDone); | my(@inc, @exc, %incDone, %excDone); | |||
foreach my $file2 ( @{$conf->{BackupFilesOnly}{$t->{shareName}}} ) { | foreach my $file2 ( @{$conf->{BackupFilesOnly}{$t->{shareName}}} ) { | |||
# | # | |||
# If the user wants to just include /home/craig, then | # If the user wants to just include /home/craig, then | |||
# we need to do create include/exclude pairs at | # we need to do create include/exclude pairs at | |||
# each level: | # each level: | |||
# --include /home --exclude /* | # --include /home --exclude /* | |||
# --include /home/craig --exclude /home/* | # --include /home/craig --exclude /home/* | |||
skipping to change at line 260 | skipping to change at line 266 | |||
# --include /home/craig --exclude /home/* | # --include /home/craig --exclude /home/* | |||
# --include /var/log --exclude /var/* | # --include /var/log --exclude /var/* | |||
# | # | |||
# To make this easier we do all the includes first and all | # To make this easier we do all the includes first and all | |||
# of the excludes at the end (hopefully they commute). | # of the excludes at the end (hopefully they commute). | |||
# | # | |||
my $file = $file2; | my $file = $file2; | |||
$file =~ s{/$}{}; | $file =~ s{/$}{}; | |||
$file = "/$file"; | $file = "/$file"; | |||
$file =~ s{//+}{/}g; | $file =~ s{//+}{/}g; | |||
if ( $file eq "/" ) { | if ( $file eq "/" ) { | |||
# | # | |||
# This is a special case: if the user specifies | # This is a special case: if the user specifies | |||
# "/" then just include it and don't exclude "/*". | # "/" then just include it and don't exclude "/*". | |||
# | # | |||
push(@inc, $file) if ( !$incDone{$file} ); | push(@inc, $file) if ( !$incDone{$file} ); | |||
next; | next; | |||
} | } | |||
my $f = ""; | my $f = ""; | |||
while ( $file =~ m{^/([^/]*)(.*)} ) { | while ( $file =~ m{^/([^/]*)(.*)} ) { | |||
my $elt = $1; | my $elt = $1; | |||
$file = $2; | $file = $2; | |||
if ( $file eq "/" ) { | if ( $file eq "/" ) { | |||
# | # | |||
# preserve a tailing slash | # preserve a tailing slash | |||
# | # | |||
$file = ""; | $file = ""; | |||
$elt = "$elt/"; | $elt = "$elt/"; | |||
} | } | |||
push(@exc, "$f/*") if ( !$excDone{"$f/*"} ); | push(@exc, "$f/*") if ( !$excDone{"$f/*"} ); | |||
$excDone{"$f/*"} = 1; | $excDone{"$f/*"} = 1; | |||
$f = "$f/$elt"; | $f = "$f/$elt"; | |||
push(@inc, $f) if ( !$incDone{$f} ); | push(@inc, $f) if ( !$incDone{$f} ); | |||
$incDone{$f} = 1; | $incDone{$f} = 1; | |||
} | } | |||
} | } | |||
foreach my $file ( @inc ) { | foreach my $file ( @inc ) { | |||
$file = encode($conf->{ClientCharset}, $file) | $file = encode($conf->{ClientCharset}, $file) | |||
if ( $conf->{ClientCharset} ne "" ); | if ( $conf->{ClientCharset} ne "" ); | |||
push(@fileList, "--include=$file"); | push(@fileList, "--include=$file"); | |||
} | } | |||
foreach my $file ( @exc ) { | foreach my $file ( @exc ) { | |||
$file = encode($conf->{ClientCharset}, $file) | $file = encode($conf->{ClientCharset}, $file) | |||
if ( $conf->{ClientCharset} ne "" ); | if ( $conf->{ClientCharset} ne "" ); | |||
push(@fileList, "--exclude=$file"); | push(@fileList, "--exclude=$file"); | |||
} | } | |||
} | } | |||
if ( defined($conf->{BackupFilesExclude}{$t->{shareName}}) ) { | if ( defined($conf->{BackupFilesExclude}{$t->{shareName}}) ) { | |||
foreach my $file2 ( @{$conf->{BackupFilesExclude}{$t->{shareName}}} ) { | foreach my $file2 ( @{$conf->{BackupFilesExclude}{$t->{shareName}}} ) { | |||
# | # | |||
# just append additional exclude lists onto the end | # just append additional exclude lists onto the end | |||
# | # | |||
my $file = $file2; | my $file = $file2; | |||
$file = encode($conf->{ClientCharset}, $file) | $file = encode($conf->{ClientCharset}, $file) | |||
if ( $conf->{ClientCharset} ne "" ); | if ( $conf->{ClientCharset} ne "" ); | |||
push(@fileList, "--exclude=$file"); | push(@fileList, "--exclude=$file"); | |||
} | } | |||
} | } | |||
# | # | |||
# A full dump is implemented with $Conf{RsyncFullArgsExtra}, | # A full dump is implemented with $Conf{RsyncFullArgsExtra}, | |||
# which is normally --checksum. This causes the client to | # which is normally --checksum. This causes the client to | |||
# generate and send a full-file checksum for each file with | # generate and send a full-file checksum for each file with | |||
# the file list. That can be directly compared with the | # the file list. That can be directly compared with the | |||
# V4 full-file digest. | # V4 full-file digest. | |||
# | # | |||
skipping to change at line 341 | skipping to change at line 347 | |||
push(@$rsyncArgs, @{$conf->{RsyncIncrArgsExtra}}); | push(@$rsyncArgs, @{$conf->{RsyncIncrArgsExtra}}); | |||
} elsif ( ref($conf->{RsyncIncrArgsExtra}) eq '' && $conf->{RsyncInc rArgsExtra} ne "" ) { | } elsif ( ref($conf->{RsyncIncrArgsExtra}) eq '' && $conf->{RsyncInc rArgsExtra} ne "" ) { | |||
push(@$rsyncArgs, $conf->{RsyncIncrArgsExtra}); | push(@$rsyncArgs, $conf->{RsyncIncrArgsExtra}); | |||
} | } | |||
} | } | |||
# | # | |||
# Add any additional rsync args | # Add any additional rsync args | |||
# | # | |||
push(@$rsyncArgs, @{$conf->{RsyncArgsExtra}}) | push(@$rsyncArgs, @{$conf->{RsyncArgsExtra}}) | |||
if ( ref($conf->{RsyncArgsExtra}) eq 'ARRAY' ); | if ( ref($conf->{RsyncArgsExtra}) eq 'ARRAY' ); | |||
if ( $conf->{ClientCharset} ne "" ) { | if ( $conf->{ClientCharset} ne "" && $conf->{ClientCharset} ne "utf8" ) | |||
{ | ||||
push(@$rsyncArgs, "--iconv=utf8,$conf->{ClientCharset}"); | push(@$rsyncArgs, "--iconv=utf8,$conf->{ClientCharset}"); | |||
} | } | |||
if ( $conf->{ClientTimeout} > 0 && $conf->{ClientTimeout} =~ /^\d+$/ ) { | if ( $conf->{ClientTimeout} > 0 && $conf->{ClientTimeout} =~ /^\d+$/ ) { | |||
push(@$rsyncArgs, "--timeout=$conf->{ClientTimeout}"); | push(@$rsyncArgs, "--timeout=$conf->{ClientTimeout}"); | |||
} | } | |||
if ( $t->{XferMethod} eq "rsync" ) { | if ( $t->{XferMethod} eq "rsync" ) { | |||
unshift(@$rsyncArgs, "--rsync-path=$conf->{RsyncClientPath}") | unshift(@$rsyncArgs, "--rsync-path=$conf->{RsyncClientPath}") | |||
if ( $conf->{RsyncClientPath} ne "" ); | if ( $conf->{RsyncClientPath} ne "" ); | |||
unshift(@$rsyncArgs, @{$conf->{RsyncSshArgs}}) | unshift(@$rsyncArgs, @{$conf->{RsyncSshArgs}}) | |||
if ( ref($conf->{RsyncSshArgs}) eq 'ARRAY' ); | if ( ref($conf->{RsyncSshArgs}) eq 'ARRAY' ); | |||
} else { | } else { | |||
if ( $conf->{RsyncdClientPort} != 873 ) { | if ( $conf->{RsyncdClientPort} != 873 ) { | |||
push(@$rsyncArgs, "--port=$conf->{RsyncdClientPort}"); | push(@$rsyncArgs, "--port=$conf->{RsyncdClientPort}"); | |||
} | } | |||
} | } | |||
# | # | |||
# Merge variables into $rsyncArgs | # Merge variables into $rsyncArgs | |||
# | # | |||
$rsyncArgs = $bpc->cmdVarSubstitute($rsyncArgs, { | $rsyncArgs = $bpc->cmdVarSubstitute( | |||
host => $t->{host}, | $rsyncArgs, | |||
hostIP => $t->{hostIP}, | { | |||
client => $t->{client}, | host => $t->{host}, | |||
shareNameOrig => $t->{shareName}, | hostIP => $t->{hostIP}, | |||
shareName => $shareNamePath, | client => $t->{client}, | |||
confDir => $conf->{ConfDir}, | shareNameOrig => $t->{shareName}, | |||
sshPath => $conf->{SshPath}, | shareName => $shareNamePath, | |||
}); | confDir => $conf->{ConfDir}, | |||
sshPath => $conf->{SshPath}, | ||||
} | ||||
); | ||||
if ( $t->{XferMethod} eq "rsync" ) { | if ( $t->{XferMethod} eq "rsync" ) { | |||
my $shareNameSlash = $t->{shareNameSlash}; | my $shareNameSlash = $t->{shareNameSlash}; | |||
#from_to($shareNameSlash, "utf8", $conf->{ClientCharset}) | #from_to($shareNameSlash, "utf8", $conf->{ClientCharset}) | |||
# if ( $conf->{ClientCharset} ne "" ); | # if ( $conf->{ClientCharset} ne "" ); | |||
push(@$rsyncArgs, @fileList) if ( @fileList ); | push(@$rsyncArgs, @fileList) if ( @fileList ); | |||
push(@$rsyncArgs, "$t->{hostIP}:$shareNameSlash", "/"); | push(@$rsyncArgs, "$t->{hostIP}:$shareNameSlash", "/"); | |||
} else { | } else { | |||
my $pwFd; | my $pwFd; | |||
$t->{pwFile} = "$conf->{TopDir}/pc/$t->{client}/.rsyncdpw$$"; | $t->{pwFile} = "$conf->{TopDir}/pc/$t->{client}/.rsyncdpw$$"; | |||
if ( !length($conf->{RsyncdPasswd}) ) { | if ( !length($conf->{RsyncdPasswd}) ) { | |||
$t->{XferLOG}->write(\"\$Conf{RsyncdPasswd} is empty; host's rsy ncd auth will fail\n"); | $t->{XferLOG}->write(\"\$Conf{RsyncdPasswd} is empty; host's rsy ncd auth will fail\n"); | |||
skipping to change at line 400 | skipping to change at line 410 | |||
binmode($pwFd); | binmode($pwFd); | |||
syswrite($pwFd, $conf->{RsyncdPasswd}); | syswrite($pwFd, $conf->{RsyncdPasswd}); | |||
close($pwFd); | close($pwFd); | |||
push(@$rsyncArgs, "--password-file=$t->{pwFile}"); | push(@$rsyncArgs, "--password-file=$t->{pwFile}"); | |||
} else { | } else { | |||
$t->{XferLOG}->write(\"Failed to open/create rsynd pw file $t->{ pwFile}\n"); | $t->{XferLOG}->write(\"Failed to open/create rsynd pw file $t->{ pwFile}\n"); | |||
$t->{_errStr} = "Failed to open/create rsynd pw file $t->{pwFile }"; | $t->{_errStr} = "Failed to open/create rsynd pw file $t->{pwFile }"; | |||
return; | return; | |||
} | } | |||
my $shareName = $shareNamePath; | my $shareName = $shareNamePath; | |||
#from_to($shareName, "utf8", $conf->{ClientCharset}) | #from_to($shareName, "utf8", $conf->{ClientCharset}) | |||
# if ( $conf->{ClientCharset} ne "" ); | # if ( $conf->{ClientCharset} ne "" ); | |||
push(@$rsyncArgs, @fileList) if ( @fileList ); | push(@$rsyncArgs, @fileList) if ( @fileList ); | |||
push(@$rsyncArgs, | push(@$rsyncArgs, "$conf->{RsyncdUserName}\@$t->{hostIP}::$shareName | |||
"$conf->{RsyncdUserName}\@$t->{hostIP}::$shareName", | ", "/"); | |||
"/"); | ||||
} | } | |||
if ( $bpc->{PoolV3} ) { | if ( $bpc->{PoolV3} ) { | |||
unshift(@$rsyncArgs, | unshift(@$rsyncArgs, | |||
'--bpc-hardlink-max', $conf->{HardLinkMax} || 31999, | '--bpc-hardlink-max', $conf->{HardLinkMax} || 31999, | |||
'--bpc-v3pool-used', $conf->{PoolV3Enabled}, | '--bpc-v3pool-used', $conf->{PoolV3Enabled}, | |||
); | ); | |||
} | } | |||
my $inode0 = 1; | my $inode0 = 1; | |||
for ( my $i = 0 ; $i < @{$t->{backups}} ; $i++ ) { | for ( my $i = 0 ; $i < @{$t->{backups}} ; $i++ ) { | |||
$inode0 = $t->{backups}[$i]{inodeLast} + 1 if ( $inode0 <= $t->{back ups}[$i]{inodeLast} ); | $inode0 = $t->{backups}[$i]{inodeLast} + 1 if ( $inode0 <= $t->{back ups}[$i]{inodeLast} ); | |||
} | } | |||
unshift(@$rsyncArgs, | unshift( | |||
'--bpc-top-dir', $conf->{TopDir}, | @$rsyncArgs, | |||
'--bpc-host-name', $t->{client}, | '--bpc-top-dir', $conf->{TopDir}, # p | |||
'--bpc-share-name', $t->{shareName}, | erltidy protect | |||
'--bpc-bkup-num', $t->{backups}[$t->{newBkupIdx}]{num}, | '--bpc-host-name', $t->{client}, | |||
'--bpc-bkup-comp', $t->{backups}[$t->{newBkupIdx}]{compress}, | '--bpc-share-name', $t->{shareName}, | |||
'--bpc-bkup-prevnum', defined($t->{lastBkupIdx}) ? $t->{backups}[$ | '--bpc-bkup-num', $t->{backups}[$t->{newBkupIdx}]{num}, | |||
t->{lastBkupIdx}]{num} : -1, | '--bpc-bkup-comp', $t->{backups}[$t->{newBkupIdx}]{compress}, | |||
'--bpc-bkup-prevcomp', defined($t->{lastBkupIdx}) ? $t->{backups}[$ | '--bpc-bkup-prevnum', defined($t->{lastBkupIdx}) ? $t->{backups}[$t | |||
t->{lastBkupIdx}]{compress} : -1, | ->{lastBkupIdx}]{num} : -1, | |||
'--bpc-bkup-inode0', $inode0, | '--bpc-bkup-prevcomp', defined($t->{lastBkupIdx}) ? $t->{backups}[$t | |||
->{lastBkupIdx}]{compress} : -1, | ||||
'--bpc-bkup-inode0', $inode0, | ||||
'--bpc-log-level', $conf->{XferLogLevel}, | ||||
'--bpc-attrib-new', | '--bpc-attrib-new', | |||
'--bpc-log-level', $conf->{XferLogLevel}, | ||||
); | ); | |||
} | } | |||
$logMsg .= " (client path $shareNamePath)" if ( $t->{shareName} ne $shareNam ePath ); | $logMsg .= " (client path $shareNamePath)" if ( $t->{shareName} ne $shareNam ePath ); | |||
#from_to($args->{shareName}, "utf8", $conf->{ClientCharset}) | #from_to($args->{shareName}, "utf8", $conf->{ClientCharset}) | |||
# if ( $conf->{ClientCharset} ne "" ); | # if ( $conf->{ClientCharset} ne "" ); | |||
if ( $conf->{RsyncBackupPCPath} eq "" || !-x $conf->{RsyncBackupPCPath} ) { | if ( $conf->{RsyncBackupPCPath} eq "" || !-x $conf->{RsyncBackupPCPath} ) { | |||
$t->{_errStr} = "\$Conf{RsyncBackupPCPath} is set to $conf->{RsyncBackup | $t->{_errStr} = | |||
PCPath}, which isn't a valid executable"; | "\$Conf{RsyncBackupPCPath} is set to $conf->{RsyncBackupPCPath}, which | |||
isn't a valid executable"; | ||||
return; | return; | |||
} | } | |||
$rsyncCmd = [$conf->{RsyncBackupPCPath}, @$rsyncArgs]; | $rsyncCmd = [$conf->{RsyncBackupPCPath}, @$rsyncArgs]; | |||
my $rsyncFd; | my $rsyncFd; | |||
if ( !defined($t->{xferPid} = open($rsyncFd, "-|")) ) { | if ( !defined($t->{xferPid} = open($rsyncFd, "-|")) ) { | |||
$t->{_errStr} = "Can't fork to run $conf->{RsyncBackupPCPath}"; | $t->{_errStr} = "Can't fork to run $conf->{RsyncBackupPCPath}"; | |||
return; | return; | |||
} | } | |||
$t->{rsyncFd} = $rsyncFd; | $t->{rsyncFd} = $rsyncFd; | |||
if ( !$t->{xferPid} ) { | if ( !$t->{xferPid} ) { | |||
# | # | |||
# This is the rsync child. We capture both stdout | # This is the rsync child. We capture both stdout | |||
# and stderr to put into the XferLOG file. | # and stderr to put into the XferLOG file. | |||
# | # | |||
setpgrp 0,0; | setpgrp 0, 0; | |||
close(STDERR); | close(STDERR); | |||
open(STDERR, ">&STDOUT"); | open(STDERR, ">&STDOUT"); | |||
# | # | |||
# Run the $conf->{RsyncBackupPCPath} command | # Run the $conf->{RsyncBackupPCPath} command | |||
# | # | |||
print("This is the rsync child about to exec $conf->{RsyncBackupPCPath}\ n"); | print("This is the rsync child about to exec $conf->{RsyncBackupPCPath}\ n"); | |||
$bpc->cmdExecOrEval($rsyncCmd); | $bpc->cmdExecOrEval($rsyncCmd); | |||
print("cmdExecOrEval failed $?\n"); | print("cmdExecOrEval failed $?\n"); | |||
# should not be reached, but just in case... | # should not be reached, but just in case... | |||
$t->{_errStr} = "Can't exec @$rsyncCmd)"; | $t->{_errStr} = "Can't exec @$rsyncCmd)"; | |||
return; | return; | |||
} | } | |||
my $str = $bpc->execCmd2ShellCmd(@$rsyncCmd); | my $str = $bpc->execCmd2ShellCmd(@$rsyncCmd); | |||
#from_to($str, $conf->{ClientCharset}, "utf8") | #from_to($str, $conf->{ClientCharset}, "utf8") | |||
# if ( $conf->{ClientCharset} ne "" ); | # if ( $conf->{ClientCharset} ne "" ); | |||
$t->{XferLOG}->write(\"Running: $str\n"); | $t->{XferLOG}->write(\"Running: $str\n"); | |||
$t->{_errStr} = undef; | $t->{_errStr} = undef; | |||
return $logMsg; | return $logMsg; | |||
} | } | |||
sub run | sub run | |||
{ | { | |||
my($t) = @_; | my($t) = @_; | |||
my $conf = $t->{conf}; | my $conf = $t->{conf}; | |||
my $bpc = $t->{bpc}; | my $bpc = $t->{bpc}; | |||
alarm(0); | alarm(0); | |||
while ( 1 ) { | while ( 1 ) { | |||
my($mesg, $done); | my($mesg, $done); | |||
if ( sysread($t->{rsyncFd}, $mesg, 32768) <= 0 ) { | if ( sysread($t->{rsyncFd}, $mesg, 32768) <= 0 ) { | |||
next if ( $!{EINTR} ); | next if ( $!{EINTR} ); | |||
if ( !close($t->{rsyncFd}) ) { | if ( !close($t->{rsyncFd}) ) { | |||
# | # | |||
# rsync exits with the RERR_* codes in errcode.h. Exit codes 23 , 24, 25 are minor (ie: some | # rsync exits with the RERR_* codes in errcode.h. Exit codes 23 , 24, 25 are minor (ie: some | |||
# error in transfer, but not fatal). Other non-zero exit codes are considered failures. | # error in transfer, but not fatal). Other non-zero exit codes are considered failures. | |||
# | # | |||
$t->{lastOutputLine} = $t->{lastErrorLine} if ( defined($t->{las tErrorLine}) ); | $t->{lastOutputLine} = $t->{lastErrorLine} if ( defined($t->{las tErrorLine}) ); | |||
my $exitCode = $? >> 8; | my $exitCode = $? >> 8; | |||
if ( $exitCode == 23 || $exitCode == 24 || $exitCode == 25 ) { | if ( $exitCode == 23 || $exitCode == 24 || $exitCode == 25 ) { | |||
$t->{rsyncOut} .= "rsync_bpc exited with benign status $exit Code ($?)\n"; | $t->{rsyncOut} .= "rsync_bpc exited with benign status $exit Code ($?)\n"; | |||
$t->{rsyncOut} .= | ||||
"That means the client rsync had errors on some files. Pl | ||||
ease check the XferLOG.\n"; | ||||
$t->{rsyncOut} .= | ||||
"It likely means that rsync's delete cleanup (which delete | ||||
s files on the backup\n"; | ||||
$t->{rsyncOut} .= | ||||
"server that are no longer on the client) was skipped. Yo | ||||
u should fix the error(s)\n"; | ||||
$t->{rsyncOut} .= "that rsync can run cleanly. You can also | ||||
specify the --ignore-errors option\n"; | ||||
$t->{rsyncOut} .= | ||||
"which will still do the delete even if there are rsync er | ||||
rors, but do that with caution.\n"; | ||||
$t->{xferOK} = 1; | $t->{xferOK} = 1; | |||
$t->{stats}{xferErrs}++; | $t->{stats}{xferErrs}++; | |||
} else { | } else { | |||
$t->{rsyncOut} .= "rsync_bpc exited with fatal status $exitC ode ($?) ($t->{lastOutputLine})\n"; | $t->{rsyncOut} .= "rsync_bpc exited with fatal status $exitC ode ($?) ($t->{lastOutputLine})\n"; | |||
$t->{xferOK} = 0; | $t->{xferOK} = 0; | |||
$t->{stats}{xferErrs}++; | $t->{stats}{xferErrs}++; | |||
} | } | |||
} else { | } else { | |||
$t->{xferOK} = 1; | $t->{xferOK} = 1; | |||
} | } | |||
$done = 1; | $done = 1; | |||
} else { | } else { | |||
$t->{rsyncOut} .= $mesg; | $t->{rsyncOut} .= $mesg; | |||
} | } | |||
while ( $t->{rsyncOut} =~ /(.*?)[\n\r]+(.*)/s ) { | while ( $t->{rsyncOut} =~ /(.*?)[\n\r]+(.*)/s ) { | |||
$_ = $1; | $_ = $1; | |||
$t->{rsyncOut} = $2; | $t->{rsyncOut} = $2; | |||
# | # | |||
# refresh our inactivity alarm | # refresh our inactivity alarm | |||
skipping to change at line 528 | skipping to change at line 550 | |||
my $fileName = $4; | my $fileName = $4; | |||
if ( $changes =~ /^\./ ) { | if ( $changes =~ /^\./ ) { | |||
$t->{logInfo}{$fileName}{seqNum} = ++$t->{logInfoSeq}; | $t->{logInfo}{$fileName}{seqNum} = ++$t->{logInfoSeq}; | |||
push(@{$t->{logInfo}{$fileName}{status}}, "same"); | push(@{$t->{logInfo}{$fileName}{status}}, "same"); | |||
} | } | |||
if ( $type eq "del." ) { | if ( $type eq "del." ) { | |||
$t->{logInfo}{$fileName}{seqNum} = ++$t->{logInfoSeq}; | $t->{logInfo}{$fileName}{seqNum} = ++$t->{logInfoSeq}; | |||
push(@{$t->{logInfo}{$fileName}{status}}, "del"); | push(@{$t->{logInfo}{$fileName}{status}}, "del"); | |||
} | } | |||
s/^log: //; | s/^log: //; | |||
push(@{$t->{logSave}}, | push( | |||
{ | @{$t->{logSave}}, | |||
mesg => $_, | { | |||
type => $type, | mesg => $_, | |||
fileName => $fileName, | type => $type, | |||
}); | fileName => $fileName, | |||
} | ||||
); | ||||
$t->logSaveFlush(); | $t->logSaveFlush(); | |||
next; | next; | |||
} | } | |||
if ( /^IOdone:\s(\S*)\s(.*)/ ) { | if ( /^IOdone:\s(\S*)\s(.*)/ ) { | |||
my $status = $1; | my $status = $1; | |||
my $fileName = $2; | my $fileName = $2; | |||
$t->{logInfo}{$fileName}{seqNum} = ++$t->{logInfoSeq}; | $t->{logInfo}{$fileName}{seqNum} = ++$t->{logInfoSeq}; | |||
push(@{$t->{logInfo}{$fileName}{status}}, $status); | push(@{$t->{logInfo}{$fileName}{status}}, $status); | |||
$t->{XferLOG}->write(\"$_\n") if ( $conf->{XferLogLevel} >= 6 ); | $t->{XferLOG}->write(\"$_\n") if ( $conf->{XferLogLevel} >= 6 ); | |||
$t->logSaveFlush(); | $t->logSaveFlush(); | |||
next; | next; | |||
} | } | |||
if ( /^__bpc_progress_fileCnt__ \d+/ ) { | if ( /^__bpc_progress_fileCnt__ \d+/ ) { | |||
print("$_\n") if ( !$t->{noProgressPrint} ); | print("$_\n") if ( !$t->{noProgressPrint} ); | |||
$t->{XferLOG}->write(\"$_\n") if ( $conf->{XferLogLevel} >= 6 ); | $t->{XferLOG}->write(\"$_\n") if ( $conf->{XferLogLevel} >= 6 ); | |||
next; | next; | |||
} | } | |||
if ( /^ERROR: / ) { | if ( /^ERROR: / ) { | |||
if ( /failed verification -- update discarded./ ) { | if ( /failed verification -- update discarded./ ) { | |||
$t->{xferBadFileCnt}++; | $t->{xferBadFileCnt}++; | |||
} | } | |||
$t->{stats}{xferErrs}++; | $t->{stats}{xferErrs}++; | |||
} | } | |||
if ( /^rsync error: / || /^rsync warning: / ) { | if ( /^rsync error: / || /^rsync warning: / ) { | |||
$t->{stats}{xferErrs}++; | $t->{stats}{xferErrs}++; | |||
} | } | |||
if ( /^IO error encountered -- skipping file deletion/ ) { | ||||
$t->{stats}{xferErrs}++; | ||||
} | ||||
if ( /^rsync: send_files failed to open / || /^file has vanished: / ) { | if ( /^rsync: send_files failed to open / || /^file has vanished: / ) { | |||
$t->{stats}{xferErrs}++; | $t->{stats}{xferErrs}++; | |||
} | } | |||
if ( /^IOrename:\s(\d+)\s(.*)/ ) { | if ( /^IOrename:\s(\d+)\s(.*)/ ) { | |||
my $oldName = substr($2, 0, $1); | my $oldName = substr($2, 0, $1); | |||
my $newName = substr($2, $1); | my $newName = substr($2, $1); | |||
$t->{logInfo}{$newName} = $t->{logInfo}{$oldName}; | $t->{logInfo}{$newName} = $t->{logInfo}{$oldName}; | |||
delete($t->{logInfo}{$oldName}); | delete($t->{logInfo}{$oldName}); | |||
$t->{XferLOG}->write(\"$_\n") if ( $conf->{XferLogLevel} >= 6 ); | $t->{XferLOG}->write(\"$_\n") if ( $conf->{XferLogLevel} >= 6 ); | |||
$t->logSaveFlush(); | $t->logSaveFlush(); | |||
next; | next; | |||
} | } | |||
if ( /^xferPids (\d+),(\d+)/ ) { | if ( /^xferPids (\d+),(\d+)/ ) { | |||
my $pidHandler = $t->{pidHandler}; | my $pidHandler = $t->{pidHandler}; | |||
if ( ref($pidHandler) eq 'CODE' ) { | if ( ref($pidHandler) eq 'CODE' ) { | |||
&$pidHandler($1, $2); | &$pidHandler($1, $2); | |||
} else { | } else { | |||
$t->{XferLOG}->write(\"$_\n") if ( $conf->{XferLogLevel} >= 4 ); | $t->{XferLOG}->write(\"$_\n") if ( $conf->{XferLogLevel} >= 4 ); | |||
} | } | |||
} | } | |||
if ( /^Done(Gen)?: (\d+) errors, (\d+) filesExist, (\d+) sizeExist, | if ( | |||
(\d+) sizeExistComp, (\d+) filesTotal, (\d+) sizeTotal, (\d+) filesNew, (\d+) si | /^Done(Gen)?: (\d+) errors, (\d+) filesExist, (\d+) sizeExist, ( | |||
zeNew, (\d+) sizeNewComp, (\d+) inode/ ) { | \d+) sizeExistComp, (\d+) filesTotal, (\d+) sizeTotal, (\d+) filesNew, (\d+) siz | |||
eNew, (\d+) sizeNewComp, (\d+) inode/ | ||||
) { | ||||
$t->{stats}{xferErrs} += $2; | $t->{stats}{xferErrs} += $2; | |||
$t->{stats}{nFilesExist} += $3; | $t->{stats}{nFilesExist} += $3; | |||
$t->{stats}{sizeExist} += $4; | $t->{stats}{sizeExist} += $4; | |||
$t->{stats}{sizeExistComp} += $5; | $t->{stats}{sizeExistComp} += $5; | |||
$t->{stats}{nFilesTotal} += $6; | $t->{stats}{nFilesTotal} += $6; | |||
$t->{stats}{sizeTotal} += $7; | $t->{stats}{sizeTotal} += $7; | |||
$t->{stats}{nFilesNew} += $8; | $t->{stats}{nFilesNew} += $8; | |||
$t->{stats}{sizeNew} += $9; | $t->{stats}{sizeNew} += $9; | |||
$t->{stats}{sizeNewComp} += $10; | $t->{stats}{sizeNewComp} += $10; | |||
$t->{stats}{inode} = $11 if ( $t->{stats}{inode} < $11 ); | $t->{stats}{inode} = $11 if ( $t->{stats}{inode} < $11 ); | |||
$t->{XferLOG}->write(\"$_\n"); | $t->{XferLOG}->write(\"$_\n"); | |||
$t->{XferLOG}->write(\"Parsing done: nFilesTotal = $t->{stats}{n FilesTotal}\n") | $t->{XferLOG}->write(\"Parsing done: nFilesTotal = $t->{stats}{n FilesTotal}\n") | |||
if ( $conf->{XferLogLevel} >= 3 ); | if ( $conf->{XferLogLevel} >= 3 ); | |||
$t->{fileCnt} = $t->{stats}{nFilesTotal}; | $t->{fileCnt} = $t->{stats}{nFilesTotal}; | |||
$t->{byteCnt} = $t->{stats}{sizeTotal}; | $t->{byteCnt} = $t->{stats}{sizeTotal}; | |||
next; | next; | |||
} | } | |||
# if ( /: \.\/(.*): Read error at byte / ) { | # if ( /: \.\/(.*): Read error at byte / ) { | |||
# my $badFile = $1; | # my $badFile = $1; | |||
# push(@{$t->{badFiles}}, { | # push(@{$t->{badFiles}}, { | |||
# share => $t->{shareName}, | # share => $t->{shareName}, | |||
# file => $badFile | # file => $badFile | |||
# }); | # }); | |||
# } | # } | |||
# from_to($_, $conf->{ClientCharset}, "utf8") | # from_to($_, $conf->{ClientCharset}, "utf8") | |||
# if ( $conf->{ClientCharset} ne "" ); | # if ( $conf->{ClientCharset} ne "" ) | |||
; | ||||
$t->{lastOutputLine} = $_ if ( !/^\s+$/ && length($_) ); | $t->{lastOutputLine} = $_ if ( !/^\s+$/ && length($_) ); | |||
$t->{lastErrorLine} = $_ if ( /^rsync_bpc: / || /^rsync error: / ); | $t->{lastErrorLine} = $_ if ( /^rsync_bpc: / || /^rsync error: / ); | |||
$t->{XferLOG}->write(\"$_\n"); | $t->{XferLOG}->write(\"$_\n"); | |||
} | } | |||
last if ( $done ); | last if ( $done ); | |||
} | } | |||
unlink($t->{pwFile}) if ( length($t->{pwFile}) && -f $t->{pwFile} ); | unlink($t->{pwFile}) if ( length($t->{pwFile}) && -f $t->{pwFile} ); | |||
unlink($t->{filesFrom}) if ( length($t->{filesFrom}) && -f $t->{filesFrom} ) ; | unlink($t->{filesFrom}) if ( length($t->{filesFrom}) && -f $t->{filesFrom} ) ; | |||
$t->logSaveFlush(1); | $t->logSaveFlush(1); | |||
$t->{lastOutputLine} = $t->{lastErrorLine} if ( defined($t->{lastErrorLine}) ); | $t->{lastOutputLine} = $t->{lastErrorLine} if ( defined($t->{lastErrorLine}) ); | |||
# | # | |||
# Remove any rsyncTmp files in the backup directory | # Remove any rsyncTmp files in the backup directory | |||
# | # | |||
my $bkupDir = $t->{type} eq "restore" ? "$conf->{TopDir}/pc/$t->{bkupSrcHost | my $bkupDir = | |||
}/$t->{bkupSrcNum}" | $t->{type} eq "restore" | |||
: "$conf->{TopDir}/pc/$t->{client}/$t-> | ? "$conf->{TopDir}/pc/$t->{bkupSrcHost}/$t->{bkupSrcNum}" | |||
{backups}[$t->{newBkupIdx}]{num}"; | : "$conf->{TopDir}/pc/$t->{client}/$t->{backups}[$t->{newBkupIdx}]{num}"; | |||
my $bkupDirEntries = BackupPC::DirOps::dirRead($bpc, $bkupDir); | my $bkupDirEntries = BackupPC::DirOps::dirRead($bpc, $bkupDir); | |||
my $pidRunning = {}; | my $pidRunning = {}; | |||
if ( ref($bkupDirEntries) eq 'ARRAY' ) { | if ( ref($bkupDirEntries) eq 'ARRAY' ) { | |||
foreach my $e ( @$bkupDirEntries ) { | foreach my $e ( @$bkupDirEntries ) { | |||
next if ( $e->{name} !~ /^rsyncTmp\.(\d+)\.\d+\.\d+$/ ); | next if ( $e->{name} !~ /^rsyncTmp\.(\d+)\.\d+\.\d+$/ ); | |||
my $pid = $1; | my $pid = $1; | |||
$pidRunning->{$pid} = kill(0, $pid) ? 1 : 0 if ( !defined($pidRunnin g->{$pid} ) ); | $pidRunning->{$pid} = kill(0, $pid) ? 1 : 0 if ( !defined($pidRunnin g->{$pid}) ); | |||
next if ( $pidRunning->{$pid} ); | next if ( $pidRunning->{$pid} ); | |||
$t->{XferLOG}->write(\"Removing rsync temporary file $bkupDir/$e->{na | $t->{XferLOG}->write(\"Removing rsync temporary file $bkupDir/$e->{n | |||
me}\n"); | ame}\n"); | |||
unlink("$bkupDir/$e->{name}"); | unlink("$bkupDir/$e->{name}"); | |||
} | } | |||
} | } | |||
if ( $t->{type} eq "restore" ) { | if ( $t->{type} eq "restore" ) { | |||
if ( $t->{xferOK} ) { | if ( $t->{xferOK} ) { | |||
return ( | return ($t->{fileCnt}, $t->{byteCnt}, 0, undef,); | |||
$t->{fileCnt}, | ||||
$t->{byteCnt}, | ||||
0, | ||||
undef, | ||||
); | ||||
} else { | } else { | |||
return ( | return ($t->{fileCnt}, $t->{byteCnt}, $t->{stats}{xferErrs}, $t->{la | |||
$t->{fileCnt}, | stOutputLine},); | |||
$t->{byteCnt}, | ||||
$t->{stats}{xferErrs}, | ||||
$t->{lastOutputLine}, | ||||
); | ||||
} | } | |||
} else { | } else { | |||
$t->{xferErrCnt} = $t->{stats}{xferErrs}; | $t->{xferErrCnt} = $t->{stats}{xferErrs}; | |||
return ( | return ( | |||
$t->{stats}{xferErrs}, | $t->{stats}{xferErrs}, $t->{stats}{nFilesExist}, $t->{stats}{si | |||
$t->{stats}{nFilesExist}, | zeExist}, | |||
$t->{stats}{sizeExist}, | $t->{stats}{sizeExistComp}, $t->{stats}{nFilesTotal}, $t->{stats}{si | |||
$t->{stats}{sizeExistComp}, | zeTotal}, | |||
$t->{stats}{nFilesTotal}, | $t->{stats}{nFilesNew}, $t->{stats}{sizeNew}, $t->{stats}{si | |||
$t->{stats}{sizeTotal}, | zeNewComp}, | |||
$t->{stats}{nFilesNew}, | ||||
$t->{stats}{sizeNew}, | ||||
$t->{stats}{sizeNewComp}, | ||||
$t->{stats}{inode}, | $t->{stats}{inode}, | |||
); | ); | |||
} | } | |||
} | } | |||
sub errStr | sub errStr | |||
{ | { | |||
my($t) = @_; | my($t) = @_; | |||
return $t->{_errStr}; | return $t->{_errStr}; | |||
} | } | |||
skipping to change at line 707 | skipping to change at line 722 | |||
$t->{abortReason} = $reason; | $t->{abortReason} = $reason; | |||
if ( @xferPid ) { | if ( @xferPid ) { | |||
kill($t->{bpc}->sigName2num("INT"), $xferPid[0]); | kill($t->{bpc}->sigName2num("INT"), $xferPid[0]); | |||
} | } | |||
} | } | |||
sub logSaveFlush | sub logSaveFlush | |||
{ | { | |||
my($t, $all) = @_; | my($t, $all) = @_; | |||
my $change = 1; | my $change = 1; | |||
my $conf = $t->{conf}; | my $conf = $t->{conf}; | |||
$all = 1 if ( $t->{type} eq "restore" ); | $all = 1 if ( $t->{type} eq "restore" ); | |||
while ( $change && @{$t->{logSave}} ) { | while ( $change && @{$t->{logSave}} ) { | |||
$change = 0; | $change = 0; | |||
my $fileName = $t->{logSave}[0]{fileName}; | my $fileName = $t->{logSave}[0]{fileName}; | |||
if ( defined($t->{logInfo}{$fileName}) || $all || @{$t->{logSave}} > 200 ) { | if ( defined($t->{logInfo}{$fileName}) || $all || @{$t->{logSave}} > 200 ) { | |||
my $mesg = sprintf(" %-6s %s", | my $mesg = sprintf(" %-6s %s", shift(@{$t->{logInfo}{$fileName}{s | |||
shift(@{$t->{logInfo}{$fileName}{status}}), | tatus}}), $t->{logSave}[0]{mesg}); | |||
$t->{logSave}[0]{mesg}); | ||||
delete($t->{logInfo}{$fileName}) if ( !@{$t->{logInfo}{$fileName}{st atus}} ); | delete($t->{logInfo}{$fileName}) if ( !@{$t->{logInfo}{$fileName}{st atus}} ); | |||
shift(@{$t->{logSave}}); | shift(@{$t->{logSave}}); | |||
#from_to($mesg, $conf->{ClientCharset}, "utf8") | #from_to($mesg, $conf->{ClientCharset}, "utf8") | |||
# if ( $conf->{ClientCharset} ne "" ); | # if ( $conf->{ClientCharset} ne "" ); | |||
$t->{lastOutputLine} = $mesg if ( !/^\s+$/ && length($mesg) ); | $t->{lastOutputLine} = $mesg if ( !/^\s+$/ && length($mesg) ); | |||
$t->{XferLOG}->write(\"$mesg\n"); | $t->{XferLOG}->write(\"$mesg\n"); | |||
$change = 1; | $change = 1; | |||
} | } | |||
} | } | |||
if ( %{$t->{logInfo}} > 2000 ) { | if ( %{$t->{logInfo}} > 2000 ) { | |||
# | # | |||
# prune the fileName logInfo array if it gets too big | # prune the fileName logInfo array if it gets too big | |||
# | # | |||
my @info = sort { $t->{logInfo}{$a}{seqNum} <=> $t->{logInfo}{$b}{seqNum } } | my @info = sort { $t->{logInfo}{$a}{seqNum} <=> $t->{logInfo}{$b}{seqNum } } | |||
keys(%{$t->{logInfo}}); | keys(%{$t->{logInfo}}); | |||
while ( @info > 500 ) { | while ( @info > 500 ) { | |||
my $fileName = shift(@info); | my $fileName = shift(@info); | |||
delete($t->{logInfo}{$fileName}); | delete($t->{logInfo}{$fileName}); | |||
} | } | |||
} | } | |||
} | } | |||
1; | 1; | |||
End of changes. 61 change blocks. | ||||
147 lines changed or deleted | 176 lines changed or added |