--- flexbackup.orig 2003-10-10 14:12:09 UTC +++ flexbackup @@ -133,6 +133,9 @@ $::zsh_pipe_exit = '; x=(${pipestatus[@] # tar has a limit of this many chars in its volume label $::tar_max_label = 99; +# Define the prune hash to avoid warnings with perl 5.12 +use vars qw( %prune ); + # Get commandline flags %::opt = (); if (! &::GetOptions(\%::opt, @@ -269,6 +272,7 @@ if (($::mode !~ m/^(list|extract|restore untie(%::index); } +system ('rm', '-rf', $cfg::tmpdir); exit(0); ###################################################################### @@ -441,7 +445,7 @@ sub backup_routine { # Get rid of trailing / $dir = &nuke_trailing_slash($dir); - # If level is icremental for the set, each dir might + # If level is incremental for the set, each dir might # have a different numeric level if (!defined($::set_incremental)) { $level = $::level; @@ -687,6 +691,8 @@ sub backup { $filename .= ".zip"; } elsif ($cfg::compress eq "compress") { $filename .= ".Z"; + } elsif ($cfg::compress eq "lzma") { + $filename .= ".lzma"; } } elsif ($cfg::type eq "afio") { # tag these a little different, the archive file itself isn't a @@ -701,6 +707,8 @@ sub backup { $filename .= "-zip"; } elsif ($cfg::compress eq "compress") { $filename .= "-Z"; + } elsif ($cfg::compress eq "lzma") { + $filename .= "-lzma"; } } @@ -811,6 +819,11 @@ sub backup { ($remove, @cmds) = &backup_filelist($label, $localdir, $title, $level, $remote); } + if(defined($remote)) { + # create our temporary directory as first remote command + unshift(@cmds, &maybe_remote_cmd("$::path{mkdir} -p $cfg::tmpdir", $remote)); + } + # Nuke any tmp files used in the above routines if ($remove ne '') { push(@cmds, &maybe_remote_cmd("$::path{rm} -f $remove", $remote)); @@ -827,6 +840,11 @@ sub backup { push(@cmds, &maybe_remote_cmd("$::path{rm} -f $pkglist", $remote)); } } + + if(defined($remote)) { + # remove temporary directory as our last remote command + push(@cmds, &maybe_remote_cmd("$::path{rm} -rf $cfg::tmpdir", $remote)); + } # Strip multiple spaces foreach my $cmd (@cmds) { @@ -1035,7 +1053,7 @@ sub backup_dump { } else { $prunekey = $dir; } - if (defined(%{$::prune{$prunekey}})) { + if (defined($prune{$prunekey})) { &log("| NOTE: \$prune is ignored for type=dump"); } @@ -1140,7 +1158,7 @@ sub backup_afio { $cmd .= "$::path{afio} -o "; $cmd .= "$no_compress "; $cmd .= "-z "; - $cmd .= "-1 m "; + $cmd .= "-1 mC "; $cmd .= "$::afio_z_flag "; $cmd .= "$::afio_verb_flag "; $cmd .= "$::afio_sparse_flag "; @@ -1286,8 +1304,8 @@ sub backup_copy_cpio { $cmd .= "$::unz"; } $cmd .= "("; - $cmd .= "mkdir -p $::device ; "; - $cmd .= "cd $::device ; "; + $cmd .= "mkdir -p \"$::device\" ; "; + $cmd .= "cd \"$::device\" ; "; $cmd .= "$::path{cpio} -i "; $cmd .= "-m "; $cmd .= "-d "; @@ -1336,9 +1354,8 @@ sub backup_copy_rsync { # Have to take leading './' off to make rsync's include/exclude work right $cmd .= " | $::path{sed} -e \"s/\\.\\///g\" | "; - $cmd .= "$::path{rsync} "; - $cmd .= "--include-from=- --exclude=* "; + $cmd .= "--files-from=- "; $cmd .= "--archive "; $cmd .= "$::rsync_verb_flag "; $cmd .= "--delete --delete-excluded "; @@ -1353,7 +1370,7 @@ sub backup_copy_rsync { $cmd .= "$remote:"; } } - $cmd .= "$dir/ $::device"; + $cmd .= "\"$dir/\" \"$::device\""; push(@cmds, $cmd); @@ -1643,7 +1660,9 @@ sub backup_ar { my $tmpfile = "$cfg::tmpdir/ar.$PROCESS_ID"; my $remove = ''; - &log("| NOTE: ar archives will not descend directories"); + &log("| NOTE: ar archives will not recurse into subdirectories,"); + &log("| which makes them inappropriate for most backups."); + &log("| Be sure this is what you want."); if (defined($remote) and ($level != 0)) { my $time = &get_last_date($label, $level, 'numeric'); @@ -1667,11 +1686,13 @@ sub backup_ar { $cmd = "cd \"$dir\" && "; $cmd .= &file_list_cmd( $dir, $stamp, 'newline', $level, $remote, '-maxdepth 1 ! -type d'); $cmd .= "> $filelist; "; + # Escape any spaces in filenames. + $cmd .= "$::path{sed} -i -e 's/ /\\\\ /g' $filelist; "; $cmd .= "$::path{ar} rc"; $cmd .= "$::ar_verb_flag "; $cmd .= "$tmpfile "; - $cmd .= "`$::path{cat} $filelist`"; + $cmd .= "\@$filelist "; $cmd .= "; $::path{cat} $tmpfile $::z"; # Buffer both sides if remote @@ -1785,12 +1806,9 @@ sub backup_lha { $cmd = "cd \"$dir\" && "; $cmd .= &file_list_cmd( $dir, $stamp, 'newline', $level, $remote); - $cmd .= "> $filelist; "; - - $cmd .= "$::path{lha} a"; + $cmd .= " | $::path{lha} a"; $cmd .= "$::lha_verb_flag "; $cmd .= "$tmpfile "; - $cmd .= "`$::path{cat} $filelist`"; $cmd .= "; $::path{cat} $tmpfile $::z"; # Buffer both sides if remote @@ -2670,7 +2688,7 @@ sub optioncheck { } # Flag old config file - if (defined(@cfg::filesystems) or defined($cfg::mt_var_blksize)) { + if (@cfg::filesystems or defined($cfg::mt_var_blksize)) { # so strict shuts up my $junk = @cfg::filesystems; $junk = $cfg::mt_var_blksize; @@ -2700,7 +2718,7 @@ sub optioncheck { # First check if things are defined in the config file # Checks exist, true/false, or one of options &checkvar(\$cfg::type,'type','dump afio cpio tar star pax zip ar shar lha copy rsync filelist','tar'); - &checkvar(\$cfg::compress,'compress','gzip bzip2 lzop compress zip false hardware','gzip'); + &checkvar(\$cfg::compress,'compress','gzip bzip2 lzop compress zip false hardware lzma','gzip'); &checkvar(\$cfg::compr_level,'compr_level','exist','4'); &checkvar(\$cfg::verbose,'verbose','bool','true'); &checkvar(\$cfg::sparse,'sparse','bool','true'); @@ -2750,8 +2768,10 @@ sub optioncheck { $::path{'find'} = &checkinpath('find'); $::path{'dd'} = &checkinpath('dd'); $::path{'printf'} = &checkinpath('printf'); + $::path{'mkdir'} = &checkinpath('mkdir'); + $::path{'sed'} = &checkinpath('sed'); - push(@::remoteprogs,($::path{'touch'},$::path{'rm'},$::path{'find'},$::path{'printf'})); + push(@::remoteprogs,($::path{'touch'},$::path{'rm'},$::path{'find'},$::path{'printf'},$::path{'mkdir'})); # Check device (or dir) $::ftape = 0; @@ -3001,6 +3021,16 @@ sub optioncheck { $::z = " | $::path{zip} -$cfg::compr_level - -"; $::unz = "$::path{funzip} | "; } + } elsif ($cfg::compress eq "lzma") { + $::path{'lzma'} = &checkinpath($cfg::compress); + push(@::remoteprogs, $::path{$cfg::compress}); + if ($cfg::compr_level !~ m/^[0123456789]$/) { + push(@::errors,"\$compr_level must be set to 1-9"); + } else { + $::z = " | $::path{$cfg::compress} -$cfg::compr_level "; + } + $::unz = "$::path{$cfg::compress} -d | "; + } else { $::z = ""; $::unz = ""; @@ -3059,12 +3089,11 @@ sub optioncheck { $::read_cmd = "$bufcmd $read_flags"; } elsif ($cfg::buffer eq "mbuffer") { - $::path{'mbuffer'} = &checkinpath('mbuffer'); push(@::remoteprogs, $::path{'mbuffer'}); my $megs = $cfg::buffer_megs . "M"; - my $bufcmd = "$::path{mbuffer} -q -m $megs -p $cfg::buffer_fill_pct $mbuffer_blk_flag "; + my $bufcmd = "$::path{mbuffer} -q -m $megs -P $cfg::buffer_fill_pct $mbuffer_blk_flag "; $::buffer_cmd = " | $bufcmd"; $::write_cmd = "$bufcmd -f -o "; @@ -3075,7 +3104,6 @@ sub optioncheck { } } } else { - # If buffering disabled, use dd or cat depending on if blocking turned off on not if ($cfg::blksize eq '0') { $::buffer_cmd = ""; @@ -3230,7 +3258,7 @@ sub optioncheck { push(@::remoteprogs, $::path{'afio'}); # Compress flag for afio must be handled differently - if ($cfg::compress =~ m/^(gzip|bzip2|lzop|compress|zip)$/) { + if ($cfg::compress =~ m/^(gzip|bzip2|lzop|compress|zip|lzma)$/) { if ($cfg::compress eq "gzip") { $::afio_z_flag = "-P $::path{$cfg::compress} -Q -$cfg::compr_level -Z"; @@ -3252,6 +3280,10 @@ sub optioncheck { $::afio_z_flag = "-P $::path{$cfg::compress} -Q -c -Z"; $::afio_unz_flag = "-P $::path{$cfg::compress} -Q -d -Q -c -Z"; + } elsif ($cfg::compress eq "lzma") { + $::afio_z_flag = "-P $::path{$cfg::compress} -Q -$cfg::compr_level -Z"; + $::afio_unz_flag = "-P $::path{$cfg::compress} -Q -d -Z"; + } $::unz = ""; # Reset & just use this for reading the archive file. @@ -3415,7 +3447,7 @@ sub optioncheck { $::path{'lha'} = &checkinpath('lha'); push(@::remoteprogs, $::path{'lha'}); - if ($cfg::compress =~ /^(gzip|bzip2|lzop|compress|zip)$/) { + if ($cfg::compress =~ /^(gzip|bzip2|lzop|compress|zip|lzma)$/) { warn("Using type \"lha\" with compress=$cfg::compress makes no sense"); warn("Setting compression to false"); $::unz = ""; @@ -3442,6 +3474,15 @@ sub optioncheck { push(@::errors,"\$tmpdir $cfg::tmpdir is not writable"); } + $cfg::hostname = `hostname`; + chomp($cfg::hostname); + + # Use a subdirectory of the user-specified directory as our tmpdir + # Also note that we make it closer to globally unique as we sometimes + # use this variable for remote systems, so PID isn't enough + $cfg::tmpdir = $cfg::tmpdir .'/flexbackup.'.$$.'.'.$cfg::hostname; + mkdir ($cfg::tmpdir) || die "Can't create temporary directory, $!"; + # Levels if (defined($::opt{'level'}) and (defined($::opt{'incremental'}) or @@ -3781,7 +3822,7 @@ sub maybe_get_filename { # Try and guess file types and commpression scheme # might as well since we are reading from a file in this case - if ($file =~ m/\.(dump|cpio|tar|star|pax|a|shar|filelist)\.(gz|bz2|lzo|Z|zip)$/) { + if ($file =~ m/\.(dump|cpio|tar|star|pax|a|shar|filelist)\.(gz|bz2|lzo|Z|zip|lzma)$/) { $cfg::type = $1; $cfg::compress = $2; $cfg::type =~ s/^a$/ar/; @@ -3789,16 +3830,18 @@ sub maybe_get_filename { $cfg::compress =~ s/bz2/bzip2/; $cfg::compress =~ s/lzo/lzop/; $cfg::compress =~ s/Z/compress/; + $cfg::compress =~ s/lzma/lzma/; &log("| Auto-set to type=$cfg::type compress=$cfg::compress"); &optioncheck(); # redo to set a few variables over - } elsif ($file =~ m/\.afio-(gz|bz2|lzo|Z|zip)$/) { + } elsif ($file =~ m/\.afio-(gz|bz2|lzo|Z|zip|lzma)$/) { $cfg::type = "afio"; $cfg::compress = $1; $cfg::compress =~ s/gz/gzip/; $cfg::compress =~ s/bz2/bzip2/; $cfg::compress =~ s/lzo/lzop/; $cfg::compress =~ s/Z/compress/; + $cfg::compress =~ s/lzma/lzma/; &log("| Auto-set to type=$cfg::type compress=$cfg::compress"); &optioncheck(); # redo to set a few variables over @@ -4841,25 +4884,32 @@ sub file_list_cmd { } else { $prunekey = $dir; } - - if (defined(%{$::prune{$prunekey}})) { + if (defined($prune{$prunekey})) { + my $rex; # FreeBSD needs -E (above) and no backslashes around the (|) chars if ($::uname =~ /FreeBSD/) { - $cmd .= '-regex "\./('; - $cmd .= join('|', keys %{$::prune{$prunekey}}); - $cmd .= ')/.*" '; - } else { - $cmd .= '-regex "\./\('; - $cmd .= join('\|', keys %{$::prune{$prunekey}}); - $cmd .= '\)/.*" '; - } - $cmd .= '-prune -o '; + $rex = '"\./('; + $rex .= join('|', keys %{$::prune{$prunekey}}); + $rex .= ')"'; + } else { + $rex = '"\./\('; + $rex .= join('\|', keys %{$::prune{$prunekey}}); + $rex .= '\)"'; + } + # Show what the darn thing is constructing for prune expressions. + (my $temp = $rex) =~ s/\\([()|])/$1/g; + &log("| \"find\" regex for pruning (shell escaping omitted for clarity) is:"); + &log("| $temp"); + $cmd .= '-regex ' . $rex . ' -prune -o '; } else { + # Show what the darn thing is constructing for prune expressions. + &log("| No pruning defined for this tree."); # Can't use find -depth with -prune (see single unix spec etc) # (not toally required anyway, only if you are archiving dirs you # don't have permissions on and are running as non-root) $cmd .= "-depth "; } + &line(); $cmd .= "$::mountpoint_flag "; $cmd .= "! -type s "; @@ -5229,6 +5279,7 @@ sub test_bufferprog { my $tmp_script = "$cfg::tmpdir/buftest.$host.$PROCESS_ID.sh"; my $retval = 0; my $pipecmd; + my $explicit_success; $buffer_cmd =~ s:^\s*\|\s*::; $buffer_cmd =~ s:\s*\|\s*$::; @@ -5236,14 +5287,14 @@ sub test_bufferprog { # Create a script which tests the buffer program open(SCR,"> $tmp_script") || die; print SCR "#!/bin/sh\n"; - print SCR "tmp_data=/tmp/bufftest\$\$.txt\n"; - print SCR "tmp_err=/tmp/bufftest\$\$.err\n"; + print SCR "tmp_data=\$(mktemp $cfg::tmpdir/data.XXXXXXXXXX)\n"; + print SCR "tmp_err=\$(mktemp $cfg::tmpdir/err.XXXXXXXXXX)\n"; print SCR "echo testme > \$tmp_data\n"; print SCR "$buffer_cmd > /dev/null 2> \$tmp_err < \$tmp_data\n"; print SCR "res=\$?\n"; print SCR "out=\`cat \$tmp_err\`\n"; print SCR "if [ \$res -eq 0 ]; then\n"; - print SCR " echo successful\n"; + print SCR " echo \"successful\"\n"; print SCR "else\n"; print SCR " echo \"unsuccessful: exit code \$res: \$out\" \n"; print SCR "fi\n"; @@ -5254,14 +5305,22 @@ sub test_bufferprog { print $::msg "| Checking '$cfg::buffer' on this machine... "; $pipecmd = "sh $tmp_script "; } else { + $pipecmd = + "$::remoteshell $host '$::path{mkdir} -p $cfg::tmpdir'; " . + "cat $tmp_script | ($::remoteshell $host 'cat > $tmp_script; " . + "sh $tmp_script; rm -rf $cfg::tmpdir')"; print $::msg "| Checking '$cfg::buffer' on host $host... "; - $pipecmd = "cat $tmp_script | ($::remoteshell $host 'cat > $tmp_script; sh $tmp_script; rm -f $tmp_script')"; } if (!defined($::debug)) { - open(PIPE,"$pipecmd |") || die; + + $explicit_success = 0; while () { + if (/^successful$/) { + $explicit_success = 1; + last; + } if (/^unsuccessful: exit code (\d+): (.*)/) { $retval = $1; my $out = $2; @@ -5290,11 +5349,15 @@ sub test_bufferprog { print $::msg "\n(debug) $pipecmd\n"; } - if ($retval == 0) { + if ($explicit_success) { print $::msg "Ok\n"; } else { + if ($retval == 0) { + push(@::errors, "Unanticipated problems encountered testing '$cfg::buffer' on host '$host'."); + } else { print $::msg "Failed!\n"; } + } unlink("$tmp_script"); return($retval); @@ -5396,10 +5459,10 @@ sub check_shell { my $shell = $1; my $ver = $2; if ($shell eq 'bash') { - if ($ver =~ m/^2/) { - $::shelltype{$host} = 'bash2'; - } else { + if ($ver =~ m/^1/) { $::shelltype{$host} = 'bash1'; + } else { + $::shelltype{$host} = 'bash2'; } } else { $::shelltype{$host} = $shell; @@ -5686,3 +5749,5 @@ sub spinner { return($spinner[$index]); } + +