rsnapshot-1.3.1/0000755000000000000000000000000011056477673013513 5ustar rootroot00000000000000rsnapshot-1.3.1/rsnapshot-preamble.pl0000644000000000000000000000010607767751305017654 0ustar rootroot00000000000000#!@PERL@ -w # the path to perl at the top was generated by autoconf rsnapshot-1.3.1/rsnapshot-program.pl0000755000000000000000000065037011056476663017552 0ustar rootroot00000000000000#!/usr/bin/perl -w ######################################################################## # # # rsnapshot # # by Nathan Rosenquist # # now maintained by David Keegel # # # # The official rsnapshot website is located at # # http://www.rsnapshot.org/ # # # # Copyright (C) 2003-2005 Nathan Rosenquist # # # # Portions Copyright (C) 2002-2006 Mike Rubel, Carl Wilhelm Soderstrom,# # Ted Zlatanov, Carl Boe, Shane Liebling, Bharat Mediratta, # # Peter Palfrader, Nicolas Kaiser, David Cantrell, Chris Petersen, # # Robert Jackson, Justin Grote, David Keegel, Alan Batie # # # # rsnapshot comes with ABSOLUTELY NO WARRANTY. This is free software, # # and you may copy, distribute and/or modify it under the terms of # # the GNU GPL (version 2 or at your option any later version). # # See the GNU General Public License (in file: COPYING) for details. # # # # Based on code originally by Mike Rubel # # http://www.mikerubel.org/computers/rsync_snapshots/ # # # ######################################################################## # $Id: rsnapshot-program.pl,v 1.398 2008/08/09 02:15:49 djk20 Exp $ # tabstops are set to 4 spaces # in vi, do: set ts=4 sw=4 ######################################## ### STANDARD MODULES ### ######################################## require 5.004; use strict; use DirHandle; # DirHandle() use Cwd; # cwd() use Getopt::Std; # getopts() use File::Path; # mkpath(), rmtree() use File::stat; # stat(), lstat() use POSIX qw(locale_h); # setlocale() use Fcntl; # sysopen() use IO::File; # recursive open in parse_config_file ######################################## ### CPAN MODULES ### ######################################## # keep track of whether we have access to the Lchown module my $have_lchown = 0; # use_lchown() is called later, so we can log the results ######################################## ### DECLARE GLOBAL VARIABLES ### ######################################## # turn off buffering $| = 1; # version of rsnapshot my $VERSION = '1.3.1'; # command or interval to execute (first cmd line arg) my $cmd; # default configuration file my $config_file; # hash to hold variables from the configuration file my %config_vars; # array of hash_refs containing the destination backup point # and either a source dir or a script to run my @backup_points; # array of backup points to rollback, in the event of failure my @rollback_points; # "intervals" are user defined time periods (e.g., hourly, daily) # this array holds hash_refs containing the name of the interval, # and the number of snapshots to keep of it # # NB, intervals and now called backup levels, and the config parameter # is 'retain' my @intervals; # store interval data (mostly info about which one we're on, what was before, etc.) # this is a convenient reference to some of the data from and metadata about @intervals my $interval_data_ref; # intervals can't have these values, because they're either taken by other commands # or reserved for future use my @reserved_words = qw( archive check-config-version configtest diff delete du get-latest-snapshot help history list print-config restore rollback sync upgrade-config-file version version-only ); # global flags that change the outcome of the program, # and are configurable by both cmd line and config flags # my $test = 0; # turn verbose on, but don't execute # any filesystem commands my $do_configtest = 0; # parse config file and exit my $one_fs = 0; # one file system (don't cross # partitions within a backup point) my $link_dest = 0; # use the --link-dest option to rsync my $stop_on_stale_lockfile = 0; # stop if there is a stale lockfile # how much noise should we make? the default is 2 # # please note that direct rsync output does not get written to the log file, only to STDOUT # this is because we're not intercepting STDOUT while rsync runs # # 0 Absolutely quiet (reserved, but not implemented) # 1 Don't display warnings about FIFOs and special files # 2 Default (errors only) # 3 Verbose (show shell commands and equivalents) # 4 Extra verbose messages (individual actions inside some subroutines, output from rsync) # 5 Debug # # define verbose and loglevel my $verbose = undef; my $loglevel = undef; # set defaults for verbose and loglevel my $default_verbose = 2; my $default_loglevel = 3; # assume the config file is valid until we find an error my $config_perfect = 1; # exit code for rsnapshot my $exit_code = 0; # global defaults for external programs my $default_rsync_short_args = '-a'; my $default_rsync_long_args = '--delete --numeric-ids --relative --delete-excluded'; my $default_ssh_args = undef; my $default_du_args = '-csh'; # set default for use_lazy_deletes my $use_lazy_deletes = 0; # do not delete the oldest archive until after backup # set default for number of tries my $rsync_numtries = 1; # by default, try once # exactly how the program was called, with all arguments # this is set before getopts() modifies @ARGV my $run_string = "$0 " . join(' ', @ARGV); # if we have any errors, we print the run string once, at the top of the list my $have_printed_run_string = 0; # pre-buffer the include/exclude parameter flags # local to parse_config_file and validate_config_file my $rsync_include_args = undef; my $rsync_include_file_args = undef; ######################################## ### SIGNAL HANDLERS ### ######################################## # shut down gracefully if necessary $SIG{'HUP'} = 'IGNORE'; $SIG{'INT'} = sub { bail('rsnapshot was sent INT signal... cleaning up'); }; $SIG{'QUIT'} = sub { bail('rsnapshot was sent QUIT signal... cleaning up'); }; $SIG{'ABRT'} = sub { bail('rsnapshot was sent ABRT signal... cleaning up'); }; $SIG{'TERM'} = sub { bail('rsnapshot was sent TERM signal... cleaning up'); }; ######################################## ### CORE PROGRAM STRUCTURE ### ######################################## # what follows is a linear sequence of events. # all of these subroutines will either succeed or terminate the program safely. # figure out the path to the default config file (with autoconf we have to check) # this sets $config_file to the full config file path find_config_file(); # parse command line options # (this can override $config_file, if the -c flag is used on the command line) parse_cmd_line_opts(); # if we need to run a command that doesn't require fully parsing the config file, do it now (and exit) if (!defined($cmd) or ((! $cmd) && ('0' ne $cmd))) { show_usage(); } elsif ($cmd eq 'help') { show_help(); } elsif ($cmd eq 'version') { show_version(); } elsif ($cmd eq 'version-only') { show_version_only(); } elsif ($cmd eq 'check-config-version') { check_config_version(); } elsif ($cmd eq 'upgrade-config-file') { upgrade_config_file(); } # if we're just doing a configtest, set that flag if ($cmd eq 'configtest') { $do_configtest = 1; } # parse config file (if it exists) if (defined($config_file) && (-f "$config_file") && (-r "$config_file")) { # if there is a problem, this subroutine will exit the program and notify the user of the error parse_config_file(); validate_config_file(); # no config file found } else { # warn user and exit the program exit_no_config_file(); } # attempt to load the Lchown module: http://search.cpan.org/dist/Lchown/ use_lchown(); # if we're just doing a configtest, exit here with the results if (1 == $do_configtest) { exit_configtest(); } # if we're just using "du" or "rsnapshot-diff" to check the disk space, do it now (and exit) # these commands are down here because they needs to know the contents of the config file if ($cmd eq 'du') { show_disk_usage(); } elsif ($cmd eq 'diff') { show_rsnapshot_diff(); } elsif ($cmd eq 'get-latest-snapshot') { show_latest_snapshot(); } # # IF WE GOT THIS FAR, PREPARE TO RUN A BACKUP # # log the beginning of this run log_startup(); # this is reported to fix some semi-obscure problems with rmtree() set_posix_locale(); # if we're using a lockfile, try to add it # (the program will bail if one exists and it's not stale) add_lockfile(); # create snapshot_root if it doesn't exist (and no_create_root != 1) create_snapshot_root(); # now chdir to the snapshot_root. # note that this is needed because in the rare case that you do this ... # sudo -u peon rsnapshot ... and are in a directory that 'peon' can't # read, then some versions of GNU rm will later fail, as they try to # lstat the cwd. It's safe to chdir because all directories etc that # we ever mention are absolute. chdir($config_vars{'snapshot_root'}); # actually run the backup job # $cmd should store the name of the interval we'll run against handle_interval( $cmd ); # if we have a lockfile, remove it remove_lockfile(); # if we got this far, the program is done running # write to the log and syslog with the status of the outcome # exit_with_status(); ######################################## ### SUBROUTINES ### ######################################## # concise usage information # runs when rsnapshot is called with no arguments # exits with an error condition sub show_usage { print< 1) { for (my $i=1; $inew($config_file) or bail("Could not open config file \"$config_file\"\nAre you sure you have permission?"); } # read it line by line @configs = <$CONFIG>; while (my $line = $configs[$file_line_num]) { chomp($line); # count line numbers $file_line_num++; # assume the line is formatted incorrectly my $line_syntax_ok = 0; # ignore comments if (is_comment($line)) { next; } # ignore blank lines if (is_blank($line)) { next; } # if the next line begins with space or tab it belongs to this line while (defined ($configs[$file_line_num]) && $configs[$file_line_num] =~ /^(\t|\s)/) { (my $newline = $configs[$file_line_num]) =~ s/^\s+|\s+$//g; $line = $line . "\t" . $newline; $file_line_num++; } # parse line my ($var, $value, $value2, $value3) = split(/\t+/, $line, 4); # warn about entries we don't understand, and immediately prevent the # program from running or parsing anything else if (!defined($var)) { config_err($file_line_num, "$line - could not find a first word on this line"); next; } if (!defined($value) && $var eq $line) { # No tabs found in $line. if ($line =~ /\s/) { # User put spaces in config line instead of tabs. config_err($file_line_num, "$line - missing tabs to separate words - change spaces to tabs."); next; } else { # User put only one word config_err($file_line_num, "$line - could not find second word on this line"); next; } } foreach (grep { defined($_) && index($_, ' ') == 0 } ($value, $value2, $value3)) { print_warn("$line - extra space found between tab and $_"); } # INCLUDEs if($var eq 'include_conf') { $value =~ /^`(.*)`$/; if( (defined($value) && -f $value && -r $value) || (defined($1) && -x $1) ) { $line_syntax_ok = 1; parse_config_file($value); } else { config_err($file_line_num, "$line - can't find or read file '$value'"); next; } } # CONFIG_VERSION if ($var eq 'config_version') { if (defined($value)) { # right now 1.2 is the only possible value if ('1.2' eq $value) { $config_vars{'config_version'} = $value; $line_syntax_ok = 1; next; } else { config_err($file_line_num, "$line - config_version not recognized!"); next; } } else { config_err($file_line_num, "$line - config_version not defined!"); next; } } # SNAPSHOT_ROOT if ($var eq 'snapshot_root') { # make sure this is a full path if (0 == is_valid_local_abs_path($value)) { if (is_ssh_path($value) || is_anon_rsync_path($value) || is_cwrsync_path($value)) { config_err($file_line_num, "$line - snapshot_root must be a local path - you cannot have a remote snapshot_root"); } else { config_err($file_line_num, "$line - snapshot_root must be a full path"); } next; # if the snapshot root already exists: } elsif ( -e "$value" ) { # if path exists already, make sure it's a directory if ((-e "$value") && (! -d "$value")) { config_err($file_line_num, "$line - snapshot_root must be a directory"); next; } # make sure it's readable if ( ! -r "$value" ) { config_err($file_line_num, "$line - snapshot_root exists but is not readable"); next; } # make sure it's writable if ( ! -w "$value" ) { config_err($file_line_num, "$line - snapshot_root exists but is not writable"); next; } } # remove the trailing slash(es) if present $value = remove_trailing_slash($value); $config_vars{'snapshot_root'} = $value; $line_syntax_ok = 1; next; } # SYNC_FIRST # if this is enabled, rsnapshot syncs data to a staging directory with the "rsnapshot sync" command, # and all "interval" runs will simply rotate files. this changes the behaviour of the lowest interval. # when a sync occurs, no directories are rotated. the sync directory is kind of like a staging area for data transfers. # the files in the sync directory will be hard linked with the others in the other snapshot directories. # the sync directory lives at: //.sync/ # if ($var eq 'sync_first') { if (defined($value)) { if ('1' eq $value) { $config_vars{'sync_first'} = 1; $line_syntax_ok = 1; next; } elsif ('0' eq $value) { $config_vars{'sync_first'} = 0; $line_syntax_ok = 1; next; } else { config_err($file_line_num, "$line - sync_first must be set to either 1 or 0"); next; } } } # NO_CREATE_ROOT if ($var eq 'no_create_root') { if (defined($value)) { if ('1' eq $value) { $config_vars{'no_create_root'} = 1; $line_syntax_ok = 1; next; } elsif ('0' eq $value) { $config_vars{'no_create_root'} = 0; $line_syntax_ok = 1; next; } else { config_err($file_line_num, "$line - no_create_root must be set to either 1 or 0"); next; } } } # CHECK FOR RSYNC (required) if ($var eq 'cmd_rsync') { $value =~ s/\s+$//; if ((-f "$value") && (-x "$value") && (1 == is_real_local_abs_path($value))) { $config_vars{'cmd_rsync'} = $value; $line_syntax_ok = 1; next; } else { config_err($file_line_num, "$line - $value is not executable"); next; } } # CHECK FOR SSH (optional) if ($var eq 'cmd_ssh') { $value =~ s/\s+$//; if ((-f "$value") && (-x "$value") && (1 == is_real_local_abs_path($value))) { $config_vars{'cmd_ssh'} = $value; $line_syntax_ok = 1; next; } else { config_err($file_line_num, "$line - $value is not executable"); next; } } # CHECK FOR GNU cp (optional) if ($var eq 'cmd_cp') { $value =~ s/\s+$//; if ((-f "$value") && (-x "$value") && (1 == is_real_local_abs_path($value))) { $config_vars{'cmd_cp'} = $value; $line_syntax_ok = 1; next; } else { config_err($file_line_num, "$line - $value is not executable"); next; } } # CHECK FOR rm (optional) if ($var eq 'cmd_rm') { $value =~ s/\s+$//; if ((-f "$value") && (-x "$value") && (1 == is_real_local_abs_path($value))) { $config_vars{'cmd_rm'} = $value; $line_syntax_ok = 1; next; } else { config_err($file_line_num, "$line - $value is not executable"); next; } } # CHECK FOR LOGGER (syslog program) (optional) if ($var eq 'cmd_logger') { $value =~ s/\s+$//; if ((-f "$value") && (-x "$value") && (1 == is_real_local_abs_path($value))) { $config_vars{'cmd_logger'} = $value; $line_syntax_ok = 1; next; } else { config_err($file_line_num, "$line - $value is not executable"); next; } } # CHECK FOR du (optional) if ($var eq 'cmd_du') { $value =~ s/\s+$//; if ((-f "$value") && (-x "$value") && (1 == is_real_local_abs_path($value))) { $config_vars{'cmd_du'} = $value; $line_syntax_ok = 1; next; } else { config_err($file_line_num, "$line - $value is not executable"); next; } } # CHECK FOR lvcreate (optional) if ($var eq 'linux_lvm_cmd_lvcreate') { if ((-f "$value") && (-x "$value") && (1 == is_real_local_abs_path($value))) { $config_vars{'linux_lvm_cmd_lvcreate'} = $value; $line_syntax_ok = 1; next; } else { config_err($file_line_num, "$line - $value is not executable"); next; } } # CHECK FOR lvremove (optional) if ($var eq 'linux_lvm_cmd_lvremove') { if ((-f "$value") && (-x "$value") && (1 == is_real_local_abs_path($value))) { $config_vars{'linux_lvm_cmd_lvremove'} = $value; $line_syntax_ok = 1; next; } else { config_err($file_line_num, "$line - $value is not executable"); next; } } # CHECK FOR mount (optional) if ($var eq 'linux_lvm_cmd_mount') { if ((-f "$value") && (-x "$value") && (1 == is_real_local_abs_path($value))) { $config_vars{'linux_lvm_cmd_mount'} = $value; $line_syntax_ok = 1; next; } else { config_err($file_line_num, "$line - $value is not executable"); next; } } # CHECK FOR umount (optional) if ($var eq 'linux_lvm_cmd_umount') { if ((-f "$value") && (-x "$value") && (1 == is_real_local_abs_path($value))) { $config_vars{'linux_lvm_cmd_umount'} = $value; $line_syntax_ok = 1; next; } else { config_err($file_line_num, "$line - $value is not executable"); next; } } # CHECK FOR cmd_preexec (optional) if ($var eq 'cmd_preexec') { my $script; # script file (no args) # make sure script exists and is executable if ( ! is_valid_script($value, \$script) ) { config_err($file_line_num, "$line - \"$script\" is not executable or can't be found.".($script !~ m{^/} ? " Please use an absolute path.":"")); next; } $config_vars{$var} = $value; $line_syntax_ok = 1; next; } # CHECK FOR cmd_postexec (optional) if ($var eq 'cmd_postexec') { my $script; # script file (no args) # make sure script exists and is executable if ( ! is_valid_script($value, \$script) ) { config_err($file_line_num, "$line - \"$script\" is not executable or can't be found.".($script !~ m{^/} ? " Please use an absolute path.":"")); next; } $config_vars{$var} = $value; $line_syntax_ok = 1; next; } # CHECK FOR rsnapshot-diff (optional) if ($var eq 'cmd_rsnapshot_diff') { $value =~ s/\s+$//; if ((-f "$value") && (-x "$value") && (1 == is_real_local_abs_path($value))) { $config_vars{'cmd_rsnapshot_diff'} = $value; $line_syntax_ok = 1; next; } else { config_err($file_line_num, "$line - $value is not executable"); next; } } # INTERVALS # 'retain' is the new name for this parameter, although for # Laziness reasons (plus the fact that I'm making this change # at 10 minutes to midnight and so am wary of making changes # throughout the code and getting it wrong) the code will # still call it 'interval'. Documentation and messages should # refer to 'retain'. The old 'interval' will be kept as an # alias. if ($var eq 'interval' || $var eq 'retain') { my $retain = $var; # either 'interval' or 'retain' # check if interval is blank if (!defined($value)) { config_err($file_line_num, "$line - $retain can not be blank"); } foreach my $word (@reserved_words) { if ($value eq $word) { config_err($file_line_num, "$line - \"$value\" is not a valid interval name, reserved word conflict"); next; } } # make sure interval is alpha-numeric if ($value !~ m/^[\w\d]+$/) { config_err($file_line_num, "$line - \"$value\" is not a valid $retain name, must be alphanumeric characters only"); next; } # check if number is blank if (!defined($value2)) { config_err($file_line_num, "$line - \"$value\" number can not be blank"); next; } # check if number is valid if ($value2 !~ m/^\d+$/) { config_err($file_line_num, "$line - \"$value2\" is not a legal value for a retention count"); next; # ok, it's a number. is it positive? } else { # make sure number is positive if ($value2 <= 0) { config_err($file_line_num, "$line - \"$value\" must be at least 1 or higher"); next; } } my %hash; $hash{'interval'} = $value; $hash{'number'} = $value2; push(@intervals, \%hash); $line_syntax_ok = 1; next; } # BACKUP POINTS if ($var eq 'backup') { my $src = $value; # source directory my $dest = $value2; # dest directory my $opt_str = $value3; # option string from this backup point my $opts_ref = undef; # array_ref to hold parsed opts if ( !defined($config_vars{'snapshot_root'}) ) { config_err($file_line_num, "$line - snapshot_root needs to be defined before backup points"); next; } if (!defined($src)) { config_err($file_line_num, "$line - no source path specified for backup point"); next; } if (!defined($dest)) { config_err($file_line_num, "$line - no destination path specified for backup point"); next; } # make sure we have a local path for the destination # (we do NOT want an absolute path) if ( is_valid_local_abs_path($dest) ) { config_err($file_line_num, "$line - Backup destination $dest must be a local, relative path"); next; } # make sure we aren't traversing directories if ( is_directory_traversal($src) ) { config_err($file_line_num, "$line - Directory traversal attempted in $src"); next; } if ( is_directory_traversal($dest) ) { config_err($file_line_num, "$line - Directory traversal attempted in $dest"); next; } # validate source path # # local absolute? if ( is_real_local_abs_path($src) ) { $line_syntax_ok = 1; # syntactically valid remote ssh? } elsif ( is_ssh_path($src) ) { # if it's an absolute ssh path, make sure we have ssh if (!defined($config_vars{'cmd_ssh'})) { config_err($file_line_num, "$line - Cannot handle $src, cmd_ssh not defined in $config_file"); next; } $line_syntax_ok = 1; # if it's anonymous rsync, we're ok } elsif ( is_anon_rsync_path($src) ) { $line_syntax_ok = 1; # check for cwrsync } elsif ( is_cwrsync_path($src) ) { $line_syntax_ok = 1; # check for lvm } elsif ( is_linux_lvm_path($src) ) { # if it's an lvm path, make sure we have lvm commands and arguments if (!defined($config_vars{'linux_lvm_cmd_lvcreate'})) { config_err($file_line_num, "$line - Cannot handle $src, linux_lvm_cmd_lvcreate not defined in $config_file"); next; } if (!defined($config_vars{'linux_lvm_cmd_lvremove'})) { config_err($file_line_num, "$line - Cannot handle $src, linux_lvm_cmd_lvremove not defined in $config_file"); next; } if (!defined($config_vars{'linux_lvm_cmd_mount'})) { config_err($file_line_num, "$line - Cannot handle $src, linux_lvm_cmd_mount not defined in $config_file"); next; } if (!defined($config_vars{'linux_lvm_cmd_umount'})) { config_err($file_line_num, "$line - Cannot handle $src, linux_lvm_cmd_umount not defined in $config_file"); next; } if (!defined($config_vars{'linux_lvm_snapshotsize'})) { config_err($file_line_num, "$line - Cannot handle $src, linux_lvm_snapshotsize not defined in $config_file"); next; } if (!defined($config_vars{'linux_lvm_snapshotname'})) { config_err($file_line_num, "$line - Cannot handle $src, linux_lvm_snapshotname not defined in $config_file"); next; } if (!defined($config_vars{'linux_lvm_vgpath'})) { config_err($file_line_num, "$line - Cannot handle $src, linux_lvm_vgpath not defined in $config_file"); next; } if (!defined($config_vars{'linux_lvm_mountpath'})) { config_err($file_line_num, "$line - Cannot handle $src, linux_lvm_mountpath not defined in $config_file"); next; } $line_syntax_ok = 1; # fear the unknown } else { config_err($file_line_num, "$line - Source directory \"$src\" doesn't exist"); next; } # validate destination path # if ( is_valid_local_abs_path($dest) ) { config_err($file_line_num, "$line - Full paths not allowed for backup destinations"); next; } # if we have special options specified for this backup point, remember them if (defined($opt_str) && $opt_str) { $opts_ref = parse_backup_opts($opt_str); if (!defined($opts_ref)) { config_err( $file_line_num, "$line - Syntax error on line $file_line_num in extra opts: $opt_str" ); next; } } # remember src/dest # also, first check to see that we're not backing up the snapshot directory # # there are now two methods of making sure the user doesn't accidentally backup their snapshot_root # recursively in a backup point: the good way, and the old way. # # in the old way, when rsnapshot detects the snapshot_root is under a backup point, the files and # directories under that backup point are enumerated and get turned into several distinct rsync calls. # for example, if you tried to back up "/", it would do a separate rsync invocation for "/bin/", "/etc/", # and so on. this wouldn't be so bad except that it makes certain rsync options like one_fs and the # include/exclude rules act funny since rsync isn't starting where the user expects (and there is no # really good way to provide a workaround, either automatically or manually). however, changing this # behaviour that users have come to rely on would not be very nice, so the old code path is left here # for those that specifically enable the rsync_long_args parameter but don't set the --relative option. # # the new way is much nicer, but relies on the --relative option to rsync, which only became the default # in rsnapshot 1.2.0 (primarily for this feature). basically, rsnapshot dynamically constructs an exclude # path to avoid backing up the snapshot_root. clean and simple. many thanks to bharat mediratta for coming # up with this solution!!! # # we only need to do any of this if the user IS trying to backup the snapshot_root if ((is_real_local_abs_path("$src")) && ($config_vars{'snapshot_root'} =~ m/^$src/)) { # old, less good, backward compatibility method if ( defined($config_vars{'rsync_long_args'}) && ($config_vars{'rsync_long_args'} !~ m/--relative/) ) { # remove trailing slashes from source and dest, since we will be using our own $src = remove_trailing_slash($src); $dest = remove_trailing_slash($dest); opendir(SRC, "$src") or bail("Could not open $src"); while (my $node = readdir(SRC)) { next if ($node =~ m/^\.\.?$/o); # skip '.' and '..' # avoid double slashes from root filesystem if ($src eq '/') { $src = ''; } # if this directory is in the snapshot_root, skip it # otherwise, back it up # if ("$config_vars{'snapshot_root'}" !~ m/^$src\/$node/) { my %hash; $hash{'src'} = "$src/$node"; $hash{'dest'} = "$dest/$node"; if (defined($opts_ref)) { $hash{'opts'} = $opts_ref; } push(@backup_points, \%hash); } } closedir(SRC); # new, shiny, preferred method. the way of the future. } else { my %hash; my $exclude_path; $hash{'src'} = $src; $hash{'dest'} = $dest; if (defined($opts_ref)) { $hash{'opts'} = $opts_ref; } # dynamically generate an exclude path to avoid backing up the snapshot root. # depending on the backup point and the snapshot_root location, this could be # almost anything. it's tempting to think that just using the snapshot_root as # the exclude path will work, but it doesn't. instead, this an exclude path that # starts relative to the backup point. for example, if snapshot_root is set to # /backup/private/snapshots/, and the backup point is /backup/, the exclude path # will be private/snapshots/. the trailing slash does not appear to matter. # # it's also worth noting that this doesn't work at all without the --relative # flag being passed to rsync (which is now the default). # # this method was added by bharat mediratta, and replaces my older, less elegant # attempt to run multiple invocations of rsync instead. # $exclude_path = $config_vars{'snapshot_root'}; $exclude_path =~ s/^$src//; # pass it to rsync on this backup point only $hash{'opts'}{'extra_rsync_long_args'} .= sprintf(' --exclude=%s', $exclude_path); push(@backup_points, \%hash); } # the user is NOT trying to backup the snapshot_root. no workarounds required at all. } else { my %hash; $hash{'src'} = $src; $hash{'dest'} = $dest; if (defined($opts_ref)) { $hash{'opts'} = $opts_ref; } push(@backup_points, \%hash); } next; } # BACKUP SCRIPTS if ($var eq 'backup_script') { my $full_script = $value; # backup script to run (including args) my $dest = $value2; # dest directory my %hash; # tmp hash to stick in the backup points array my $script; # script file (no args) my @script_argv; # tmp array to help us separate the script from the args if ( !defined($config_vars{'snapshot_root'}) ) { config_err($file_line_num, "$line - snapshot_root needs to be defined before backup scripts"); next; } if (!defined($dest)) { config_err($file_line_num, "$line - no destination path specified"); next; } # get the base name of the script, not counting any arguments to it @script_argv = split(/\s+/, $full_script); $script = $script_argv[0]; # make sure the destination is a full path if (1 == is_valid_local_abs_path($dest)) { config_err($file_line_num, "$line - Backup destination $dest must be a local, relative path"); next; } # make sure we aren't traversing directories (exactly 2 dots can't be next to each other) if (1 == is_directory_traversal($dest)) { config_err($file_line_num, "$line - Directory traversal attempted in $dest"); next; } # make sure script exists and is executable if (((! -f "$script") or (! -x "$script")) or !is_real_local_abs_path($script)) { config_err($file_line_num, "$line - \"$script\" is not executable or can't be found.".($script !~ m{^/} ? " Please use an absolute path.":"")); next; } $hash{'script'} = $full_script; $hash{'dest'} = $dest; $line_syntax_ok = 1; push(@backup_points, \%hash); next; } # GLOBAL OPTIONS from the config file # ALL ARE OPTIONAL # # LINK_DEST if ($var eq 'link_dest') { if (!defined($value)) { config_err($file_line_num, "$line - link_dest can not be blank"); next; } if (!is_boolean($value)) { config_err( $file_line_num, "$line - \"$value\" is not a legal value for link_dest, must be 0 or 1 only" ); next; } $link_dest = $value; $line_syntax_ok = 1; next; } # ONE_FS if ($var eq 'one_fs') { if (!defined($value)) { config_err($file_line_num, "$line - one_fs can not be blank"); next; } if (!is_boolean($value)) { config_err( $file_line_num, "$line - \"$value\" is not a legal value for one_fs, must be 0 or 1 only" ); next; } $one_fs = $value; $line_syntax_ok = 1; next; } # LOCKFILE if ($var eq 'lockfile') { if (!defined($value)) { config_err($file_line_num, "$line - lockfile can not be blank"); } if (0 == is_valid_local_abs_path("$value")) { config_err($file_line_num, "$line - lockfile must be a full path"); next; } $config_vars{'lockfile'} = $value; $line_syntax_ok = 1; next; } #STOP_ON_STALE_LOCKFILE if ($var eq 'stop_on_stale_lockfile') { if (!defined($value)) { config_err($file_line_num, "$line - stop_on_stale_lockfile can not be blank"); next; } if (!is_boolean($value)) { config_err( $file_line_num, "$line - \"$value\" is not a legal value for stop_on_stale_lockfile, must be 0 or 1 only" ); next; } $stop_on_stale_lockfile = $value; $line_syntax_ok = 1; next; } # INCLUDE if ($var eq 'include') { if (!defined($rsync_include_args)) { $rsync_include_args = "--include=$value"; } else { $rsync_include_args .= " --include=$value"; } $line_syntax_ok = 1; next; } # EXCLUDE if ($var eq 'exclude') { if (!defined($rsync_include_args)) { $rsync_include_args = "--exclude=$value"; } else { $rsync_include_args .= " --exclude=$value"; } $line_syntax_ok = 1; next; } # INCLUDE FILE if ($var eq 'include_file') { if (0 == is_real_local_abs_path($value)) { config_err($file_line_num, "$line - include_file $value must be a valid absolute path"); next; } elsif (1 == is_directory_traversal($value)) { config_err($file_line_num, "$line - Directory traversal attempted in $value"); next; } elsif (( -e "$value" ) && ( ! -f "$value" )) { config_err($file_line_num, "$line - include_file $value exists, but is not a file"); next; } elsif ( ! -r "$value" ) { config_err($file_line_num, "$line - include_file $value exists, but is not readable"); next; } else { if (!defined($rsync_include_file_args)) { $rsync_include_file_args = "--include-from=$value"; } else { $rsync_include_file_args .= " --include-from=$value"; } $line_syntax_ok = 1; next; } } # EXCLUDE FILE if ($var eq 'exclude_file') { if (0 == is_real_local_abs_path($value)) { config_err($file_line_num, "$line - exclude_file $value must be a valid absolute path"); next; } elsif (1 == is_directory_traversal($value)) { config_err($file_line_num, "$line - Directory traversal attempted in $value"); next; } elsif (( -e "$value" ) && ( ! -f "$value" )) { config_err($file_line_num, "$line - exclude_file $value exists, but is not a file"); next; } elsif ( ! -r "$value" ) { config_err($file_line_num, "$line - exclude_file $value exists, but is not readable"); next; } else { if (!defined($rsync_include_file_args)) { $rsync_include_file_args = "--exclude-from=$value"; } else { $rsync_include_file_args .= " --exclude-from=$value"; } $line_syntax_ok = 1; next; } } # RSYNC SHORT ARGS if ($var eq 'rsync_short_args') { # must be in the format '-abcde' if (0 == is_valid_rsync_short_args($value)) { config_err($file_line_num, "$line - rsync_short_args \"$value\" not in correct format"); next; } else { $config_vars{'rsync_short_args'} = $value; $line_syntax_ok = 1; next; } } # RSYNC LONG ARGS if ($var eq 'rsync_long_args') { $config_vars{'rsync_long_args'} = $value; $line_syntax_ok = 1; next; } # SSH ARGS if ($var eq 'ssh_args') { if (!defined($default_ssh_args) && defined($config_vars{'ssh_args'})) { config_err($file_line_num, "$line - global ssh_args can only be set once, but is already set. Perhaps you wanted to use a per-backup-point ssh_args instead."); next; } else { $config_vars{'ssh_args'} = $value; $line_syntax_ok = 1; next; } } # DU ARGS if ($var eq 'du_args') { $config_vars{'du_args'} = $value; $line_syntax_ok = 1; next; } # LVM CMDS if ($var =~ m/^linux_lvm_cmd_(lvcreate|mount)$/) { $config_vars{$var} = $value; $line_syntax_ok = 1; next; } # LVM ARGS if ($var =~ m/^linux_lvm_(vgpath|snapshotname|snapshotsize|mountpath)$/) { $config_vars{$var} = $value; $line_syntax_ok = 1; next; } # LOGFILE if ($var eq 'logfile') { if (0 == is_valid_local_abs_path($value)) { config_err($file_line_num, "$line - logfile must be a valid absolute path"); next; } elsif (1 == is_directory_traversal($value)) { config_err($file_line_num, "$line - Directory traversal attempted in $value"); next; } elsif (( -e "$value" ) && ( ! -f "$value" ) && ( ! -p "$value" ) ) { config_err($file_line_num, "$line - logfile $value exists, but is not a file"); next; } else { $config_vars{'logfile'} = $value; $line_syntax_ok = 1; next; } } # VERBOSE if ($var eq 'verbose') { if (1 == is_valid_loglevel($value)) { if (!defined($verbose)) { $verbose = $value; } $line_syntax_ok = 1; next; } else { config_err($file_line_num, "$line - verbose must be a value between 1 and 5"); next; } } # LOGLEVEL if ($var eq 'loglevel') { if (1 == is_valid_loglevel($value)) { if (!defined($loglevel)) { $loglevel = $value; } $line_syntax_ok = 1; next; } else { config_err($file_line_num, "$line - loglevel must be a value between 1 and 5"); next; } } # USE LAZY DELETES if ($var eq 'use_lazy_deletes') { if (!defined($value)) { config_err($file_line_num, "$line - use_lazy_deletes can not be blank"); next; } if (!is_boolean($value)) { config_err( $file_line_num, "$line - \"$value\" is not a legal value for use_lazy_deletes, must be 0 or 1 only" ); next; } if (1 == $value) { $use_lazy_deletes = 1; } $line_syntax_ok = 1; next; } # RSYNC NUMBER OF TRIES if ($var eq 'rsync_numtries') { if (!defined($value)) { config_err($file_line_num, "$line - rsync_numtries can not be blank"); next; } if (!is_valid_rsync_numtries($value)) { config_err( $file_line_num, "$line - \"$value\" is not a legal value for rsync_numtries, must be greater than or equal to 0" ); next; } $rsync_numtries = int($value); $line_syntax_ok = 1; next; } # make sure we understood this line # if not, warn the user, and prevent the program from executing # however, don't bother if the user has already been notified if (1 == $config_perfect) { if (0 == $line_syntax_ok) { config_err($file_line_num, $line); next; } } } } sub validate_config_file { #################################################################### # SET SOME SENSIBLE DEFAULTS FOR VALUES THAT MAY NOT HAVE BEEN SET # #################################################################### # if we didn't manage to get a verbose level yet, either through the config file # or the command line, use the default if (!defined($verbose)) { $verbose = $default_verbose; } # same for loglevel if (!defined($loglevel)) { $loglevel = $default_loglevel; } # assemble rsync include/exclude args if (defined($rsync_include_args)) { if (!defined($config_vars{'rsync_long_args'})) { $config_vars{'rsync_long_args'} = $default_rsync_long_args; } $config_vars{'rsync_long_args'} .= " $rsync_include_args"; } # assemble rsync include/exclude file args if (defined($rsync_include_file_args)) { if (!defined($config_vars{'rsync_long_args'})) { $config_vars{'rsync_long_args'} = $default_rsync_long_args; } $config_vars{'rsync_long_args'} .= " $rsync_include_file_args"; } ############################################### # NOW THAT THE CONFIG FILE HAS BEEN READ IN, # # DO A SANITY CHECK ON THE DATA WE PULLED OUT # ############################################### # SINS OF COMMISSION # (incorrect entries in config file) if (0 == $config_perfect) { print_err("---------------------------------------------------------------------", 1); print_err("Errors were found in $config_file,", 1); print_err("rsnapshot can not continue. If you think an entry looks right, make", 1); print_err("sure you don't have spaces where only tabs should be.", 1); # if this wasn't a test, report the error to syslog if (0 == $do_configtest) { syslog_err("Errors were found in $config_file, rsnapshot can not continue."); } # exit showing an error exit(1); } # SINS OF OMISSION # (things that should be in the config file that aren't) # # make sure config_version was set if (!defined($config_vars{'config_version'})) { print_err ("config_version was not defined. rsnapshot can not continue.", 1); syslog_err("config_version was not defined. rsnapshot can not continue."); exit(1); } # make sure rsync was defined if (!defined($config_vars{'cmd_rsync'})) { print_err ("cmd_rsync was not defined.", 1); syslog_err("cmd_rsync was not defined.", 1); exit(1); } # make sure we got a snapshot_root if (!defined($config_vars{'snapshot_root'})) { print_err ("snapshot_root was not defined. rsnapshot can not continue.", 1); syslog_err("snapshot_root was not defined. rsnapshot can not continue."); exit(1); } # make sure we have at least one interval if (0 == scalar(@intervals)) { print_err ("At least one backup level must be set. rsnapshot can not continue.", 1); syslog_err("At least one backup level must be set. rsnapshot can not continue."); exit(1); } # make sure we have at least one backup point if (0 == scalar(@backup_points)) { print_err ("At least one backup point must be set. rsnapshot can not continue.", 1); syslog_err("At least one backup point must be set. rsnapshot can not continue."); exit(1); } # SINS OF CONFUSION # (various, specific, undesirable interactions) # # make sure that we don't have only one copy of the first interval, # yet expect rotations on the second interval if (scalar(@intervals) > 1) { if (defined($intervals[0]->{'number'})) { if (1 == $intervals[0]->{'number'}) { print_err ("Can not have first backup level's retention count set to 1, and have a second backup level", 1); syslog_err("Can not have first backup level's retention count set to 1, and have a second backup level"); exit(1); } } } # make sure that the snapshot_root exists if no_create_root is set to 1 if (defined($config_vars{'no_create_root'})) { if (1 == $config_vars{'no_create_root'}) { if ( ! -d "$config_vars{'snapshot_root'}" ) { if ( -e "$config_vars{'snapshot_root'}" ) { print_err ("$config_vars{'snapshot_root'} is not a directory.", 1); } else { print_err ("$config_vars{'snapshot_root'} does not exist.", 1); } print_err ("rsnapshot refuses to create snapshot_root when no_create_root is enabled", 1); syslog_err("rsnapshot refuses to create snapshot_root when no_create_root is enabled"); exit(1); } } } # make sure that the user didn't call "sync" if sync_first isn't enabled if (($cmd eq 'sync') && (! $config_vars{'sync_first'})) { print_err ("\"sync_first\" must be enabled for \"sync\" to work", 1); syslog_err("\"sync_first\" must be enabled for \"sync\" to work"); exit(1); } # make sure that the backup_script destination paths don't nuke data copied over for backup points { my @backup_dest = (); my @backup_script_dest = (); # remember where the destination paths are... foreach my $bp_ref (@backup_points) { my $tmp_dest_path = $$bp_ref{'dest'}; # normalize multiple slashes, and strip trailing slash $tmp_dest_path =~ s/\/+/\//g; $tmp_dest_path =~ s/\/$//; # backup if (defined($$bp_ref{'src'})) { push(@backup_dest, $tmp_dest_path); # backup_script } elsif (defined($$bp_ref{'script'})) { push(@backup_script_dest, $tmp_dest_path); # something else is wrong } else { print_err ("logic error in parse_config_file(): a backup point has no src and no script", 1); syslog_err("logic error in parse_config_file(): a backup point has no src and no script"); exit(1); } } # loop through and check for conflicts between backup and backup_script destination paths foreach my $b_dest (@backup_dest) { foreach my $bs_dest (@backup_script_dest) { if (defined($b_dest) && defined($bs_dest)) { my $tmp_b = $b_dest; my $tmp_bs = $bs_dest; # add trailing slashes back in so similarly named directories don't match # e.g., localhost/abc/ and localhost/ab/ $tmp_b .= '/'; $tmp_bs .= '/'; if ("$b_dest" =~ m/^$bs_dest/) { # duplicate entries, stop here print_err ( "destination conflict between \"$tmp_b\" and \"$tmp_bs\" in backup / backup_script entries", 1 ); syslog_err( "destination conflict between \"$tmp_b\" and \"$tmp_bs\" in backup / backup_script entries" ); exit(1); } } else { print_err ("logic error in parse_config_file(): unique destination check failed unexpectedly", 1); syslog_err("logic error in parse_config_file(): unique destination check failed unexpectedly"); exit(1); } } } # loop through and check for conflicts between different backup_scripts for (my $i=0; $i= 3)) { print wrap_cmd($str), "\n"; } } # accepts a string # wraps the text to fit in 80 columns with backslashes at the end of each wrapping line # returns the wrapped string sub wrap_cmd { my $str = shift(@_); my $colmax = shift(@_); my $indent = shift(@_); my @tokens; my $chars = 0; # character tally my $outstr = ''; # string to return # max chars before wrap (default to 80 column terminal) if (!defined($colmax)) { $colmax = 76; } # number of spaces to indent subsequent lines if (!defined($indent)) { $indent = 4; } # break up string into individual pieces @tokens = split(/\s+/, $str); # stop here if we don't have anything if (0 == scalar(@tokens)) { return (''); } # print the first token as a special exception, since we should never start out by line wrapping if (defined($tokens[0])) { $chars = (length($tokens[0]) + 1); $outstr .= $tokens[0]; # don't forget to put the space back in if (scalar(@tokens) > 1) { $outstr .= ' '; } } # loop through the rest of the tokens and print them out, wrapping when necessary for (my $i=1; $i $colmax) { $outstr .= "\\\n"; $outstr .= (' ' x $indent); # 4 spaces + string length $chars = $indent + length($tokens[$i]); } # print out this token $outstr .= $tokens[$i]; # print out a space unless this is the last one if ($i < scalar(@tokens)) { $outstr .= ' '; } } return ($outstr); } # accepts string, and level # prints string if level is as high as verbose # logs string if level is as high as loglevel sub print_msg { my $str = shift(@_); my $level = shift(@_); if (!defined($str)) { return (undef); } if (!defined($level)) { $level = 0; } chomp($str); # print to STDOUT if ((!defined($verbose)) or ($verbose >= $level)) { print $str, "\n"; } # write to log log_msg($str, $level); } # accepts string, and level # prints string if level is as high as verbose # logs string if level is as high as loglevel # also raises a warning for the exit code sub print_warn { my $str = shift(@_); my $level = shift(@_); if (!defined($str)) { return (undef); } if (!defined($level)) { $level = 0; } # we can no longer say the execution of the program has been error free raise_warning(); chomp($str); # print to STDERR if ((!defined($verbose)) or ($level <= $verbose)) { print STDERR 'WARNING: ', $str, "\n"; } # write to log log_msg($str, $level); } # accepts string, and level # prints string if level is as high as verbose # logs string if level is as high as loglevel # also raises an error for the exit code sub print_err { my $str = shift(@_); my $level = shift(@_); if (!defined($str)) { return (undef); } if (!defined($level)) { $level = 0; } # we can no longer say the execution of the program has been error free raise_error(); chomp($str); # print the run string once # this way we know where the message came from if it's in an e-mail # but we can still read messages at the console if (0 == $have_printed_run_string) { if ((!defined($verbose)) or ($level <= $verbose)) { print STDERR "----------------------------------------------------------------------------\n"; print STDERR "rsnapshot encountered an error! The program was invoked with these options:\n"; print STDERR wrap_cmd($run_string), "\n"; print STDERR "----------------------------------------------------------------------------\n"; } $have_printed_run_string = 1; } # print to STDERR if ((!defined($verbose)) or ($level <= $verbose)) { #print STDERR $run_string, ": ERROR: ", $str, "\n"; print STDERR "ERROR: ", $str, "\n"; } # write to log log_err($str, $level); } # accepts string, and level # logs string if level is as high as loglevel sub log_msg { my $str = shift(@_); my $level = shift(@_); my $result = undef; if (!defined($str)) { return (undef); } if (!defined($level)) { return (undef); } chomp($str); # if this is just noise, don't log it if (defined($loglevel) && ($level > $loglevel)) { return (undef); } # open logfile, write to it, close it back up # if we fail, don't use the usual print_* functions, since they just call this again if ((0 == $test) && (0 == $do_configtest)) { if (defined($config_vars{'logfile'})) { $result = open (LOG, ">> $config_vars{'logfile'}"); if (!defined($result)) { print STDERR "Could not open logfile $config_vars{'logfile'} for writing\n"; print STDERR "Do you have write permission for this file?\n"; exit(1); } print LOG '[', get_current_date(), '] ', $str, "\n"; $result = close(LOG); if (!defined($result)) { print STDERR "Could not close logfile $config_vars{'logfile'}\n"; } } } } # accepts string, and level # logs string if level is as high as loglevel # also raises a warning for the exit code sub log_warn { my $str = shift(@_); my $level = shift(@_); if (!defined($str)) { return (undef); } if (!defined($level)) { return (undef); } # this run is no longer perfect since we have an error raise_warning(); chomp($str); $str = 'WARNING: ' . $str; log_msg($str, $level); } # accepts string, and level # logs string if level is as high as loglevel # also raises an error for the exit code sub log_err { my $str = shift(@_); my $level = shift(@_); if (!defined($str)) { return (undef); } if (!defined($level)) { return (undef); } # this run is no longer perfect since we have an error raise_error(); chomp($str); $str = "$run_string: ERROR: " . $str; log_msg($str, $level); } # log messages to syslog # accepts message, facility, level # only message is required # return 1 on success, undef on failure sub syslog_msg { my $msg = shift(@_); my $facility = shift(@_); my $level = shift(@_); my $result = undef; if (!defined($msg)) { return (undef); } if (!defined($facility)) { $facility = 'user'; } if (!defined($level)) { $level = 'info'; } if (defined($config_vars{'cmd_logger'})) { # print out our call to syslog if (defined($verbose) && ($verbose >= 4)) { print_cmd("$config_vars{'cmd_logger'} -i -p $facility.$level -t rsnapshot $msg"); } # log to syslog if (0 == $test) { $result = system($config_vars{'cmd_logger'}, '-i', '-p', "$facility.$level", '-t', 'rsnapshot', $msg); if (0 != $result) { print_warn("Could not log to syslog:", 2); print_warn("$config_vars{'cmd_logger'} -i -p $facility.$level -t rsnapshot $msg", 2); } } } return (1); } # log warnings to syslog # accepts warning message # returns 1 on success, undef on failure # also raises a warning for the exit code sub syslog_warn { my $msg = shift(@_); # this run is no longer perfect since we have an error raise_warning(); return syslog_msg("WARNING: $msg", 'user', 'err'); } # log errors to syslog # accepts error message # returns 1 on success, undef on failure # also raises an error for the exit code sub syslog_err { my $msg = shift(@_); # this run is no longer perfect since we have an error raise_error(); return syslog_msg("$run_string: ERROR: $msg", 'user', 'err'); } # sets exit code for at least a warning sub raise_warning { if ($exit_code != 1) { $exit_code = 2; } } # sets exit code for error sub raise_error { $exit_code = 1; } # accepts no arguments # returns the current date (for the logfile) # # there's probably a wonderful module that can do this all for me, # but unless it comes standard with perl 5.004 and later, i'd rather do it this way :) # sub get_current_date { # localtime() gives us an array with these elements: # 0 = seconds # 1 = minutes # 2 = hours # 3 = day of month # 4 = month + 1 # 5 = year + 1900 # example date format (just like Apache logs) # 28/Feb/2004:23:45:59 my @months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'); my @fields = localtime(time()); my $datestr = # day of month sprintf("%02i", $fields[3]) . '/' . # name of month $months[$fields[4]] . '/' . # year ($fields[5]+1900) . ':' . # hours (24 hour clock) sprintf("%02i", $fields[2]) . ':' . # minutes sprintf("%02i", $fields[1]) . ':' . # seconds sprintf("%02i", $fields[0]); return ($datestr); } # accepts no arguments # returns nothing # simply prints out a startup message to the logs and STDOUT sub log_startup { log_msg("$run_string: started", 2); } # accepts no arguments # returns undef if lockfile isn't defined in the config file, and 1 upon success # also, it can make the program exit with 1 as the return value if it can't create the lockfile # # we don't use bail() to exit on error, because that would remove the # lockfile that may exist from another invocation # # if a lockfile exists, we try to read it (and stop if we can't) to get a PID, # then see if that PID exists. If it does, we stop, otherwise we assume it's # a stale lock and remove it first. sub add_lockfile { # if we don't have a lockfile defined, just return undef if (!defined($config_vars{'lockfile'})) { return (undef); } my $lockfile = $config_vars{'lockfile'}; # valid? if (0 == is_valid_local_abs_path($lockfile)) { print_err ("Lockfile $lockfile is not a valid file name", 1); syslog_err("Lockfile $lockfile is not a valid file name"); exit(1); } # does a lockfile already exist? if (1 == is_real_local_abs_path($lockfile)) { if(!open(LOCKFILE, $lockfile)) { print_err ("Lockfile $lockfile exists and can't be read, can not continue!", 1); syslog_err("Lockfile $lockfile exists and can't be read, can not continue"); exit(1); } my $pid = ; chomp($pid); close(LOCKFILE); if(kill(0, $pid)) { print_err ("Lockfile $lockfile exists and so does its process, can not continue"); syslog_err("Lockfile $lockfile exists and so does its process, can not continue"); exit(1); } else { if(1 == $stop_on_stale_lockfile) { print_err ("Stale lockfile $lockfile detected. You need to remove it manually to continue", 1); syslog_err("Stale lockfile $lockfile detected. Exiting."); exit(1); } else { print_warn("Removing stale lockfile $lockfile", 1); syslog_warn("Removing stale lockfile $lockfile"); remove_lockfile(); } } } # create the lockfile print_cmd("echo $$ > $lockfile"); if (0 == $test) { # sysopen() can do exclusive opens, whereas perl open() can not my $result = sysopen(LOCKFILE, $lockfile, O_WRONLY | O_EXCL | O_CREAT, 0644); if (!defined($result) || 0 == $result) { print_err ("Could not write lockfile $lockfile: $!", 1); syslog_err("Could not write lockfile $lockfile"); exit(1); } # print PID to lockfile print LOCKFILE $$; $result = close(LOCKFILE); if (!defined($result) || 0 == $result) { print_warn("Could not close lockfile $lockfile: $!", 2); } } return (1); } # accepts no arguments # accepts the path to a lockfile and tries to remove it # returns undef if lockfile isn't defined in the config file, and 1 upon success # also, it can exit the program with a value of 1 if it can't remove the lockfile # # we don't use bail() to exit on error, because that would call # this subroutine twice in the event of a failure sub remove_lockfile { # if we don't have a lockfile defined, return undef if (!defined($config_vars{'lockfile'})) { return (undef); } my $lockfile = $config_vars{'lockfile'}; my $result = undef; if ( -e "$lockfile" ) { print_cmd("rm -f $lockfile"); if (0 == $test) { $result = unlink($lockfile); if (0 == $result) { print_err ("Could not remove lockfile $lockfile", 1); syslog_err("Error! Could not remove lockfile $lockfile"); exit(1); } } } else { print_msg("No need to remove non-existent lock $lockfile", 5); } return (1); } # accepts no arguments # returns nothing # sets the locale to POSIX (C) to mitigate some problems with the rmtree() command # sub set_posix_locale { # set POSIX locale # this may fix some potential problems with rmtree() # another solution is to enable "cmd_rm" in rsnapshot.conf print_msg("Setting locale to POSIX \"C\"", 4); setlocale(POSIX::LC_ALL, 'C'); } # accepts no arguments # returns nothing # creates the snapshot_root directory (chmod 0700), if it doesn't exist and no_create_root == 0 sub create_snapshot_root { # attempt to create the directory if it doesn't exist if ( ! -d "$config_vars{'snapshot_root'}" ) { # make sure no_create_root == 0 if (defined($config_vars{'no_create_root'})) { if (1 == $config_vars{'no_create_root'}) { print_err ("rsnapshot refuses to create snapshot_root when no_create_root is enabled", 1); syslog_err("rsnapshot refuses to create snapshot_root when no_create_root is enabled"); bail(); } } # actually create the directory print_cmd("mkdir -m 0700 -p $config_vars{'snapshot_root'}/"); if (0 == $test) { eval { # don't pass a trailing slash to mkpath mkpath( "$config_vars{'snapshot_root'}", 0, 0700 ); }; if ($@) { bail( "Unable to create $config_vars{'snapshot_root'}/,\nPlease make sure you have the right permissions." ); } } } } # accepts current interval # returns a hash_ref containing information about the intervals # exits the program if we don't have good data to work with sub get_interval_data { my $cur_interval = shift(@_); # make sure we were passed an interval if (!defined($cur_interval)) { bail("cur_interval not specified in get_interval_data()\n"); } # the hash to return my %hash; # which of the intervals are we operating on? # if we defined hourly, daily, weekly ... hourly = 0, daily = 1, weekly = 2 my $interval_num; # the highest possible number for the current interval context # if we are working on hourly, and hourly is set to 6, this would be # equal to 5 (since we start at 0) my $interval_max; # this is the name of the previous interval, in relation to the one we're # working on. e.g., if we're operating on weekly, this should be "daily" my $prev_interval; # same as $interval_max, except for the previous interval. # this is used to determine which of the previous snapshots to pull from # e.g., cp -al hourly.$prev_interval_max/ daily.0/ my $prev_interval_max; # FIGURE OUT WHICH INTERVAL WE'RE RUNNING, AND HOW IT RELATES TO THE OTHERS # THEN RUN THE ACTION FOR THE CHOSEN INTERVAL # remember, in each hashref in this loop: # "interval" is something like "daily", "weekly", etc. # "number" is the number of these intervals to keep on the filesystem my $i = 0; foreach my $i_ref (@intervals) { # this is the interval we're set to run if ($$i_ref{'interval'} eq $cur_interval) { $interval_num = $i; # how many of these intervals should we keep? # we start counting from 0, so subtract one # e.g., 6 intervals == interval.0 .. interval.5 $interval_max = $$i_ref{'number'} - 1; # we found our interval, exit the foreach loop last; } # since the "last" command above breaks from this entire block, # and since we loop through the intervals in order, if we got this # far in the first place it means that we're looking at an interval # which isn't selected to run, and that there will be more intervals in the loop. # therefore, this WILL be the previous interval's information, the next time through. # $prev_interval = $$i_ref{'interval'}; # which of the previous interval's numbered directories should we pull from # for the interval we're currently set to run? # e.g., daily.0/ might get pulled from hourly.6/ # $prev_interval_max = $$i_ref{'number'} - 1; $i++; } # make sure we got something that makes sense if ($cur_interval ne 'sync') { if (!defined($interval_num)) { bail("Interval \"$cur_interval\" unknown, check $config_file"); } } # populate our hash $hash{'interval'} = $cur_interval; $hash{'interval_num'} = $interval_num; $hash{'interval_max'} = $interval_max; $hash{'prev_interval'} = $prev_interval; $hash{'prev_interval_max'} = $prev_interval_max; # and return the values return (\%hash); } # accepts no arguments # prints the most recent snapshot directory and exits # this is for use with the get-latest-snapshot command line argument sub show_latest_snapshot { # this should only be called after parse_config_file(), but just in case... if (! @intervals) { bail("Error! intervals not defined in show_latest_snapshot()"); } if (! %config_vars) { bail("Error! config_vars not defined in show_latest_snapshot()"); } # regardless of .sync, this is the latest "real" snapshot print $config_vars{'snapshot_root'} . '/' . $intervals[0]->{'interval'} . '.0/' . "\n"; exit(0); } # accepts no args # prints out status to the logs, then exits the program with the current exit code sub exit_with_status { if (0 == $exit_code) { syslog_msg("$run_string: completed successfully"); log_msg ("$run_string: completed successfully", 2); exit ($exit_code); } elsif (1 == $exit_code) { syslog_err("$run_string: completed, but with some errors"); log_err ("$run_string: completed, but with some errors", 2); exit ($exit_code); } elsif (2 == $exit_code) { syslog_warn("$run_string: completed, but with some warnings"); log_warn ("$run_string: completed, but with some warnings", 2); exit ($exit_code); # this should never happen } else { syslog_err("$run_string: completed, but with no definite status"); log_err ("$run_string: completed, but with no definite status", 2); exit (1); } } # accepts no arguments # returns nothing # # exits the program with the status of the config file (e.g., Syntax OK). # the exit code is 0 for success, 1 for failure (although failure should never happen) sub exit_configtest { # if we're just doing a configtest, exit here with the results if (1 == $do_configtest) { if (1 == $config_perfect) { print "Syntax OK\n"; exit(0); # this should never happen, because any errors should have killed the program before now } else { print "Syntax Error\n"; exit(1); } } } # accepts no arguments # prints out error messages since we can't find the config file # exits with a return code of 1 sub exit_no_config_file { # warn that the config file could not be found print STDERR "Config file \"$config_file\" does not exist or is not readable.\n"; if (0 == $do_configtest) { syslog_err("Config file \"$config_file\" does not exist or is not readable."); } # if we have the default config from the install, remind the user to create the real config if ((-e "$config_file.default") && (! -e "$config_file")) { print STDERR "Did you copy $config_file.default to $config_file yet?\n"; } # exit showing an error exit(1); } # accepts a loglevel # returns 1 if it's valid, 0 otherwise sub is_valid_loglevel { my $value = shift(@_); if (!defined($value)) { return (0); } if ($value =~ m/^\d$/) { if (($value >= 1) && ($value <= 5)) { return (1); } } return (0); } # accepts a positive number formatted as string # returns 1 if it's valid, 0 otherwise sub is_valid_rsync_numtries { my $value = shift(@_); if (!defined($value)) { return (0); } if ($value =~ m/^\d+$/) { if (($value >= 0)) { return (1); } } } # accepts one argument # checks to see if that argument is set to 1 or 0 # returns 1 on success, 0 on failure sub is_boolean { my $var = shift(@_); if (!defined($var)) { return (0); } if ($var !~ m/^\d+$/) { return (0); } if (1 == $var) { return (1); } if (0 == $var) { return (1); } return (0); } # accepts string # returns 1 if it is a comment line (beginning with #) # returns 0 otherwise sub is_comment { my $str = shift(@_); if (!defined($str)) { return (undef); } if ($str =~ m/^#/) { return (1); } return (0); } # accepts string # returns 1 if it is blank, or just pure white space # returns 0 otherwise sub is_blank { my $str = shift(@_); if (!defined($str)) { return (undef); } if ($str !~ m/\S/) { return (1); } return (0); } # accepts path # returns 1 if it's a valid ssh absolute path # returns 0 otherwise sub is_ssh_path { my $path = shift(@_); if (!defined($path)) { return (undef); } # make sure we don't have leading/trailing spaces if ($path =~ m/^\s/) { return (undef); } if ($path =~ m/\s$/) { return (undef); } # must have user@host:[~]/path syntax for ssh if ($path =~ m/^.*?\@.*?:~?\/.*$/) { return (1); } return (0); } # accepts path # returns 1 if it's a valid cwrsync server path (user@host::sharename) # return 0 otherwise sub is_cwrsync_path { my $path = shift(@_); if (!defined($path)) { return (undef); } if ($path =~ m/^[^\/]+::/) { return (1); } return (0); } # accepts path # returns 1 if it's a syntactically valid anonymous rsync path # returns 0 otherwise sub is_anon_rsync_path { my $path = shift(@_); if (!defined($path)) { return (undef); } if ($path =~ m/^rsync:\/\/.*$/) { return (1); } return (0); } # accepts path # returns 1 if it's a syntactically valid LVM path # returns 0 otherwise sub is_linux_lvm_path { my $path = shift(@_); if (!defined($path)) { return (undef); } if ($path =~ m|^lvm://.*$|) { return (1); } return (0); } # accepts proposed list for rsync_short_args # makes sure that rsync_short_args is in the format '-abcde' # (not '-a -b' or '-ab c', etc) # returns 1 if it's OK, or 0 otherwise sub is_valid_rsync_short_args { my $rsync_short_args = shift(@_); if (!defined($rsync_short_args)) { return (0); } # no blank space allowed if ($rsync_short_args =~ m/\s/) { return (0); } # first character must be a dash, followed by alphanumeric characters if ($rsync_short_args !~ m/^\-{1,1}\w+$/) { return (0); } return (1); } # accepts path # returns 1 if it's a real absolute path that currently exists # returns 0 otherwise sub is_real_local_abs_path { my $path = shift(@_); if (!defined($path)) { return (undef); } if (1 == is_valid_local_abs_path($path)) { # check for symlinks first, since they might not link to a real file if ((-l "$path") or (-e "$path")) { return (1); } } return (0); } # accepts path # returns 1 if it's a syntactically valid absolute path # returns 0 otherwise sub is_valid_local_abs_path { my $path = shift(@_); if (!defined($path)) { return (undef); } if ($path =~ m/^\//) { if (0 == is_directory_traversal($path)) { return (1); } } return (0); } # accepts path # returns 1 if it's a directory traversal attempt # returns 0 if it's safe sub is_directory_traversal { my $path = shift(@_); if (!defined($path)) { return (undef); } # /.. if ($path =~ m/\/\.\./) { return (1); } # ../ if ($path =~ m/\.\.\//) { return (1); } return (0); } # accepts path # returns 1 if it's a file (doesn't have a trailing slash) # returns 0 otherwise sub is_file { my $path = shift(@_); if (!defined($path)) { return (undef); } if ($path !~ m/\/$/o) { return (1); } return (0); } # accepts path # returns 1 if it's a directory (has a trailing slash) # returns 0 otherwise sub is_directory { my $path = shift(@_); if (!defined($path)) { return (undef); } if ($path =~ m/\/$/o) { return (1); } return (0); } # accepts a string with a script file and optional arguments # returns 1 if it the script file exists, is executable and has absolute path. # returns 0 otherwise sub is_valid_script { my $full_script = shift(@_); # script to run (including args) my $script_ref = shift(@_); # reference to script file name my $script; # script file (no args) my @script_argv; # all script arguments # get the base name of the script, not counting any arguments to it @script_argv = split(/\s+/, $full_script); $script = $script_argv[0]; $$script_ref = $script; # Output $script in case caller wants it # make sure script exists and is executable if ( -f "$script" && -x "$script" && is_real_local_abs_path($script)) { return 1; } return 0; } # accepts string # removes trailing slash, returns the string sub remove_trailing_slash { my $str = shift(@_); # it's not a trailing slash if it's the root filesystem if ($str eq '/') { return ($str); } # it's not a trailing slash if it's a remote root filesystem if ($str =~ m%:/$% ) { return ($str); } $str =~ s/\/+$//; return ($str); } # accepts string # returns /. if passed /, returns input otherwise # this is to work around a bug in some versions of rsync sub add_slashdot_if_root { my $str = shift(@_); if ($str eq '/') { return '/.'; } return ($str); } # accepts the interval (cmd) to run against # returns nothing # calls the appropriate subroutine, depending on whether this is the lowest interval or a higher one # also calls preexec/postexec scripts if we're working on the lowest interval # sub handle_interval { my $cmd = shift(@_); if (!defined($cmd)) { bail('cmd not defined in handle_interval()'); } my $id_ref = get_interval_data( $cmd ); my $result = 0; # here we used to check for interval.delete directories. This was # removed when we switched to using _delete.$$ directories. This # was done so that you can run another (eg) rsnapshot hourly, while # the .delete directory from the previous hourly backup was still # going. Potentially you may have several parallel deletes going on # with the new scheme, but I'm pretty sure that you'll catch up # eventually and not hopelessly wedge the machine -- DRC # handle toggling between sync_first being enabled and disabled # link_dest is enabled if (1 == $link_dest) { # sync_first is enabled if ($config_vars{'sync_first'}) { # create the sync root if it doesn't exist (and we need it right now) if ($cmd eq 'sync') { # don't create the .sync directory, it gets created later on } # sync_first is disabled } else { # if the sync directory is still here after sync_first is disabled, delete it if ( -d "$config_vars{'snapshot_root'}/.sync" ) { display_rm_rf("$config_vars{'snapshot_root'}/.sync/"); if (0 == $test) { $result = rm_rf( "$config_vars{'snapshot_root'}/.sync/" ); if (0 == $result) { bail("Error! rm_rf(\"$config_vars{'snapshot_root'}/.sync/\")"); } } } } # link_dest is disabled } else { # sync_first is enabled if ($config_vars{'sync_first'}) { # create the sync root if it doesn't exist if ( ! -d "$config_vars{'snapshot_root'}/.sync" ) { # If .sync does not exist but lowest.0 does, then copy that. # call generic cp_al() subroutine my $interval_0 = "$config_vars{'snapshot_root'}/" . $intervals[0]->{'interval'} . ".0"; my $sync_dir = "$config_vars{'snapshot_root'}/.sync"; if ( -d $interval_0 ) { display_cp_al( "$interval_0", "$sync_dir" ); if (0 == $test) { $result = cp_al( "$interval_0", "$sync_dir" ); if (! $result) { bail("Error! cp_al(\"$interval_0\", \"$sync_dir\")"); } } } } # sync_first is disabled } else { # if the sync directory still exists, delete it if ( -d "$config_vars{'snapshot_root'}/.sync" ) { display_rm_rf("$config_vars{'snapshot_root'}/.sync/"); if (0 == $test) { $result = rm_rf( "$config_vars{'snapshot_root'}/.sync/" ); if (0 == $result) { bail("Error! rm_rf(\"$config_vars{'snapshot_root'}/.sync/\")"); } } } } } # # now that the preliminaries are out of the way, the main backups happen here # # backup the lowest interval (or sync content to staging area) # we're not sure yet going in whether we'll be doing an actual backup, or just rotating snapshots for the lowest interval if ((defined($$id_ref{'interval_num'}) && (0 == $$id_ref{'interval_num'})) or ($cmd eq 'sync')) { # if we're doing a sync, run the pre/post exec scripts, and do the backup if ($cmd eq 'sync') { exec_cmd_preexec(); backup_lowest_interval( $id_ref ); exec_cmd_postexec(); # if we're working on the lowest interval, either run the backup and rotate the snapshots, or just rotate them # (depending on whether sync_first is enabled } else { if ($config_vars{'sync_first'}) { rotate_lowest_snapshots( $$id_ref{'interval'} ); } else { exec_cmd_preexec(); rotate_lowest_snapshots( $$id_ref{'interval'} ); backup_lowest_interval( $id_ref ); exec_cmd_postexec(); } } # just rotate the higher intervals } else { # this is not the most frequent unit, just rotate rotate_higher_interval( $id_ref ); } # if use_lazy_delete is on, delete the _delete.$$ directory # we just check for the directory, it will have been created or not depending on the value of use_lazy_delete if ( -d "$config_vars{'snapshot_root'}/_delete.$$" ) { # this is the last thing to do here, and it can take quite a while. # we remove the lockfile here since this delete shouldn't block other rsnapshot jobs from running remove_lockfile(); # start the delete display_rm_rf("$config_vars{'snapshot_root'}/_delete.$$"); if (0 == $test) { my $result = rm_rf( "$config_vars{'snapshot_root'}/_delete.$$" ); if (0 == $result) { bail("Error! rm_rf(\"$config_vars{'snapshot_root'}/_delete.$$\")\n"); } } } else { print_msg("No directory to delete: $config_vars{'snapshot_root'}/_delete.$$", 5); } } # accepts an interval_data_ref # acts on the interval defined as $$id_ref{'interval'} (e.g., hourly) # this should be the smallest interval (e.g., hourly, not daily) # # rotates older dirs within this interval, hard links .0 to .1, # and rsync data over to .0 # # does not return a value, it bails instantly if there's a problem sub backup_lowest_interval { my $id_ref = shift(@_); # this should never happen if (!defined($id_ref)) { bail('backup_lowest_interval() expects an argument'); } if (!defined($$id_ref{'interval'})) { bail('backup_lowest_interval() expects an interval'); } # this also should never happen if ($$id_ref{'interval'} ne 'sync') { if (!defined($$id_ref{'interval_num'}) or (0 != $$id_ref{'interval_num'})) { bail('backup_lowest_interval() can only operate on the lowest interval'); } } my $sync_dest_matches = 0; my $sync_dest_dir = undef; # if we're trying to sync only certain directories, remember the path to match if ($ARGV[1]) { $sync_dest_dir = $ARGV[1]; } # sync live filesystem data and backup script output to $interval.0 # loop through each backup point and backup script foreach my $bp_ref (@backup_points) { # rsync the given backup point into the snapshot root if ( defined($$bp_ref{'dest'}) && (defined($$bp_ref{'src'}) or defined($$bp_ref{'script'})) ) { # if we're doing a sync and we specified an parameter on the command line (for the destination path), # only sync directories matching the destination path if (($$id_ref{'interval'} eq 'sync') && (defined($sync_dest_dir))) { my $avail_path = remove_trailing_slash( $$bp_ref{'dest'} ); my $req_path = remove_trailing_slash( $sync_dest_dir ); # if we have a match, sync this entry if ($avail_path eq $req_path) { # rsync if ($$bp_ref{'src'}) { rsync_backup_point( $$id_ref{'interval'}, $bp_ref ); # backup_script } elsif ($$bp_ref{'script'}) { exec_backup_script( $$id_ref{'interval'}, $bp_ref ); } # ok, we got at least one dest match $sync_dest_matches++; } # this is a normal operation, either a sync or a lowest interval sync/rotate } else { # rsync if ($$bp_ref{'src'}) { rsync_backup_point( $$id_ref{'interval'}, $bp_ref ); # backup_script } elsif ($$bp_ref{'script'}) { exec_backup_script( $$id_ref{'interval'}, $bp_ref ); } } # this should never happen } else { bail('invalid backup point data in backup_lowest_interval()'); } } if ($$id_ref{'interval'} eq 'sync') { if (defined($sync_dest_dir) && (0 == $sync_dest_matches)) { bail ("No matches found for \"$sync_dest_dir\""); } } # rollback failed backups rollback_failed_backups( $$id_ref{'interval'} ); # update mtime on $interval.0/ to show when the snapshot completed touch_interval_dir( $$id_ref{'interval'} ); } # accepts $interval # returns nothing # # operates on directories in the given interval (it should be the lowest one) # deletes the highest numbered directory in the interval, and rotates the ones below it # if link_dest is enabled, .0 gets moved to .1 # otherwise, we do cp -al .0 .1 # # if we encounter an error, this script will terminate the program with an error condition # sub rotate_lowest_snapshots { my $interval = shift(@_); if (!defined($interval)) { bail('interval not defined in rotate_lowest_snapshots()'); } my $id_ref = get_interval_data($interval); my $interval_num = $$id_ref{'interval_num'}; my $interval_max = $$id_ref{'interval_max'}; my $prev_interval = $$id_ref{'prev_interval'}; my $prev_interval_max = $$id_ref{'prev_interval_max'}; my $result; # remove oldest directory if ( (-d "$config_vars{'snapshot_root'}/$interval.$interval_max") && ($interval_max > 0) ) { # if use_lazy_deletes is set move the oldest directory to _delete.$$ if (1 == $use_lazy_deletes) { print_cmd("mv", "$config_vars{'snapshot_root'}/$interval.$interval_max/", "$config_vars{'snapshot_root'}/_delete.$$/" ); if (0 == $test) { my $result = safe_rename( "$config_vars{'snapshot_root'}/$interval.$interval_max", "$config_vars{'snapshot_root'}/_delete.$$" ); if (0 == $result) { my $errstr = ''; $errstr .= "Error! safe_rename(\"$config_vars{'snapshot_root'}/$interval.$interval_max/\", \""; $errstr .= "$config_vars{'snapshot_root'}/_delete.$$/\")"; bail($errstr); } } # otherwise the default is to delete the oldest directory for this interval } else { display_rm_rf("$config_vars{'snapshot_root'}/$interval.$interval_max/"); if (0 == $test) { my $result = rm_rf( "$config_vars{'snapshot_root'}/$interval.$interval_max/" ); if (0 == $result) { bail("Error! rm_rf(\"$config_vars{'snapshot_root'}/$interval.$interval_max/\")\n"); } } } } # rotate the middle ones if ($interval_max > 0) { # Have we rotated a directory for this interval? my $dir_rotated = 0; for (my $i=($interval_max-1); $i>0; $i--) { if ( -d "$config_vars{'snapshot_root'}/$interval.$i" ) { print_cmd("mv", "$config_vars{'snapshot_root'}/$interval.$i/ ", "$config_vars{'snapshot_root'}/$interval." . ($i+1) . "/" ); if (0 == $test) { my $result = safe_rename( "$config_vars{'snapshot_root'}/$interval.$i", ("$config_vars{'snapshot_root'}/$interval." . ($i+1)) ); if (0 == $result) { my $errstr = ''; $errstr .= "Error! safe_rename(\"$config_vars{'snapshot_root'}/$interval.$i/\", \""; $errstr .= "$config_vars{'snapshot_root'}/$interval." . ($i+1) . '/' . "\")"; bail($errstr); } } $dir_rotated = 1; } elsif ($dir_rotated) { # We have rotated a directory for this interval, but $i # does not exist - that probably means a hole. print_msg("Note: $config_vars{'snapshot_root'}/$interval.$i missing, cannot rotate it", 4); } } } # .0 and .1 require more attention, especially now with link_dest and sync_first # sync_first enabled if ($config_vars{'sync_first'}) { # we move .0 to .1 no matter what (assuming it exists) if ( -d "$config_vars{'snapshot_root'}/$interval.0/" ) { print_cmd("mv", "$config_vars{'snapshot_root'}/$interval.0/", "$config_vars{'snapshot_root'}/$interval.1/" ); if (0 == $test) { my $result = safe_rename( "$config_vars{'snapshot_root'}/$interval.0", "$config_vars{'snapshot_root'}/$interval.1" ); if (0 == $result) { my $errstr = ''; $errstr .= "Error! safe_rename(\"$config_vars{'snapshot_root'}/$interval.0/\", \""; $errstr .= "$config_vars{'snapshot_root'}/$interval.1/\")"; bail($errstr); } } } # if we're using rsync --link-dest, we need to mv sync to .0 now if (1 == $link_dest) { # mv sync .0 if ( -d "$config_vars{'snapshot_root'}/.sync" ) { print_cmd("mv", "$config_vars{'snapshot_root'}/.sync/", "$config_vars{'snapshot_root'}/$interval.0/" ); if (0 == $test) { my $result = safe_rename( "$config_vars{'snapshot_root'}/.sync", "$config_vars{'snapshot_root'}/$interval.0" ); if (0 == $result) { my $errstr = ''; $errstr .= "Error! safe_rename(\"$config_vars{'snapshot_root'}/.sync/\", \""; $errstr .= "$config_vars{'snapshot_root'}/$interval.0/\")"; bail($errstr); } } } # otherwise, we hard link (except for directories, symlinks, and special files) sync to .0 } else { # cp -al .sync .0 if ( -d "$config_vars{'snapshot_root'}/.sync/" ) { display_cp_al( "$config_vars{'snapshot_root'}/.sync/", "$config_vars{'snapshot_root'}/$interval.0/" ); if (0 == $test) { $result = cp_al( "$config_vars{'snapshot_root'}/.sync", "$config_vars{'snapshot_root'}/$interval.0" ); if (! $result) { bail("Error! cp_al(\"$config_vars{'snapshot_root'}/.sync\", \"$config_vars{'snapshot_root'}/$interval.0\")"); } } } } # sync_first disabled (make sure we have a .0 directory and someplace to put it) } elsif ( (-d "$config_vars{'snapshot_root'}/$interval.0") && ($interval_max > 0) ) { # if we're using rsync --link-dest, we need to mv .0 to .1 now if (1 == $link_dest) { # move .0 to .1 if ( -d "$config_vars{'snapshot_root'}/$interval.0/" ) { print_cmd("mv $config_vars{'snapshot_root'}/$interval.0/ $config_vars{'snapshot_root'}/$interval.1/"); if (0 == $test) { my $result = safe_rename( "$config_vars{'snapshot_root'}/$interval.0", "$config_vars{'snapshot_root'}/$interval.1" ); if (0 == $result) { my $errstr = ''; $errstr .= "Error! safe_rename(\"$config_vars{'snapshot_root'}/$interval.0/\", "; $errstr .= "\"$config_vars{'snapshot_root'}/$interval.1/\")"; bail($errstr); } } } # otherwise, we hard link (except for directories, symlinks, and special files) .0 over to .1 } else { # call generic cp_al() subroutine if ( -d "$config_vars{'snapshot_root'}/$interval.0/" ) { display_cp_al( "$config_vars{'snapshot_root'}/$interval.0", "$config_vars{'snapshot_root'}/$interval.1" ); if (0 == $test) { $result = cp_al( "$config_vars{'snapshot_root'}/$interval.0/", "$config_vars{'snapshot_root'}/$interval.1/" ); if (! $result) { my $errstr = ''; $errstr .= "Error! cp_al(\"$config_vars{'snapshot_root'}/$interval.0/\", "; $errstr .= "\"$config_vars{'snapshot_root'}/$interval.1/\")"; bail($errstr); } } } } } } # accepts interval, backup_point_ref, ssh_rsync_args_ref # returns no args # runs rsync on the given backup point # this is only run on the lowest points, not for rotations sub rsync_backup_point { my $interval = shift(@_); my $bp_ref = shift(@_); # validate subroutine args if (!defined($interval)) { bail('interval not defined in rsync_backup_point()'); } if (!defined($bp_ref)) { bail('bp_ref not defined in rsync_backup_point()'); } if (!defined($$bp_ref{'src'})) { bail('src not defined in rsync_backup_point()'); } if (!defined($$bp_ref{'dest'})) { bail('dest not defined in rsync_backup_point()'); } # set up default args for rsync and ssh my $ssh_args = $default_ssh_args; my $rsync_short_args = $default_rsync_short_args; my $rsync_long_args = $default_rsync_long_args; # other misc variables my @cmd_stack = undef; my $src = undef; my $result = undef; my $using_relative = 0; my $linux_lvm = 0; my $linux_lvm_oldpwd = undef; my $linux_lvm_snapshotname = undef; if (defined($$bp_ref{'src'})) { $src = remove_trailing_slash( "$$bp_ref{'src'}" ); $src = add_slashdot_if_root( "$src" ); } # if we're using link-dest later, that target depends on whether we're doing a 'sync' or a regular interval # if we're doing a "sync", then look at [lowest-interval].0 instead of [cur-interval].1 my $interval_link_dest; my $interval_num_link_dest; # start looking for link_dest targets at interval.$start_num my $start_num = 1; my $sync_dir_was_present = 0; # if we're doing a sync, we'll start looking at [lowest-interval].0 for a link_dest target if ($interval eq 'sync') { $start_num = 0; # remember now if the .sync directory exists if ( -d "$config_vars{'snapshot_root'}/.sync" ) { $sync_dir_was_present = 1; } } # look for the most recent link_dest target directory # loop through all snapshots until we find the first match foreach my $i_ref (@intervals) { if (defined($$i_ref{'number'})) { for (my $i = $start_num; $i < $$i_ref{'number'}; $i++) { # once we find a valid link_dest target, the search is over if ( -e "$config_vars{'snapshot_root'}/$$i_ref{'interval'}.$i/$$bp_ref{'dest'}" ) { if (!defined($interval_link_dest) && !defined($interval_num_link_dest)) { $interval_link_dest = $$i_ref{'interval'}; $interval_num_link_dest = $i; } # we'll still loop through the outer loop a few more times, but the defined() check above # will make sure the first match wins last; } } } } # check to see if this destination path has already failed # if it's set to be rolled back, skip out now foreach my $rollback_point (@rollback_points) { if (defined($rollback_point)) { my $tmp_dest = $$bp_ref{'dest'}; my $tmp_rollback_point = $rollback_point; # don't compare the slashes at the end $tmp_dest = remove_trailing_slash($tmp_dest); $tmp_rollback_point = remove_trailing_slash($tmp_rollback_point); if ("$tmp_dest" eq "$tmp_rollback_point") { print_warn ("$$bp_ref{'src'} skipped due to rollback plan", 2); syslog_warn("$$bp_ref{'src'} skipped due to rollback plan"); return (undef); } } } # if the config file specified rsync or ssh args, use those instead of the hard-coded defaults in the program if (defined($config_vars{'rsync_short_args'})) { $rsync_short_args = $config_vars{'rsync_short_args'}; } if (defined($config_vars{'rsync_long_args'})) { $rsync_long_args = $config_vars{'rsync_long_args'}; } if (defined($config_vars{'ssh_args'})) { $ssh_args = $config_vars{'ssh_args'}; } # extra verbose? if ($verbose > 3) { $rsync_short_args .= 'v'; } # split up rsync long args into an array, paying attention to # quoting - ideally we'd use Text::Balanced or similar, but that's # only relatively recently gone into core my @rsync_long_args_stack = split_long_args_with_quotes('rsync_long_args', $rsync_long_args); # create $interval.0/$$bp_ref{'dest'} or .sync/$$bp_ref{'dest'} directory if it doesn't exist # (this may create the .sync dir, which is why we had to check for it above) # create_backup_point_dir($interval, $bp_ref); # check opts, first unique to this backup point, and then global # # with all these checks, we try the local option first, and if # that isn't specified, we attempt to use the global setting as # a fallback plan # # we do the rsync args first since they overwrite the rsync_* variables, # whereas the subsequent options append to them # # RSYNC SHORT ARGS if ( defined($$bp_ref{'opts'}) && defined($$bp_ref{'opts'}->{'rsync_short_args'}) ) { $rsync_short_args = $$bp_ref{'opts'}->{'rsync_short_args'}; } if ( defined($$bp_ref{'opts'}) && defined($$bp_ref{'opts'}->{'extra_rsync_short_args'}) ) { $rsync_short_args .= ' ' if ($rsync_short_args); $rsync_short_args .= $$bp_ref{'opts'}->{'extra_rsync_short_args'}; } # RSYNC LONG ARGS if ( defined($$bp_ref{'opts'}) && defined($$bp_ref{'opts'}->{'rsync_long_args'}) ) { @rsync_long_args_stack = split_long_args_with_quotes('rsync_long_args (for a backup point)', $$bp_ref{'opts'}->{'rsync_long_args'}); } if ( defined($$bp_ref{'opts'}) && defined($$bp_ref{'opts'}->{'extra_rsync_long_args'}) ) { push(@rsync_long_args_stack, split_long_args_with_quotes('extra_rsync_long_args (for a backup point)', $$bp_ref{'opts'}->{'extra_rsync_long_args'})); } # SSH ARGS if ( defined($$bp_ref{'opts'}) && defined($$bp_ref{'opts'}->{'ssh_args'}) ) { $ssh_args = $$bp_ref{'opts'}->{'ssh_args'}; } if ( defined($$bp_ref{'opts'}) && defined($$bp_ref{'opts'}->{'extra_ssh_args'}) ) { $ssh_args .= ' ' . $$bp_ref{'opts'}->{'extra_ssh_args'}; } # ONE_FS if ( defined($$bp_ref{'opts'}) && defined($$bp_ref{'opts'}->{'one_fs'}) ) { if (1 == $$bp_ref{'opts'}->{'one_fs'}) { $rsync_short_args .= 'x'; } } elsif ($one_fs) { $rsync_short_args .= 'x'; } # SEE WHAT KIND OF SOURCE WE'RE DEALING WITH # # local filesystem if ( is_real_local_abs_path($$bp_ref{'src'}) ) { # no change # if this is a user@host:/path, use ssh } elsif ( is_ssh_path($$bp_ref{'src'}) ) { # if we have any args for SSH, add them if ( defined($ssh_args) ) { push( @rsync_long_args_stack, "--rsh=\"$config_vars{'cmd_ssh'} $ssh_args\"" ); # no arguments is the default } else { push( @rsync_long_args_stack, "--rsh=$config_vars{'cmd_ssh'}" ); } # anonymous rsync } elsif ( is_anon_rsync_path($$bp_ref{'src'}) ) { # make rsync quiet if we're running in quiet mode if ($verbose < 2) { $rsync_short_args .= 'q'; } # cwrsync path } elsif ( is_cwrsync_path($$bp_ref{'src'}) ) { # make rsync quiet if we're running in quiet mode if ($verbose < 2) { $rsync_short_args .= 'q'; } # LVM path } elsif ( is_linux_lvm_path($$bp_ref{'src'}) ) { # take LVM snapshot and mount, reformat src into local path unless (defined($config_vars{'linux_lvm_snapshotsize'})) { bail("Missing required argument for LVM source: linux_lvm_snapshotsize"); } unless (defined($config_vars{'linux_lvm_snapshotname'})) { bail("Missing required argument for LVM source: linux_lvm_snapshotname"); } unless (defined($config_vars{'linux_lvm_vgpath'})) { bail("Missing required argument for LVM source: linux_lvm_vgpath"); } unless (defined($config_vars{'linux_lvm_mountpath'})) { bail("Missing required argument for LVM source: linux_lvm_mountpath"); } # parse LVM src ('lvm://vgname/volname/path') my ($linux_lvmvgname,$linux_lvmvolname, $linux_lvmpath) = ($$bp_ref{'src'} =~ m|^lvm://([^/]+)/([^/]+)/(.*)$|); # lvmvolname and/or path could be the string "0", so test for 'defined': unless (defined($linux_lvmvgname) and defined($linux_lvmvolname) and defined($linux_lvmpath)) { bail("Could not understand LVM source \"$$bp_ref{'src'}\" in backup_lowest_interval()"); } # assemble and execute LVM snapshot command @cmd_stack = (); push(@cmd_stack, $config_vars{'linux_lvm_cmd_lvcreate'}); push(@cmd_stack, '--snapshot'); push(@cmd_stack, '--size'); push(@cmd_stack, $config_vars{'linux_lvm_snapshotsize'}); push(@cmd_stack, '--name'); push(@cmd_stack, $config_vars{'linux_lvm_snapshotname'}); push(@cmd_stack, join('/', $config_vars{'linux_lvm_vgpath'}, $linux_lvmvgname, $linux_lvmvolname)); print_cmd(@cmd_stack); if (0 == $test) { # silence gratuitous lvcreate output #$result = system(@cmd_stack); $result = system(join " ", @cmd_stack, ">/dev/null"); if ($result != 0) { bail("Create LVM snapshot failed: $result"); } } # mount the snapshot @cmd_stack = (); push(@cmd_stack, $config_vars{'linux_lvm_cmd_mount'}); $linux_lvm_snapshotname = join('/', $config_vars{'linux_lvm_vgpath'}, $linux_lvmvgname, $config_vars{'linux_lvm_snapshotname'}); push(@cmd_stack, $linux_lvm_snapshotname); push(@cmd_stack, $config_vars{'linux_lvm_mountpath'}); print_cmd(@cmd_stack); if (0 == $test) { $result = system(@cmd_stack); if ($result != 0) { bail("Mount LVM snapshot failed: $result"); } } # rewrite src to point to mount path # - to avoid including the mountpath in the snapshot, change the working directory and use a relative source $linux_lvm_oldpwd = $ENV{PWD}; print_cmd("chdir($config_vars{'linux_lvm_mountpath'})"); if (0 == $test) { $result = chdir($config_vars{'linux_lvm_mountpath'}); if (0 == $result) { bail("Could not change directory to \"$config_vars{'linux_lvm_mountpath'}\""); } } $$bp_ref{'src'} = './' . $linux_lvmpath; $linux_lvm = 1; # this should have already been validated once, but better safe than sorry } else { bail("Could not understand source \"$$bp_ref{'src'}\" in backup_lowest_interval()"); } # if we're using --link-dest, we'll need to specify the link-dest directory target # this varies depending on whether we're operating on the lowest interval or doing a 'sync' if (1 == $link_dest) { # bp_ref{'dest'} and snapshot_root have already been validated, but these might be blank if (defined($interval_link_dest) && defined($interval_num_link_dest)) { # make sure the directory exists if ( -d "$config_vars{'snapshot_root'}/$interval_link_dest.$interval_num_link_dest/$$bp_ref{'dest'}" ) { # we don't use link_dest if we already synced once to this directory if (0 && $sync_dir_was_present) { # always false # skip --link-dest, this is the second time the sync has been run, because the .sync directory already exists # default: push link_dest arguments onto cmd stack } else { push( @rsync_long_args_stack, "--link-dest=$config_vars{'snapshot_root'}/$interval_link_dest.$interval_num_link_dest/$$bp_ref{'dest'}" ); } } } } # SPECIAL EXCEPTION: # If we're using --link-dest AND the source is a file AND we have a copy from the last time, # manually link interval.1/foo to interval.0/foo # # This is necessary because --link-dest only works on directories # if ( (1 == $link_dest) && (is_file($$bp_ref{'src'})) && defined($interval_link_dest) && defined($interval_num_link_dest) && (-f "$config_vars{'snapshot_root'}/$interval_link_dest.$interval_num_link_dest/$$bp_ref{'dest'}") ) { # these are both "destination" paths, but we're moving from .1 to .0 my $srcpath; my $destpath; $srcpath = "$config_vars{'snapshot_root'}/$interval_link_dest.$interval_num_link_dest/$$bp_ref{'dest'}"; if ($interval eq 'sync') { $destpath = "$config_vars{'snapshot_root'}/.sync/$$bp_ref{'dest'}"; } else { $destpath = "$config_vars{'snapshot_root'}/$interval.0/$$bp_ref{'dest'}"; } print_cmd("ln $srcpath $destpath"); if (0 == $test) { $result = link( "$srcpath", "$destpath" ); if (!defined($result) or (0 == $result)) { print_err ("link(\"$srcpath\", \"$destpath\") failed", 2); syslog_err("link(\"$srcpath\", \"$destpath\") failed"); } } } # figure out if we're using the --relative flag to rsync. # this influences how the source paths are constructed below. foreach my $rsync_long_arg (@rsync_long_args_stack) { if (defined($rsync_long_arg)) { if ('--relative' eq $rsync_long_arg) { $using_relative = 1; } } } if (defined($$bp_ref{'src'})) { # make sure that the source path doesn't have a trailing slash if we're using the --relative flag # this is to work around a bug in most versions of rsync that don't properly delete entries # when the --relative flag is set. # if (1 == $using_relative) { $src = remove_trailing_slash( "$$bp_ref{'src'}" ); $src = add_slashdot_if_root( "$src" ); # no matter what, we need a source path } else { # put a trailing slash on it if we know it's a directory and it doesn't have one if ((-d "$$bp_ref{'src'}") && ($$bp_ref{'src'} !~ /\/$/)) { $src = $$bp_ref{'src'} . '/'; # just use it as-is } else { $src = $$bp_ref{'src'}; } } } # BEGIN RSYNC COMMAND ASSEMBLY # take care not to introduce blank elements into the array, # since it can confuse rsync, which in turn causes strange errors # @cmd_stack = (); # # rsync command push(@cmd_stack, $config_vars{'cmd_rsync'}); # # rsync short args if (defined($rsync_short_args) && ($rsync_short_args ne '')) { push(@cmd_stack, $rsync_short_args); } # # rsync long args if (@rsync_long_args_stack && (scalar(@rsync_long_args_stack) > 0)) { foreach my $tmp_long_arg (@rsync_long_args_stack) { if (defined($tmp_long_arg) && ($tmp_long_arg ne '')) { push(@cmd_stack, $tmp_long_arg); } } } # # src push(@cmd_stack, "$src"); # # dest if ($interval eq 'sync') { push(@cmd_stack, "$config_vars{'snapshot_root'}/.sync/$$bp_ref{'dest'}"); } else { push(@cmd_stack, "$config_vars{'snapshot_root'}/$interval.0/$$bp_ref{'dest'}"); } # # END RSYNC COMMAND ASSEMBLY # RUN THE RSYNC COMMAND FOR THIS BACKUP POINT BASED ON THE @cmd_stack VARS print_cmd(@cmd_stack); my $tryCount = 0; $result = 1; if (0 == $test) { while ($tryCount < $rsync_numtries && $result !=0) { # join is Michael Ashley's fix for some filter/space problems $result = system(join(' ', @cmd_stack)); $tryCount += 1; } # now we see if rsync ran successfully, and what to do about it if ($result != 0) { # bitmask return value my $retval = get_retval($result); # print warnings, and set this backup point to rollback if we're using --link-dest # handle_rsync_error($retval, $bp_ref); } else { print_msg("rsync succeeded", 5); } } # unmount and drop snapshot if required if ($linux_lvm) { print_cmd("chdir($linux_lvm_oldpwd)"); if (0 == $test) { $result = chdir($linux_lvm_oldpwd); if (0 == $result) { bail("Could not change directory to \"$linux_lvm_oldpwd\""); } } @cmd_stack = (); push(@cmd_stack, $config_vars{'linux_lvm_cmd_umount'}); push(@cmd_stack, $config_vars{'linux_lvm_mountpath'}); print_cmd(@cmd_stack); if (0 == $test) { # silence gratuitous lvremove output #$result = system(@cmd_stack); $result = system(join " ", @cmd_stack, ">/dev/null"); if ($result != 0) { bail("Unmount LVM snapshot failed: $result"); } } @cmd_stack = (); push(@cmd_stack, $config_vars{'linux_lvm_cmd_lvremove'}); push(@cmd_stack, '--force'); push(@cmd_stack, $linux_lvm_snapshotname); print_cmd(@cmd_stack); if (0 == $test) { $result = system(@cmd_stack); if ($result != 0) { bail("Removal of LVM snapshot failed: $result"); } } } } # accepts the name of the argument to split, and its value # the name is used for spitting out error messages # # returns a list sub split_long_args_with_quotes { my($argname, $argvalue) = @_; my $inquotes = ''; my @stack = (''); for(my $i = 0; $i < length($argvalue); $i++) { my $thischar = substr($argvalue, $i, 1); # got whitespace and not in quotes? end this argument, start next if($thischar =~ /\s/ && !$inquotes) { $#stack++; next; # not in quotes and got a quote? remember that we're in quotes } elsif($thischar =~ /['"]/ && !$inquotes) { $inquotes = $thischar; # in quotes and got a different quote? no nesting allowed } elsif($thischar =~ /['"]/ && $inquotes ne $thischar) { print_err("Nested quotes not allowed in $argname", 1); syslog_err("Nested quotes not allowed in $argname"); exit(1); # in quotes and got a close quote } elsif($thischar eq $inquotes) { $inquotes = ''; } $stack[-1] .= $thischar; } if($inquotes) { print_err("Unbalanced quotes in $argname", 1); syslog_err("Unbalanced quotes in $argname"); exit(1); } return @stack; } # accepts rsync exit code, backup_point_ref # prints out an appropriate error message (and logs it) # also adds destination path to the rollback queue if link_dest is enabled sub handle_rsync_error { my $retval = shift(@_); my $bp_ref = shift(@_); # shouldn't ever happen if (!defined($retval)) { bail('retval undefined in handle_rsync_error()'); } if (0 == $retval) { bail('retval == 0 in handle_rsync_error()'); } if (!defined($bp_ref)) { bail('bp_ref undefined in handle_rsync_error()'); } # a partial list of rsync exit values (from the rsync 2.6.0 man page) # # 0 Success # 1 Syntax or usage error # 23 Partial transfer due to error # 24 Partial transfer due to vanished source files # # if we got error 1 and we were attempting --link-dest, there's # a very good chance that this version of rsync is too old. # if ((1 == $link_dest) && (1 == $retval)) { print_err ("$config_vars{'cmd_rsync'} syntax or usage error. Does this version of rsync support --link-dest?", 2); syslog_err("$config_vars{'cmd_rsync'} syntax or usage error. Does this version of rsync support --link-dest?"); # 23 and 24 are treated as warnings because users might be using the filesystem during the backup # if you want perfect backups, don't allow the source to be modified while the backups are running :) } elsif (23 == $retval) { print_warn ("Some files and/or directories in $$bp_ref{'src'} only transferred partially during rsync operation", 4); syslog_warn("Some files and/or directories in $$bp_ref{'src'} only transferred partially during rsync operation"); } elsif (24 == $retval) { print_warn ("Some files and/or directories in $$bp_ref{'src'} vanished during rsync operation", 4); syslog_warn("Some files and/or directories in $$bp_ref{'src'} vanished during rsync operation"); # other error } else { print_err ("$config_vars{'cmd_rsync'} returned $retval while processing $$bp_ref{'src'}", 2); syslog_err("$config_vars{'cmd_rsync'} returned $retval while processing $$bp_ref{'src'}"); # set this directory to rollback if we're using link_dest # (since $interval.0/ will have been moved to $interval.1/ by now) if (1 == $link_dest) { push(@rollback_points, $$bp_ref{'dest'}); } } } # accepts interval, backup_point_ref, ssh_rsync_args_ref # returns no args # runs rsync on the given backup point sub exec_backup_script { my $interval = shift(@_); my $bp_ref = shift(@_); # validate subroutine args if (!defined($interval)) { bail('interval not defined in exec_backup_script()'); } if (!defined($bp_ref)) { bail('bp_ref not defined in exec_backup_script()'); } # other misc variables my $script = undef; my $tmpdir = undef; my $result = undef; # remember what directory we started in my $cwd = cwd(); # create $interval.0/$$bp_ref{'dest'} directory if it doesn't exist # create_backup_point_dir($interval, $bp_ref); # work in a temp dir, and make this the source for the rsync operation later # not having a trailing slash is a subtle distinction. it allows us to use # the same path if it's NOT a directory when we try to delete it. $tmpdir = "$config_vars{'snapshot_root'}/tmp"; # remove the tmp directory if it's still there for some reason # (this shouldn't happen unless the program was killed prematurely, etc) if ( -e "$tmpdir" ) { display_rm_rf("$tmpdir/"); if (0 == $test) { $result = rm_rf("$tmpdir/"); if (0 == $result) { bail("Could not rm_rf(\"$tmpdir/\");"); } } } # create the tmp directory print_cmd("mkdir -m 0755 -p $tmpdir/"); if (0 == $test) { eval { # don't ever pass a trailing slash to mkpath mkpath( "$tmpdir", 0, 0755 ); }; if ($@) { bail("Unable to create \"$tmpdir/\",\nPlease make sure you have the right permissions."); } } # no more calls to mkpath here. the tmp dir needs a trailing slash $tmpdir .= '/'; # change to the tmp directory print_cmd("cd $tmpdir"); if (0 == $test) { $result = chdir("$tmpdir"); if (0 == $result) { bail("Could not change directory to \"$tmpdir\""); } } # run the backup script # # the assumption here is that the backup script is written in such a way # that it creates files in its current working directory. # # the backup script should return 0 on success, anything else is # considered a failure. # print_cmd($$bp_ref{'script'}); if (0 == $test) { $result = system( $$bp_ref{'script'} ); if ($result != 0) { # bitmask return value my $retval = get_retval($result); print_err ("backup_script $$bp_ref{'script'} returned $retval", 2); syslog_err("backup_script $$bp_ref{'script'} returned $retval"); # if the backup script failed, roll back to the last good data push(@rollback_points, $$bp_ref{'dest'} ); } } # change back to the previous directory # (/ is a special case) if ('/' eq $cwd) { print_cmd("cd $cwd"); } else { print_cmd("cd $cwd/"); } if (0 == $test) { chdir($cwd); } # if we're using link_dest, pull back the previous files (as links) that were moved up if any. # this is because in this situation, .0 will always be empty, so we'll pull select things # from .1 back to .0 if possible. these will be used as a baseline for diff comparisons by # sync_if_different() down below. if (1 == $link_dest) { my $lastdir; my $curdir; if ($interval eq 'sync') { $lastdir = "$config_vars{'snapshot_root'}/" . $intervals[0]->{'interval'} . ".0/$$bp_ref{'dest'}"; $curdir = "$config_vars{'snapshot_root'}/.sync/$$bp_ref{'dest'}"; } else { $lastdir = "$config_vars{'snapshot_root'}/$interval.1/$$bp_ref{'dest'}"; $curdir = "$config_vars{'snapshot_root'}/$interval.0/$$bp_ref{'dest'}"; } # make sure we have a slash at the end if ($lastdir !~ m/\/$/) { $lastdir .= '/'; } if ($curdir !~ m/\/$/) { $curdir .= '/'; } # if we even have files from last time if ( -e "$lastdir" ) { # and we're not somehow clobbering an existing directory (shouldn't happen) if ( ! -e "$curdir" ) { # call generic cp_al() subroutine display_cp_al( "$lastdir", "$curdir" ); if (0 == $test) { $result = cp_al( "$lastdir", "$curdir" ); if (! $result) { print_err("Warning! cp_al(\"$lastdir\", \"$curdir/\")", 2); } } } } } # sync the output of the backup script into this snapshot interval # this is using a native function since rsync doesn't quite do what we want # # rsync doesn't work here because it sees that the timestamps are different, and # insists on changing things even if the files are bit for bit identical on content. # # check to see where we're syncing to my $target_dir; if ($interval eq 'sync') { $target_dir = "$config_vars{'snapshot_root'}/.sync/$$bp_ref{'dest'}"; } else { $target_dir = "$config_vars{'snapshot_root'}/$interval.0/$$bp_ref{'dest'}"; } print_cmd("sync_if_different(\"$tmpdir\", \"$target_dir\")"); if (0 == $test) { $result = sync_if_different("$tmpdir", "$target_dir"); if (!defined($result)) { print_err("Warning! sync_if_different(\"$tmpdir\", \"$$bp_ref{'dest'}\") returned undef", 2); } } # remove the tmp directory if ( -e "$tmpdir" ) { display_rm_rf("$tmpdir"); if (0 == $test) { $result = rm_rf("$tmpdir"); if (0 == $result) { bail("Could not rm_rf(\"$tmpdir\");"); } } } } # accepts and runs an arbitrary command string # returns the exit value of the command sub exec_cmd { my $cmd = shift(@_); my $return = 0; my $retval = 0; if (!defined($cmd) or ('' eq $cmd)) { print_err("Warning! Command \"$cmd\" not found", 2); return (undef); } print_cmd($cmd); if (0 == $test) { $return = system($cmd); if (!defined($return)) { print_err("Warning! exec_cmd(\"$cmd\") returned undef", 2); } # bitmask to get the real return value $retval = get_retval($return); } return ($retval); } # accepts no arguments # returns the exit code of the defined preexec script, or undef if the command is not found sub exec_cmd_preexec { my $retval = 0; # exec_cmd will only run if we're not in test mode if (defined($config_vars{'cmd_preexec'})) { $retval = exec_cmd( "$config_vars{'cmd_preexec'}" ); } if (!defined($retval)) { print_err("$config_vars{'cmd_preexec'} not found", 2); } if (0 != $retval) { print_warn("cmd_preexec \"$config_vars{'cmd_preexec'}\" returned $retval", 2); } return ($retval); } # accepts no arguments # returns the exit code of the defined preexec script, or undef if the command is not found sub exec_cmd_postexec { my $retval = 0; # exec_cmd will only run if we're not in test mode if (defined($config_vars{'cmd_postexec'})) { $retval = exec_cmd( "$config_vars{'cmd_postexec'}" ); } if (!defined($retval)) { print_err("$config_vars{'cmd_postexec'} not found", 2); } if (0 != $retval) { print_warn("cmd_postexec \"$config_vars{'cmd_postexec'}\" returned $retval", 2); } return ($retval); } # accepts interval, backup_point_ref # returns nothing # exits the program if it encounters a fatal error sub create_backup_point_dir { my $interval = shift(@_); my $bp_ref = shift(@_); # validate subroutine args if (!defined($interval)) { bail('interval not defined in create_interval_0()'); } if (!defined($bp_ref)) { bail('bp_ref not defined in create_interval_0()'); } # create missing parent directories inside the $interval.x directory my @dirs = split(/\//, $$bp_ref{'dest'}); pop(@dirs); # don't mkdir for dest unless we have to my $destpath; if ($interval eq 'sync') { $destpath = "$config_vars{'snapshot_root'}/.sync/" . join('/', @dirs); } else { $destpath = "$config_vars{'snapshot_root'}/$interval.0/" . join('/', @dirs); } # make sure we DON'T have a trailing slash (for mkpath) if ($destpath =~ m/\/$/) { $destpath = remove_trailing_slash($destpath); } # create the directory if it doesn't exist if ( ! -e "$destpath" ) { print_cmd("mkdir -m 0755 -p $destpath/"); if (0 == $test) { eval { mkpath( "$destpath", 0, 0755 ); }; if ($@) { bail("Could not mkpath(\"$destpath/\", 0, 0755);"); } } } } # accepts interval we're operating on # returns nothing important # rolls back failed backups, as defined in the @rollback_points array # this is necessary if we're using link_dest, since it moves the .0 to .1 directory, # instead of recursively copying links to the files. it also helps with failed # backup scripts. # sub rollback_failed_backups { my $interval = shift(@_); if (!defined($interval)) { bail('interval not defined in rollback_failed_backups()'); } my $result; my $rsync_short_args = $default_rsync_short_args; # handle 'sync' case my $interval_src; my $interval_dest; if ($interval eq 'sync') { $interval_src = $intervals[0]->{'interval'} . '.0'; $interval_dest = '.sync'; } else { $interval_src = "$interval.1"; $interval_dest = "$interval.0"; } # extra verbose? if ($verbose > 3) { $rsync_short_args .= 'v'; } # rollback failed backups (if we're using link_dest) foreach my $rollback_point (@rollback_points) { # make sure there's something to rollback from if ( ! -e "$config_vars{'snapshot_root'}/$interval_src/$rollback_point" ) { next; } print_warn ("Rolling back \"$rollback_point\"", 2); syslog_warn("Rolling back \"$rollback_point\""); # using link_dest, this probably won't happen # just in case, we may have to delete the old backup point from interval.0 / .sync if ( -e "$config_vars{'snapshot_root'}/$interval_dest/$rollback_point" ) { display_rm_rf("$config_vars{'snapshot_root'}/$interval_dest/$rollback_point"); if (0 == $test) { $result = rm_rf( "$config_vars{'snapshot_root'}/$interval_dest/$rollback_point" ); if (0 == $result) { bail("Error! rm_rf(\"$config_vars{'snapshot_root'}/$interval_dest/$rollback_point\")\n"); } } } # copy hard links back from .1 to .0 # this will re-populate the .0 directory without taking up (much) additional space # # if we're doing a 'sync', then instead of .1 and .0, it's lowest.0 and .sync display_cp_al( "$config_vars{'snapshot_root'}/$interval_src/$rollback_point", "$config_vars{'snapshot_root'}/$interval_dest/$rollback_point" ); if (0 == $test) { $result = cp_al( "$config_vars{'snapshot_root'}/$interval_src/$rollback_point", "$config_vars{'snapshot_root'}/$interval_dest/$rollback_point" ); if (! $result) { my $errstr = ''; $errstr .= "Error! cp_al(\"$config_vars{'snapshot_root'}/$interval_src/$rollback_point\", "; $errstr .= "\"$config_vars{'snapshot_root'}/$interval_dest/$rollback_point\")"; bail($errstr); } } } } # accepts interval # returns nothing # updates mtime on $interval.0 sub touch_interval_dir { my $interval = shift(@_); if (!defined($interval)) { bail('interval not defined in touch_interval()'); } my $interval_dir; if ($interval eq 'sync') { $interval_dir = '.sync'; } else { $interval_dir = $interval . '.0'; } # update mtime of $interval.0 to reflect the time this snapshot was taken print_cmd("touch $config_vars{'snapshot_root'}/$interval_dir/"); if (0 == $test) { my $result = utime(time(), time(), "$config_vars{'snapshot_root'}/$interval_dir/"); if (0 == $result) { bail("Could not utime(time(), time(), \"$config_vars{'snapshot_root'}/$interval_dir/\");"); } } } # accepts an interval_data_ref # looks at $$id_ref{'interval'} as the interval to act on, # and the previous interval $$id_ref{'prev_interval'} to pull up the directory from (e.g., daily, hourly) # the interval being acted upon should not be the lowest one. # # rotates older dirs within this interval, and hard links # the previous interval's highest numbered dir to this interval's .0, # # does not return a value, it bails instantly if there's a problem sub rotate_higher_interval { my $id_ref = shift(@_); # this should never happen if (!defined($id_ref)) { bail('rotate_higher_interval() expects an interval_data_ref'); } # this also should never happen if (!defined($$id_ref{'interval_num'}) or (0 == $$id_ref{'interval_num'})) { bail('rotate_higher_interval() can only operate on the higher intervals'); } # set up variables for convenience since we refer to them extensively my $interval = $$id_ref{'interval'}; my $interval_num = $$id_ref{'interval_num'}; my $interval_max = $$id_ref{'interval_max'}; my $prev_interval = $$id_ref{'prev_interval'}; my $prev_interval_max = $$id_ref{'prev_interval_max'}; # ROTATE DIRECTORIES # # delete the oldest one (if we're keeping more than one) if ( -d "$config_vars{'snapshot_root'}/$interval.$interval_max" ) { # if use_lazy_deletes is set move the oldest directory to _delete.$$ # otherwise preform the default behavior if (1 == $use_lazy_deletes) { print_cmd("mv ", "$config_vars{'snapshot_root'}/$interval.$interval_max/ ", "$config_vars{'snapshot_root'}/_delete.$$/" ); if (0 == $test) { my $result = safe_rename( "$config_vars{'snapshot_root'}/$interval.$interval_max", ("$config_vars{'snapshot_root'}/_delete.$$") ); if (0 == $result) { my $errstr = ''; $errstr .= "Error! safe_rename(\"$config_vars{'snapshot_root'}/$interval.$interval_max/\", \""; $errstr .= "$config_vars{'snapshot_root'}/_delete.$$/\")"; bail($errstr); } } } else { display_rm_rf("$config_vars{'snapshot_root'}/$interval.$interval_max/"); if (0 == $test) { my $result = rm_rf( "$config_vars{'snapshot_root'}/$interval.$interval_max/" ); if (0 == $result) { bail("Could not rm_rf(\"$config_vars{'snapshot_root'}/$interval.$interval_max/\");"); } } } } else { print_msg("$config_vars{'snapshot_root'}/$interval.$interval_max not present (yet), nothing to delete", 4); } # rotate the middle ones for (my $i=($interval_max-1); $i>=0; $i--) { if ( -d "$config_vars{'snapshot_root'}/$interval.$i" ) { print_cmd( "mv $config_vars{'snapshot_root'}/$interval.$i/ ", "$config_vars{'snapshot_root'}/$interval." . ($i+1) . "/" ); if (0 == $test) { my $result = safe_rename( "$config_vars{'snapshot_root'}/$interval.$i", ("$config_vars{'snapshot_root'}/$interval." . ($i+1)) ); if (0 == $result) { my $errstr = ''; $errstr .= "Error! safe_rename(\"$config_vars{'snapshot_root'}/$interval.$i/\", \""; $errstr .= "$config_vars{'snapshot_root'}/$interval." . ($i+1) . '/' . "\")"; bail($errstr); } } } else { print_msg("$config_vars{'snapshot_root'}/$interval.$i not present (yet), nothing to rotate", 4); } } # prev.max and interval.0 require more attention if ( -d "$config_vars{'snapshot_root'}/$prev_interval.$prev_interval_max" ) { my $result; # if the previous interval has at least 2 snapshots, # or if the previous interval isn't the smallest one, # move the last one up a level if (($prev_interval_max >= 1) or ($interval_num >= 2)) { # mv hourly.5 to daily.0 (or whatever intervals we're using) print_cmd( "mv $config_vars{'snapshot_root'}/$prev_interval.$prev_interval_max/ ", "$config_vars{'snapshot_root'}/$interval.0/" ); if (0 == $test) { $result = safe_rename( "$config_vars{'snapshot_root'}/$prev_interval.$prev_interval_max", "$config_vars{'snapshot_root'}/$interval.0" ); if (0 == $result) { my $errstr = ''; $errstr .= "Error! safe_rename(\"$config_vars{'snapshot_root'}/$prev_interval.$prev_interval_max/\", "; $errstr .= "\"$config_vars{'snapshot_root'}/$interval.0/\")"; bail($errstr); } } } else { print_err("$prev_interval must be above 1 to keep snapshots at the $interval level", 1); exit(1); } } else { print_msg("$config_vars{'snapshot_root'}/$prev_interval.$prev_interval_max not present (yet), nothing to copy", 3); } } # accepts src, dest # prints out the cp -al command that would be run, based on config file data sub display_cp_al { my $src = shift(@_); my $dest = shift(@_); # remove trailing slashes (for newer versions of GNU cp) $src = remove_trailing_slash($src); $dest = remove_trailing_slash($dest); if (!defined($src)) { bail('src not defined in display_cp_al()'); } if (!defined($dest)) { bail('dest not defined in display_cp_al()'); } if (defined($config_vars{'cmd_cp'})) { print_cmd("$config_vars{'cmd_cp'} -al $src $dest"); } else { print_cmd("native_cp_al(\"$src\", \"$dest\")"); } } # stub subroutine # calls either gnu_cp_al() or native_cp_al() # returns the value directly from whichever subroutine it calls # also prints out what's happening to the screen, if appropriate sub cp_al { my $src = shift(@_); my $dest = shift(@_); my $result = 0; # use gnu cp if we have it if (defined($config_vars{'cmd_cp'})) { $result = gnu_cp_al("$src", "$dest"); # fall back to the built-in native perl replacement, followed by an rsync clean-up step } else { # native cp -al $result = native_cp_al("$src", "$dest"); if (1 != $result) { return ($result); } # rsync clean-up $result = rsync_cleanup_after_native_cp_al("$src", "$dest"); } return ($result); } # this is a wrapper to call the GNU version of "cp" # it might fail in mysterious ways if you have a different version of "cp" # sub gnu_cp_al { my $src = shift(@_); my $dest = shift(@_); my $result = 0; my $status; # make sure we were passed two arguments if (!defined($src)) { return(0); } if (!defined($dest)) { return(0); } # remove trailing slashes (for newer versions of GNU cp) $src = remove_trailing_slash($src); $dest = remove_trailing_slash($dest); if ( ! -d "$src" ) { print_err("gnu_cp_al() needs a valid directory as an argument", 2); return (0); } # make the system call to GNU cp $result = system( $config_vars{'cmd_cp'}, '-al', "$src", "$dest" ); if ($result != 0) { $status = $result >> 8; print_err("$config_vars{'cmd_cp'} -al $src $dest failed (result $result, exit status $status). Perhaps your cp does not support -al options?", 2); return (0); } return (1); } # This is a purpose built, native perl replacement for GNU "cp -al". # However, it is not quite as good. it does not copy "special" files: # block, char, fifo, or sockets. # Never the less, it does do regular files, directories, and symlinks # which should be enough for 95% of the normal cases. # If you absolutely have to have snapshots of FIFOs, etc, just get GNU # cp on your system, and specify it in the config file. # # Please note that more recently, this subroutine is followed up by # an rsync clean-up step. This combination effectively removes most of # the limitations of this technique. # # In the great perl tradition, this returns 1 on success, 0 on failure. # sub native_cp_al { my $src = shift(@_); my $dest = shift(@_); my $dh = undef; my $result = 0; # make sure we were passed two arguments if (!defined($src)) { return(0); } if (!defined($dest)) { return(0); } # make sure we have a source directory if ( ! -d "$src" ) { print_err("native_cp_al() needs a valid source directory as an argument", 2); return (0); } # strip trailing slashes off the directories, # since we'll add them back on later $src = remove_trailing_slash($src); $dest = remove_trailing_slash($dest); # LSTAT SRC my $st = lstat("$src"); if (!defined($st)) { print_err("Warning! Could not lstat source dir (\"$src\") : $!", 2); return(0); } # MKDIR DEST (AND SET MODE) if ( ! -d "$dest" ) { # print and/or log this if necessary if (($verbose > 4) or ($loglevel > 4)) { my $cmd_string = "mkdir(\"$dest\", " . get_perms($st->mode) . ")"; if ($verbose > 4) { print_cmd($cmd_string); } elsif ($loglevel > 4) { log_msg($cmd_string, 4); } } $result = mkdir("$dest", $st->mode); if ( ! $result ) { print_err("Warning! Could not mkdir(\"$dest\", $st->mode) : $!", 2); return(0); } } # CHOWN DEST (if root) if (0 == $<) { # make sure destination is not a symlink if ( ! -l "$dest" ) { # print and/or log this if necessary if (($verbose > 4) or ($loglevel > 4)) { my $cmd_string = "safe_chown(" . $st->uid . ", " . $st->gid . ", \"$dest\")"; if ($verbose > 4) { print_cmd($cmd_string); } elsif ($loglevel > 4) { log_msg($cmd_string, 4); } } $result = safe_chown($st->uid, $st->gid, "$dest"); if (! $result) { print_err("Warning! Could not safe_chown(" . $st->uid . ", " . $st->gid . ", \"$dest\");", 2); return(0); } } } # READ DIR CONTENTS $dh = new DirHandle( "$src" ); if (defined($dh)) { my @nodes = $dh->read(); # loop through all nodes in this dir foreach my $node (@nodes) { # skip '.' and '..' next if ($node =~ m/^\.\.?$/o); # make sure the node we just got is valid (this is highly unlikely to fail) my $st = lstat("$src/$node"); if (!defined($st)) { print_err("Warning! Could not lstat source node (\"$src/$node\") : $!", 2); next; } # SYMLINK (must be tested for first, because it will also pass the file and dir tests) if ( -l "$src/$node" ) { # print and/or log this if necessary if (($verbose > 4) or ($loglevel > 4)) { my $cmd_string = "copy_symlink(\"$src/$node\", \"$dest/$node\")"; if ($verbose > 4) { print_cmd($cmd_string); } elsif ($loglevel > 4) { log_msg($cmd_string, 4); } } $result = copy_symlink("$src/$node", "$dest/$node"); if (0 == $result) { print_err("Warning! copy_symlink(\"$src/$node\", \"$dest/$node\")", 2); next; } # FILE } elsif ( -f "$src/$node" ) { # print and/or log this if necessary if (($verbose > 4) or ($loglevel > 4)) { my $cmd_string = "link(\"$src/$node\", \"$dest/$node\");"; if ($verbose > 4) { print_cmd($cmd_string); } elsif ($loglevel > 4) { log_msg($cmd_string, 4); } } # make a hard link $result = link("$src/$node", "$dest/$node"); if (! $result) { print_err("Warning! Could not link(\"$src/$node\", \"$dest/$node\") : $!", 2); next; } # DIRECTORY } elsif ( -d "$src/$node" ) { # print and/or log this if necessary if (($verbose > 4) or ($loglevel > 4)) { my $cmd_string = "native_cp_al(\"$src/$node\", \"$dest/$node\")"; if ($verbose > 4) { print_cmd($cmd_string); } elsif ($loglevel > 4) { log_msg($cmd_string, 4); } } # call this subroutine recursively, to create the directory $result = native_cp_al("$src/$node", "$dest/$node"); if (! $result) { print_err("Warning! Recursion error in native_cp_al(\"$src/$node\", \"$dest/$node\")", 2); next; } } ## rsync_cleanup_after_native_cp_al() will take care of the files we can't handle here # ## FIFO #} elsif ( -p "$src/$node" ) { # # print_err("Warning! Ignoring FIFO $src/$node", 2); # ## SOCKET #} elsif ( -S "$src/$node" ) { # # print_err("Warning! Ignoring socket: $src/$node", 2); # ## BLOCK DEVICE #} elsif ( -b "$src/$node" ) { # # print_err("Warning! Ignoring special block file: $src/$node", 2); # ## CHAR DEVICE #} elsif ( -c "$src/$node" ) { # # print_err("Warning! Ignoring special character file: $src/$node", 2); #} } } else { print_err("Could not open \"$src\". Do you have adequate permissions?", 2); return(0); } # close open dir handle if (defined($dh)) { $dh->close(); } undef( $dh ); # UTIME DEST # print and/or log this if necessary if (($verbose > 4) or ($loglevel > 4)) { my $cmd_string = "utime(" . $st->atime . ", " . $st->mtime . ", \"$dest\");"; if ($verbose > 4) { print_cmd($cmd_string); } elsif ($loglevel > 4) { log_msg($cmd_string, 4); } } $result = utime($st->atime, $st->mtime, "$dest"); if (! $result) { print_err("Warning! Could not set utime(" . $st->atime . ", " . $st->mtime . ", \"$dest\") : $!", 2); return(0); } return (1); } # If we're using native_cp_al(), it can't transfer special files. # So, to make sure no one misses out, this subroutine gets called every time directly # after native_cp_al(), with the same source and destinations paths. # # Essentially it is running between two almost identical hard linked directory trees. # However, it will transfer over the few (if any) special files that were otherwise # missed. # # This subroutine specifies its own parameters for rsync's arguments. This is to make # sure that nothing goes wrong, since there is not much here that should be left to # interpretation. # sub rsync_cleanup_after_native_cp_al { my $src = shift(@_); my $dest = shift(@_); my $local_rsync_short_args = '-a'; # if the user asked for -E, we should use it here too. # should we check for OS X? Dunno, but for now that extra # check is in here as we know we need it there, and so # this is the smallest change for the smallest number of # people $local_rsync_short_args .= 'E' if( defined($config_vars{'rsync_short_args'}) && $config_vars{'rsync_short_args'} =~ /E/ && $^O eq 'darwin' ); my @cmd_stack = (); # make sure we were passed two arguments if (!defined($src)) { return(0); } if (!defined($dest)) { return(0); } # make sure this is directory to directory if (($src !~ m/\/$/o) or ($dest !~ m/\/$/o)) { print_err("rsync_cleanup_after_native_cp_al() only works on directories", 2); return (0); } # make sure we have a source directory if ( ! -d "$src" ) { print_err("rsync_cleanup_after_native_cp_al() needs a valid source directory as an argument", 2); return (0); } # make sure we have a destination directory if ( ! -d "$dest" ) { print_err("rsync_cleanup_after_native_cp_al() needs a valid destination directory as an argument", 2); return (0); } # check verbose settings and modify rsync's short args accordingly if ($verbose > 3) { $local_rsync_short_args .= 'v'; } # setup rsync command # # rsync push(@cmd_stack, $config_vars{'cmd_rsync'}); # # short args push(@cmd_stack, $local_rsync_short_args); # # long args (not the defaults) push(@cmd_stack, '--delete'); push(@cmd_stack, '--numeric-ids'); # # src push(@cmd_stack, "$src"); # # dest push(@cmd_stack, "$dest"); print_cmd(@cmd_stack); if (0 == $test) { # join is Michael Ashley's fix for some filter/space problems my $result = system(join(' ', @cmd_stack)); if ($result != 0) { # bitmask return value my $retval = get_retval($result); # a partial list of rsync exit values # 0 Success # 23 Partial transfer due to error # 24 Partial transfer due to vanished source files if (23 == $retval) { print_warn ("Some files and/or directories in $src only transferred partially during rsync_cleanup_after_native_cp_al operation", 2); syslog_warn("Some files and/or directories in $src only transferred partially during rsync_cleanup_after_native_cp_al operation"); } elsif (24 == $retval) { print_warn ("Some files and/or directories in $src vanished during rsync_cleanup_after_native_cp_al operation", 2); syslog_warn("Some files and/or directories in $src vanished during rsync_cleanup_after_native_cp_al operation"); } else { # other error bail("rsync returned error $retval in rsync_cleanup_after_native_cp_al()"); } } } return (1); } # accepts a path # displays the rm command according to the config file sub display_rm_rf { my $path = shift(@_); if (!defined($path)) { bail('display_rm_rf() requires an argument'); } if (defined($config_vars{'cmd_rm'})) { print_cmd("$config_vars{'cmd_rm'} -rf $path"); } else { print_cmd("rm -rf $path"); } } # stub subroutine # calls either cmd_rm_rf() or the native perl rmtree() # returns 1 on success, 0 on failure sub rm_rf { my $path = shift(@_); my $result = 0; # make sure we were passed an argument if (!defined($path)) { return(0); } # extra bonus safety feature! # confirm that whatever we're deleting must be inside the snapshot_root if ("$path" !~ m/^$config_vars{'snapshot_root'}/o) { bail("rm_rf() tried to delete something outside of $config_vars{'snapshot_root'}! Quitting now!"); } # use the rm command if we have it if (defined($config_vars{'cmd_rm'})) { $result = cmd_rm_rf("$path"); # fall back on rmtree() } else { # remove trailing slash just in case $path =~ s/\/$//; $result = rmtree("$path", 0, 0); } return ($result); } # this is a wrapper to the "rm" program, called with the "-rf" flags. sub cmd_rm_rf { my $path = shift(@_); my $result = 0; # make sure we were passed an argument if (!defined($path)) { return(0); } if ( ! -e "$path" ) { print_err("cmd_rm_rf() needs a valid file path as an argument", 2); return (0); } # make the system call to /bin/rm $result = system( $config_vars{'cmd_rm'}, '-rf', "$path" ); if ($result != 0) { print_err("Warning! $config_vars{'cmd_rm'} failed.", 2); return (0); } return (1); } # accepts no arguments # calls the 'du' command to show rsnapshot's disk usage # exits the program with 0 for success, 1 for failure # # this subroutine isn't like a lot of the "real" ones that write to logfiles, etc. # that's why the print_* subroutines aren't used here. # sub show_disk_usage { my $intervals_str = ''; my $cmd_du = 'du'; my $du_args = '-csh'; my $dest_path = ''; my $retval; # first, make sure we have permission to see the snapshot root if ( ! -r "$config_vars{'snapshot_root'}" ) { print STDERR ("ERROR: Permission denied\n"); exit(1); } # check for 'du' program if ( defined($config_vars{'cmd_du'}) ) { # it was specified in the config file, use that version $cmd_du = $config_vars{'cmd_du'}; } # check for du args if ( defined($config_vars{'du_args'}) ) { # it this was specified in the config file, use that version $du_args = $config_vars{'du_args'}; } # are we looking in subdirectories or at files? if (defined($ARGV[1])) { $dest_path = $ARGV[1]; # consolidate multiple slashes $dest_path =~ s/\/+/\//o; if (is_directory_traversal($dest_path)) { print STDERR "ERROR: Directory traversal is not allowed\n"; exit(1); } if (is_valid_local_abs_path($dest_path)) { print STDERR "ERROR: Full paths are not allowed\n"; exit(1); } } # find the directories to look through, in order # only add them to the list if we have read permissions if (-r "$config_vars{'snapshot_root'}/") { # if we have a .sync directory, that will have the most recent files, and should be first if (-d "$config_vars{'snapshot_root'}/.sync") { if (-r "$config_vars{'snapshot_root'}/.sync") { $intervals_str .= "$config_vars{'snapshot_root'}/.sync "; } } # loop through the intervals, most recent to oldest foreach my $interval_ref (@intervals) { my $interval = $$interval_ref{'interval'}; my $max_interval_num = $$interval_ref{'number'}; for (my $i=0; $i < $max_interval_num; $i++) { if (-r "$config_vars{'snapshot_root'}/$interval.$i/$dest_path") { $intervals_str .= "$config_vars{'snapshot_root'}/$interval.$i/$dest_path "; } } } } chop($intervals_str); # if we can see any of the intervals, find out how much space they're taking up # most likely we can either see all of them or none at all if ('' ne $intervals_str) { if (defined($verbose) && ($verbose >= 3)) { print wrap_cmd("$cmd_du $du_args $intervals_str"), "\n\n"; } if (0 == $test) { $retval = system("$cmd_du $du_args $intervals_str"); if (0 == $retval) { # exit showing success exit(0); } else { # exit showing error print STDERR "Error while calling $cmd_du.\n"; print STDERR "Please make sure this version of du supports the \"$du_args\" flags.\n"; print STDERR "GNU du is recommended.\n"; exit(1); } } else { # test was successful exit(0); } } else { print STDERR ("No files or directories found\n"); exit(1); } # shouldn't happen exit(1); } # accept two args from $ARGV[1] and [2], like "daily.0" "daily.1" etc. # stick the full snapshot_root path on the beginning, and call rsnapshot-diff with these args # NOTE: since this is a read-only operation, we're not concerned with directory traversals and relative paths sub show_rsnapshot_diff { my $cmd_rsnapshot_diff = 'rsnapshot-diff'; my $retval; # this will only hold two entries, no more no less # paths_in holds the incoming arguments # args will be assigned the arguments that rsnapshot-diff will use # my @paths_in = (); my @cmd_args = (); # first, make sure we have permission to see the snapshot root if ( ! -r "$config_vars{'snapshot_root'}" ) { print STDERR ("ERROR: Permission denied\n"); exit(1); } # check for rsnapshot-diff program (falling back on $PATH) if (defined($config_vars{'cmd_rsnapshot_diff'})) { $cmd_rsnapshot_diff = $config_vars{'cmd_rsnapshot_diff'}; } # see if we even got the right number of arguments (none is OK, but 1 isn't. 2 is also OK) if (defined($ARGV[1]) && !defined($ARGV[2])) { print STDERR "Usage: rsnapshot diff [backup level|dir] [backup level|dir]\n"; exit(1); } # make this automatically pick the two lowest intervals (or .sync dir) for comparison, as the default # we actually want to specify the older directory first, since rsnapshot-diff will flip them around # anyway based on mod times. doing it this way should make both programs consistent, and cause less # surprises. if (!defined($ARGV[1]) && !defined($ARGV[2])) { # sync_first is enabled, and .sync exists if ($config_vars{'sync_first'} && (-d "$config_vars{'snapshot_root'}/.sync/")) { # interval.0 if ( -d ("$config_vars{'snapshot_root'}/" . $intervals[0]->{'interval'} . ".0" ) ) { $cmd_args[0] = "$config_vars{'snapshot_root'}/" . $intervals[0]->{'interval'} . ".0"; } # .sync $cmd_args[1] = "$config_vars{'snapshot_root'}/.sync"; # sync_first is not enabled, or .sync doesn't exist } else { # interval.1 if ( -d ("$config_vars{'snapshot_root'}/" . $intervals[0]->{'interval'} . ".1" ) ) { $cmd_args[0] = "$config_vars{'snapshot_root'}/" . $intervals[0]->{'interval'} . ".1"; } # interval.0 if ( -d ("$config_vars{'snapshot_root'}/" . $intervals[0]->{'interval'} . ".0" ) ) { $cmd_args[1] = "$config_vars{'snapshot_root'}/" . $intervals[0]->{'interval'} . ".0"; } } # if we got some command line arguments, loop through twice and figure out what they mean } else { $paths_in[0] = $ARGV[1]; # the 1st path is the 2nd cmd line argument $paths_in[1] = $ARGV[2]; # the 2nd path is the 3rd cmd line argument for (my $i=0; $i<2; $i++) { # no interval would start with ../ if (is_directory_traversal( "$paths_in[$i]" )) { $cmd_args[$i] = $paths_in[$i]; # if this directory exists locally, it must be local } elsif ( -e "$paths_in[$i]" ) { $cmd_args[$i] = $paths_in[$i]; # absolute path } elsif (is_valid_local_abs_path( "$paths_in[$i]" )) { $cmd_args[$i] = $paths_in[$i]; # we didn't find it locally, but it's in the snapshot root } elsif ( -e "$config_vars{'snapshot_root'}/$paths_in[$i]" ) { $cmd_args[$i] = "$config_vars{'snapshot_root'}/$paths_in[$i]"; } } } # double check to make sure the directories exists (and are directories) if ( (!defined($cmd_args[0]) or (!defined($cmd_args[1]))) or ((! -d "$cmd_args[0]") or (! -d "$cmd_args[1]")) ) { print STDERR "ERROR: Arguments must be valid backup levels or directories\n"; exit(1); } # remove trailing slashes from directories $cmd_args[0] = remove_trailing_slash($cmd_args[0]); $cmd_args[1] = remove_trailing_slash($cmd_args[1]); # increase verbosity (by possibly sticking a verbose flag in as the first argument) # # debug if ($verbose >= 5) { unshift(@cmd_args, '-V'); } elsif ($verbose >= 4) { unshift(@cmd_args, '-v'); # verbose } elsif ($verbose >= 3) { unshift(@cmd_args, '-vi'); } # run rsnapshot-diff if (defined($verbose) && ($verbose >= 3)) { print wrap_cmd(("$cmd_rsnapshot_diff " . join(' ', @cmd_args))), "\n\n"; } if (0 == $test) { $retval = system($cmd_rsnapshot_diff, @cmd_args); if (0 == $retval) { exit(0); } else { # exit showing error print STDERR "Error while calling $cmd_rsnapshot_diff\n"; exit(1); } } else { # test was successful exit(0); } # shouldn't happen exit(1); } # This subroutine works the way I hoped rsync would under certain conditions. # This is no fault of rsync, I just had something slightly different in mind :) # # This subroutine accepts two arguments, a source path and a destination path. # It traverses both recursively. # If a file is in the source, but not the destination, it is hard linked into dest # If a file is in the destination, but not the source, it is deleted # If a file is in both locations and is different, dest is unlinked and src is linked to dest # If a file is in both locations and is the same, nothing happens # # What makes this different than rsync is that it looks only at the file contents to # see if the files are different, not at the metadata such as timestamps. # I was unable to make rsync work recursively on identical files without unlinking # at the destination and using another inode for a new file with the exact same content. # # If anyone knows of a better way (that doesn't add dependencies) i'd love to hear it! # sub sync_if_different { my $src = shift(@_); my $dest = shift(@_); my $result = 0; # make sure we were passed two arguments if (!defined($src)) { return(0); } if (!defined($dest)) { return(0); } # make sure we have a source directory if ( ! -d "$src" ) { print_err("sync_if_different() needs a valid source directory as its first argument", 2); return (0); } # strip trailing slashes off the directories, # since we'll add them back on later $src = remove_trailing_slash($src); $dest = remove_trailing_slash($dest); # copy everything from src to dest # print and/or log this if necessary if (($verbose > 4) or ($loglevel > 4)) { my $cmd_string = "sync_cp_src_dest(\"$src\", \"$dest\")"; if ($verbose > 4) { print_cmd($cmd_string); } elsif ($loglevel > 4) { log_msg($cmd_string, 4); } } $result = sync_cp_src_dest("$src", "$dest"); if ( ! $result ) { print_err("Warning! sync_cp_src_dest(\"$src\", \"$dest\")", 2); return (0); } # delete everything from dest that isn't in src # print and/or log this if necessary if (($verbose > 4) or ($loglevel > 4)) { my $cmd_string = "sync_rm_dest(\"$src\", \"$dest\")"; if ($verbose > 4) { print_cmd($cmd_string); } elsif ($loglevel > 4) { log_msg($cmd_string, 4); } } $result = sync_rm_dest("$src", "$dest"); if ( ! $result ) { print_err("Warning! sync_rm_dest(\"$src\", \"$dest\")", 2); return (0); } return (1); } # accepts src, dest # "copies" everything from src to dest, mainly using hard links # called only from sync_if_different() # returns 1 on success, 0 if any failures occur sub sync_cp_src_dest { my $src = shift(@_); my $dest = shift(@_); my $dh = undef; my $result = 0; my $retval = 1; # return code for this subroutine # make sure we were passed two arguments if (!defined($src)) { return(0); } if (!defined($dest)) { return(0); } # make sure we have a source directory if ( ! -d "$src" ) { print_err("sync_if_different() needs a valid source directory as its first argument", 2); return (0); } # strip trailing slashes off the directories, # since we'll add them back on later $src = remove_trailing_slash($src); $dest = remove_trailing_slash($dest); # LSTAT SRC my $st = lstat("$src"); if (!defined($st)) { print_err("Could not lstat(\"$src\")", 2); return(0); } # MKDIR DEST (AND SET MODE) if ( ! -d "$dest" ) { # check to make sure we don't have something here that's not a directory if ( -e "$dest" ) { $result = unlink("$dest"); if (0 == $result) { print_err("Warning! Could not unlink(\"$dest\")", 2); return(0); } } # create the directory $result = mkdir("$dest", $st->mode); if ( ! $result ) { print_err("Warning! Could not mkdir(\"$dest\", $st->mode);", 2); return(0); } } # CHOWN DEST (if root) if (0 == $<) { # make sure destination is not a symlink (should never happen because of unlink() above) if ( ! -l "$dest" ) { $result = safe_chown($st->uid, $st->gid, "$dest"); if (! $result) { print_err("Warning! Could not safe_chown(" . $st->uid . ", " . $st->gid . ", \"$dest\");", 2); return(0); } } } # copy anything different from src into dest $dh = new DirHandle( "$src" ); if (defined($dh)) { my @nodes = $dh->read(); # loop through all nodes in this dir foreach my $node (@nodes) { # skip '.' and '..' next if ($node =~ m/^\.\.?$/o); # if it's a symlink, create the link # this check must be done before dir and file because it will # pretend to be a file or a directory as well as a symlink if ( -l "$src/$node" ) { # nuke whatever is in the destination, since we'd have to recreate the symlink anyway # and a real file or directory will be in our way # symlinks pretend to be directories, which is why we check it the way that we do if ( -e "$dest/$node" ) { if ((-l "$dest/$node") or (! -d "$dest/$node")) { $result = unlink("$dest/$node"); if (0 == $result) { print_err("Warning! Could not unlink(\"$dest/$node\")", 2); next; } # nuke the destination directory } else { $result = rm_rf("$dest/$node"); if (0 == $result) { print_err("Could not rm_rf(\"$dest/$node\")", 2); next; } } } $result = copy_symlink("$src/$node", "$dest/$node"); if (0 == $result) { print_err("Warning! copy_symlink(\"$src/$node\", \"$dest/$node\") failed", 2); return(0); } # if it's a directory, recurse! } elsif ( -d "$src/$node" ) { # if the destination exists but isn't a directory, delete it if (-e "$dest/$node") { # a symlink might claim to be a directory, so check for that first if ((-l "$dest/$node") or (! -d "$dest/$node")) { $result = unlink("$dest/$node"); if (0 == $result) { print_err("Warning! unlink(\"$dest/$node\") failed", 2); next; } } } # ok, dest is a real directory or it isn't there yet, go recurse $result = sync_cp_src_dest("$src/$node", "$dest/$node"); if (! $result) { print_err("Warning! Recursion error in sync_cp_src_dest(\"$src/$node\", \"$dest/$node\")", 2); } # if it's a file... } elsif ( -f "$src/$node" ) { # if dest is a symlink, we need to remove it first if ( -l "$dest/$node" ) { $result = unlink("$dest/$node"); if (0 == $result) { print_err("Warning! unlink(\"$dest/$node\") failed", 2); next; } } # if dest is a directory, we need to wipe it out first if ( -d "$dest/$node" ) { $result = rm_rf("$dest/$node"); if (0 == $result) { print_err("Could not rm_rf(\"$dest/$node\")", 2); return(0); } } # if dest (still) exists, check for differences if ( -e "$dest/$node" ) { # if they are different, unlink dest and link src to dest if (1 == file_diff("$src/$node", "$dest/$node")) { $result = unlink("$dest/$node"); if (0 == $result) { print_err("Warning! unlink(\"$dest/$node\") failed", 2); next; } $result = link("$src/$node", "$dest/$node"); if (0 == $result) { print_err("Warning! link(\"$src/$node\", \"$dest/$node\") failed", 2); next; } # if they are the same, just leave dest alone } else { next; } # ok, dest doesn't exist. just link src to dest } else { $result = link("$src/$node", "$dest/$node"); if (0 == $result) { print_err("Warning! link(\"$src/$node\", \"$dest/$node\") failed", 2); } } # FIFO } elsif ( -p "$src/$node" ) { print_err("Warning! Ignoring FIFO $src/$node", 2); # SOCKET } elsif ( -S "$src/$node" ) { print_err("Warning! Ignoring socket: $src/$node", 2); # BLOCK DEVICE } elsif ( -b "$src/$node" ) { print_err("Warning! Ignoring special block file: $src/$node", 2); # CHAR DEVICE } elsif ( -c "$src/$node" ) { print_err("Warning! Ignoring special character file: $src/$node", 2); } } } # close open dir handle if (defined($dh)) { $dh->close(); } undef( $dh ); return (1); } # accepts src, dest # deletes everything from dest that isn't in src also # called only from sync_if_different() sub sync_rm_dest { my $src = shift(@_); my $dest = shift(@_); my $dh = undef; my $result = 0; # make sure we were passed two arguments if (!defined($src)) { return(0); } if (!defined($dest)) { return(0); } # make sure we have a source directory if ( ! -d "$src" ) { print_err("sync_rm_dest() needs a valid source directory as its first argument", 2); return (0); } # make sure we have a destination directory if ( ! -d "$dest" ) { print_err("sync_rm_dest() needs a valid destination directory as its second argument", 2); return (0); } # strip trailing slashes off the directories, # since we'll add them back on later $src = remove_trailing_slash($src); $dest = remove_trailing_slash($dest); # delete anything from dest that isn't found in src $dh = new DirHandle( "$dest" ); if (defined($dh)) { my @nodes = $dh->read(); # loop through all nodes in this dir foreach my $node (@nodes) { # skip '.' and '..' next if ($node =~ m/^\.\.?$/o); # if this node isn't present in src, delete it if ( ! -e "$src/$node" ) { # file or symlink if ((-l "$dest/$node") or (! -d "$dest/$node")) { $result = unlink("$dest/$node"); if (0 == $result) { print_err("Warning! Could not delete \"$dest/$node\"", 2); next; } # directory } else { $result = rm_rf("$dest/$node"); if (0 == $result) { print_err("Warning! Could not delete \"$dest/$node\"", 2); } } next; } # ok, this also exists in src... # theoretically, sync_cp_src_dest() should have caught this already, but better safe than sorry # also, symlinks can pretend to be directories, so we have to check for those too # if src is a file but dest is a directory, we need to recursively remove the dest dir if ((-l "$src/$node") or (! -d "$src/$node")) { if (-d "$dest/$node") { $result = rm_rf("$dest/$node"); if (0 == $result) { print_err("Warning! Could not delete \"$dest/$node\"", 2); } } # otherwise, if src is a directory, but dest is a file, remove the file in dest } elsif (-d "$src/$node") { if ((-l "$dest/$node") or (! -d "$dest/$node")) { $result = unlink("$dest/$node"); if (0 == $result) { print_err("Warning! Could not delete \"$dest/$node\"", 2); next; } } } # if it's a directory in src, let's recurse into it and compare files there if ( -d "$src/$node" ) { $result = sync_rm_dest("$src/$node", "$dest/$node"); if ( ! $result ) { print_err("Warning! Recursion error in sync_rm_dest(\"$src/$node\", \"$dest/$node\")", 2); } } } } # close open dir handle if (defined($dh)) { $dh->close(); } undef( $dh ); return (1); } # accepts src, dest # "copies" a symlink from src by recreating it in dest # returns 1 on success, 0 on failure sub copy_symlink { my $src = shift(@_); my $dest = shift(@_); my $st = undef; my $result = undef; my $link_deref_path = undef; # make sure it's actually a symlink if ( ! -l "$src" ) { print_err("Warning! \"$src\" not a symlink in copy_symlink()", 2); return (0); } # make sure we aren't clobbering the destination if ( -e "$dest" ) { print_err("Warning! \"$dest\" exists!", 2); return (0); } # LSTAT $st = lstat("$src"); if (!defined($st)) { print_err("Warning! lstat(\"$src\") failed", 2); return (0); } # CREATE THE SYMLINK # This is done in two steps: # Reading/dereferencing the link, and creating a new one # # Step 1: READ THE LINK if (($verbose > 4) or ($loglevel > 4)) { my $cmd_string = "readlink(\"$src\")\n"; if ($verbose > 4) { print_cmd($cmd_string); } elsif ($loglevel > 4) { log_msg($cmd_string, 4); } } $link_deref_path = readlink("$src"); if (!defined($link_deref_path)) { print_err("Warning! Could not readlink(\"$src\")", 2); return (0); } # # Step 2: RECREATE THE LINK if (($verbose > 4) or ($loglevel > 4)) { my $cmd_string = "symlink(\"$link_deref_path\", \"$dest\")\n"; if ($verbose > 4) { print_cmd($cmd_string); } elsif ($loglevel > 4) { log_msg($cmd_string, 4); } } $result = symlink("$link_deref_path", "$dest"); if (0 == $result) { print_err("Warning! Could not symlink(\"$link_deref_path\"), \"$dest\")", 2); return (0); } # CHOWN DEST (if root) if (0 == $<) { # make sure the symlink even exists if ( -e "$dest" ) { # print and/or log this if necessary if (($verbose > 4) or ($loglevel > 4)) { my $cmd_string = "safe_chown(" . $st->uid . ", " . $st->gid . ", \"$dest\");"; if ($verbose > 4) { print_cmd($cmd_string); } elsif ($loglevel > 4) { log_msg($cmd_string, 4); } } $result = safe_chown($st->uid, $st->gid, "$dest"); if (0 == $result) { print_err("Warning! Could not safe_chown(" . $st->uid . ", " . $st->gid . ", \"$dest\")", 2); return (0); } } } return (1); } # accepts a file permission number from $st->mode (e.g., 33188) # returns a "normal" file permission number (e.g., 644) # do the appropriate bit shifting to get a "normal" UNIX file permission mode sub get_perms { my $raw_mode = shift(@_); if (!defined($raw_mode)) { return (undef); } # a lot of voodoo for just one line # http://www.perlmonks.org/index.pl?node_id=159906 my $mode = sprintf("%04o", ($raw_mode & 07777)); return ($mode); } # accepts return value from the system() command # bitmasks it, and returns the same thing "echo $?" would from the shell sub get_retval { my $retval = shift(@_); if (!defined($retval)) { bail('get_retval() was not passed a value'); } if ($retval !~ m/^\d+$/) { bail("get_retval() was passed $retval, a number is required"); } return ($retval / 256); } # accepts two file paths # returns 0 if they're the same, 1 if they're different # returns undef if one or both of the files can't be found, opened, or closed sub file_diff { my $file1 = shift(@_); my $file2 = shift(@_); my $st1 = undef; my $st2 = undef; my $buf1 = undef; my $buf2 = undef; my $result = undef; # number of bytes to read at once my $BUFSIZE = 16384; # boolean file comparison flag. assume they're the same. my $is_different = 0; if (! -r "$file1") { return (undef); } if (! -r "$file2") { return (undef); } # CHECK FILE SIZES FIRST $st1 = lstat("$file1"); $st2 = lstat("$file2"); if (!defined($st1)) { return (undef); } if (!defined($st2)) { return (undef); } # if the files aren't even the same size, they can't possibly be the same. # don't waste time comparing them more intensively if ($st1->size != $st2->size) { return (1); } # ok, we're still here. # that means we have to compare files one chunk at a time # open both files $result = open(FILE1, "$file1"); if (!defined($result)) { return (undef); } $result = open(FILE2, "$file2"); if (!defined($result)) { close(FILE1); return (undef); } # compare files while (read(FILE1, $buf1, $BUFSIZE) && read(FILE2, $buf2, $BUFSIZE)) { # exit this loop as soon as possible if ($buf1 ne $buf2) { $is_different = 1; last; } } # close both files $result = close(FILE2); if (!defined($result)) { close(FILE1); return (undef); } $result = close(FILE1); if (!defined($result)) { return (undef); } # return our findings return ($is_different); } # accepts src, dest (file paths) # calls rename(), forcing the mtime to be correct (to work around a bug in rare versions of the Linux 2.4 kernel) # returns 1 on success, 0 on failure, just like the real rename() command sub safe_rename { my $src = shift(@_); my $dest = shift(@_); my $st; my $retval; my $result; # validate src and dest paths if (!defined($src)) { print_err("safe_rename() needs a valid source file path as an argument", 2); return (0); } if (!defined($dest)) { print_err("safe_rename() needs a valid destination file path as an argument", 2); return (0); } # stat file before rename $st = stat($src); if (!defined($st)) { print_err("Could not stat() \"$src\"", 2); return (0); } # rename the file $retval = rename( "$src", "$dest" ); if (1 != $retval) { print_err("Could not rename(\"$src\", \"$dest\")", 2); return (0); } # give it back the old mtime and atime values $result = utime( $st->atime, $st->mtime, "$dest" ); if (!defined($result)) { print_err("Could not utime( $st->atime, $st->mtime, \"$dest\")", 2); return (0); } # if we made it this far, it must have worked return (1); } # accepts no args # checks the config file for version number # prints the config version to stdout # exits the program, 0 on success, 1 on failure # this feature is "undocumented", for use with scripts, etc sub check_config_version { my $version = get_config_version(); if (!defined($version)) { print "error\n"; exit(1); } print $version, "\n"; exit(0); } # accepts no args # scans the config file for the config_version parameter # returns the config version, or undef sub get_config_version { my $result; my $version; # make sure the config file exists and we can read it if (!defined($config_file)) { return (undef); } if (! -r "$config_file") { return (undef); } # open the config file $result = open(CONFIG, "$config_file"); if (!defined($result)) { return (undef); } # scan the config file looking for the config_version parameter # if we find it, exit the loop while (my $line = ) { chomp($line); if ($line =~ m/^config_version/o) { if ($line =~ m/^config_version\t+([\d\.\-\w]+)$/o) { $version = $1; last; } else { $version = 'undefined'; } } } $result = close(CONFIG); if (!defined($result)) { return (undef); } if (!defined($version)) { $version = 'unknown'; } return ($version); } # accepts no args # exits the program, 0 on success, 1 on failure # attempts to upgrade the rsnapshot.conf file for compatibility with this version sub upgrade_config_file { my $result; my @lines; my $config_version; # check if rsync_long_args is already enabled my $rsync_long_args_enabled = 0; # first, see if the file isn't already up to date $config_version = get_config_version(); if (!defined($config_version)) { print STDERR "ERROR: Could not read config file during version check.\n"; exit(1); } # right now 1.2 is the only valid version if ('1.2' eq $config_version) { print "$config_file file is already up to date.\n"; exit(0); # config_version is set, but not to anything we know about } elsif ('unknown' eq $config_version) { # this is good, it means the config_version was not already set to anything # and is a good candidate for the upgrade } else { print STDERR "ERROR: config_version is set to unknown version: $config_version.\n"; exit(1); } # make sure config file is present and readable if (!defined($config_file)) { print STDERR "ERROR: Config file not defined.\n"; exit(1); } if (! -r "$config_file") { print STDERR "ERROR: $config_file not readable.\n"; exit(1); } # read in original config file $result = open(CONFIG, "$config_file"); if (!defined($result)) { print STDERR "ERROR: Could not open $config_file for reading.\n"; exit(1); } @lines = ; $result = close(CONFIG); if (!defined($result)) { print STDERR "ERROR: Could not close $config_file after reading.\n"; exit(1); } # see if we can find rsync_long_args, either commented out or uncommented foreach my $line (@lines) { if ($line =~ m/^rsync_long_args/o) { $rsync_long_args_enabled = 1; } } # back up old config file backup_config_file(\@lines); # found rsync_long_args enabled if ($rsync_long_args_enabled) { print "Found \"rsync_long_args\" uncommented. Attempting upgrade...\n"; write_upgraded_config_file(\@lines, 0); # did not find rsync_long_args enabled } else { print "Could not find old \"rsync_long_args\" parameter. Attempting upgrade...\n"; write_upgraded_config_file(\@lines, 1); } print "\"$config_file\" was successfully upgraded.\n"; exit(0); } # accepts array_ref of config file lines # exits 1 on errors # attempts to backup rsnapshot.conf to rsnapshot.conf.backup.(#) sub backup_config_file { my $lines_ref = shift(@_); my $result; my $backup_config_file; my $backup_exists = 0; if (!defined($lines_ref)) { print STDERR "ERROR: backup_config_file() was not passed an argument.\n"; exit(1); } if (!defined($config_file)) { print STDERR "ERROR: Could not find config file.\n"; exit(1); } $backup_config_file = "$config_file.backup"; print "Backing up \"$config_file\".\n"; # pick a unique name for the backup file if ( -e "$backup_config_file" ) { $backup_exists = 1; for (my $i=0; $i<100; $i++) { if ( ! -e "$backup_config_file.$i" ) { $backup_config_file = "$backup_config_file.$i"; $backup_exists = 0; last; } } # if we couldn't write a backup file, exit with an error if (1 == $backup_exists) { print STDERR "ERROR: Refusing to overwrite $backup_config_file.\n"; print STDERR "Please move $backup_config_file out of the way and try again.\n"; print STDERR "$config_file has NOT been upgraded!\n"; exit(1); } } $result = open(OUTFILE, "> $backup_config_file"); if (!defined($result) or ($result != 1)) { print STDERR "Error opening $backup_config_file for writing.\n"; print STDERR "$config_file has NOT been upgraded!\n"; exit(1); } foreach my $line (@$lines_ref) { print OUTFILE $line; } $result = close(OUTFILE); if (!defined($result) or (1 != $result)) { print STDERR "could not cleanly close $backup_config_file.\n"; print STDERR "$config_file has NOT been upgraded!\n"; exit(1); } print "Config file was backed up to \"$backup_config_file\".\n"; } # accepts no args # exits 1 on errors # attempts to write an upgraded config file to rsnapshot.conf sub write_upgraded_config_file { my $lines_ref = shift(@_); my $add_rsync_long_args = shift(@_); my $result; my $upgrade_notice = ''; $upgrade_notice .= "#-----------------------------------------------------------------------------\n"; $upgrade_notice .= "# UPGRADE NOTICE:\n"; $upgrade_notice .= "#\n"; $upgrade_notice .= "# This file was upgraded automatically by rsnapshot.\n"; $upgrade_notice .= "#\n"; $upgrade_notice .= "# The \"config_version\" parameter was added, since it is now required.\n"; $upgrade_notice .= "#\n"; $upgrade_notice .= "# The default value for \"rsync_long_args\" has changed in this release.\n"; $upgrade_notice .= "# By explicitly setting it to the old default values, rsnapshot will still\n"; $upgrade_notice .= "# behave like it did in previous versions.\n"; $upgrade_notice .= "#\n"; if (defined($add_rsync_long_args) && (1 == $add_rsync_long_args)) { $upgrade_notice .= "# In this file, \"rsync_long_args\" was not enabled before the upgrade,\n"; $upgrade_notice .= "# so it has been set to the old default value.\n"; } else { $upgrade_notice .= "# In this file, \"rsync_long_args\" was already enabled before the upgrade,\n"; $upgrade_notice .= "# so it was not changed.\n"; } $upgrade_notice .= "#\n"; $upgrade_notice .= "# New features and improvements have been added to rsnapshot that can\n"; $upgrade_notice .= "# only be fully utilized by making some additional changes to\n"; $upgrade_notice .= "# \"rsync_long_args\" and your \"backup\" points. If you would like to get the\n"; $upgrade_notice .= "# most out of rsnapshot, please read the INSTALL file that came with this\n"; $upgrade_notice .= "# program for more information.\n"; $upgrade_notice .= "#-----------------------------------------------------------------------------\n"; if (!defined($config_file)) { print STDERR "ERROR: Config file not found.\n"; exit(1); } if (! -w "$config_file") { print STDERR "ERROR: \"$config_file\" is not writable.\n"; exit(1); } $result = open(CONFIG, "> $config_file"); if (!defined($result)) { print "ERROR: Could not open \"$config_file\" for writing.\n"; exit(1); } print CONFIG $upgrade_notice; print CONFIG "\n"; print CONFIG "config_version\t1.2\n"; print CONFIG "\n"; if (defined($add_rsync_long_args) && (1 == $add_rsync_long_args)) { print CONFIG "rsync_long_args\t--delete --numeric-ids\n"; print CONFIG "\n"; } foreach my $line (@$lines_ref) { print CONFIG "$line"; } $result = close(CONFIG); if (!defined($result)) { print STDERR "ERROR: Could not close \"$config_file\" after writing\n."; exit(1); } } # accepts no arguments # dynamically loads the CPAN Lchown module, if available # sets the global variable $have_lchown sub use_lchown { if ($verbose >= 5) { print_msg('require Lchown', 5); } eval { require Lchown; }; if ($@) { $have_lchown = 0; if ($verbose >= 5) { print_msg('Lchown module not found', 5); } return(0); } # if it loaded, see if this OS supports the lchown() system call { no strict 'subs'; if (defined(Lchown) && defined(Lchown::LCHOWN_AVAILABLE)) { if (1 == Lchown::LCHOWN_AVAILABLE()) { $have_lchown = 1; if ($verbose >= 5) { print_msg('Lchown module loaded successfully', 5); } return(1); } } } if ($verbose >= 5) { print_msg("Lchown module loaded, but operating system doesn't support lchown()", 5); } return(0); } # accepts uid, gid, filepath # uses lchown() to change ownership of the file, if possible # returns 1 upon success (or if lchown() not present) # returns 0 on failure sub safe_chown { my $uid = shift(@_); my $gid = shift(@_); my $filepath = shift(@_); my $result = undef; if (!defined($uid) or !defined($gid) or !defined($filepath)) { print_err("safe_chown() needs uid, gid, and filepath", 2); return(0); } if ( ! -e "$filepath" ) { print_err("safe_chown() needs a valid filepath (not \"$filepath\")", 2); return(0); } # if it's a symlink, use lchown() or skip it if (-l "$filepath") { # use Lchown if (1 == $have_lchown) { $result = Lchown::lchown($uid, $gid, "$filepath"); if (!defined($result)) { return (0); } # we can't safely do anything here, skip it } else { raise_warning(); if ($verbose > 2) { print_warn("Could not lchown() symlink \"$filepath\"", 2); } elsif ($loglevel > 2) { log_warn("Could not lchown() symlink \"$filepath\"", 2); } # we'll still return 1 at the bottom, because we did as well as we could # the warning raised will tell the user what happened } # if it's not a symlink, use chown() } else { $result = chown($uid, $gid, "$filepath"); if (! $result) { return (0); } } return (1); } ######################################## ### PERLDOC / POD ### ######################################## =pod =head1 NAME rsnapshot - remote filesystem snapshot utility =head1 SYNOPSIS B [B<-vtxqVD>] [B<-c> cfgfile] [command] [args] =head1 DESCRIPTION B is a filesystem snapshot utility. It can take incremental snapshots of local and remote filesystems for any number of machines. Local filesystem snapshots are handled with B. Secure remote connections are handled with rsync over B, while anonymous rsync connections simply use an rsync server. Both remote and local transfers depend on rsync. B saves much more disk space than you might imagine. The amount of space required is roughly the size of one full backup, plus a copy of each additional file that is changed. B makes extensive use of hard links, so if the file doesn't change, the next snapshot is simply a hard link to the exact same file. B will typically be invoked as root by a cron job, or series of cron jobs. It is possible, however, to run as any arbitrary user with an alternate configuration file. All important options are specified in a configuration file, which is located by default at B. An alternate file can be specified on the command line. There are also additional options which can be passed on the command line. The command line options are as follows: =over 4 B<-v> verbose, show shell commands being executed B<-t> test, show shell commands that would be executed B<-c> path to alternate config file B<-x> one filesystem, don't cross partitions within each backup point B<-q> quiet, suppress non-fatal warnings B<-V> same as -v, but with more detail B<-D> a firehose of diagnostic information =back =head1 CONFIGURATION B is the default configuration file. All parameters in this file must be separated by tabs. B can be used as a reference. It is recommended that you copy B to B, and then modify B to suit your needs. Long lines may be split over several lines. "Continuation" lines B begin with a space or a tab character. Continuation lines will have all leading and trailing whitespace stripped off, and then be appended with an intervening tab character to the previous line when the configuation file is parsed. Here is a list of allowed parameters: =over 4 B Config file version (required). Default is 1.2 B Local filesystem path to save all snapshots B Include another file in the configuration at this point. =over 4 This is recursive, but you may need to be careful about paths when specifying which file to include. We check to see if the file you have specified is readable, and will yell an error if it isn't. We recommend using a full path. As a special case, include_conf's value may be enclosed in `backticks` in which case it will be executed and whatever it spits to STDOUT will be included in the configuration. Note that shell meta-characters may be interpreted. =back B If set to 1, rsnapshot won't create snapshot_root directory B Full path to rsync (required) B Full path to ssh (optional) B Full path to cp (optional, but must be GNU version) =over 4 If you are using Linux, you should uncomment cmd_cp. If you are using a platform which does not have GNU cp, you should leave cmd_cp commented out. With GNU cp, rsnapshot can take care of both normal files and special files (such as FIFOs, sockets, and block/character devices) in one pass. If cmd_cp is disabled, rsnapshot will use its own built-in function, native_cp_al() to backup up regular files and directories. This will then be followed up by a separate call to rsync, to move the special files over (assuming there are any). =back B Full path to rm (optional) B Full path to logger (optional, for syslog support) B Full path to du (optional, for disk usage reports) B Full path to rsnapshot-diff (optional) B =over 4 Full path (plus any arguments) to preexec script (optional). This script will run immediately before each backup operation (but not any rotations). =back B =over 4 Full path (plus any arguments) to postexec script (optional). This script will run immediately after each backup operation (but not any rotations). =back B B B B =over 4 Paths to lvcreate, lvremove, mount and umount commands, for use with Linux LVMs. The lvcreate, lvremove, mount and umount commands are required for managing snapshots of LVM volumes and are otherwise optional. =back B [name] [number] =over 4 "name" refers to the name of this backup level (e.g., hourly, daily, so also called the 'interval'). "number" is the number of snapshots for this type of interval that will be retained. The value of "name" will be the command passed to B to perform this type of backup. A deprecated alias for 'retain' is 'interval'. Example: B [root@localhost]# B For this example, every time this is run, the following will happen: /hourly.5/ will be deleted, if it exists. /hourly.{1,2,3,4} will all be rotated +1, if they exist. /hourly.0/ will be copied to /hourly.1/ using hard links. Each backup point (explained below) will then be rsynced to the corresponding directories in /hourly.0/ Backup levels must be specified in the config file in order, from most frequent to least frequent. The first entry is the one which will be synced with the backup points. The subsequent backup levels (e.g., daily, weekly, etc) simply rotate, with each higher backup level pulling from the one below it for its .0 directory. Example: =over 4 B B B =back daily.0/ will be copied from hourly.5/, and weekly.0/ will be copied from daily.6/ hourly.0/ will be rsynced directly from the filesystem. =back B =over 4 If your version of rsync supports --link-dest (2.5.7 or newer), you can enable this to let rsync handle some things that GNU cp or the built-in subroutines would otherwise do. Enabling this makes rsnapshot take a slightly more complicated code branch, but it's the best way to support special files on non-Linux systems. =back B =over 4 sync_first changes the behaviour of rsnapshot. When this is enabled, all calls to rsnapshot with various backup levels simply rotate files. All backups are handled by calling rsnapshot with the "sync" argument. The synced files are stored in a ".sync" directory under the snapshot_root. This allows better recovery in the event that rsnapshot is interrupted in the middle of a sync operation, since the sync step and rotation steps are separated. This also means that you can easily run "rsnapshot sync" on the command line without fear of forcing all the other directories to rotate up. This benefit comes at the cost of one more snapshot worth of disk space. The default is 0 (off). =back B =over 4 The amount of information to print out when the program is run. Allowed values are 1 through 5. The default is 2. 1 Quiet Show fatal errors only 2 Default Show warnings and errors 3 Verbose Show equivalent shell commands being executed 4 Extra Verbose Same as verbose, but with more detail 5 Debug All kinds of information =back B =over 4 This number means the same thing as B above, but it determines how much data is written to the logfile, if one is being written. The only thing missing from this at the higher levels is the direct output from rsync. We hope to add support for this in a future release. =back B =over 4 Full filesystem path to the rsnapshot log file. If this is defined, a log file will be written, with the amount of data being controlled by B. If this is commented out, no log file will be written. =back B =over 4 This gets passed directly to rsync using the --include directive. This parameter can be specified as many times as needed, with one pattern defined per line. See the rsync(1) man page for the syntax. =back B =over 4 This gets passed directly to rsync using the --exclude directive. This parameter can be specified as many times as needed, with one pattern defined per line. See the rsync(1) man page for the syntax. =back B =over 4 This gets passed directly to rsync using the --include-from directive. See the rsync(1) man page for the syntax. =back B =over 4 This gets passed directly to rsync using the --exclude-from directive. See the rsync(1) man page for the syntax. =back B =over 4 List of short arguments to pass to rsync. If not specified, "-a" is the default. Please note that these must be all next to each other. For example, "-az" is valid, while "-a -z" is not. "-a" is rsync's "archive mode" which tells it to copy as much of the filesystem metadata as it can for each file. This specifically does *not* include information about hard links, as that would greatly increase rsync's memory usage and slow it down. If you need to preserve hard links in your backups, then add "H" to this. =back B =over 4 List of long arguments to pass to rsync. Beginning with rsnapshot 1.2.0, this default has changed. In previous versions, the default values were --delete --numeric-ids Starting with version 1.2.0, the default values are --delete --numeric-ids --relative --delete-excluded This directly affects how the destination paths in your backup points are constructed. Depending on what behaviour you want, you can explicitly set the values to make the program behave like the old version or the current version. The newer settings are recommended if you're just starting. If you are upgrading, read the upgrade guide in the INSTALL file in the source distribution for more information. Quotes are permitted in rsync_long_args, eg --rsync-path="sudo /usr/bin/rsync". You may use either single (') or double (") quotes, but nested quotes (including mixed nested quotes) are not permitted. Similar quoting is also allowed in per-backup-point rsync_long_args. =back B =over 4 Arguments to be passed to ssh. If not specified, the default is none. =back B =over 4 Arguments to be passed to du. If not specified, the default is -csh. GNU du supports -csh, BSD du supports -csk, Solaris du doesn't support -c at all. The GNU version is recommended, since it offers the most features. =back B B =over 4 Lockfile to use when rsnapshot is run. This prevents a second invocation from clobbering the first one. If not specified, no lock file is used. Make sure to use a directory that is not world writeable for security reasons. Use of a lock file is strongly recommended. If a lockfile exists when rsnapshot starts, it will try to read the file and stop with an error if it can't. If it *can* read the file, it sees if a process exists with the PID noted in the file. If it does, rsnapshot stops with an error message. If there is no process with that PID, then we assume that the lockfile is stale and ignore it *unless* stop_on_stale_lockfile is set to 1 in which case we stop. stop_on_stale_lockfile defaults to 0. =back B =over 4 Prevents rsync from crossing filesystem partitions. Setting this to a value of 1 enables this feature. 0 turns it off. This parameter is optional. The default is 0 (off). =back B =over 4 Changes default behavior of rsnapshot and does not initially remove the oldest snapshot. Instead it moves that directory to _delete.[processid] and continues as normal. Once the backup has been completed, the lockfile will be removed before rsnapshot starts deleting the directory. Enabling this means that snapshots get taken sooner (since the delete doesn't come first), and any other rsnapshot processes are allowed to start while the final delete is happening. This benefit comes at the cost of using more disk space. The default is 0 (off). The details of how this works have changed in rsnapshot version 1.3.1. Originally you could only ever have one .delete directory per backup level. Now you can have many, so if your next (eg) hourly backup kicks off while the previous one is still doing a lazy delete you may temporarily have extra _delete directories hanging around. =back B =over 4 LVM snapshot(s) size (lvcreate --size option). =back B =over 4 Name to be used when creating the LVM logical volume snapshot(s) (lvcreate --name option). =back B =over 4 Path to the LVM Volume Groups. =back B =over 4 Mount point to use to temporarily mount the snapshot(s). =back B =over 4 If you have used an older version of rsnapshot, you might notice that the destination paths on the backup points have changed. Please read the INSTALL file in the source distribution for upgrade options. =back B /etc/ localhost/ B root@example.com:/etc/ example.com/ B rsync://example.com/path2/ example.com/ B /var/ localhost/ one_fs=1 B lvm://vg0/home/path2/ lvm-vg0/ B /usr/local/bin/backup_pgsql.sh pgsql_backup/ =over 4 Examples: B =over 4 Backs up /etc/ to /.0/localhost/etc/ using rsync on the local filesystem =back B =over 4 Backs up /usr/local/ to /.0/localhost/usr/local/ using rsync on the local filesystem =back B =over 4 Backs up root@example.com:/etc/ to /.0/example.com/etc/ using rsync over ssh =back B =over 4 Backs up root@example.com:/usr/local/ to /.0/example.com/usr/local/ using rsync over ssh =back B =over 4 Backs up rsync://example.com/pub/ to /.0/example.com/pub/ using an anonymous rsync server. Please note that unlike backing up local paths and using rsync over ssh, rsync servers have "modules", which are top level directories that are exported. Therefore, the module should also be specified in the destination path, as shown in the example above (the pub/ directory at the end). =back B =over 4 This is the same as the other examples, but notice the fourth column. This is how you specify per-backup-point options to over-ride global settings. This extra parameter can take several options, separated by B. It is most useful when specifying per-backup rsync excludes thus: B Note the + sign. That tells rsnapshot to I to the list of arguments to pass to rsync instead of replacing the list. =back B =over 4 Backs up the LVM logical volume called home, of volume group vg0, to /.0/lvm-vg0/. Will create, mount, backup, unmount and remove an LVM snapshot for each lvm:// entry. =back B =over 4 In this example, we specify a script or program to run. This script should simply create files and/or directories in its current working directory. rsnapshot will then take that output and move it into the directory specified in the third column. Please note that whatever is in the destination directory will be completely deleted and recreated. For this reason, rsnapshot prevents you from specifying a destination directory for a backup_script that will clobber other backups. So in this example, say the backup_database.sh script simply runs a command like: =over 4 #!/bin/sh mysqldump -uusername mydatabase > mydatabase.sql chmod u=r,go= mydatabase.sql # r-------- (0400) =back rsnapshot will take the generated "mydatabase.sql" file and move it into the /.0/db_backup/ directory. On subsequent runs, rsnapshot checks the differences between the files created against the previous files. If the backup script generates the same output on the next run, the files will be hard linked against the previous ones, and no additional disk space will be taken up. =back =back Remember that tabs must separate all elements, and that there must be a trailing slash on the end of every directory. A hash mark (#) on the beginning of a line is treated as a comment. Putting it all together (an example file): =over 4 # THIS IS A COMMENT, REMEMBER TABS MUST SEPARATE ALL ELEMENTS config_version 1.2 snapshot_root /.snapshots/ cmd_rsync /usr/bin/rsync cmd_ssh /usr/bin/ssh #cmd_cp /bin/cp cmd_rm /bin/rm cmd_logger /usr/bin/logger cmd_du /usr/bin/du linux_lvm_cmd_lvcreate /sbin/lvcreate linux_lvm_cmd_lvremove /sbin/lvremove linux_lvm_cmd_mount /bin/mount linux_lvm_cmd_umount /bin/umount linux_lvm_snapshotsize 2G linux_lvm_snapshotname rsnapshot linux_lvm_vgpath /dev linux_lvm_mountpath /mnt/lvm-snapshot retain hourly 6 retain daily 7 retain weekly 7 retain monthly 3 backup /etc/ localhost/ backup /home/ localhost/ backup_script /usr/local/bin/backup_mysql.sh mysql_backup/ backup root@foo.com:/etc/ foo.com/ backup root@foo.com:/home/ foo.com/ backup root@mail.foo.com:/home/ mail.foo.com/ backup rsync://example.com/pub/ example.com/pub/ backup lvm://vg0/xen-home/ lvm-vg0/xen-home/ =back =head1 USAGE B can be used by any user, but for system-wide backups you will probably want to run it as root. Since backups usually get neglected if human intervention is required, the preferred way is to run it from cron. When you are first setting up your backups, you will probably also want to run it from the command line once or twice to get a feel for what it's doing. Here is an example crontab entry, assuming that backup levels B, B, B and B have been defined in B =over 4 B<0 */4 * * * /usr/local/bin/rsnapshot hourly> B<50 23 * * * /usr/local/bin/rsnapshot daily> B<40 23 * * 6 /usr/local/bin/rsnapshot weekly> B<30 23 1 * * /usr/local/bin/rsnapshot monthly> =back This example will do the following: =over 4 6 hourly backups a day (once every 4 hours, at 0,4,8,12,16,20) 1 daily backup every day, at 11:50PM 1 weekly backup every week, at 11:40PM, on Saturdays (6th day of week) 1 monthly backup every month, at 11:30PM on the 1st day of the month =back It is usually a good idea to schedule the larger backup levels to run a bit before the lower ones. For example, in the crontab above, notice that "daily" runs 10 minutes before "hourly". The main reason for this is that the daily rotate will pull out the oldest hourly and make that the youngest daily (which means that the next hourly rotate will not need to delete the oldest hourly), which is more efficient. A secondary reason is that it is harder to predict how long the lowest backup level will take, since it needs to actually do an rsync of the source as well as the rotate that all backups do. If rsnapshot takes longer than 10 minutes to do the "daily" rotate (which usually includes deleting the oldest daily snapshot), then you should increase the time between the backup levels. Otherwise (assuming you have set the B parameter, as is recommended) your hourly snapshot will fail sometimes because the daily still has the lock. Remember that these are just the times that the program runs. To set the number of backups stored, set the B numbers in B To check the disk space used by rsnapshot, you can call it with the "du" argument. For example: =over 4 B =back This will show you exactly how much disk space is taken up in the snapshot root. This feature requires the UNIX B command to be installed on your system, for it to support the "-csh" command line arguments, and to be in your path. You can also override your path settings and the flags passed to du using the cmd_du and du_args parameters. It is also possible to pass a relative file path as a second argument, to get a report on a particular file or subdirectory. =over 4 B =back The GNU version of "du" is preferred. The BSD version works well also, but does not support the -h flag (use -k instead, to see the totals in kilobytes). Other versions of "du", such as Solaris, may not work at all. To check the differences between two directories, call rsnapshot with the "diff" argument, followed by two backup levels or directory paths. For example: =over 4 B B B =back This will call the rsnapshot-diff program, which will scan both directories looking for differences (based on hard links). B =over 4 When B is enabled, rsnapshot must first be called with the B argument, followed by the other usual cron entries. The sync should happen as the lowest, most frequent backup level, and right before. For example: =over 4 B<0 */4 * * * /usr/local/bin/rsnapshot sync && /usr/local/bin/rsnapshot hourly> B<50 23 * * * /usr/local/bin/rsnapshot daily> B<40 23 1,8,15,22 * * /usr/local/bin/rsnapshot weekly> B<30 23 1 * * /usr/local/bin/rsnapshot monthly> =back The sync operation simply runs rsync and all backup scripts. In this scenario, all calls simply rotate directories, even the lowest backup level. =back B =over 4 When B is enabled, all sync behaviour happens during an additional sync step (see above). When using the sync argument, it is also possible to specify a backup point destination as an optional parameter. If this is done, only backup points sharing that destination path will be synced. For example, let's say that example.com is a destination path shared by one or more of your backup points. =over 4 rsnapshot sync example.com =back This command will only sync the files that normally get backed up into example.com. It will NOT get any other backup points with slightly different values (like example.com/etc/, for example). In order to sync example.com/etc, you would need to run rsnapshot again, using example.com/etc as the optional parameter. =back =head1 EXIT VALUES =over 4 B<0> All operations completed successfully B<1> A fatal error occurred B<2> Some warnings occurred, but the backup still finished =back =head1 FILES /etc/rsnapshot.conf =head1 SEE ALSO rsync(1), ssh(1), logger(1), sshd(1), ssh-keygen(1), perl(1), cp(1), du(1), crontab(1) =head1 DIAGNOSTICS Use the B<-t> flag to see what commands would have been executed. This will show you the commands rsnapshot would try to run. There are a few minor differences (for example, not showing an attempt to remove the lockfile because it wasn't really created in the test), but should give you a very good idea what will happen. Using the B<-v>, B<-V>, and B<-D> flags will print increasingly more information to STDOUT. Make sure you don't have spaces in the config file that you think are actually tabs. Much other weird behavior can probably be attributed to plain old file system permissions and ssh authentication issues. =head1 BUGS Please report bugs (and other comments) to the rsnapshot-discuss mailing list: B =head1 NOTES Make sure your /etc/rsnapshot.conf file has all elements separated by tabs. See /etc/rsnapshot.conf.default for a working example file. Make sure you put a trailing slash on the end of all directory references. If you don't, you may have extra directories created in your snapshots. For more information on how the trailing slash is handled, see the B manpage. Make sure to make the snapshot directory chmod 700 and owned by root (assuming backups are made by the root user). If the snapshot directory is readable by other users, they will be able to modify the snapshots containing their files, thus destroying the integrity of the snapshots. If you would like regular users to be able to restore their own backups, there are a number of ways this can be accomplished. One such scenario would be: Set B to B in B Set the file permissions on these directories as follows: =over 4 drwx------ /.private drwxr-xr-x /.private/.snapshots =back Export the /.private/.snapshots directory over read-only NFS, a read-only Samba share, etc. See the rsnapshot HOWTO for more information on making backups accessible to non-privileged users. For ssh to work unattended through cron, you will probably want to use public key logins. Create an ssh key with no passphrase for root, and install the public key on each machine you want to backup. If you are backing up system files from remote machines, this probably means unattended root logins. Another possibility is to create a second user on the machine just for backups. Give the user a different name such as "rsnapshot", but keep the UID and GID set to 0, to give root privileges. However, make logins more restrictive, either through ssh configuration, or using an alternate shell. BE CAREFUL! If the private key is obtained by an attacker, they will have free run of all the systems involved. If you are unclear on how to do this, see B, B, and B. Backup scripts are run as the same user that rsnapshot is running as. Typically this is root. Make sure that all of your backup scripts are only writable by root, and that they don't call any other programs that aren't owned by root. If you fail to do this, anyone who can write to the backup script or any program it calls can fully take over the machine. Of course, this is not a situation unique to rsnapshot. By default, rsync transfers are done using the --numeric-ids option. This means that user names and group names are ignored during transfers, but the UID/GID information is kept intact. The assumption is that the backups will be restored in the same environment they came from. Without this option, restoring backups for multiple heterogeneous servers would be unmanageable. If you are archiving snapshots with GNU tar, you may want to use the --numeric-owner parameter. Also, keep a copy of the archived system's /etc/passwd and /etc/group files handy for the UID/GID to name mapping. If you remove backup points in the config file, the previously archived files under those points will permanently stay in the snapshots directory unless you remove the files yourself. If you want to conserve disk space, you will need to go into the directory and manually remove the files from the smallest backup level's ".0" directory. For example, if you were previously backing up /home/ with a destination of localhost/, and hourly is your smallest backup level, you would need to do the following to reclaim that disk space: =over 4 rm -rf /hourly.0/localhost/home/ =back Please note that the other snapshots previously made of /home/ will still be using that disk space, but since the files are flushed out of hourly.0/, they will no longer be copied to the subsequent directories, and will thus be removed in due time as the rotations happen. =head1 AUTHORS Mike Rubel - B =over 4 =item - Created the original shell scripts on which this project is based =back Nathan Rosenquist (B) =over 4 =item - Primary author and previous maintainer of rsnapshot. =back David Cantrell (B) =over 4 =item - Current co-maintainer of rsnapshot =item - Wrote the rsnapshot-diff utility =item - Improved how use_lazy_deletes work so slow deletes don't screw up the next backup at that backup level. =back David Keegel =over 4 =item - Co-maintainer, with responsibility for release management since 1.2.9 =item - Fixed race condition in lock file creation, improved error reporting =item - Allowed remote ssh directory paths starting with "~/" as well as "/" =item - Fixed a number of other bugs and buglets =back Carl Wilhelm Soderstrom B<(chrome@real-time.com)> =over 4 =item - Created the RPM .spec file which allowed the RPM package to be built, among other things. =back Ted Zlatanov (B) =over 4 =item - Added the one_fs feature, autoconf support, good advice, and much more. =back Ralf van Dooren (B) =over 4 =item - Added and maintains the rsnapshot entry in the FreeBSD ports tree. =back SlapAyoda =over 4 =item - Provided access to his computer museum for software testing. =back Carl Boe (B) =over 4 =item - Found several subtle bugs and provided fixes for them. =back Shane Leibling (B) =over 4 =item - Fixed a compatibility bug in utils/backup_smb_share.sh =back Christoph Wegscheider (B) =over 4 =item - Added (and previously maintained) the Debian rsnapshot package. =back Bharat Mediratta (B) =over 4 =item - Improved the exclusion rules to avoid backing up the snapshot root (among other things). =back Peter Palfrader (B) =over 4 =item - Enhanced error reporting to include command line options. =back Nicolas Kaiser (B) =over 4 =item - Fixed typos in program and man page =back Chris Petersen - (B) =over 4 Added cwrsync permanent-share support =back Robert Jackson (B) =over 4 Added use_lazy_deletes feature =back Justin Grote (B) =over 4 Improved rsync error reporting code =back Anthony Ettinger (B) =over 4 Wrote the utils/mysqlbackup.pl script =back Sherman Boyd =over 4 Wrote utils/random_file_verify.sh script =back William Bear (B) =over 4 Wrote the utils/rsnapreport.pl script (pretty summary of rsync stats) =back Eric Anderson (B) =over 4 Improvements to utils/rsnapreport.pl. =back Alan Batie (B) =over 4 Bug fixes for include_conf =back Dieter Bloms (B) =over 4 Multi-line configuration options =back Henning Moll (B) =over 4 stop_on_stale_lockfile =back Ben Low (B) =over 4 Linux LVM snapshot support =back =head1 COPYRIGHT Copyright (C) 2003-2005 Nathan Rosenquist Portions Copyright (C) 2002-2007 Mike Rubel, Carl Wilhelm Soderstrom, Ted Zlatanov, Carl Boe, Shane Liebling, Bharat Mediratta, Peter Palfrader, Nicolas Kaiser, David Cantrell, Chris Petersen, Robert Jackson, Justin Grote, David Keegel, Alan Batie, Dieter Bloms, Henning Moll, Ben Low, Anthony Ettinger This man page is distributed under the same license as rsnapshot: the GPL (see below). This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA =cut rsnapshot-1.3.1/rsnapshot-diff.pl0000755000000000000000000001632310440460236016766 0ustar rootroot00000000000000#!/usr/bin/perl -w ############################################################################## # rsnapshot-diff # by David Cantrell # # This program calculates the differences between two directories. It is # designed to work with two different subdirectories under the rsnapshot # snapshot_root. For example: # # rsnapshot-diff /.snapshots/daily.0/ /.snapshots/daily.1/ # # http://www.rsnapshot.org/ ############################################################################## # $Id: rsnapshot-diff.pl,v 1.3 2006/05/31 19:51:03 drhyde Exp $ =head1 NAME rsnapshot-diff - a utility for comparing the disk usage of two snapshots taken by rsnapshot =cut use strict; use constant DEBUG => 0; use Getopt::Std; my $program_name = 'rsnapshot-diff'; my %opts; my $verbose = 0; my $ignore = 0; my $result = getopts('vVhi', \%opts); # help if ($opts{'h'}) { print qq{ $program_name [-vVhi] dir1 dir2 $program_name shows the differences between two 'rsnapshot' backups. -h show this help -v be verbose -V be more verbose (mutter about unchanged files) -i ignore symlinks, directories, and special files in verbose output dir1 the first directory to look at dir2 the second directory to look at if you want to look at directories called '-h' or '-v' pass a first parameter of '--'. $program_name always show the changes made starting from the older of the two directories. }; exit; } =head1 SYNOPSIS rsnapshot-diff [-h|vVi] dir1 dir2 =head1 DESCRIPTION rsnapshot-diff is a companion utility for rsnapshot, which traverses two parallel directory structures and calculates the difference between them. By default it is silent apart from displaying summary information at the end, but it can be made more verbose. In the summary, "added" files may very well include files which at first glance also appear at the same place in the older directory structure. However, because the files differ in some respect, they are different files. They have a different inode number. Consequently if you use -v most of its output may appear to be pairs of files with the same name being removed and added. =head1 OPTIONS =over 4 =item -h (help) Displays help information =item -v (verbose) Be verbose. This will spit out a list of all changes as they are encountered, as well as the summary at the end. =item -V (more verbose) Be more verbose - as well as listed changes, unchanged files will be listed too. =item -i (ignore) If verbosity is turned on, -i suppresses information about symlinks, directories, and special files. =item dir1 and dir2 These are the only compulsory parameters, and should be the names of two directories to compare. Their order doesn't matter, rsnapshot-diff will always compare the younger to the older, so files that appear only in the older will be reported as having been removed, and files that appear only in the younger will be reported as having been added. =back =cut # verbose if ($opts{'v'}) { $verbose = 1; } # extra verbose if ($opts{'V'}) { $verbose = 2; } # ignore if ($opts{'i'}) { $ignore = 1; } if(!exists($ARGV[1]) || !-d $ARGV[0] || !-d $ARGV[1]) { die("$program_name\nUsage: $program_name [-vVhi] dir1 dir2\nType $program_name -h for details\n"); } my($dirold, $dirnew) = @ARGV; ($dirold, $dirnew) = ($dirnew, $dirold) if(-M $dirold < -M $dirnew); print "Comparing $dirold to $dirnew\n"; my($addedfiles, $addedspace, $deletedfiles, $deletedspace) = (0, 0, 0, 0); compare_dirs($dirold, $dirnew); print "Between $dirold and $dirnew:\n"; print " $addedfiles were added, taking $addedspace bytes;\n"; print " $deletedfiles were removed, saving $deletedspace bytes;\n"; sub compare_dirs { my($old, $new) = @_; opendir(OLD, $old) || die("Can't open dir $old\n"); opendir(NEW, $new) || die("Can't open dir $new\n"); my %old = map { my $fn = $old.'/'.$_; ($_, (mystat($fn))[1]) } grep { $_ ne '.' && $_ ne '..' } readdir(OLD); my %new = map { my $fn = $new.'/'.$_; ($_, (mystat($fn))[1]) } grep { $_ ne '.' && $_ ne '..' } readdir(NEW); closedir(OLD); closedir(NEW); my @added = grep { !exists($old{$_}) } keys %new; my @deleted = grep { !exists($new{$_}) } keys %old; my @changed = grep { !-d $new.'/'.$_ && exists($old{$_}) && $old{$_} != $new{$_} } keys %new; add(map { $new.'/'.$_ } @added, @changed); remove(map { $old.'/'.$_ } @deleted, @changed); if($verbose == 2) { my %changed = map { ($_, 1) } @changed, @added, @deleted; print "0 $new/$_\n" foreach(grep { !-d "$new/$_" && !exists($changed{$_}) } keys %new); } foreach (grep { !-l $new.'/'.$_ && !-l $old.'/'.$_ && -d $new.'/'.$_ && -d $old.'/'.$_ } keys %new) { print "Comparing subdirs $new/$_ and $old/$_ ...\n" if(DEBUG); compare_dirs($old.'/'.$_, $new.'/'.$_); } } sub add { my @added = @_; print "Adding ".join(', ', @added)."\n" if(DEBUG && @added); foreach(grep { !-d } @added) { $addedfiles++; $addedspace += (mystat($_))[7]; # if ignore is on, only print files unless ($ignore && (-l || !-f)) { print "+ $_\n" if($verbose); } } foreach my $dir (grep { !-l && -d } @added) { opendir(DIR, $dir) || die("Can't open dir $dir\n"); add(map { $dir.'/'.$_ } grep { $_ ne '.' && $_ ne '..' } readdir(DIR)) } } sub remove { my @removed = @_; print "Removing ".join(', ', @removed)."\n" if(DEBUG && @removed); foreach(grep { !-d } @removed) { $deletedfiles++; $deletedspace += (mystat($_))[7]; # if ignore is on, only print files unless ($ignore && (-l || !-f)) { print "- $_\n" if($verbose); } } foreach my $dir (grep { !-l && -d } @removed) { opendir(DIR, $dir) || die("Can't open dir $dir\n"); remove(map { $dir.'/'.$_ } grep { $_ ne '.' && $_ ne '..' } readdir(DIR)) } } { my $device; sub mystat { local $_ = shift; my @stat = (-l) ? lstat() : stat(); # on first stat, memorise device $device = $stat[0] unless(defined($device)); die("Can't compare across devices.\n(looking at $_)\n") unless($device == $stat[0] || -p $_); return @stat; } } =head1 SEE ALSO rsnapshot =head1 BUGS Please report bugs (and other comments) to the rsnapshot-discuss mailing list: L =head1 AUTHOR David Cantrell Edavid@cantrell.org.ukE =head1 COPYRIGHT Copyright 2005 David Cantrell =head1 LICENCE This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA =cut rsnapshot-1.3.1/rsnapshot.conf.default.in0000644000000000000000000001612711005052310020405 0ustar rootroot00000000000000################################################# # rsnapshot.conf - rsnapshot configuration file # ################################################# # # # PLEASE BE AWARE OF THE FOLLOWING RULES: # # # # This file requires tabs between elements # # # # Directories require a trailing slash: # # right: /home/ # # wrong: /home # # # ################################################# ####################### # CONFIG FILE VERSION # ####################### config_version 1.2 ########################### # SNAPSHOT ROOT DIRECTORY # ########################### # All snapshots will be stored under this root directory. # snapshot_root /.snapshots/ # If no_create_root is enabled, rsnapshot will not automatically create the # snapshot_root directory. This is particularly useful if you are backing # up to removable media, such as a FireWire or USB drive. # #no_create_root 1 ################################# # EXTERNAL PROGRAM DEPENDENCIES # ################################# # LINUX USERS: Be sure to uncomment "cmd_cp". This gives you extra features. # EVERYONE ELSE: Leave "cmd_cp" commented out for compatibility. # # See the README file or the man page for more details. # #@CMD_CP@ # uncomment this to use the rm program instead of the built-in perl routine. # @CMD_RM@ # rsync must be enabled for anything to work. This is the only command that # must be enabled. # @CMD_RSYNC@ # Uncomment this to enable remote ssh backups over rsync. # #@CMD_SSH@ # Comment this out to disable syslog support. # @CMD_LOGGER@ # Uncomment this to specify the path to "du" for disk usage checks. # If you have an older version of "du", you may also want to check the # "du_args" parameter below. # #@CMD_DU@ # Uncomment this to specify the path to rsnapshot-diff. # #cmd_rsnapshot_diff /usr/local/bin/rsnapshot-diff # Specify the path to a script (and any optional arguments) to run right # before rsnapshot syncs files # #cmd_preexec /path/to/preexec/script # Specify the path to a script (and any optional arguments) to run right # after rsnapshot syncs files # #cmd_postexec /path/to/postexec/script ######################################### # BACKUP INTERVALS # # Must be unique and in ascending order # # i.e. hourly, daily, weekly, etc. # ######################################### interval hourly 6 interval daily 7 interval weekly 4 #interval monthly 3 ############################################ # GLOBAL OPTIONS # # All are optional, with sensible defaults # ############################################ # Verbose level, 1 through 5. # 1 Quiet Print fatal errors only # 2 Default Print errors and warnings only # 3 Verbose Show equivalent shell commands being executed # 4 Extra Verbose Show extra verbose information # 5 Debug mode Everything # verbose 2 # Same as "verbose" above, but controls the amount of data sent to the # logfile, if one is being used. The default is 3. # loglevel 3 # If you enable this, data will be written to the file you specify. The # amount of data written is controlled by the "loglevel" parameter. # #logfile /var/log/rsnapshot # If enabled, rsnapshot will write a lockfile to prevent two instances # from running simultaneously (and messing up the snapshot_root). # If you enable this, make sure the lockfile directory is not world # writable. Otherwise anyone can prevent the program from running. # lockfile /var/run/rsnapshot.pid # Default rsync args. All rsync commands have at least these options set. # #rsync_short_args -a #rsync_long_args --delete --numeric-ids --relative --delete-excluded # ssh has no args passed by default, but you can specify some here. # #ssh_args -p 22 # Default arguments for the "du" program (for disk space reporting). # The GNU version of "du" is preferred. See the man page for more details. # If your version of "du" doesn't support the -h flag, try -k flag instead. # #du_args -csh # If this is enabled, rsync won't span filesystem partitions within a # backup point. This essentially passes the -x option to rsync. # The default is 0 (off). # #one_fs 0 # The include and exclude parameters, if enabled, simply get passed directly # to rsync. If you have multiple include/exclude patterns, put each one on a # separate line. Please look up the --include and --exclude options in the # rsync man page for more details on how to specify file name patterns. # #include ??? #include ??? #exclude ??? #exclude ??? # The include_file and exclude_file parameters, if enabled, simply get # passed directly to rsync. Please look up the --include-from and # --exclude-from options in the rsync man page for more details. # #include_file /path/to/include/file #exclude_file /path/to/exclude/file # If your version of rsync supports --link-dest, consider enable this. # This is the best way to support special files (FIFOs, etc) cross-platform. # The default is 0 (off). # #link_dest 0 # When sync_first is enabled, it changes the default behaviour of rsnapshot. # Normally, when rsnapshot is called with its lowest interval # (i.e.: "rsnapshot hourly"), it will sync files AND rotate the lowest # intervals. With sync_first enabled, "rsnapshot sync" handles the file sync, # and all interval calls simply rotate files. See the man page for more # details. The default is 0 (off). # #sync_first 0 # If enabled, rsnapshot will move the oldest directory for each interval # to [interval_name].delete, then it will remove the lockfile and delete # that directory just before it exits. The default is 0 (off). # #use_lazy_deletes 0 # Number of rsync re-tries. If you experience any network problems or # network card issues that tend to cause ssh to crap-out with # "Corrupted MAC on input" errors, for example, set this to a non-zero # value to have the rsync operation re-tried # #rsync_numtries 0 ############################### ### BACKUP POINTS / SCRIPTS ### ############################### # LOCALHOST backup /home/ localhost/ backup /etc/ localhost/ backup /usr/local/ localhost/ #backup /var/log/rsnapshot localhost/ #backup /etc/passwd localhost/ #backup /home/foo/My Documents/ localhost/ #backup /foo/bar/ localhost/ one_fs=1, rsync_short_args=-urltvpog #backup_script /usr/local/bin/backup_pgsql.sh localhost/postgres/ # EXAMPLE.COM #backup_script /bin/date "+ backup of example.com started at %c" unused1 #backup root@example.com:/home/ example.com/ +rsync_long_args=--bwlimit=16,exclude=core #backup root@example.com:/etc/ example.com/ exclude=mtab,exclude=core #backup_script ssh root@example.com "mysqldump -A > /var/db/dump/mysql.sql" unused2 #backup root@example.com:/var/db/dump/ example.com/ #backup_script /bin/date "+ backup of example.com ended at %c" unused9 # CVS.SOURCEFORGE.NET #backup_script /usr/local/bin/backup_rsnapshot_cvsroot.sh rsnapshot.cvs.sourceforge.net/ # RSYNC.SAMBA.ORG #backup rsync://rsync.samba.org/rsyncftp/ rsync.samba.org/rsyncftp/ rsnapshot-1.3.1/rsnapshot.10000644000000000000000000012101311056477456015613 0ustar rootroot00000000000000.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.14 .\" .\" Standard preamble: .\" ======================================================================== .de Sh \" Subsection heading .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. | will give a .\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to .\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' .\" expand to `' in nroff, nothing in troff, for use with C<>. .tr \(*W-|\(bv\*(Tr .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .\" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .hy 0 .if n .na .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "rsnapshot 1" .TH rsnapshot 1 "2008-08-31" "" "" .SH "NAME" rsnapshot \- remote filesystem snapshot utility .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBrsnapshot\fR [\fB\-vtxqVD\fR] [\fB\-c\fR cfgfile] [command] [args] .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fBrsnapshot\fR is a filesystem snapshot utility. It can take incremental snapshots of local and remote filesystems for any number of machines. .PP Local filesystem snapshots are handled with \fB\f(BIrsync\fB\|(1)\fR. Secure remote connections are handled with rsync over \fB\f(BIssh\fB\|(1)\fR, while anonymous rsync connections simply use an rsync server. Both remote and local transfers depend on rsync. .PP \&\fBrsnapshot\fR saves much more disk space than you might imagine. The amount of space required is roughly the size of one full backup, plus a copy of each additional file that is changed. \fBrsnapshot\fR makes extensive use of hard links, so if the file doesn't change, the next snapshot is simply a hard link to the exact same file. .PP \&\fBrsnapshot\fR will typically be invoked as root by a cron job, or series of cron jobs. It is possible, however, to run as any arbitrary user with an alternate configuration file. .PP All important options are specified in a configuration file, which is located by default at \fB/etc/rsnapshot.conf\fR. An alternate file can be specified on the command line. There are also additional options which can be passed on the command line. .PP The command line options are as follows: .Sp .RS 4 \&\fB\-v\fR verbose, show shell commands being executed .Sp \&\fB\-t\fR test, show shell commands that would be executed .Sp \&\fB\-c\fR path to alternate config file .Sp \&\fB\-x\fR one filesystem, don't cross partitions within each backup point .Sp \&\fB\-q\fR quiet, suppress non-fatal warnings .Sp \&\fB\-V\fR same as \-v, but with more detail .Sp \&\fB\-D\fR a firehose of diagnostic information .RE .SH "CONFIGURATION" .IX Header "CONFIGURATION" \&\fB/etc/rsnapshot.conf\fR is the default configuration file. All parameters in this file must be separated by tabs. \fB/etc/rsnapshot.conf.default\fR can be used as a reference. .PP It is recommended that you copy \fB/etc/rsnapshot.conf.default\fR to \&\fB/etc/rsnapshot.conf\fR, and then modify \fB/etc/rsnapshot.conf\fR to suit your needs. .PP Long lines may be split over several lines. \*(L"Continuation\*(R" lines \&\fBmust\fR begin with a space or a tab character. Continuation lines will have all leading and trailing whitespace stripped off, and then be appended with an intervening tab character to the previous line when the configuation file is parsed. .PP Here is a list of allowed parameters: .Sp .RS 4 \&\fBconfig_version\fR Config file version (required). Default is 1.2 .Sp \&\fBsnapshot_root\fR Local filesystem path to save all snapshots .Sp \&\fBinclude_conf\fR Include another file in the configuration at this point. .Sp .RS 4 This is recursive, but you may need to be careful about paths when specifying which file to include. We check to see if the file you have specified is readable, and will yell an error if it isn't. We recommend using a full path. As a special case, include_conf's value may be enclosed in `backticks` in which case it will be executed and whatever it spits to \s-1STDOUT\s0 will be included in the configuration. Note that shell meta-characters may be interpreted. .RE .RE .RS 4 .Sp \&\fBno_create_root\fR If set to 1, rsnapshot won't create snapshot_root directory .Sp \&\fBcmd_rsync\fR Full path to rsync (required) .Sp \&\fBcmd_ssh\fR Full path to ssh (optional) .Sp \&\fBcmd_cp\fR Full path to cp (optional, but must be \s-1GNU\s0 version) .Sp .RS 4 If you are using Linux, you should uncomment cmd_cp. If you are using a platform which does not have \s-1GNU\s0 cp, you should leave cmd_cp commented out. .Sp With \s-1GNU\s0 cp, rsnapshot can take care of both normal files and special files (such as FIFOs, sockets, and block/character devices) in one pass. .Sp If cmd_cp is disabled, rsnapshot will use its own built-in function, \&\fInative_cp_al()\fR to backup up regular files and directories. This will then be followed up by a separate call to rsync, to move the special files over (assuming there are any). .RE .RE .RS 4 .Sp \&\fBcmd_rm\fR Full path to rm (optional) .Sp \&\fBcmd_logger\fR Full path to logger (optional, for syslog support) .Sp \&\fBcmd_du\fR Full path to du (optional, for disk usage reports) .Sp \&\fBcmd_rsnapshot_diff\fR Full path to rsnapshot-diff (optional) .Sp \&\fBcmd_preexec\fR .Sp .RS 4 Full path (plus any arguments) to preexec script (optional). This script will run immediately before each backup operation (but not any rotations). .RE .RE .RS 4 .Sp \&\fBcmd_postexec\fR .Sp .RS 4 Full path (plus any arguments) to postexec script (optional). This script will run immediately after each backup operation (but not any rotations). .RE .RE .RS 4 .Sp \&\fBlinux_lvm_cmd_lvcreate\fR .Sp \&\fBlinux_lvm_cmd_lvremove\fR .Sp \&\fBlinux_lvm_cmd_mount\fR .Sp \&\fBlinux_lvm_cmd_umount\fR .Sp .RS 4 Paths to lvcreate, lvremove, mount and umount commands, for use with Linux LVMs. The lvcreate, lvremove, mount and umount commands are required for managing snapshots of \s-1LVM\s0 volumes and are otherwise optional. .RE .RE .RS 4 .Sp \&\fBretain\fR [name] [number] .Sp .RS 4 \&\*(L"name\*(R" refers to the name of this backup level (e.g., hourly, daily, so also called the 'interval'). \*(L"number\*(R" is the number of snapshots for this type of interval that will be retained. The value of \*(L"name\*(R" will be the command passed to \fBrsnapshot\fR to perform this type of backup. .Sp A deprecated alias for 'retain' is 'interval'. .Sp Example: \fBretain hourly 6\fR .Sp [root@localhost]# \fBrsnapshot hourly\fR .Sp For this example, every time this is run, the following will happen: .Sp /hourly.5/ will be deleted, if it exists. .Sp /hourly.{1,2,3,4} will all be rotated +1, if they exist. .Sp /hourly.0/ will be copied to /hourly.1/ using hard links. .Sp Each backup point (explained below) will then be rsynced to the corresponding directories in /hourly.0/ .Sp Backup levels must be specified in the config file in order, from most frequent to least frequent. The first entry is the one which will be synced with the backup points. The subsequent backup levels (e.g., daily, weekly, etc) simply rotate, with each higher backup level pulling from the one below it for its .0 directory. .Sp Example: .Sp .RS 4 \&\fBretain hourly 6\fR .Sp \&\fBretain daily 7\fR .Sp \&\fBretain weekly 4\fR .RE .RE .RS 4 .Sp daily.0/ will be copied from hourly.5/, and weekly.0/ will be copied from daily.6/ .Sp hourly.0/ will be rsynced directly from the filesystem. .RE .RE .RS 4 .Sp \&\fBlink_dest 1\fR .Sp .RS 4 If your version of rsync supports \-\-link\-dest (2.5.7 or newer), you can enable this to let rsync handle some things that \s-1GNU\s0 cp or the built-in subroutines would otherwise do. Enabling this makes rsnapshot take a slightly more complicated code branch, but it's the best way to support special files on non-Linux systems. .RE .RE .RS 4 .Sp \&\fBsync_first 1\fR .Sp .RS 4 sync_first changes the behaviour of rsnapshot. When this is enabled, all calls to rsnapshot with various backup levels simply rotate files. All backups are handled by calling rsnapshot with the \*(L"sync\*(R" argument. The synced files are stored in a \*(L".sync\*(R" directory under the snapshot_root. .Sp This allows better recovery in the event that rsnapshot is interrupted in the middle of a sync operation, since the sync step and rotation steps are separated. This also means that you can easily run \*(L"rsnapshot sync\*(R" on the command line without fear of forcing all the other directories to rotate up. This benefit comes at the cost of one more snapshot worth of disk space. The default is 0 (off). .RE .RE .RS 4 .Sp \&\fBverbose 2\fR .Sp .RS 4 The amount of information to print out when the program is run. Allowed values are 1 through 5. The default is 2. .Sp .Vb 5 \& 1 Quiet Show fatal errors only \& 2 Default Show warnings and errors \& 3 Verbose Show equivalent shell commands being executed \& 4 Extra Verbose Same as verbose, but with more detail \& 5 Debug All kinds of information .Ve .RE .RE .RS 4 .Sp \&\fBloglevel 3\fR .Sp .RS 4 This number means the same thing as \fBverbose\fR above, but it determines how much data is written to the logfile, if one is being written. .Sp The only thing missing from this at the higher levels is the direct output from rsync. We hope to add support for this in a future release. .RE .RE .RS 4 .Sp \&\fBlogfile /var/log/rsnapshot\fR .Sp .RS 4 Full filesystem path to the rsnapshot log file. If this is defined, a log file will be written, with the amount of data being controlled by \fBloglevel\fR. If this is commented out, no log file will be written. .RE .RE .RS 4 .Sp \&\fBinclude [file\-name\-pattern]\fR .Sp .RS 4 This gets passed directly to rsync using the \-\-include directive. This parameter can be specified as many times as needed, with one pattern defined per line. See the \fIrsync\fR\|(1) man page for the syntax. .RE .RE .RS 4 .Sp \&\fBexclude [file\-name\-pattern]\fR .Sp .RS 4 This gets passed directly to rsync using the \-\-exclude directive. This parameter can be specified as many times as needed, with one pattern defined per line. See the \fIrsync\fR\|(1) man page for the syntax. .RE .RE .RS 4 .Sp \&\fBinclude_file /path/to/include/file\fR .Sp .RS 4 This gets passed directly to rsync using the \-\-include\-from directive. See the \&\fIrsync\fR\|(1) man page for the syntax. .RE .RE .RS 4 .Sp \&\fBexclude_file /path/to/exclude/file\fR .Sp .RS 4 This gets passed directly to rsync using the \-\-exclude\-from directive. See the \&\fIrsync\fR\|(1) man page for the syntax. .RE .RE .RS 4 .Sp \&\fBrsync_short_args \-a\fR .Sp .RS 4 List of short arguments to pass to rsync. If not specified, \&\*(L"\-a\*(R" is the default. Please note that these must be all next to each other. For example, \*(L"\-az\*(R" is valid, while \*(L"\-a \-z\*(R" is not. .Sp \&\*(L"\-a\*(R" is rsync's \*(L"archive mode\*(R" which tells it to copy as much of the filesystem metadata as it can for each file. This specifically does *not* include information about hard links, as that would greatly increase rsync's memory usage and slow it down. If you need to preserve hard links in your backups, then add \*(L"H\*(R" to this. .RE .RE .RS 4 .Sp \&\fBrsync_long_args \-\-delete \-\-numeric\-ids \-\-relative \-\-delete\-excluded\fR .Sp .RS 4 List of long arguments to pass to rsync. Beginning with rsnapshot 1.2.0, this default has changed. In previous versions, the default values were .Sp .Vb 1 \& --delete --numeric-ids .Ve .Sp Starting with version 1.2.0, the default values are .Sp .Vb 1 \& --delete --numeric-ids --relative --delete-excluded .Ve .Sp This directly affects how the destination paths in your backup points are constructed. Depending on what behaviour you want, you can explicitly set the values to make the program behave like the old version or the current version. The newer settings are recommended if you're just starting. If you are upgrading, read the upgrade guide in the \s-1INSTALL\s0 file in the source distribution for more information. .Sp Quotes are permitted in rsync_long_args, eg \-\-rsync\-path=\*(L"sudo /usr/bin/rsync\*(R". You may use either single (') or double (") quotes, but nested quotes (including mixed nested quotes) are not permitted. Similar quoting is also allowed in per-backup-point rsync_long_args. .RE .RE .RS 4 .Sp \&\fBssh_args \-p 22\fR .Sp .RS 4 Arguments to be passed to ssh. If not specified, the default is none. .RE .RE .RS 4 .Sp \&\fBdu_args \-csh\fR .Sp .RS 4 Arguments to be passed to du. If not specified, the default is \-csh. \&\s-1GNU\s0 du supports \-csh, \s-1BSD\s0 du supports \-csk, Solaris du doesn't support \&\-c at all. The \s-1GNU\s0 version is recommended, since it offers the most features. .RE .RE .RS 4 .Sp \&\fBlockfile /var/run/rsnapshot.pid\fR .Sp \&\fBstop_on_stale_lockfile 0\fR .Sp .RS 4 Lockfile to use when rsnapshot is run. This prevents a second invocation from clobbering the first one. If not specified, no lock file is used. Make sure to use a directory that is not world writeable for security reasons. Use of a lock file is strongly recommended. .Sp If a lockfile exists when rsnapshot starts, it will try to read the file and stop with an error if it can't. If it *can* read the file, it sees if a process exists with the \s-1PID\s0 noted in the file. If it does, rsnapshot stops with an error message. If there is no process with that \s-1PID\s0, then we assume that the lockfile is stale and ignore it *unless* stop_on_stale_lockfile is set to 1 in which case we stop. .Sp stop_on_stale_lockfile defaults to 0. .RE .RE .RS 4 .Sp \&\fBone_fs 1\fR .Sp .RS 4 Prevents rsync from crossing filesystem partitions. Setting this to a value of 1 enables this feature. 0 turns it off. This parameter is optional. The default is 0 (off). .RE .RE .RS 4 .Sp \&\fBuse_lazy_deletes 1\fR .Sp .RS 4 Changes default behavior of rsnapshot and does not initially remove the oldest snapshot. Instead it moves that directory to _delete.[processid] and continues as normal. Once the backup has been completed, the lockfile will be removed before rsnapshot starts deleting the directory. .Sp Enabling this means that snapshots get taken sooner (since the delete doesn't come first), and any other rsnapshot processes are allowed to start while the final delete is happening. This benefit comes at the cost of using more disk space. The default is 0 (off). .Sp The details of how this works have changed in rsnapshot version 1.3.1. Originally you could only ever have one .delete directory per backup level. Now you can have many, so if your next (eg) hourly backup kicks off while the previous one is still doing a lazy delete you may temporarily have extra _delete directories hanging around. .RE .RE .RS 4 .Sp \&\fBlinux_lvm_snapshotsize 2G\fR .Sp .RS 4 \&\s-1LVM\s0 snapshot(s) size (lvcreate \-\-size option). .RE .RE .RS 4 .Sp \&\fBlinux_lvm_snapshotname rsnapshot\fR .Sp .RS 4 Name to be used when creating the \s-1LVM\s0 logical volume snapshot(s) (lvcreate \-\-name option). .RE .RE .RS 4 .Sp \&\fBlinux_lvm_vgpath /dev\fR .Sp .RS 4 Path to the \s-1LVM\s0 Volume Groups. .RE .RE .RS 4 .Sp \&\fBlinux_lvm_mountpath /mnt/lvm\-snapshot\fR .Sp .RS 4 Mount point to use to temporarily mount the snapshot(s). .RE .RE .RS 4 .Sp \&\fB\s-1UPGRADE\s0 \s-1NOTICE:\s0\fR .Sp .RS 4 If you have used an older version of rsnapshot, you might notice that the destination paths on the backup points have changed. Please read the \s-1INSTALL\s0 file in the source distribution for upgrade options. .RE .RE .RS 4 .Sp \&\fBbackup\fR /etc/ localhost/ .Sp \&\fBbackup\fR root@example.com:/etc/ example.com/ .Sp \&\fBbackup\fR rsync://example.com/path2/ example.com/ .Sp \&\fBbackup\fR /var/ localhost/ one_fs=1 .Sp \&\fBbackup\fR lvm://vg0/home/path2/ lvm\-vg0/ .Sp \&\fBbackup_script\fR /usr/local/bin/backup_pgsql.sh pgsql_backup/ .Sp .RS 4 Examples: .Sp \&\fBbackup /etc/ localhost/\fR .Sp .RS 4 Backs up /etc/ to /.0/localhost/etc/ using rsync on the local filesystem .RE .RE .RS 4 .Sp \&\fBbackup /usr/local/ localhost/\fR .Sp .RS 4 Backs up /usr/local/ to /.0/localhost/usr/local/ using rsync on the local filesystem .RE .RE .RS 4 .Sp \&\fBbackup root@example.com:/etc/ example.com/\fR .Sp .RS 4 Backs up root@example.com:/etc/ to /.0/example.com/etc/ using rsync over ssh .RE .RE .RS 4 .Sp \&\fBbackup root@example.com:/usr/local/ example.com/\fR .Sp .RS 4 Backs up root@example.com:/usr/local/ to /.0/example.com/usr/local/ using rsync over ssh .RE .RE .RS 4 .Sp \&\fBbackup rsync://example.com/pub/ example.com/pub/\fR .Sp .RS 4 Backs up rsync://example.com/pub/ to /.0/example.com/pub/ using an anonymous rsync server. Please note that unlike backing up local paths and using rsync over ssh, rsync servers have \*(L"modules\*(R", which are top level directories that are exported. Therefore, the module should also be specified in the destination path, as shown in the example above (the pub/ directory at the end). .RE .RE .RS 4 .Sp \&\fBbackup /var/ localhost/ one_fs=1\fR .Sp .RS 4 This is the same as the other examples, but notice the fourth column. This is how you specify per-backup-point options to over-ride global settings. This extra parameter can take several options, separated by \fBcommas\fR. .Sp It is most useful when specifying per-backup rsync excludes thus: .Sp \&\fBbackup root@somehost:/ somehost +rsync_long_args=\-\-exclude=/var/spool/\fR .Sp Note the + sign. That tells rsnapshot to \fIadd\fR to the list of arguments to pass to rsync instead of replacing the list. .RE .RE .RS 4 .Sp \&\fBbackup lvm://vg0/home/path2/ lvm\-vg0/\fR .Sp .RS 4 Backs up the \s-1LVM\s0 logical volume called home, of volume group vg0, to /.0/lvm\-vg0/. Will create, mount, backup, unmount and remove an \s-1LVM\s0 snapshot for each lvm:// entry. .RE .RE .RS 4 .Sp \&\fBbackup_script /usr/local/bin/backup_database.sh db_backup/\fR .Sp .RS 4 In this example, we specify a script or program to run. This script should simply create files and/or directories in its current working directory. rsnapshot will then take that output and move it into the directory specified in the third column. .Sp Please note that whatever is in the destination directory will be completely deleted and recreated. For this reason, rsnapshot prevents you from specifying a destination directory for a backup_script that will clobber other backups. .Sp So in this example, say the backup_database.sh script simply runs a command like: .Sp .RS 4 #!/bin/sh .Sp mysqldump \-uusername mydatabase > mydatabase.sql .Sp chmod u=r,go= mydatabase.sql # r\-\-\-\-\-\-\-\- (0400) .RE .RE .RS 4 .Sp rsnapshot will take the generated \*(L"mydatabase.sql\*(R" file and move it into the /.0/db_backup/ directory. On subsequent runs, rsnapshot checks the differences between the files created against the previous files. If the backup script generates the same output on the next run, the files will be hard linked against the previous ones, and no additional disk space will be taken up. .RE .RE .RS 4 .RE .RE .RS 4 .Sp Remember that tabs must separate all elements, and that there must be a trailing slash on the end of every directory. .Sp A hash mark (#) on the beginning of a line is treated as a comment. .Sp Putting it all together (an example file): .Sp .Vb 1 \& # THIS IS A COMMENT, REMEMBER TABS MUST SEPARATE ALL ELEMENTS .Ve .Sp .Vb 1 \& config_version 1.2 .Ve .Sp .Vb 1 \& snapshot_root /.snapshots/ .Ve .Sp .Vb 6 \& cmd_rsync /usr/bin/rsync \& cmd_ssh /usr/bin/ssh \& #cmd_cp /bin/cp \& cmd_rm /bin/rm \& cmd_logger /usr/bin/logger \& cmd_du /usr/bin/du .Ve .Sp .Vb 4 \& linux_lvm_cmd_lvcreate /sbin/lvcreate \& linux_lvm_cmd_lvremove /sbin/lvremove \& linux_lvm_cmd_mount /bin/mount \& linux_lvm_cmd_umount /bin/umount .Ve .Sp .Vb 4 \& linux_lvm_snapshotsize 2G \& linux_lvm_snapshotname rsnapshot \& linux_lvm_vgpath /dev \& linux_lvm_mountpath /mnt/lvm-snapshot .Ve .Sp .Vb 4 \& retain hourly 6 \& retain daily 7 \& retain weekly 7 \& retain monthly 3 .Ve .Sp .Vb 3 \& backup /etc/ localhost/ \& backup /home/ localhost/ \& backup_script /usr/local/bin/backup_mysql.sh mysql_backup/ .Ve .Sp .Vb 5 \& backup root@foo.com:/etc/ foo.com/ \& backup root@foo.com:/home/ foo.com/ \& backup root@mail.foo.com:/home/ mail.foo.com/ \& backup rsync://example.com/pub/ example.com/pub/ \& backup lvm://vg0/xen-home/ lvm-vg0/xen-home/ .Ve .RE .RS 4 .SH "USAGE" .IX Header "USAGE" \&\fBrsnapshot\fR can be used by any user, but for system-wide backups you will probably want to run it as root. .Sp Since backups usually get neglected if human intervention is required, the preferred way is to run it from cron. .Sp When you are first setting up your backups, you will probably also want to run it from the command line once or twice to get a feel for what it's doing. .Sp Here is an example crontab entry, assuming that backup levels \fBhourly\fR, \&\fBdaily\fR, \fBweekly\fR and \fBmonthly\fR have been defined in \fB/etc/rsnapshot.conf\fR .Sp .RS 4 \&\fB0 */4 * * * /usr/local/bin/rsnapshot hourly\fR .Sp \&\fB50 23 * * * /usr/local/bin/rsnapshot daily\fR .Sp \&\fB40 23 * * 6 /usr/local/bin/rsnapshot weekly\fR .Sp \&\fB30 23 1 * * /usr/local/bin/rsnapshot monthly\fR .RE .RE .RS 4 .Sp This example will do the following: .Sp .RS 4 6 hourly backups a day (once every 4 hours, at 0,4,8,12,16,20) .Sp 1 daily backup every day, at 11:50PM .Sp 1 weekly backup every week, at 11:40PM, on Saturdays (6th day of week) .Sp 1 monthly backup every month, at 11:30PM on the 1st day of the month .RE .RE .RS 4 .Sp It is usually a good idea to schedule the larger backup levels to run a bit before the lower ones. For example, in the crontab above, notice that \*(L"daily\*(R" runs 10 minutes before \*(L"hourly\*(R". The main reason for this is that the daily rotate will pull out the oldest hourly and make that the youngest daily (which means that the next hourly rotate will not need to delete the oldest hourly), which is more efficient. A secondary reason is that it is harder to predict how long the lowest backup level will take, since it needs to actually do an rsync of the source as well as the rotate that all backups do. .Sp If rsnapshot takes longer than 10 minutes to do the \*(L"daily\*(R" rotate (which usually includes deleting the oldest daily snapshot), then you should increase the time between the backup levels. Otherwise (assuming you have set the \fBlockfile\fR parameter, as is recommended) your hourly snapshot will fail sometimes because the daily still has the lock. .Sp Remember that these are just the times that the program runs. To set the number of backups stored, set the \fBretain\fR numbers in \&\fB/etc/rsnapshot.conf\fR .Sp To check the disk space used by rsnapshot, you can call it with the \*(L"du\*(R" argument. .Sp For example: .Sp .RS 4 \&\fBrsnapshot du\fR .RE .RE .RS 4 .Sp This will show you exactly how much disk space is taken up in the snapshot root. This feature requires the \s-1UNIX\s0 \fBdu\fR command to be installed on your system, for it to support the \*(L"\-csh\*(R" command line arguments, and to be in your path. You can also override your path settings and the flags passed to du using the cmd_du and du_args parameters. .Sp It is also possible to pass a relative file path as a second argument, to get a report on a particular file or subdirectory. .Sp .RS 4 \&\fBrsnapshot du localhost/home/\fR .RE .RE .RS 4 .Sp The \s-1GNU\s0 version of \*(L"du\*(R" is preferred. The \s-1BSD\s0 version works well also, but does not support the \-h flag (use \-k instead, to see the totals in kilobytes). Other versions of \*(L"du\*(R", such as Solaris, may not work at all. .Sp To check the differences between two directories, call rsnapshot with the \*(L"diff\*(R" argument, followed by two backup levels or directory paths. .Sp For example: .Sp .RS 4 \&\fBrsnapshot diff daily.0 daily.1\fR .Sp \&\fBrsnapshot diff daily.0/localhost/etc daily.1/localhost/etc\fR .Sp \&\fBrsnapshot diff /.snapshots/daily.0 /.snapshots/daily.1\fR .RE .RE .RS 4 .Sp This will call the rsnapshot-diff program, which will scan both directories looking for differences (based on hard links). .Sp \&\fBrsnapshot sync\fR .Sp .RS 4 When \fBsync_first\fR is enabled, rsnapshot must first be called with the \fBsync\fR argument, followed by the other usual cron entries. The sync should happen as the lowest, most frequent backup level, and right before. For example: .Sp .RS 4 \&\fB0 */4 * * * /usr/local/bin/rsnapshot sync && /usr/local/bin/rsnapshot hourly\fR .Sp \&\fB50 23 * * * /usr/local/bin/rsnapshot daily\fR .Sp \&\fB40 23 1,8,15,22 * * /usr/local/bin/rsnapshot weekly\fR .Sp \&\fB30 23 1 * * /usr/local/bin/rsnapshot monthly\fR .RE .RE .RS 4 .Sp The sync operation simply runs rsync and all backup scripts. In this scenario, all calls simply rotate directories, even the lowest backup level. .RE .RE .RS 4 .Sp \&\fBrsnapshot sync [dest]\fR .Sp .RS 4 When \fBsync_first\fR is enabled, all sync behaviour happens during an additional sync step (see above). When using the sync argument, it is also possible to specify a backup point destination as an optional parameter. If this is done, only backup points sharing that destination path will be synced. .Sp For example, let's say that example.com is a destination path shared by one or more of your backup points. .Sp .RS 4 rsnapshot sync example.com .RE .RE .RS 4 .Sp This command will only sync the files that normally get backed up into example.com. It will \s-1NOT\s0 get any other backup points with slightly different values (like example.com/etc/, for example). In order to sync example.com/etc, you would need to run rsnapshot again, using example.com/etc as the optional parameter. .RE .RE .RS 4 .SH "EXIT VALUES" .IX Header "EXIT VALUES" .RS 4 \&\fB0\fR All operations completed successfully .Sp \&\fB1\fR A fatal error occurred .Sp \&\fB2\fR Some warnings occurred, but the backup still finished .RE .RE .RS 4 .SH "FILES" .IX Header "FILES" /etc/rsnapshot.conf .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fIrsync\fR\|(1), \fIssh\fR\|(1), \fIlogger\fR\|(1), \fIsshd\fR\|(1), \fIssh\-keygen\fR\|(1), \fIperl\fR\|(1), \fIcp\fR\|(1), \fIdu\fR\|(1), \fIcrontab\fR\|(1) .SH "DIAGNOSTICS" .IX Header "DIAGNOSTICS" Use the \fB\-t\fR flag to see what commands would have been executed. This will show you the commands rsnapshot would try to run. There are a few minor differences (for example, not showing an attempt to remove the lockfile because it wasn't really created in the test), but should give you a very good idea what will happen. .Sp Using the \fB\-v\fR, \fB\-V\fR, and \fB\-D\fR flags will print increasingly more information to \s-1STDOUT\s0. .Sp Make sure you don't have spaces in the config file that you think are actually tabs. .Sp Much other weird behavior can probably be attributed to plain old file system permissions and ssh authentication issues. .SH "BUGS" .IX Header "BUGS" Please report bugs (and other comments) to the rsnapshot-discuss mailing list: .Sp \&\fBhttp://lists.sourceforge.net/lists/listinfo/rsnapshot\-discuss\fR .SH "NOTES" .IX Header "NOTES" Make sure your /etc/rsnapshot.conf file has all elements separated by tabs. See /etc/rsnapshot.conf.default for a working example file. .Sp Make sure you put a trailing slash on the end of all directory references. If you don't, you may have extra directories created in your snapshots. For more information on how the trailing slash is handled, see the \&\fB\f(BIrsync\fB\|(1)\fR manpage. .Sp Make sure to make the snapshot directory chmod 700 and owned by root (assuming backups are made by the root user). If the snapshot directory is readable by other users, they will be able to modify the snapshots containing their files, thus destroying the integrity of the snapshots. .Sp If you would like regular users to be able to restore their own backups, there are a number of ways this can be accomplished. One such scenario would be: .Sp Set \fBsnapshot_root\fR to \fB/.private/.snapshots\fR in \fB/etc/rsnapshot.conf\fR .Sp Set the file permissions on these directories as follows: .Sp .RS 4 drwx\-\-\-\-\-\- /.private .Sp drwxr-xr-x /.private/.snapshots .RE .RE .RS 4 .Sp Export the /.private/.snapshots directory over read-only \s-1NFS\s0, a read-only Samba share, etc. .Sp See the rsnapshot \s-1HOWTO\s0 for more information on making backups accessible to non-privileged users. .Sp For ssh to work unattended through cron, you will probably want to use public key logins. Create an ssh key with no passphrase for root, and install the public key on each machine you want to backup. If you are backing up system files from remote machines, this probably means unattended root logins. Another possibility is to create a second user on the machine just for backups. Give the user a different name such as \*(L"rsnapshot\*(R", but keep the \s-1UID\s0 and \s-1GID\s0 set to 0, to give root privileges. However, make logins more restrictive, either through ssh configuration, or using an alternate shell. .Sp \&\s-1BE\s0 \s-1CAREFUL\s0! If the private key is obtained by an attacker, they will have free run of all the systems involved. If you are unclear on how to do this, see \fB\f(BIssh\fB\|(1)\fR, \fB\f(BIsshd\fB\|(1)\fR, and \fB\f(BIssh\-keygen\fB\|(1)\fR. .Sp Backup scripts are run as the same user that rsnapshot is running as. Typically this is root. Make sure that all of your backup scripts are only writable by root, and that they don't call any other programs that aren't owned by root. If you fail to do this, anyone who can write to the backup script or any program it calls can fully take over the machine. Of course, this is not a situation unique to rsnapshot. .Sp By default, rsync transfers are done using the \-\-numeric\-ids option. This means that user names and group names are ignored during transfers, but the \s-1UID/GID\s0 information is kept intact. The assumption is that the backups will be restored in the same environment they came from. Without this option, restoring backups for multiple heterogeneous servers would be unmanageable. If you are archiving snapshots with \s-1GNU\s0 tar, you may want to use the \-\-numeric\-owner parameter. Also, keep a copy of the archived system's /etc/passwd and /etc/group files handy for the \s-1UID/GID\s0 to name mapping. .Sp If you remove backup points in the config file, the previously archived files under those points will permanently stay in the snapshots directory unless you remove the files yourself. If you want to conserve disk space, you will need to go into the directory and manually remove the files from the smallest backup level's \*(L".0\*(R" directory. .Sp For example, if you were previously backing up /home/ with a destination of localhost/, and hourly is your smallest backup level, you would need to do the following to reclaim that disk space: .Sp .RS 4 rm \-rf /hourly.0/localhost/home/ .RE .RE .RS 4 .Sp Please note that the other snapshots previously made of /home/ will still be using that disk space, but since the files are flushed out of hourly.0/, they will no longer be copied to the subsequent directories, and will thus be removed in due time as the rotations happen. .SH "AUTHORS" .IX Header "AUTHORS" Mike Rubel \- \fBhttp://www.mikerubel.org/computers/rsync_snapshots/\fR .IP "\- Created the original shell scripts on which this project is based" 4 .IX Item "- Created the original shell scripts on which this project is based" .RE .RS 4 .Sp Nathan Rosenquist (\fBnathan@rsnapshot.org\fR) .IP "\- Primary author and previous maintainer of rsnapshot." 4 .IX Item "- Primary author and previous maintainer of rsnapshot." .RE .RS 4 .Sp David Cantrell (\fBdavid@cantrell.org.uk\fR) .IP "\- Current co-maintainer of rsnapshot" 4 .IX Item "- Current co-maintainer of rsnapshot" .PD 0 .IP "\- Wrote the rsnapshot-diff utility" 4 .IX Item "- Wrote the rsnapshot-diff utility" .IP "\- Improved how use_lazy_deletes work so slow deletes don't screw up the next backup at that backup level." 4 .IX Item "- Improved how use_lazy_deletes work so slow deletes don't screw up the next backup at that backup level." .RE .RS 4 .PD .Sp David Keegel .IP "\- Co\-maintainer, with responsibility for release management since 1.2.9" 4 .IX Item "- Co-maintainer, with responsibility for release management since 1.2.9" .PD 0 .IP "\- Fixed race condition in lock file creation, improved error reporting" 4 .IX Item "- Fixed race condition in lock file creation, improved error reporting" .ie n .IP "\- Allowed remote ssh directory paths starting with ""~/"" as well as ""/""" 4 .el .IP "\- Allowed remote ssh directory paths starting with ``~/'' as well as ``/''" 4 .IX Item "- Allowed remote ssh directory paths starting with ~/ as well as /" .IP "\- Fixed a number of other bugs and buglets" 4 .IX Item "- Fixed a number of other bugs and buglets" .RE .RS 4 .PD .Sp Carl Wilhelm Soderstrom \fB(chrome@real\-time.com)\fR .IP "\- Created the \s-1RPM\s0 .spec file which allowed the \s-1RPM\s0 package to be built, among other things." 4 .IX Item "- Created the RPM .spec file which allowed the RPM package to be built, among other things." .RE .RS 4 .Sp Ted Zlatanov (\fBtzz@lifelogs.com\fR) .IP "\- Added the one_fs feature, autoconf support, good advice, and much more." 4 .IX Item "- Added the one_fs feature, autoconf support, good advice, and much more." .RE .RS 4 .Sp Ralf van Dooren (\fBr.vdooren@snow.nl\fR) .IP "\- Added and maintains the rsnapshot entry in the FreeBSD ports tree." 4 .IX Item "- Added and maintains the rsnapshot entry in the FreeBSD ports tree." .RE .RS 4 .Sp SlapAyoda .IP "\- Provided access to his computer museum for software testing." 4 .IX Item "- Provided access to his computer museum for software testing." .RE .RS 4 .Sp Carl Boe (\fBboe@demog.berkeley.edu\fR) .IP "\- Found several subtle bugs and provided fixes for them." 4 .IX Item "- Found several subtle bugs and provided fixes for them." .RE .RS 4 .Sp Shane Leibling (\fBshane@cryptio.net\fR) .IP "\- Fixed a compatibility bug in utils/backup_smb_share.sh" 4 .IX Item "- Fixed a compatibility bug in utils/backup_smb_share.sh" .RE .RS 4 .Sp Christoph Wegscheider (\fBchristoph.wegscheider@wegi.net\fR) .IP "\- Added (and previously maintained) the Debian rsnapshot package." 4 .IX Item "- Added (and previously maintained) the Debian rsnapshot package." .RE .RS 4 .Sp Bharat Mediratta (\fBbharat@menalto.com\fR) .IP "\- Improved the exclusion rules to avoid backing up the snapshot root (among other things)." 4 .IX Item "- Improved the exclusion rules to avoid backing up the snapshot root (among other things)." .RE .RS 4 .Sp Peter Palfrader (\fBweasel@debian.org\fR) .IP "\- Enhanced error reporting to include command line options." 4 .IX Item "- Enhanced error reporting to include command line options." .RE .RS 4 .Sp Nicolas Kaiser (\fBnikai@nikai.net\fR) .IP "\- Fixed typos in program and man page" 4 .IX Item "- Fixed typos in program and man page" .RE .RS 4 .Sp Chris Petersen \- (\fBhttp://www.forevermore.net/\fR) .Sp .RS 4 Added cwrsync permanent-share support .RE .RE .RS 4 .Sp Robert Jackson (\fBRobertJ@promedicalinc.com\fR) .Sp .RS 4 Added use_lazy_deletes feature .RE .RE .RS 4 .Sp Justin Grote (\fBjustin@grote.name\fR) .Sp .RS 4 Improved rsync error reporting code .RE .RE .RS 4 .Sp Anthony Ettinger (\fBapwebdesign@yahoo.com\fR) .Sp .RS 4 Wrote the utils/mysqlbackup.pl script .RE .RE .RS 4 .Sp Sherman Boyd .Sp .RS 4 Wrote utils/random_file_verify.sh script .RE .RE .RS 4 .Sp William Bear (\fBbear@umn.edu\fR) .Sp .RS 4 Wrote the utils/rsnapreport.pl script (pretty summary of rsync stats) .RE .RE .RS 4 .Sp Eric Anderson (\fBanderson@centtech.com\fR) .Sp .RS 4 Improvements to utils/rsnapreport.pl. .RE .RE .RS 4 .Sp Alan Batie (\fBalan@batie.org\fR) .Sp .RS 4 Bug fixes for include_conf .RE .RE .RS 4 .Sp Dieter Bloms (\fBdieter@bloms.de\fR) .Sp .RS 4 Multi-line configuration options .RE .RE .RS 4 .Sp Henning Moll (\fBnewsScott@gmx.de\fR) .Sp .RS 4 stop_on_stale_lockfile .RE .RE .RS 4 .Sp Ben Low (\fBben@bdlow.net\fR) .Sp .RS 4 Linux \s-1LVM\s0 snapshot support .RE .RE .RS 4 .SH "COPYRIGHT" .IX Header "COPYRIGHT" Copyright (C) 2003\-2005 Nathan Rosenquist .Sp Portions Copyright (C) 2002\-2007 Mike Rubel, Carl Wilhelm Soderstrom, Ted Zlatanov, Carl Boe, Shane Liebling, Bharat Mediratta, Peter Palfrader, Nicolas Kaiser, David Cantrell, Chris Petersen, Robert Jackson, Justin Grote, David Keegel, Alan Batie, Dieter Bloms, Henning Moll, Ben Low, Anthony Ettinger .Sp This man page is distributed under the same license as rsnapshot: the \s-1GPL\s0 (see below). .Sp This program is free software; you can redistribute it and/or modify it under the terms of the \s-1GNU\s0 General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. .Sp This program is distributed in the hope that it will be useful, but \s-1WITHOUT\s0 \s-1ANY\s0 \s-1WARRANTY\s0; without even the implied warranty of \&\s-1MERCHANTABILITY\s0 or \s-1FITNESS\s0 \s-1FOR\s0 A \s-1PARTICULAR\s0 \s-1PURPOSE\s0. See the \&\s-1GNU\s0 General Public License for more details. .Sp You should have received a copy of the \s-1GNU\s0 General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, \s-1MA\s0 02110\-1301 \s-1USA\s0 rsnapshot-1.3.1/rsnapshot-diff.10000644000000000000000000001510511056477457016526 0ustar rootroot00000000000000.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.14 .\" .\" Standard preamble: .\" ======================================================================== .de Sh \" Subsection heading .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. | will give a .\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to .\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' .\" expand to `' in nroff, nothing in troff, for use with C<>. .tr \(*W-|\(bv\*(Tr .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .\" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .hy 0 .if n .na .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "rsnapshot-diff 1" .TH rsnapshot-diff 1 "2008-08-31" "" "" .SH "NAME" rsnapshot\-diff \- a utility for comparing the disk usage of two snapshots taken by rsnapshot .SH "SYNOPSIS" .IX Header "SYNOPSIS" rsnapshot-diff [\-h|vVi] dir1 dir2 .SH "DESCRIPTION" .IX Header "DESCRIPTION" rsnapshot-diff is a companion utility for rsnapshot, which traverses two parallel directory structures and calculates the difference between them. By default it is silent apart from displaying summary information at the end, but it can be made more verbose. .PP In the summary, \*(L"added\*(R" files may very well include files which at first glance also appear at the same place in the older directory structure. However, because the files differ in some respect, they are different files. They have a different inode number. Consequently if you use \-v most of its output may appear to be pairs of files with the same name being removed and added. .SH "OPTIONS" .IX Header "OPTIONS" .IP "\-h (help)" 4 .IX Item "-h (help)" Displays help information .IP "\-v (verbose)" 4 .IX Item "-v (verbose)" Be verbose. This will spit out a list of all changes as they are encountered, as well as the summary at the end. .IP "\-V (more verbose)" 4 .IX Item "-V (more verbose)" Be more verbose \- as well as listed changes, unchanged files will be listed too. .IP "\-i (ignore)" 4 .IX Item "-i (ignore)" If verbosity is turned on, \-i suppresses information about symlinks, directories, and special files. .IP "dir1 and dir2" 4 .IX Item "dir1 and dir2" These are the only compulsory parameters, and should be the names of two directories to compare. Their order doesn't matter, rsnapshot-diff will always compare the younger to the older, so files that appear only in the older will be reported as having been removed, and files that appear only in the younger will be reported as having been added. .SH "SEE ALSO" .IX Header "SEE ALSO" rsnapshot .SH "BUGS" .IX Header "BUGS" Please report bugs (and other comments) to the rsnapshot-discuss mailing list: .PP .SH "AUTHOR" .IX Header "AUTHOR" David Cantrell .SH "COPYRIGHT" .IX Header "COPYRIGHT" Copyright 2005 David Cantrell .SH "LICENCE" .IX Header "LICENCE" This program is free software; you can redistribute it and/or modify it under the terms of the \s-1GNU\s0 General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. .PP This program is distributed in the hope that it will be useful, but \s-1WITHOUT\s0 \s-1ANY\s0 \s-1WARRANTY\s0; without even the implied warranty of \&\s-1MERCHANTABILITY\s0 or \s-1FITNESS\s0 \s-1FOR\s0 A \s-1PARTICULAR\s0 \s-1PURPOSE\s0. See the \&\s-1GNU\s0 General Public License for more details. .PP You should have received a copy of the \s-1GNU\s0 General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, \s-1MA\s0 02110\-1301 \s-1USA\s0 rsnapshot-1.3.1/AUTHORS0000644000000000000000000000545111005052310014533 0ustar rootroot00000000000000Mike Rubel - http://www.mikerubel.org/computers/rsync_snapshots/ - Created the original shell scripts on which this project is based Nathan Rosenquist - Primary author and ex-maintainer of rsnapshot (until 2005). David Cantrell - ex-maintainer of rsnapshot (2005-2007) - Wrote the rsnapshot-diff utility David Keegel - Current maintainer of rsnapshot (2008-) - Allowed remote ssh directory paths starting with "~/" as well as "/" - Fixed race condition in lock file creation, improved error reporting - Fixed a number of other bugs and buglets - Release management for rsnapshot 1.2.9, 1.3.0 Carl Wilhelm Soderstrom - Created the RPM .spec file which allowed the RPM package to be built, among other things. Ted Zlatanov - Added the one_fs feature, autoconf support, good advice, and much more. Ralf van Dooren - Added and maintains the rsnapshot entry in the FreeBSD ports tree. SlapAyoda - Provided access to his computer museum for software testing. Carl Boe - Found several subtle bugs and provided fixes for them. Shane Liebling - Fixed a compatibility bug in utils/backup_smb_share.sh Christoph Wegscheider - Added and maintains the Debian rsnapshot package Bharat Mediratta - Improved the exclusion rules to avoid backing up the snapshot root (among other things). Peter Palfrader - Enhanced error reporting to include command line options Nicolas Kaiser - Fixed typos in program and man page Chris Petersen - http://www.forevermore.net/ - Added cwrsync permanent-share support Robert Jackson - Added use_lazy_deletes option Justin Grote - Improved rsync error reporting code Anthony Ettinger - Wrote the utils/mysqlbackup.pl script - Wrote utils/rsnapshotdb Sherman Boyd - Wrote the utils/random_file_verify.sh script William Bear - Wrote the utils/rsnapreport.pl script (pretty summary of rsync stats) Eric Anderson - Improvements to utils/rsnapreport.pl. Alan Batie - Bug fixes for include_conf Dieter Bloms - Multi-line configuration options Henning Moll - stop_on_stale_lockfile Ben Low - Added support for Linux LVM snapshots David Grant - Added support for retrying rsync "rsync_numtries" number of times Matt McCutchen - Wrote rsnapshot-copy (to copy snapshot roots using rsync --link-dest) rsnapshot-1.3.1/COPYING0000644000000000000000000004310610440460235014530 0ustar rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. rsnapshot-1.3.1/INSTALL0000644000000000000000000001255211005052310014514 0ustar rootroot00000000000000rsnapshot 1.3.1 http://www.rsnapshot.org/ rsnapshot is a filesystem snapshot utility. It uses rsync to take snapshots of local and remote filesystems for any number of machines, and then rotates the snapshots according to your rsnapshot.conf. rsnapshot comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See the GNU General Public Licence for details. +------------------------+ | CONTENTS | +------------------------+ - Installation - Quick Start - Upgrading - Additional Options ------------------------------------------------------------------------------ INSTALLATION ------------------------------------------------------------------------------ --------------- QUICK START --------------- If you are installing for the first time (and just want the defaults): Run these commands for a quick installation from source code: (skip these commands if you have installed rpm or debian package) ./configure --sysconfdir=/etc su make install cp /etc/rsnapshot.conf.default /etc/rsnapshot.conf Open up /etc/rsnapshot.conf with a text editor, and modify it for your system. Make sure the config file syntax is valid (remember, tabs, not spaces): /usr/local/bin/rsnapshot configtest The rsnapshot HOWTO is recommended reading for first time setups. It will walk you through this process in great detail. The rsnapshot HOWTO can be found online at http://www.rsnapshot.org/ ------------- UPGRADING ------------- If you are upgrading from a previous installation of rsnapshot 1.1.x, please read the file: docs/Upgrading_from_1.1 There are no special instructions for upgrading from rsnapshot 1.2.x to 1.3.x, since both use config_version 1.2. If you are not sure whether you need to do anything to upgrade your old rsnapshot.conf, you can run make upgrade or rsnapshot upgrade-config-file or rsnapshot -c /etc/rsnapshot.conf upgrade-config-file ---------------------- ADDITIONAL OPTIONS ---------------------- If you require more precise control over the locations of files: You can pass the following options to ./configure for more control over where various parts of rsnapshot are installed. The example values shown also happen to be the defaults. --prefix=/usr/local This will install everything under /usr/local --sysconfdir=/usr/local/etc This will install the example config file (rsnapshot.conf.default) under /usr/local/etc. This will also be the default directory where rsnapshot looks for its config file. It is recommended that you copy rsnapshot.conf.default and use it as a basis for the actual config file (rsnapshot.conf). --bindir=/usr/local/bin This will install the rsnapshot program under /usr/local/bin --mandir=/usr/local/man This will install the man page under /usr/local/man --with-perl=/usr/bin/perl Specify your preferred path to perl. If you don't specify this, the build process will detect the first version of perl it finds in your path. --with-rsync=/usr/bin/rsync Specify your preferred path to rsync. If you don't specify this, the build process will detect the first version of rsync it finds in your path. You can always change this later by editing the config file (rsnapshot.conf). --with-cp=/bin/cp Specify the path to GNU cp. The traditional UNIX cp command is not sufficient. If you don't specify this, the build process will detect the first version of cp it finds in your path. If you don't have the GNU version of cp, leave this commented out in the config file (rsnapshot.conf). --with-rm=/bin/rm Specify the path to the rm command. If you don't specify this, the build process will detect the first version of rm it finds in your path. --with-ssh=/usr/bin/ssh Specify your preferred path to ssh. If you don't specify this, the build process will detect the first version of ssh it finds in your path. SSH is an optional feature, so it is OK if it isn't on your system. Either way, if you want to use ssh, you need to specifically enable this feature by uncommenting the "cmd_ssh" parameter in the config file (rsnapshot.conf). --with-logger=/usr/bin/logger Specify your preferred path to logger. If you don't specify this, the build process will detect the first version of logger it finds in your path. If you want syslog support, make sure this is enabled in the config file. Syslog support is optional, so if you don't have it or comment it out it's OK. --with-du=/usr/bin/du Specify your preferred path to du. If you don't specify this, the build process will detect the first version of du it finds in your path. The "du" command only gets used when rsnapshot is called with the "du" argument to calculate the amount of disk space used. This is optional, so if you don't have it or comment it out it's OK. rsnapshot-1.3.1/README0000644000000000000000000001423311005052310014341 0ustar rootroot00000000000000rsnapshot 1.3.1 http://www.rsnapshot.org/ ------------------------------------------------------------------------------ rsnapshot comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See the GNU General Public Licence for details. For installation or upgrade instructions, read INSTALL ------------------------------------------------------------------------------ rsnapshot is a filesystem snapshot utility based on rsync. rsnapshot makes it easy to make periodic snapshots of local machines, and remote machines over ssh. The code makes extensive use of hard links whenever possible, to greatly reduce the disk space required. It is written entirely in perl with no module dependencies, and has been tested with versions 5.004 through 5.8.5. This program should work on any reasonably modern UNIX compatible OS. It has been tested successfully on the following operating systems: - Debian: 3.0 (woody), 3.1 (sarge), unstable (sid) - Redhat: 7.x, 8.0, Enterprise Linux 3.0 ES - Fedora Core 1, 3 - CentOS 3, 4 - WhiteBox Enterprise Linux 3.0 - Slackware 9.0 - SuSE: 9.0 - FreeBSD 4.9-STABLE - OpenBSD 3.x - Solaris 8 (SPARC and x86) - Mac OS X - IRIX 6.5 If this is your first experience with rsnapshot, you may want to read the rsnapshot HOWTO at http://www.rsnapshot.org/ The HOWTO will give you a detailed walk-through on how to get rsnapshot up and running in explicit detail. For a reference of all available commands, see the rsnapshot man page. If you are upgrading from version 1.1.6 or earlier, make sure you read the file docs/Upgrading_from_1.1. ------------------------------------------------------------------------------ COMPATIBILITY NOTICES (Please read) ------------------------------------------------------------------------------ (1) Note that systems which use GNU cp version 5.9 or later will have problems with rsnapshot versions up to and including 1.2.3, if cmd_cp is enabled (and points at the later gnu cp). This is no longer a problem since rsnapshot 1.2.9, as it strips off trailing slashes when running cp. (2) If you have rsync version 2.5.7 or later, you may want to enable the link_dest parameter in the rsnapshot.conf file. If you are running Linux but do not have the problem above, you should enable the cmd_cp parameter in rsnapshot.conf (especially if you do not have link_dest enabled). Be advised that currently link_dest doesn't do well with unavailable hosts. Specifically, if a remote host is unavailable using link_dest, there will be no latest backup of that machine, and a full re-sync will be required when it becomes available. Using the other methods, the last good snapshot will be preserved, preventing the need for a re-sync. We hope to streamline this in the future. ------------------------------------------------------------------------------ Once you have installed rsnapshot, you will need to configure it. The default configuration file is /etc/rsnapshot.conf, although the exact path may be different depending on how the program was installed. If this file does not exist, copy /etc/rsnapshot.conf.default over to /etc/rsnapshot.conf and edit it to suit your tastes. See the man page for the full list of configuration options. When /etc/rsnapshot.conf contains your chosen settings, do a quick sanity check to make sure everything is ready to go: rsnapshot configtest If this works, you can see essentially what will happen when you run it for real by executing the following command (where interval is hourly, daily, etc): rsnapshot -t [interval] Once you are happy with everything, the final step is to setup a cron job to automate your backups. Here is a quick example which makes backups every four hours, and daily backups for a week: 0 */4 * * * /usr/local/bin/rsnapshot hourly 50 23 * * * /usr/local/bin/rsnapshot daily In the previous example, there will be six "hourly" snapshots taken each day (at 0,4,8,12,16, and 20 hours). There will also be daily snapshots taken every night at 11:50PM. The number of snapshots that are saved depends on the "interval" settings in /etc/rsnapshot.conf. For example: interval hourly 6 This means that every time "rsnapshot hourly" is run, it will make a new snapshot, rotate the old ones, and retain the most recent six (hourly.0 - hourly.5). If you prefer instead to have daily, weekly and monthly backups, you might set up cron like this: 00 00 * * * /usr/local/bin/rsnapshot daily 00 23 * * 6 /usr/local/bin/rsnapshot weekly 00 22 1 * * /usr/local/bin/rsnapshot monthly This specifies a daily rsnapshot at midnight, a weekly snapshot on Saturdays at 11:00pm and a monthly rsnapshot at 10pm on the first day of each month. Note that the backups are done from the highest interval first (in this case monthly) and go down to the lowest interval. If you are not having cron invoke the "hourly" snapshot interval, then you must also ensure that hourly is not listed as one of your intervals in rsnapshot.conf (for example, comment out hourly, so that "daily" becomes the lowest interval). Remember that it is only the lowest interval which actually does the rsync to back up the relevant source directories, the higher intervals just rotate snapshots around. Unless you have enabled sync_first in your rsnapshot.conf, in which case only the "sync" pseudo-interval does the actual rsync, and all real intervals just rotate snapshots. For the full documentation, type "man rsnapshot" once it is installed, or visit http://www.rsnapshot.org/. The HowTo on the web site has a detailed overview of how to install and configure rsnapshot, and things like how to set it up so users can restore their own files. If you plan on using the "backup_script" parameter in your backup scheme, take a look at the utils/ directory in the source distribution for several example scripts. The utils/rsnapreport.pl script is well worth a look. ------------------------------------------------------------------------------ AUTHORS ------------------------------------------------------------------------------ Please see the AUTHORS file for the complete list of contributors. rsnapshot-1.3.1/TODO0000644000000000000000000000315410512105564014165 0ustar rootroot00000000000000rsnapshot TODO list: Future versions (in no particular order) ------------------------------------------------------------------------------ - Add "print-config" command. (Added: djk 2006-09-24) - Converge rpm packages/spec files between rsnapshot, fedora, suse. (Added: djk 2006-09-24) - Go through old TODO list. (Added: djk 2006-09-24) Old TODO list -- from 1.2.x (2005) and earlier ------------------------------------------------------------------------------ - Add visible return values for error messages on commands like rm, cp, etc - Add global and per-backup "bwlimit" parameter, and pass it along to rsync - Revamp config file to allow better representation of hierarchial data - Add "delete" feature, to allow deleting specific directories or files from the snapshot_root without having to get your hands dirty. This code will be extremely well tested and fault tolerant. - Tighten up validation of third argument on backup points - Add e-mail reporting patch from David Tejedor. - Look into using IPC to make backup calls asynchronous (with a configurable limit on the upper number of simultaneous backups, and auto-limiting to one backup job per remote or local host at once). - Add interactive mode to generate config files. - Add rsync STDOUT/STDERR output to logfile at higher log settings. This will be accomplished by opening the rsync command as a pipe to a filehandle and printing / logging the output. - Think of a way to be able to backup different backup points at different speeds. I.E. some things would get backed up hourly, whereas other backup points would get backed up daily. rsnapshot-1.3.1/NEWS0000644000000000000000000000007410270772230014173 0ustar rootroot00000000000000Please see the ChangeLog, README, and man page for updates. rsnapshot-1.3.1/ChangeLog0000644000000000000000000006102011056477361015256 0ustar rootroot00000000000000------------------------------------------------------------------------------ rsnapshot changelog http://www.rsnapshot.org/ ------------------------------------------------------------------------------ VERSION 1.3.1 (Aug 31 2008) ------------------------------------------------------------------------------ - Fix help message mixup in lines between -c and -t. - Add more specific error messages for not currently implemented potential per backup point options, like cmd_preexec. - Allow named pipe as logfile - suggested by Patrice Levesque. - Include rsnapshot-copy script written by Matt McCutchen. - Allow `backticks` in include_conf. - Apply fix-sync_first-rollback.diff patch from Matt McCutchen (02 Apr 2008). - hopefully fix bug with link_dest not being used on second and later backups when you have link_dest 1 and sync_first 1. (Ignore $sync_dir_was_present) - Patch from Adam Greenbaum to allow passing of ssh arguments correctly. - David Grant added rsync_numtries to rsnapshot.conf. - Applied Ben Low's Linux LVM patch. - Added stop_on_stale_lockfile, thanks to Henning Moll. - Michael Ashley's fix for filter/space problems on the rsync command line. - Remove trailing whitespace from command names in rsnapshot.conf. - Warn about extra spaces between tab and argument. - Added multi-line config options, thanks to Dieter Bloms. - The 'interval' config option is now called 'retain'. - chdir to avoid an obscure bug in some versions of GNU rm. - Changed use_lazy_deletes option to use _delete.$$ directories. - Added note about -H and hard links to docs for rsync_short_args. - Include rsnapshot-diff.1 in rpm. - Fix bug with rsnapshot sync the first time (when .sync does not exist) trying to copy hourly.0 to .sync, even if hourly.0 doesn't exist. http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=413439 VERSION 1.3.0 (Oct 21 2006) ------------------------------------------------------------------------------ - Add files rsnapreport.pl Upgrading_from_1.1 rsnapshot-HOWTO.en.html to rpm. - fix a bug with removing interval.delete (with use_lazy_deletes). - rsnapshot detects the global ssh_args option being set multiple times, and gives a config error suggesting the per-backup ssh_args instead. - Move Upgrading section of INSTALL to docs/Upgrading_from_1.1. - Incorporate patch from Alan Batie to fix bugs with include_conf. - check for quoting on $rsync_long_args rather than just splitting on space. - Change rsnapshot.conf default to have lockfile enabled. - Check for stale lock files (PID not currently running). - explicitly add mode 0644 to sysopen() to create lockfile - give warning if write() or close() return 0 when writing/closing lockfile - Make prev_max_interval "not present (yet), nothing to copy" message when rotating interval.0 more visible (level 3 instead of level 4). - Add man page for rsnapshot-diff (generated from perldoc). - Updates to rsnapshot man pages (via perldoc). - Use =item in AUTHORS section - move mis-placed =back - document stale lock file detection - strongly recommend using a lock file - add a chmod to example backup script - change crontab example for weekly from 4 "weekly"s per month to 1 per week - expand on why higher intervals are done first via cron. - Change space to tab after #cmd_rsnapshot_diff in rsnapshot.conf.default.in. - In rpm patch, set cmd_rsnapshot_diff to /usr/bin/rsnapshot-diff. - Set the test scripts t/*.t.in to run from the source directory and create directory t/support/files/a if necessary. - Trim comments in README about gnu cp versions > 5.3 since rsnapshot strips trailing slashes for gnu cp with rsnapshot 1.2.9 and later. - Add pointers to HOWTO and utils/rsnapreport.pl in README. - More examples (eg: timestamp backup_script) in rsnapshot.conf.default.in. - Change "Perhaps this is not GNU cp?" error message. VERSION 1.2.9 (May 18 2006) ------------------------------------------------------------------------------ - David Keegel now responsible for release management - Added utils/rsnapreport.pl, written by William Bear. - Detect exit status 23 and 24 from rsync in rsync_cleanup_after_native_cp_al - Add $! (system error message) to various warning messages in native_cp_al - Add more examples and comments to rsnapshot.conf.default.in - In Makefile*, for "make tar", include "t" (testing) in the tar file. - Do not strip the trailing slash if it's a remote root filesystem. (This was a bug in rsnapshot 1.2.3 if you use "backup host:/ ...") - Give a more descriptive error message "cannot have a remote snapshot_root" if user tries to configure an ssh path or rsync path as snapshot_root. - Add some more description to the error "rsnapshot refuses to create snapshot_root when no_create_root is enabled", after checking whether the snapshot_root is a non-directory file, or just plain non-existent. - Changed default syslog level to 'info' instead of 'notice' - Added include_conf directive - Allowed remote ssh directory paths starting with "~/" as well as "/". - Changed rsnapshot maintainer from Nathan Rosenquist to David Cantrell - David Cantrell wrote the rsnapshot-diff utility - Chris Petersen added cwrsync permanent-share support - Robert Jackson added use_lazy_deletes - Added rollback for backup_scripts - Added rsnapshot-diff to Autoconf/Automake install/build process - Added sha1sum to utils/sign_packages.sh - Added a CVS Id to key files - Fixed exit value for some test invocations - Added 'rsnapshot diff' front-end to rsnapshot-diff - Added cmd_rsnapshot_diff - Added cmd_preexec - Added cmd_postexec - Added db prefs examples to utils/backup_mysql.sh and utils/backup_pgsql.sh - Fixed formatting with email addresses under AUTHORS section of man page - Added an extra safety check in copy_symlink() - Fixed swapped config comments about rsync_long_args in write_upgrade_config_file() - Added optional use of the CPAN Lchown module - Added safe_chown() wrapper to handle chown() calls safely - Added warning message if we can't properly lchown a symlink - Added fixes in sync_cp_src_dest() and sync_rm_dest() to properly delete a file that is being replaced with a directory - Fixed error message for dest not being specified in sync_rm_dest() - Changed skip message level to 2 in rsync_backup_point() - Added better file type checking in sync_cp_src_dest() - Removed redundant stat() calls in sync_cp_src_dest() and sync_rm_dest() - Removed trailing slashes from file paths when calling cp -al subroutines - Changed show_usage() to use here printing - Changed strip trailing slash operation in rsync_backup_point() to use strip_trailing_slash() - Fixed incorrect call to cmd_rm_rf() in handle_interval() - Fixed trailing slash on call to bail() in handle_interval() - Added sync_first feature (touches a lot of code) - When link_dest is enabled, rsnapshot will now hunt for the newest available directory to use as a link_dest target (up to the oldest directory) - When use_lazy_deletes is enabled, remove the lockfile before the final delete - Expanded on default (no args) and help messages - Added show_latest_snapshot() subroutine for shell scripts - Fixed sync_if_different() to allow alternating directories and files to be created with the same names between runs - Removed redundant line width and indent values in wrap_cmd() calls - Anthony Ettinger wrote utils/mysqlbackup.pl - Sherman Boyd wrote utils/random_file_verify.sh VERSION 1.2.3 (Aug ?? ??:?? 2005) ------------------------------------------------------------------------------ - Fixed a bug introduced in 1.2.2 when rsync is not using --relative - Fixed a bug where the snapshot_root could be included in backups if the root filesystem was being backed up and --relative was not set VERSION 1.2.2 (Aug 20 18:07 2005) ------------------------------------------------------------------------------ - David Keegel fixed a race condition in add_lockfile() - David Keegel improved error reporting when config file isn't present - Provided a workaround for a bug in some versions of rsync which caused files to not be deleted properly when the --relative flag was set. VERSION 1.2.1 (Apr 09 15:10 2005) ------------------------------------------------------------------------------ - Fixed security bug when neither cmd_cp or link_dest are enabled - Disabled chown() call in copy_symlink() - Check for symlink before all chown() calls VERSION 1.2.0 (Jan 31 21:43 2005) ------------------------------------------------------------------------------ - Turned off buffering ($|=1) - Changed default lockfile to /var/run/rsnapshot.pid, for FHS compliance - Clarified man page licensing (GPL) - Fixed is_real_local_abs_path() to handle dangling symlinks - Changed utils/backup_smb_share.sh to re-order the smbtar arguments - Added "-uroot" to utils/backup_mysql.sh example file - Changed regex in is_blank() subroutine - Changed rsync include/exclude mode to relative - Peter Palfrader enhanced error reporting to include command line options - Bharat Mediratta improved the exclusion rules to avoid backing up the snapshot root. The old way was also kept for users who can't or don't want to upgrade their destination paths in their backup points. - Bharat Mediratta added a "+" feature to the per-backup point args to allow additive include/exclude rules. - Added safe_rename() subroutine to work around a semi-obscure timestamp bug in certain Linux kernels - Clarified error message about local/relative paths in config file parsing - Added check for leading/trailing spaces in remote (ssh) paths - Added du(1) and crontab(1) to man page references - Added config.guess and config.sub for automake - Changed default destination paths for backup points in example config file for compatibility with --relative rsync flag - Added formatting fix to show one slash only when invoking backup_script with link_dest option enabled - Broke backwards compatibility for the benefit of fixing several outstanding issues. The default value for rsync_long_args is now different. - Changed add_lockfile() verbose message to "echo $$ > /path/to/lockfile.pid" which is actually what the code is doing - Added check to make sure backup_scripts can't share destination path with backup points - Added check to make sure different backup_script destinations don't overlap and don't clobber backup point destinations - Added "cmd_du" parameter to allow specifying the path to "du" - Nicolas Kaiser provided various typo fixes in the program and man page - Fixed "missing rsync/configtest ok" bug - Added config_version parameter, which is now required - All autoconf files were updated with the ones from Debian sarge - Added upgrade-config-file feature for "make upgrade" target and manual use - Added upgrade feature to RPM spec file - Added check-config-version feature for use with shell scripts, etc. - Changed version_only argument to version-only, for consistency with new options - Conditionalized configure script to only advise the user to copy the rsnapshot.conf.default file to rsnapshot.conf if it's a new installation - Added rollback feature to restore interval.0 snapshots when using link_dest - Added second option for du, to compare subdirectories or files - Added "du_args" to pass arguments to du - Relaxed cmd line option validation, but only when du is the command - Now only show command invocation for logger on verbose level 4 - Added rsync cleanup after native_cp_al() to preserve special files - Removed warning messages from native_cp_al() about special files - Modified error printing so full run string is displayed once at the top of a list of error messages - Fixed bug in old method of preventing the snapshot root from being backed up, which occurred when snapshot root was more than one level down from a backup point - Added commented out du_args to rsnapshot.conf.default.in - Added descriptive error if "du" fails VERSION 1.1.6 (Jul 05 16:35 2004) ------------------------------------------------------------------------------ - Moved the bulk of the program into smaller subroutines (finally) - show_disk_usage() now exits the program directly instead of returning a value - "0" can now be used as a valid interval name - Config error messages now wrap before 80 columns. - Moved $file_line_num global var into parse_config_file() - Split on \s+ instead of \s where appropriate - Moved $rsync_include_args and $rsync_include_file_args into parse_config_file() - Removed the $have_{cmd} global variables entirely - Took %opts out of the global namespace and into get_cmd_line_opts() - Changed a failed syslog call from an error to a warning - Removed $cwd from global namespace - Fixed bug where cp_al() commands would not be displayed in test mode - Removed redundant $done flag from file_diff() while loop - Downgraded close() file errors to warnings - Added utils/backup_dpkg.sh to backup Debian package information - Simplified the utils/ section of the Makefile under "make tar" - Now exits with an error if unknown command line flags are found - Added a check in parse_cmd_line_opts() for the config file if specified - Changed link_dest rsync error message to description instead of number - Changed description of test mode in the help cmd - Changed description of -V mode - Removed perl defaults from man page - Clarified crontab entry timing in man page - Removed trailing slashes on calls to mkpath() to fix bug with NetBSD - Removed trailing slashes on calls to rename() to fix bug with NetBSD - Removed trailing slashes on calls to rmtree() just in case - Fixed man page generation in "make tar" target - Changed -V message when there's no directory to rotate VERSION 1.1.5 (Jun 20 20:56 2004) ------------------------------------------------------------------------------ - /bin/rm is the default for deleting directories (in the default config file) - Removed redundant validation (re: intervals) in execution section - Print PID in lockfile - Added a few more comments, clarified some existing comments - Made some minor updates to the man page - Fix display formatting double-slash bug when '/' is a backup point - Changed return value when called with no cmd line args to 1 - Added a new exit code, for warnings (2) - rsync exit codes 23 and 24 make rsnapshot return a warning exit code instead of an error - Changed link_dest comment in config file to mention "cross-platform" - Added utils/debug_moving_files.sh abuse script for testing - Added 'du' option to show disk usage in snapshot_root - Moved setlocale() after begin message - Added manual link() call when we're using --link-dest and a single file - Don't call syslog in bail() if it's a test run VERSION 1.1.4 (May 16 23:44 2004) ------------------------------------------------------------------------------ - (re)added the cmd_rm parameter. rmtree() can't delete some obscure files on some systems - Added rm_rf() stub function to recursively remove things using either rmtree() or /bin/rm -rf, depending on the configuration. - Added cp and rm detection to ./configure script - Set LC_ALL locale variable to C in an attempt to fix rmtree() locale issue - Added no_create_root option to rsnapshot - Added utils/make_cvs_snapshot.sh utility script - Added utils/sign_packages.sh utility script - Added utils/rsnapshot_if_mounted.sh utility script - Standardized comment headers in utils/ scripts - Added DEBIAN/copyright file - Fixed man page to say RSNAPSHOT instead of RSNAPSHOT-PROGRAM for the title VERSION 1.1.3 (Apr 06 14:24 2004) ------------------------------------------------------------------------------ - Validating rsync_short_args, must be in format '-an', not '-a -n' - Assembling @cmd_stack list one at a time, rather than using join() - Added "don't panic" message in rotate_interval() at verbose >= 4 when no filesystem actions get performed - Fixed latent display bug in print_msg() (now that it's getting used) - Fixed "cd //" display bug when running from root directory (removed extra /) VERSION 1.1.2 (Mar 17 02:12 2004) ------------------------------------------------------------------------------ - Fixed slash formatting issue with non-ssh rsync protocol calls - Fixed a slightly inconvenient permissions issue in rsnaptar - Added support for arbitrary arguments to backup_script files VERSION 1.1.1 (Feb 11 23:24 2004) ------------------------------------------------------------------------------ - Changed some fatal errors to warnings in some recursive subroutines - Added optional GPG support to the rsnaptar utility shell script VERSION 1.1.0 (Jan 24 16:41 2004) ------------------------------------------------------------------------------ - The first interval must now have a value of at least 2 if more than one interval is being used - Now allows "/" as a backup point on the local drive - Cleaned up command formatting to consolidate slashes - Added subroutines for centralized print/logging - Added logfile and loglevel parameters to the config file - Added logging feature - Moved loglevel/verbose number validation into a seperate subroutine - Added much more error checking on the config file - Changed @snapshot_points to @backup_points for more consistent terminology - Made all "-x" executable checks also check for "-f" file - Made rsync error messages report the full path to rsync and the correct return value - Fixed minor screen formatting issue with print_cmd() subroutine where it could line wrap the first element of a command - Changed exit error code from -1 (255) to 1, to be more standard - Added include, exclude, include_file, and exclude_file params - Fixed bug where not all locally specified backup options would be parsed - Replaced calls to bail() from config parsing code with config_err() calls - Added directory traversal checks for commands - Changed indentation in print_cmd() to 4 spaces instead of 2 - Fixed bug where a file named "tmp" in the snapshot root would not be deleted properly at runtime (if sync_if_different() was used) VERSION 1.0.10 (Jan 20 00:43 2004) ------------------------------------------------------------------------------ - Added link_dest option, to use the --link-dest flag with rsync - Now checking the return values from rsync, with conditional syntax warning for --link-dest on older versions - Added additional calls to syslog, to report rsync failures - Now checking the return value of scripts called from backup_script - Conditionalized the backup_interval() and rotate_interval() subroutines to only delete the oldest interval if we're keeping more than one of that interval - Reformatted source code so it doesn't wrap (at 126 columns, or 1024x768) - Shortened output when invoked with no args or from help to fix in 80 columns - Changed rotate_interval() subroutine to simply move directories from lower intervals up instead of recursively copying hard links - Added formatting subroutine to wrap all verbose command output at 80 columns VERSION 1.0.9 (Jan 6 19:17 2004) ------------------------------------------------------------------------------ - Added backup_mysql.sh example script in utils/ to backup a MySQL database - Added backup_smb_share.sh example script in utils/ to backup an SMB share - Changed verbose settings internally to use numbers, instead of several arbitrary variables. - Added optional "verbose" field to the config file, with values 1-5 - Fixed lockfile code to not run in test mode VERSION 1.0.8 (Dec 26 12:56 2003) ------------------------------------------------------------------------------ - Added backup_script option to have rsnapshot invoke backup scripts directly - Added two example backup scripts in the utils/ directory, one for Postgres, and one for downloading the CVS root for rsnapshot - Added optional syslog support using the "logger" command - Fixed ssh_args local override for individual backup points - Added additional comments to various sections of the code - Removed redundant rsync arguments from the default - Moved add_lockfile() call so it runs later in the program VERSION 1.0.7 (Dec 19 19:22 2003) ------------------------------------------------------------------------------ - Added ssh_args parameter to pass arbitrary args to ssh - Fully integrated Autoconf build support for the program and config file - Provided more helpful error messages when the config file is not found - Fixed false "Can not remove lockfile" error when cmd_ssh is not defined but is referenced later in backup points VERSION 1.0.6 (Nov 26 21:03 2003) ------------------------------------------------------------------------------ - added \n to utime() debug message - moved all rsync calls into dynamically populated arrays - added rsync_short_args and rsync_long_args to config file - improved parse_backup_opts() validation code - Fixed "make install" vs. INSTALL bug for Mac OS X - Ted Zlatanov added Autoconf support! VERSION 1.0.5 (Nov 14 00:22 2003) ------------------------------------------------------------------------------ - Changed domain to rsnapshot.org - Added lockfile feature, with patch to enable it by default in the RPM - Updated man page to include the one_fs feature, did general clean up - Fixed '..' pattern matching bug that would exclude valid files - Updated Makefile to use "install", now allows "make tar" as a non-root user - Moved most remaining regexes into dedicated subroutines VERSION 1.0.4 (Nov 6 23:18 2003) ------------------------------------------------------------------------------ - Added one_fs feature to the config file (same as -x on the command line) - Fixed anonymous rsync feature, which had been broken in 1.0.3 - Added verification data to the RPM package VERSION 1.0.3 (Nov 2 14:43 2003) ------------------------------------------------------------------------------ - Carl Wilhelm Soderstrom added RPM format to release. - Added "one filesystem" option to prevent rsnapshot from crossing filesystems within a backup point. Patch provided by Ted Zlatanov - Minor typographical errors fixed. VERSION 1.0.2 (Oct 24 23:22 2003) ------------------------------------------------------------------------------ - added -V "extra verbose" option, to show rsync verbose output VERSION 1.0.1 (Oct 18 03:22 2003) ------------------------------------------------------------------------------ - Make sure the snapshot directory either needs to be created or already is a directory. Previously we were checking only if the snapshot root existed, which would cause problems if it were a file. - Cleaned up and streamlined the config file parsing portion of the code. - Changed numeric comparisons so that a typo would prevent compilation, instead of acting weird. i.e. (0 == $foo) instead of ($foo == 0) VERSION 1.0.0 (Sep 14 02:58 2003) ------------------------------------------------------------------------------ - Removed backward compatibility cruft for mkdir, touch, rm, and mv. - rsnapshot has now been tested successfully on Debian and Redhat Linux, as well as IRIX and Solaris. - Man pages are no longer gzipped, for compatibility with Solaris and others. VERSION 0.9.5 (Sep 9 20:11 2003) ------------------------------------------------------------------------------ - Removed most dependencies on external shell programs. - Added compatibility for non-Linux platforms. - Did significant testing/debugging to ensure compatibility with perl 5.004, 5.6, and 5.8 - Tested and working successfully on IRIX, more tests to follow. VERSION 0.9.4 (Sep 1 23:55 2003) ------------------------------------------------------------------------------ - Heavily commented variables, and added much stricter syntax checking of the config file. - Additional error checking on mkdir - updated the man page. VERSION 0.9.3 (Sep 1 01:46 2003) ------------------------------------------------------------------------------ - Anonymous rsync connections now supported. - Reverted back from recycling the oldest snapshots to the tried and true method of deleting the old ones. - Now rsnapshot will not only create the snapshot root directory as it did before, but it will also chmod 0700 the directory when it creates it. VERSION 0.9.2 (Aug 31 04:08 2003) ------------------------------------------------------------------------------ - Optimized rotating snapshot intervals by recycling the last directory to the first, instead of deleting the last and copying .0 to .1 - Added support for spaces in path names. - The config file now requires tabs to seperate all entries, where spaces were before acceptable. This was the easiest way to support spaces in path names. - Directory entries now require a trailing slash. This is so that files can be treated correctly without having to be examined directly (which is impractical over rsync/ssh). rsnapshot-1.3.1/docs/0000755000000000000000000000000011056477673014443 5ustar rootroot00000000000000rsnapshot-1.3.1/docs/HOWTOs/0000755000000000000000000000000011056477673015526 5ustar rootroot00000000000000rsnapshot-1.3.1/docs/HOWTOs/rsnapshot-HOWTO.en.html0000644000000000000000000017230210511467157021730 0ustar rootroot00000000000000 rsnapshot HOWTO

rsnapshot HOWTO

David Cantrell

2004-01-20

Abstract

rsnapshot is a filesystem backup utility based on rsync. Using rsnapshot, it is possible to take snapshots of your filesystems at different points in time. Using hard links, rsnapshot creates the illusion of multiple full backups, while only taking up the space of one full backup plus differences. When coupled with ssh, it is possible to take snapshots of remote filesystems as well. This document is a tutorial in the installation and configuration of rsnapshot.


1. Introduction

rsnapshot is a filesystem backup utility based on rsync. Using rsnapshot, it is possible to take snapshots of your filesystems at different points in time. Using hard links, rsnapshot creates the illusion of multiple full backups, while only taking up the space of one full backup plus differences. When coupled with ssh, it is possible to take snapshots of remote filesystems as well.

rsnapshot is written in Perl, and depends on rsync. OpenSSH, GNU cp, GNU du, and the BSD logger program are also recommended, but not required. All of these should be present on most Linux systems. rsnapshot is written with the lowest common denominator in mind. It only requires at minimum Perl 5.004 and rsync. As a result of this, it works on pretty much any UNIX-like system you care to throw at it. It has been successfully tested with Perl 5.004 through 5.8.2, on Debian, Redhat, Fedora, Solaris, Mac OS X, FreeBSD, OpenBSD, NetBSD, and IRIX.

The latest version of the program and this document can always be found at http://www.rsnapshot.org/.

1.1. What you will need

At a minimum: perl, rsync

Optionally: ssh, logger, GNU cp, GNU du

Additionally, it will help if you have reasonably good sysadmin skills.

1.2. Copyright and License

This document, rsnapshot HOWTO, is copyrighted (c) 2005 by Nathan Rosenquist, with some portions (c) 2006 David Cantrell. You can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. A copy of the license is available at http://www.gnu.org/copyleft/gpl.html.

1.3. Disclaimer

No liability for the contents of this document can be accepted. Use the concepts, examples and information at your own risk. There may be errors and inaccuracies, that could be damaging to your system. Proceed with caution, and although this is highly unlikely, the author(s) do not take any responsibility.

All copyrights are held by their by their respective owners, unless specifically noted otherwise. Use of a term in this document should not be regarded as affecting the validity of any trademark or service mark. Naming of particular products or brands should not be seen as endorsements.

1.4. Feedback

Feedback is most certainly welcome for this document. Send your additions, comments and criticisms to the following email address : .

2. Motivation

I originally used Mike Rubel's shell scripts to do rsync snapshots a while back. These worked very well, but there were a number of things that I wanted to improve upon. I had to write two shell scripts that were customized for my server. If I wanted to change the number of intervals stored, or the parts of the filesystem that were archived, that meant manually editing these shell scripts. If I wanted to install them on a different server with a different configuration, this meant manually editing the scripts for the new server, and hoping the logic and the sequence of operations was correct. Also, I was doing all the backups locally, on a single machine, on a single hard drive (just to protect from dumb user mistakes like deleting files). Never the less, I continued on with this system for a while, and it did work very well.

Several months later, the IDE controller on my web server failed horribly (when I typed /sbin/shutdown, it said the command was not found). I was then faced with what was in the back of my mind all along: I had not been making regular remote backups of my server, and the local backups were of no use to me since the entire drive was corrupted. The reason I had only been making sporadic, partial remote backups is that they weren't automatic and effortless. Of course, this was no one's fault but my own, but I got frustrated enough to write a tool that would make automated remote snapshots so easy that I wouldn't ever have to worry about them again. This goal has long been reached, but work on rsnapshot still continues as people submit patches, request features, and ways are found to improve the program.

3. Installation

This section will walk you through the installation of rsnapshot, step by step. This is not the only way to do it, but it is a way that works and that is well documented. Feel free to improvise if you know what you're doing.

This guide assumes you are installing rsnapshot 1.2.0 for the first time. If you are upgrading from an earlier version, please read the INSTALL file that comes with the source distribution instead.

3.1. 30 second version (for the impatient)

./configure --sysconfdir=/etc
su
make install
cp /etc/rsnapshot.conf.default /etc/rsnapshot.conf

The rest of this section is the long version.

3.2. Untar the source code package

tar xzvf rsnapshot-1.2.0.tar.gz

If you don't have GNU tar, you may have to do this in two steps instead:

gunzip rsnapshot-1.2.0.tar.gz
tar xvf rsnapshot-1.2.0.tar

3.3. Change to the source directory

cd rsnapshot-1.2.0/

3.4. Decide where you want to install

By default, the installation procedure will install all files under /usr/local. For this tutorial, this will be OK except we will install the config file under /etc.

We are assuming that rsync, ssh, logger, and du are all in your search path. If this is not the case, you can specify the path to any of these programs using the typical Autoconf --with-program=/path/to/program syntax. For example, if Perl was in /opt/bin/perl and rsync was in /home/me/bin/rsync, you could run configure like:

./configure --with-perl=/opt/bin/perl --with-rsync=/home/me/bin/rsync

3.5. Run the configure script

This will poke and prod your system to figure out where the various external programs that rsnapshot depends on live. It also generates the Makefile that we will use to install the program. The configure script accepts arguments that can be used to tell it where to install the program, and also where to find the supporting programs. For this installation, the only non-default option we want is to put the config file in the /etc directory. To do this, run this command at the shell:

./configure --sysconfdir=/etc

If all goes well, you're ready to install the program. If there was a problem, it should be descriptive. Most likely a problem would be the result of something that was required and not found (like rsync or perl). If this happens, you must figure out where the missing program is located on your system, or install it if necessary. If you know where it is but configure couldn't find it, you can specify the path using the --with-program=/path/to/program options described above.

3.6. Install the program

If you've followed these instructions so far, you will have configured rsnapshot to be installed under /usr/local, with the config file in /etc. Under these circumstances, it will be necessary to become root to install the program. Now is the time to do so. You will, of course, need the root password to do this:

su

This will prompt you for the root password.

Now, to install rsnapshot, run the following command:

make install

This will install rsnapshot with all the settings you specified in the ./configure stage. If all goes well, you will have the following files on your system:

/usr/local/bin/rsnapshot The rsnapshot program

/usr/local/man/man1/rsnapshot.1 Man page

/etc/rsnapshot.conf.default The example config file

If you decide later that you don't want rsnapshot on your system anymore, simply remove the files listed above, or run make uninstall in the same source directory you installed from. Of course, if you installed with different options, the location of these files may be different.

4. Configuration

4.1. Create the config file

In the install process, the config file is not created or installed. However, a working example is provided that you can copy. To copy the example config file into the location rsnapshot will be looking for the real config file:

cp /etc/rsnapshot.conf.default /etc/rsnapshot.conf

As a general rule, you should avoid modifying /etc/rsnapshot.conf.default, simply because it is a working example that you may wish to refer to later. Also, if you perform an upgrade, the rsnapshot.conf.default file will always be upgraded to the latest version, while your real config file will be safe out of harm's way. Please note that if you run make upgrade during an upgrade, your rsnapshot.conf may be modified slightly, and the original will then be saved in rsnapshot.conf.backup in the same directory.

4.2. Where to go for more info

The rsnapshot.conf config file is well commented, and much of it should be fairly self-explanatory. For a full reference of all the various options, please consult the rsnapshot man page. Type:

man rsnapshot

This will give you the complete documentation. However, it assumes that you already know what you're doing to a certain extent. If you just want to get something up and running, this tutorial is a better place to start. If your system can't find the man page, /usr/local/man probably isn't in your $MANPATH environmental variable. This is beyond the scope of this document, but if it isn't working for you, you can always read the newest man page on the rsnapshot web site at http://www.rsnapshot.org/

4.3. Modifying the config file

In this example, we will be using the /.snapshots/ directory to hold the filesystem snapshots. This is referred to as the “snapshot rootâ€. Feel free to put this anywhere you have lots of free disk space. However, the examples in this document assume you have not changed this parameter, so you will have to substitute this in your commands if you put it somewhere else.

Also please note that fields are separated by tabs, not spaces. The reason for this is so it's easier to specify file paths with spaces in them.

4.3.1. cmd_cp

If enabled, the cmd_cp parameter should contain the path to the GNU cp program on your filesystem. If you are using Linux, be sure to uncomment this by removing the hash mark (#) in front of it. If you are using BSD, Solaris, IRIX, or most other UNIX variants, you should leave this commented out.

What makes GNU cp so special is that unlike the traditional UNIX cp, it has the ability to make recursive “copies†of directories as hard links.

If you don't have GNU cp, there is a subroutine in rsnapshot that somewhat approximates this functionality (although it won't support more esoteric files such as device nodes, FIFOs, sockets, etc). This gets followed up by another call to rsync, which transfers the remaining special files, if any. In this way, rsnapshot can support all file types on every platform.

The rule of thumb is that if you're on a Linux system, leave cmd_cp enabled. If you aren't on a Linux system, leave cmd_cp disabled. There are reports of GNU cp working on BSD and other non-Linux platforms, but there have also been some cases where problems have been encountered. If you enable cmd_cp on a non-Linux platform, please let the mailing list know how it worked out for you.

4.3.2. cmd_rsync

The cmd_rsync parameter must not be commented out, and it must point to a working version of rsync. If it doesn't, the program just will not work at all.

Please note that if you are using IRIX, there is another program named rsync that is different than the “real†rsync most people know of. If you're on an IRIX machine, you should double check this.

4.3.3. cmd_ssh

If you have ssh installed on your system, you will want to uncomment the cmd_ssh parameter. By enabling ssh, you can take snapshots of any number of remote systems. If you don't have ssh, or plan to only take snapshots of the local filesystem, you may safely leave this commented out.

4.3.4. cmd_logger

The cmd_logger parameter specifies the path to the logger program. logger is a command line interface to syslog. See the logger man page for more details. logger should be a standard part of most UNIX-like systems. It appears to have remained unchanged since about 1993, which is good for cross-platform stability. If you comment out this parameter, it will disable syslog support in rsnapshot. It is recommended that you leave this enabled.

4.3.5. cmd_du

The cmd_du parameter specifies the path to the du program. du is a command line tool that reports on disk usage. rsnapshot uses du to generate reports about the actual amount of disk space taken up, which is otherwise difficult to estimate because of all the hard links.

If you comment this out, rsnapshot will try to use the version of du it finds in your path, if possible. The GNU version of du is recommended, since it has the best selection of features, and supports the most options. The BSD version also seems to work, although it doesn't support the -h flag. Solaris du does not work at all, because it doesn't support the -c parameter.

4.3.6. link_dest

If you have rsync version 2.5.7 or later, you may want to enable this. With link_dest enabled, rsnapshot relies on rsync to create recursive hard links, overriding GNU cp in most, but not all, cases. With link_dest enabled, every single file on your system can be backed up in one pass, on any operating system. To get the most out of rsnapshot on non-Linux platforms, link_dest should be enabled. Be advised, however, that if a remote host is unavailable during a backup, rsnapshot will take an extra step and roll back the files from the previous backup. Using GNU cp, this would not be necessary.

4.3.7. interval

rsnapshot has no idea how often you want to take snapshots. Everyone's backup scheme may be different. In order to specify how much data to save, you need to tell rsnapshot which “intervals†to keep, and how many of each. An interval, in the context of the rsnapshot config file, is a unit of time measurement. These can actually be named anything (as long as it's alphanumeric, and not a reserved word), but by convention we will call ours hourly and daily. In this example, we want to take a snapshot every four hours, or six times a day (these are the hourly intervals). We also want to keep a second set, which are taken once a day, and stored for a week (or seven days). This happens to be the default, so as you can see the config file reads:

interval    hourly  6
interval    daily   7

It also has some other entries, but you can either ignore them or comment them out for now.

Please note that the hourly interval is specified first. This is very important. The first interval line is assumed to be the smallest unit of time, with each additional line getting successively larger. Thus, if you add a yearly interval, it should go at the bottom, and if you add a minutes interval, it should go before hourly. It's also worth noting that the snapshots get “pulled up†from the smallest interval to the largest. In this example, the daily snapshots get pulled from the oldest hourly snapshot, not directly from the main filesystem.

4.3.8. backup

Please note that the destination paths specified here are based on the assumption that the --relative flag is being passed to rsync via the rsync_long_args parameter. If you are installing for the first time, this is the default setting. If you upgraded from a previous version, please read the INSTALL file that came with the source distribution for more information.

This is the section where you tell rsnapshot what files you actually want to back up. You put a “backup†parameter first, followed by the full path to the directory or network path you're backing up. The third column is the relative path you want to back up to inside the snapshot root. Let's look at an example:

backup      /etc/      localhost/

In this example, backup tells us it's a backup point. /etc/ is the full path to the directory we want to take snapshots of, and localhost/ is a directory inside the snapshot_root we're going to put them in. Using the word localhost as the destination directory is just a convention. You might also choose to use the server's fully qualified domain name instead of localhost. If you are taking snapshots of several machines on one dedicated backup server, it's a good idea to use their various hostnames as directories to keep track of which files came from which server.

In addition to full paths on the local filesystem, you can also backup remote systems using rsync over ssh. If you have ssh installed and enabled (via the cmd_ssh parameter), you can specify a path like:

backup      root@example.com:/etc/     example.com/

This behaves fundamentally the same way, but you must take a few extra things into account.

  • The ssh daemon must be running on example.com

  • You must have access to the account you specify the remote machine, in this case the root user on example.com.

  • You must have key-based logins enabled for the root user at example.com, without passphrases. If you wanted to perform backups as another user, you could specify the other user instead of root for the source (i.e. user@domain.com). Please note that allowing remote logins with no passphrase is a security risk that may or may not be acceptable in your situation. Make sure you guard access to the backup server very carefully! For more information on how to set this up, please consult the ssh man page, or a tutorial on using ssh public and private keys. You will find that the key based logins are better in many ways, not just for rsnapshot but for convenience and security in general. One thing you can do to mitigate the potential damage from a backup server breach is to create alternate users on the client machines with uid and gid set to 0, but with a more restrictive shell such as scponly.

  • This backup occurs over the network, so it may be slower. Since this uses rsync, this is most noticeable during the first backup. Depending on how much your data changes, subsequent backups should go much, much faster since rsync only sends the differences between files.

4.3.9. backup_script

With this parameter, the second column is the full path to an executable backup script, and the third column is the local path you want to store it in (just like with the "backup" parameter). For example:

backup_script      /usr/local/bin/backup_pgsql.sh       localhost/postgres/

In this example, rsnapshot will run the script /usr/local/bin/backup_pgsql.sh in a temp directory, then sync the results into the localhost/postgres/ directory under the snapshot root. You can find the backup_pgsql.sh example script in the utils/ directory of the source distribution. Feel free to modify it for your system.

Your backup script simply needs to dump out the contents of whatever it does into it's current working directory. It can create as many files and/or directories as necessary, but it should not put its files in any pre-determined path. The reason for this is that rsnapshot creates a temp directory, changes to that directory, runs the backup script, and then syncs the contents of the temp directory to the local path you specified in the third column. A typical backup script would be one that archives the contents of a database. It might look like this:

#!/bin/sh
/usr/bin/mysqldump -uroot mydatabase > mydatabase.sql
/bin/chmod 644 mydatabase.sql

There are several example scripts in the utils/ directory of the rsnapshot source distribution to give you more ideas.

Make sure the destination path you specify is unique. The backup script will completely overwrite anything in the destination path, so if you tried to specify the same destination twice, you would be left with only the files from the last script. Fortunately, rsnapshot will try to prevent you from doing this when it reads the config file.

Please remember that these backup scripts will be invoked as the user running rsnapshot. In our example, this is root. Make sure your backup scripts are owned by root, and not writable by anyone else. If you fail to do this, anyone with write access to these backup scripts will be able to put commands in them that will be run as the root user. If they are malicious, they could take over your server.

4.4. Testing your config file

When you have made all your changes, you should verify that the config file is syntactically valid, and that all the supporting programs are where you think they are. To do this, run rsnapshot with the configtest argument:

rsnapshot configtest

If all is well, it should say Syntax OK. If there's a problem, it should tell you exactly what it is. Make sure your config file is using tabs and not spaces, etc.

The final step to test your configuration is to run rsnapshot in test mode. This will print out a verbose list of the things it will do, without actually doing them. To do a test run, run this command:

rsnapshot -t hourly

This tells rsnapshot to simulate an "hourly" backup. It should print out the commands it will perform when it runs for real. Please note that the test output might be slightly different than the real execution, but only because the test doesn't actually do things that may be checked for later in the program. For example, if the program will create a directory and then later test to see if that directory exists, the test run might claim that it would create the directory twice, since it didn't actually get created during the test. This should be the only type of difference you will see while running a test.

5. Automation

Now that you have your config file set up, it's time to set up rsnapshot to be run from cron. As the root user, edit root's crontab by typing:

crontab -e

You could alternately keep a crontab file that you load in, but the concepts are the same. You want to enter the following information into root's crontab:

0 */4 * * *       /usr/local/bin/rsnapshot hourly
30 23 * * *       /usr/local/bin/rsnapshot daily

It is usually a good idea to schedule the larger intervals to run a bit before the lower ones. For example, in the crontab above, notice that daily runs 30 minutes before hourly. This helps prevent race conditions where the daily would try to run before the hourly job had finished. This same strategy should be extended so that a weekly entry would run before the daily and so on.

6. How it works

We have a snapshot root under which all backups are stored. By default, this is the directory /.snapshots/. Within this directory, other directories are created for the various intervals that have been defined. In the beginning it will be empty, but once rsnapshot has been running for a week, it should look something like this:

[root@localhost]# ls -l /.snapshots/
drwxr-xr-x    7 root     root         4096 Dec 28 00:00 daily.0
drwxr-xr-x    7 root     root         4096 Dec 27 00:00 daily.1
drwxr-xr-x    7 root     root         4096 Dec 26 00:00 daily.2
drwxr-xr-x    7 root     root         4096 Dec 25 00:00 daily.3
drwxr-xr-x    7 root     root         4096 Dec 24 00:00 daily.4
drwxr-xr-x    7 root     root         4096 Dec 23 00:00 daily.5
drwxr-xr-x    7 root     root         4096 Dec 22 00:00 daily.6
drwxr-xr-x    7 root     root         4096 Dec 29 00:00 hourly.0
drwxr-xr-x    7 root     root         4096 Dec 28 20:00 hourly.1
drwxr-xr-x    7 root     root         4096 Dec 28 16:00 hourly.2
drwxr-xr-x    7 root     root         4096 Dec 28 12:00 hourly.3
drwxr-xr-x    7 root     root         4096 Dec 28 08:00 hourly.4
drwxr-xr-x    7 root     root         4096 Dec 28 04:00 hourly.5

Inside each of these directories is a “full†backup of that point in time. The destination directory paths you specified under the backup and backup_script parameters get stuck directly under these directories. In the example:

backup          /etc/           localhost/

The /etc/ directory will initially get backed up into /.snapshots/hourly.0/localhost/etc/

Each subsequent time rsnapshot is run with the hourly command, it will rotate the hourly.X directories, and then “copy†the contents of the hourly.0 directory (using hard links) into hourly.1.

When rsnapshot daily is run, it will rotate all the daily.X directories, then rename hourly.5 to daily.0.

hourly.0 will always contain the most recent snapshot, and daily.6 will always contain a snapshot from a week ago. Unless the files change between snapshots, the “full†backups are really just multiple hard links to the same files. Thus, if your /etc/passwd file doesn't change in a week, hourly.0/localhost/etc/passwd and daily.6/localhost/etc/passwd will literally be the same exact file. This is how rsnapshot can be so efficient on space. If the file changes at any point, the next backup will unlink the hard link in hourly.0, and replace it with a brand new file. This will now take double the disk space it did before, but it is still considerably less than it would be to have full unique copies of this file 13 times over.

Remember that if you are using different intervals than the ones in this example, the first interval listed is the one that gets updates directly from the main filesystem. All subsequently listed intervals pull from the previous intervals. For example, if you had weekly, monthly, and yearly intervals defined (in that order), the weekly ones would get updated directly from the filesystem, the monthly ones would get updated from weekly, and the yearly ones would get updated from monthly.

7. Restoring backups

When rsnapshot is first run, it will create the snapshot_root directory (/.snapshots/ by default). It assigns this directory the permissions 700, and for good reason. The snapshot root will probably contain files owned by all sorts of users on your system. If any of these files are writeable (and of course some of them will be), the users will still have write access to their files. Thus, if they can see the snapshots directly, they can modify them, and the integrity of the snapshots can not be guaranteed.

For example, if a user had write permission to the backups and accidentally ran rm -rf /, they would delete all their files in their home directory and all the files they owned in the backups!

7.1. root only

The simplest, but least flexible solution, is to simply deny non-root users access to the snapshot root altogether. The root user will still have access of course, and as with all other aspects of system administration, must be trusted not to go messing with things too much. However, by simply denying access to everyone, the root user will be the only one who can pull backups. This may or may not be desirable, depending on your situation. For a small setup or a single-user machine, this may be all you need.

7.2. All users

If users need to be able to pull their own backups, you will need to do a little extra work up front (but probably less work in the long run). The best way to do this seems to be creating a container directory for the snapshot root with 700 permissions, giving the snapshot root directory 755 permissions, and mounting the snapshot root for the users read-only. This can be done over NFS and Samba, to name two possibilities. Let's explore how to do this using NFS on a single machine:

Set the snapshot_root variable in /etc/rsnapshot.conf equal to /.private/.snapshots/

snapshot_root       /.private/.snapshots/

Create the container directory:

mkdir /.private/

Create the real snapshot root:

mkdir /.private/.snapshots/

Create the read-only snapshot root mount point:

mkdir /.snapshots/

Set the proper permissions on these new directories:

chmod 0700 /.private/
chmod 0755 /.private/.snapshots/
chmod 0755 /.snapshots/

In /etc/exports, add /.private/.snapshots/ as a read only NFS export:

/.private/.snapshots/  127.0.0.1(ro,no_root_squash)

In /etc/fstab, mount /.private/.snapshots/ read-only under /.snapshots/

localhost:/.private/.snapshots/   /.snapshots/   nfs    ro   0 0

You should now restart your NFS daemon.

Now mount the read-only snapshot root:

mount /.snapshots/

To test this, go into the /.snapshots/ directory as root. It is set to read-only, so even root shouldn't be able to write to it. As root, try:

touch /.snapshots/testfile

This should fail, citing insufficient permissions. This is what you want. It means that your users won't be able to mess with the snapshots either.

Now, all your users have to do to recover old files is go into the /.snapshots directory, select the interval they want, and browse through the filesystem until they find the files they are looking for. They can't modify anything in here because NFS will prevent them, but they can copy anything that they had read permission for in the first place. All the regular filesystem permissions are still at work, but the read-only NFS mount prevents any writes from happening.

Please note that some NFS configurations may prevent you from accessing files that are owned by root and set to only be readable by root. In this situation, you may wish to pull backups for root from the "real" snapshot root, and let non-privileged users pull from the read-only NFS mount.

8. Conclusion

If you followed the instructions in this document, you should now have rsnapshot installed and set up to perform automatic backups of your system. If it's not working, go back and trace your steps back to see if you can isolate the problem.

The amount of disk space taken up will be equal to one full backup, plus an additional copy of every file that is changed. There is also a slight disk space overhead with creating multiple hard links, but it's not very much. On my system, adding a second, completely identical 3 Gigabyte interval alongside the original one only added about 15 Megabytes.

You can use the du option to rsnapshot to generate disk usage reports. To see the sum total of all space used, try:

rsnapshot du

If you were storing backups under localhost/home/ and wanted to see how much this subdirectory takes up throughout all your backups, try this instead:

rsnapshot du localhost/home/

The latest version of this document and the rsnapshot program can always be found at http://www.rsnapshot.org/

9. More resources

Web sites

Mike Rubel's original shell scripts, upon which this project is based

http://www.mikerubel.org/computers/rsync_snapshots/

Perl

http://www.perl.org/

GNU cp and du (coreutils package)

http://www.gnu.org/software/coreutils/

rsync

http://rsync.samba.org/

OpenSSH

http://www.openssh.org/

rsnapshot

http://www.rsnapshot.org/

rsnapshot-1.3.1/docs/HOWTOs/rsnapshot-Mac-howto0000644000000000000000000003777110627275217021336 0ustar rootroot00000000000000To: rsnapshot-discuss@lists.sourceforge.net From: Jonathan Guyer Date: Thu, 19 Apr 2007 11:18:06 -0400 Subject: [rsnapshot-discuss] Backing up a Mac to an external FireWire drive I've been fumbling around trying to get a satisfactory backup of my Mac laptop to an external FireWire drive. I like the design principles of rsnapshot much better than the (large) number of other backup tools (including some very expensive commercial options). There are a number of issues though, some relating to it being a Mac (I've been using a Mac since '84, so I still have and still care about things like resource forks) and some relating to it being a laptop (it's not on full-time and not reliably configured the same way all the time, so cron jobs aren't entirely reliable). After a lot of fumbling around, I've come up with a scheme that seems to back up *all* of the information I care about and which does so as automatically and painlessly as possible when I plug in my backup drive. I wrote this up for my own purposes, just so I'd remember how to get things working again when some future OS upgrade or hardware purchase inevitably breaks things, but in the hopes that it might prove useful to others, I offer it here. Any comments or corrections are more than welcome. ========================================================= What I did to back up a Mac to an external FireWire drive ========================================================= :Author: Jonathan Guyer :Contact: guyer@nist.gov :Date: 19 April 2007 :Copyright: This document has been placed in the public domain - Get, build and install ``rsync`` version 3 from `CVS `_. The ``rsync`` shipped by Apple is buggy and the fixes proposed by http://www.onthenet.com.au/~q/ rsync/ and by http://lartmaker.nl/rsync/ don't work. .. note:: If you don't care about Mac meta data (resource forks and such) then you don't need this, but are you *sure* you don't care about Mac meta data? You *are* using a Mac, right? - Edit your ``rsnapshot.conf`` file - set, e.g.:: snapshot_root /Volumes/Backup/snapshot/ and be sure to create the appropriate directory. .. note:: If you wish to `Set the backup to run automatically when a FireWire drive is mounted`_, you don't need to declare ``snapshot_root`` in the ``rsnapshot.conf`` file, but you do still need to create the appropriate directories. .. note:: The NFS protection schemes suggested in the ``rsnapshot`` documentation aren't too applicable to a Mac, but you can protect the backup directory from all but ``sudo``. This idea was suggested by `Giuliano Gavazzi `_ - Create a ``backup`` group using NetInfo Manager (not in ``/etc/groups``) containing all user accounts. (Is there a more automatic group that will accomplish this?) - Use Access Control Lists (ACLs) to secure the backup directory - Enable ACLs:: $ sudo fsaclctl -p /Volumes/Backup -e - Set desired ACLs:: $ sudo chmod +a "backup deny add_file, delete, \ add_subdirectory, delete_child, writeattr, writeextattr \ directory_inherit" /Volumes/Backup/snapshot - set:: no_create_root 1 to prevent ``rsnapshot`` from making a mess in your ``/Volumes/`` directory when the drive is not mounted. - set the path to the ``rsync`` you installed above:: cmd_rsync /usr/local/bin/rsync - set the backup intervals appropriately - pass the following arguments to ``rsync``:: rsync_short_args -a rsync_long_args --delete --numeric-ids --relative --delete- excluded --xattrs The important one here for the Mac is ``--xattrs``. If you don't care about Macish resource forks (are you sure you don't?), then you can omit this and you don't need ``rsync`` 3. - you may want to set:: one_fs 1 - exclude transitory, dangerous, and boring things:: exclude /dev/ exclude /automount/ exclude /cores/ exclude /.vol/ exclude /Volumes/ exclude .Trashes/ exclude .Trash/ exclude .TemporaryItems/ exclude .Spotlight-V100/ exclude Library/Caches/ exclude Library/Safari/Icons/ exclude /private/tmp/ exclude /private/var/vm/ exclude /private/var/tmp/ exclude /private/var/spool/ exclude /private/var/launchd/ exclude /private/var/run/ - back up everything else:: backup / path.to.machine/ Backing up to ``path.to.machine`` is arbitrary, but makes it easy to sort things out later if you back up more than one thing and ``rsnapshot`` requires you to back up somewhere. .. note:: Can you back up to ``.``? .. attention:: If your home directory is protected by FileVault, then you'll want to add:: exclude /Users/.username/ to the excludes list and:: backup /Users/username/ path.to.machine/ to the backup list, otherwise the encrypted FileVault archive will be recopied, in its entirety, and the visible ``$HOME`` directory will be empty in the backup. .. caution:: If you do this, the backup ``$HOME`` directory will not be encrypted. Appropriate physical security measures must be taken with the backup drive. Set the backup to run automatically when a FireWire drive is mounted -------------------------------------------------------------------- - Apple's `exhortation to use the disk arbitration framework `_ is somewhat less than helpful, and R. Matthew Emerson has a peculiar definition of "well-commented", but `his code `_ is a useful starting point:: // rsnapshotd // // Mac OS X daemon for detecting the mount of a backup drive and launching // rsnapshot // // Jonathan Guyer // // This code is in the public domain #include #include #include #include typedef struct { CFUUIDRef uuid; const char * snapshot_root_conf; const char * snapshot_root_dir; const char * cmd; const char ** argv; pid_t pid; } tRsnapshotContext; // Lifted from Steve Christensen on carbon-dev char* CopyCStringFromCFString(CFStringRef cfString, CFStringEncoding encoding) { CFIndex bufferSize = CFStringGetMaximumSizeForEncoding (CFStringGetLength(cfString), encoding) + 1; char* buffer = malloc(bufferSize); if (buffer != NULL) { if (!CFStringGetCString(cfString, buffer, bufferSize, encoding)) { free(buffer); buffer = NULL; } } return buffer; } void hello_disk(DADiskRef disk, void *contextP) { CFDictionaryRef diskref = DADiskCopyDescription (disk); CFUUIDRef uuid = CFDictionaryGetValue (diskref, kDADiskDescriptionVolumeUUIDKey); tRsnapshotContext * context = (tRsnapshotContext *) contextP; diskref = DADiskCopyDescription(disk); if (uuid != NULL && uuid == context->uuid) { CFURLRef pathURL = CFDictionaryGetValue (diskref, kDADiskDescriptionVolumePathKey); CFStringRef uuidStr = CFUUIDCreateString (kCFAllocatorDefault, uuid); char * uuidCStr = CopyCStringFromCFString (uuidStr, kCFStringEncodingUTF8); if (pathURL != NULL) { CFStringRef pathStr = CFURLCopyFileSystemPath (pathURL, kCFURLPOSIXPathStyle); char * path = CopyCStringFromCFString (pathStr, kCFStringEncodingUTF8); FILE * f = fopen(context- >snapshot_root_conf, "w"); syslog(LOG_NOTICE, "performing rsnapshot backup to disk %s, UUID: %s", path, uuidCStr); CFRelease(pathStr); fprintf(f, "# This file automatically generated by rsnapshotd\n"); fprintf(f, "snapshot_root\t%s/%s\n", path, context->snapshot_root_dir); fclose(f); free(path); } else { syslog(LOG_NOTICE, "performing rsnapshot backup to nameless disk, UUID: %s", uuidCStr); } free(uuidCStr); CFRelease(uuidStr); switch (context->pid = vfork()) { case 0: { // child process int err = execv(context->cmd, context- >argv); syslog(LOG_ERR, "rsnapshot backup failed to launch: %d", err); exit(1); // in case exec fails } case -1: syslog(LOG_ERR, "vfork failed"); break; default: { } } } CFRelease(diskref); } // // This handler is pointless. The disk won't unmount as long as the process is running, // // so the the process must be killed first, which means there's nothign to kill here. // // I welcome suggestions of how to do something useful with this // void goodbye_disk(DADiskRef disk, void *contextP) // { // CFDictionaryRef diskref = DADiskCopyDescription (disk); // CFUUIDRef uuid = CFDictionaryGetValue (diskref, kDADiskDescriptionVolumeUUIDKey); // tRsnapshotContext * context = (tRsnapshotContext *) contextP; // // diskref = DADiskCopyDescription(disk); // // if (uuid != NULL && uuid == context->uuid && context->pid != 0) { // kill(context->pid, 3); // printf("\n\ndisk unmounted\n"); // } // } int main (int argc, const char * argv[]) { DASessionRef session; CFStringRef uuidStr; tRsnapshotContext context; if (argc < 5) { syslog(LOG_ERR, "Usage: rsnapshotd UUID SNAPSHOT_ROOT.CONFIG SHAPSHOT_ROOT_DIR CMD [OPTION ...]"); exit(1); } uuidStr = CFStringCreateWithCString (kCFAllocatorDefault, argv[1], kCFStringEncodingUTF8); if (!uuidStr) { syslog(LOG_ERR, "Unable to create UUID string"); exit(1); } context.uuid = CFUUIDCreateFromString (kCFAllocatorDefault, uuidStr); if (!context.uuid) { syslog(LOG_ERR, "Unable to parse UUID string"); exit(1); } context.snapshot_root_conf = argv[2]; context.snapshot_root_dir = argv[3]; context.cmd = argv[4]; context.argv = &argv[4]; context.pid = -1; session = DASessionCreate(kCFAllocatorDefault); DARegisterDiskAppearedCallback(session, NULL, hello_disk, &context); // DARegisterDiskDisappearedCallback(session, NULL, goodbye_disk, &context); DASessionScheduleWithRunLoop(session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); CFRunLoopRun(); CFRelease(session); exit(0); } If you save this as, e.g., ``rsnapshotd.c``, you can build it with:: gcc -framework DiskArbitration -framework CoreFoundation rsnapshotd.c -o rsnapshotd ``rsnapshotd`` takes four required arguments, followed by any options to pass to the command: ``UUID`` The Universally Unique Identifier for the disk you wish to back up to. You can obtain the ``UUID`` by executing ``diskutil info `` (run ``diskutil list`` to find the device ID). ``/PATH/TO/snapshot_root.conf`` The (writable) location of a file to put the path of the backup disk. This is necessary. .. attention:: You must be sure to include the line:: include_conf /PATH/TO/snapshot_root.conf after (or in place of) the ``snapshot_root`` parameter in your ``rsnapshot.conf`` file. ``snapshot_root_directory`` The relative path to the backup on the backup drive associated with ``UUID``, e.g., ``snapshot/``. ``CMD`` The fully qualified path to ``rsnapshot``. .. note:: There's nothing magical about ``rsnapshot``. This daemon will launch any command with any options you supply when the appropriate disk is mounted. ``ARGS`` Arguments to send to ``rsnapshot``, e.g., ``-c``, ``/PATH/TO/rsnapshot.conf`` and ``daily``. - Rather than setting up a cron job, add a file ``net.sourceforge.rsnapshotd.plst`` to ``/Library/LaunchDaemons/``:: Label net.sourceforge.rsnapshotd ProgramArguments /PATH/TO/rsnapshotd UUID /PATH/TO/snapshot_root.conf snapshot/ /PATH/TO/rsnapshot -c /PATH/TO/rsnapshot.conf daily OnDemand RunAtLoad LowPriorityIO Nice 20 This will cause the daemon to sit quietly, waiting for the disk to mount (it will trigger if the disk is already mounted when the daemon is loaded). The ``LowPriorityIO`` and ``Nice`` keys should prevent the rsnapshot process from being too much of a resource hog when it launches (``LowPriorityIO`` is probably more important than ``Nice``). - Install the daemon by executing:: $ sudo launchctl load /Library/LaunchDaemons/ net.sourceforge.rsnapshotd.plst -- Jonathan E. Guyer, PhD Metallurgy Division National Institute of Standards and Technology rsnapshot-1.3.1/docs/HOWTOs/rsnapshot-windows-howto0000644000000000000000000002631210571561724022314 0ustar rootroot00000000000000Date: Sun, 25 Feb 2007 13:34:00 -0800 (PST) From: Bruce Hohl To: Rsnapshot mailing list Using cwRsync 2.0.10 and Rsnapshot 1.2.1 to backup a WinXP computer. ---------------- A- What to use: ---------------- 1- Method #1 - connect to cwRsync server on WinXP source: Install cwRsync server on the WinXP box and define modules (rsync file share). An Rsync client will connect to the cwRsync server module on the WinXP box. Files are transferred over port 873 unencrypted. B 1-3 Except OpenSSH parts. B 4 Module definition; Add module security as desired (man rsyncd.conf). C 1 Rsnapshot config entry for connection to a cwRsync server module. E Restoring files. 2- Method #2 - connect to OpenSSH server on WinXP source: Install cwRsync server and OpenSSH server on the WinXP box. An SSH client will connect to the OpenSSH server on the WinXP box. Files will be read from a CygWin drive. cwRsync will be used for incremental file transfer. Files will be transferred over port 22 encrypted. B 1-3 Except cwRsync parts in steps 2-3. B 5 SSH key authentication C 2 Rsnapshot config entry for connection to Cygwin drive over ssh. E Restoring files. 3- Optional Features: B 6 SSH and SFTP access with passwords. D 1-2 Backing up using Rsync. Notes: - Routing: Routing over a WAN (internet) will work only if only if DNS and routers (firewalls) are configured such that the destination (pc1.mycompany.com) can be reached reachable. +++++ Alternatives: Use VPN between source and destination. Use SSH tunnel(s) to the internal source(s). Incorporate into each backup entry. Open and close tunnels with preexec and postexec. Use firewall port forward rule(s) to the internal source(s). - cwRsync Server: Under Method #2 the cwRsync server is not used. - Windows file permissions: Rsync (Rsnapshot) does not preserve Windows files permissions. So use an appropriate method to restore files - see last section. Rsync runs on the WinXP box as SvcwRsync 1007:513. When files are copied from an Rsync module the files at the destination are owned by 1007:513 with mode of 755 for directories and 644 for files. The files on the WinXP box are seen by SSH as: rwx------+ ???????? ???????? When files are copied via Rsync over SSH the files at the destination are owned by root:root with mode of 700 for directories and 700 for files. - Rsnapshot relative parameter: backup administrator@apost1.mycompany.com:/cygdrive/c/\ Documents\ and\ Settings/apost/My\ Documents apost_My_Documents/ \ rsync_long_args=--delete --numeric-ids --delete-excluded Without --relative path to backuped files is: "/home/rsnapshot/daily.0/apost_My_Documents/My Documents/..." With --relative path to backuped files is: "/home/rsnapshot/daily.0/apost_My_Documents/c/Documents and Settings/\ apost/My Documents/..." ---------------------------------------------- B- cwRsync 2.0.10 with OpenSSH setup on WinXP: ---------------------------------------------- 1- Installation: Install cwRsync_Server_2.0.10_Installer.zip on WinXP computer. Choose the Optional OpenSSH server. Service account user:pswd = SvcwRsync:Ncj97P8hO1 2- Server settings: Set Rsync and OpenSSH to start at boot: Control Panel > Admin Tools > Services For RsyncServer: Right click then click Properties. Click Start button. Set Startup = Automatic. For Openssh SSHD: Right click then click Properties. Click Start button. Set Startup = Automatic. 3- Firewall settings: Open Firewall ports needed - for Windows firewall: Control Panel > Security Center > Windows Firewall General tab: On = Y. Exceptions tab: Click "Add Port" and add follow: RsyncServer 873 TCP RsyncServer 873 UCP Secure Shell (ssh) 22 TCP Secure Shell (ssh) 22 UCP 4- Rysync [file share] module: Add a file access module in C:\Program Files\cwRsyncServer\rsyncd.conf for the directory to be made available. Restart RsyncServer after any change. The default setup allows anonymous read-only access using the rsync client. Access can be limited to specified hosts and by module specific passwords. # global parameters: use chroot = false strict modes = false hosts allow = * log file = rsyncd.log pid file = rsyncd.pid [My_Documents] path = cygdrive/c/Documents and Settings/apost/My Documents/ read only = true transfer logging = yes 5- SSH key authentication: For passwordless rsa public key access to the WinXP PC do the following. During connection ssh requests a public keys before prompting for a password. (1) On the other computer (key maker) generate a key set as follows: root@linux_box:~# ssh-keygen -t rsa -b 2048 Accept default location and press enter when promted for a password. This creates key files id_rsa and id_rsa.pub. (2) On the WinXP box add the contents of id_rsa.pub to: c:\Program Files\cwRsyncServer\home\administrator\.ssh\authorized_keys (3) On the WinXP box edit config file: c:\Program Files\cwRsyncServer\etc\sshd_config to include "StrictModes no" Now root@linux_box can ssh to administrator@WinXP_box and will connect without being prompted for a password. This allows secure automated connections. 6- SSH passwords: Optional: for ssh and sftp password connections: For ssh and sftp access using local accounts on the Windows PC copy the local Windows users and groups to the CygWin environment as follows. These steps must be repeated if a needed change is made to a local account. Start > Programs > cwRsync Server > Start a UNIX BASH Shell $ mkpasswd --local > /etc/passwd $ mkgroup --local > /etc/group Note: A partial CygWin environment is installed at C:\Program Files\cwRsyncServer\ It includes a small subset of a Unix environment including directories for bin, doc, etc, home, tmp, var. OpenSSH access: To access the Windows ssh server using a local account with a known password: Secure shell $ ssh administrator@apost1 Secure FTP $ sftp administrator@aposta1 ------------------- C- Rsnapshot setup: ------------------- 1- Method 1 - Connect to a cwRsync Server module over port 873 (unencrypted): Add the following to /etc/rsnapshot.conf on rsnapshot server. Use tab separated entries. +++++ backup rsync://apost1.mycompany.com/My_Documents/ apost1/My_Documents/ +++++ Use a /etc/crontab entry to run rsnapshot: 0 22 * * * root /usr/bin/rsnapshot daily > /dev/null 2>&1 0 22 * * * root /usr/bin/rsnapshot weekly > /dev/null 2>&1 2- Method 2 - Connect to a Cygwin drive over ssh port 22 (encrypted): cwRsync client will be used for incremental file transfer. Add the following to /etc/rsnapshot.conf on rsnapshot server. Use tab separated entries. +++++ backup administrator@apost1.mycompany.com:/cygdrive/c/\ Documents\ and\ Settings/apost/My\ Documents apost_My_Documents/ \ rsync_long_args=--delete --numeric-ids --delete-excluded +++++ Use a /etc/crontab entry to run rsnapshot: 0 22 * * * root /usr/bin/rsnapshot daily > /dev/null 2>&1 0 22 * * * root /usr/bin/rsnapshot weekly > /dev/null 2>&1 ------------------ D- Rsync commands: ------------------ 1- Method 1 - get files from cwRsync module over port 873: To see the modules available from the rsync server: # rsync apost1.mycompany.com:: My_Documents +++++ Files are accessed from rsync module "My_Documents". Anonymous connections are allowed (if so configured). Uses rsync on port 873 without encryption. +++++ command: # rsync -azSP --numeric-ids --delete apost1.mycompany.com::My_Documents \ /home/rsnapshot/My_Documents/ 2- Method 2 - get files from CygWin drive over port 22: File access via CygWin drive "/cygdrive/c/Documents and Settings/apost/My Documents" Uses encrypted ssh connection over port 22. Under this method the password for user 'administrator' must be entered unless passwordless rsa public key authentication is setup (see above). +++++ command: # rsync -azSP --numeric-ids --delete --rsh=ssh "administrator@apost1.\ mycompany.com:/cygdrive/c/Documents\ and\ Settings/apost/My\ Documents" \ /home/rsnapshot/ command (alternate form): # rsync -azSP --numeric-ids --delete -e "ssh -l administrator" "apost1.\ mycompany.com:/cygdrive/c/Documents\ and\ Settings/apost/My\ Documents" \ /home/rsnapshot/ ------------------- E- Restoring Files: ------------------- 1- Method #1 - From the backup server by the administrator: Mount the client WinXP box: # smbmunt //apost1/C$ /mnt -o username=administrator/MYCOMPANY Copy needed files from the backup server to the mounted computer: # cp "/home/workstations/daily.1/apost1/My Documents/Some File" \ "/mnt/C/Documents and Settings/apost/My Documents/ 2- Method #2 - From any computer by the administrator: SFTP into the backup box as root. Move needed files to a public file share. Have user to retrieve the files. 3- Method #3 - From source computer by the administrator: SFTP into the backup box as root. Copy needed files to the source computer. 4- Method #4 - From source computer via Samba by the user: Here is one possible approach under which the user would have read only access to the workstation backup intervals via a Samba file share at //backup1/user. a- Install Samba. Join backup1 to the domain for centralized user accounts management. Or create a local unix and samba accounts for each user. b- Set the homes shares to read only in /etc/samba/smb.conf. [homes] comment = Home Directories browseable = no writable = no c- Create home directories as needed: Example: # mkdir /home/apost d- Create symbolic links to the appropriate backup interval directories: Example: # ln -s /home/workstations/daily.0/apost /home/apost/daily.O # ln -s /home/workstations/daily.1/apost /home/apost/daily.1 # ln -s /home/workstations/daily.2/apost /home/apost/daily.2 # ln -s /home/workstations/daily.3/apost /home/apost/daily.3 # ln -s /home/workstations/daily.4/apost /home/apost/daily.4 # ln -s /home/workstations/daily.5/apost /home/apost/daily.5 # ln -s /home/workstations/daily.6/apost /home/apost/daily.6 # ln -s /home/workstations/weekly.0/apost /home/apost/weekly.O # ln -s /home/workstations/weekly.1/apost /home/apost/weekly.1 # ln -s /home/workstations/weekly.2/apost /home/apost/weekly.2 # ln -s /home/workstations/weekly.3/apost /home/apost/weekly.3 e- If rsync via ssh is used add a cmd_postexec script to the /etc/rsnapshot config to set file modes so that file acls do not block the user from reading the needed files. script: find /home/workstations/daily.0 -type d -exec chmod 777 {} \; find /home/workstations/daily.0 -type f -exec chmod 666 {} \; rsnapshot-1.3.1/docs/Upgrading_from_1.10000644000000000000000000003161310512103102017655 0ustar rootroot00000000000000 Starting with rsnapshot 1.2.0, the default value for "rsync_long_args" has changed. This is a global change, that affects which directories your backups are stored in under the snapshot root. IT IS ABSOLUTELY VITAL THAT YOU UNDERSTAND THIS SECTION, AND MAKE SURE THAT YOU UPGRADE YOUR CONFIG FILE. Here is a quick summary of what is needed to upgrade: Run the configure script with the same arguments you used for the previous installation For example: ./configure --sysconfdir=/etc configure will look at your old rsnapshot.conf file, and prompt you to upgrade. Read the message it displays, and then type: make upgrade An upgrade script will read your existing config file and make changes if necessary. If it does, the original will be saved as "rsnapshot.conf.backup" in the same directory. After the upgrade is complete, it is recommended you look at rsnapshot.conf and make sure everything is OK. Specifically, the "rsync_long_args" parameter should now be uncommented, along with a note explaining the change. Finally, to install rsnapshot, type: make install For the last step, to make sure the upgrade went OK, run: rsnapshot configtest Now rsnapshot will continue to work just as before. However, you may want to read the section below, as it gives information on how to fully update your config file to take advantage of the new features. What follows is a detailed description of the change: In previous versions of rsnapshot (before 1.2.0), the default value for "rsync_long_args" was: --delete --numeric-ids Starting with rsnapshot 1.2.0, the new default value for "rsync_long_args" is: --delete --numeric-ids --relative --delete-excluded In both the old and new versions, explicitly setting this parameter overrides the defaults. This is what the "make upgrade" script does, it manually sets this to the old default value for backwards compatibility. This change was made for a number of good reasons: rsnapshot has a feature to prevent you from accidentally backing up your snapshot root inside itself (recursively). Without this feature, it would be very easy to do something like specifying "/" as the backup point and forgetting to exclude the snapshot root. In the past, rsnapshot would avoid this by detecting the presence of the snapshot root in a backup point. If there was a conflict, the backup point would be rewritten internally, so that rsync would get called several times, once for each top level directory in the backup point, except for the one containing the snapshot root. This was not terrible, but it prevented taking full advantage of some other features that were added over time, such as "one_fs", and the include/exclude rules. For instance, if you wanted to backup your root filesystem (but only that disk partition), you couldn't really do so without figuring out which top level directories were housed on that partition, and then specifying them all as different backup points. Attempting to use the one_fs option would not have worked, since one_fs would be passed to rsync, but once for every single top level directory. Thus, if (for example) /var was housed on a different partition, it wouldn't matter since rsync was using /var as it's starting point, not "/". Additionally, in the past it was impossible to exclude a full path with rsync's include/exclude rules, regardless of what you were backing up. The best that could be done was to exclude a pattern (like "CVS"), or once again resort to listing all the top-level directories as seperate backup points surrounding anything you wanted to exclude. Now, because of the "--relative" option, it is possible to do all these things. "--delete-excluded" is nice too, since it will automatically remove things from your backups when you decide not to back them up anymore. Of course, there is a downside as well: With "--relative" enabled in "rsync_long_args", rsync treats the destination paths differently. Before, rsync would take the files from the source path and stick them directly into the destination path. Now, it takes the full source path and recreates all the parent directories in the destination path. This limits flexibility somewhat in the destination paths, since they are now tied to the namespace of the source paths. For example, something like this can no longer be done under the new system: backup /var/qmail/ localhost/email/ Before, the finished snapshot would look like this: /.snapshots/hourly.0/localhost/email/ Now, the finished snapshot will look like this: /.snapshots/hourly.0/localhost/email/var/qmail/ By explicitly setting the "rsync_long_args" parameter, you can operate rsnapshot in either of these two ways. Please be aware that if you are using an anonymous rsync server, the rules are just a little bit different. Unlike with a local filesystem or rsync over ssh, you can not rsync directly from the top level of the remote host. Instead, an rsync server has "modules" that are exported. These are essentially just top level directories. So instead of just specifying the hostname for the destination path, you should specify the module as well. Here is an example, where example.com is the rsync server, and the exported module is called "pub": Before backup rsync://example.com/pub/cvs/ example.com/pub/cvs/ After backup rsync://example.com/pub/cvs/ example.com/pub/ If you want to keep things the way they were, make sure you run "make upgrade" or otherwise set the rsync_long_args parameter to the old value. If you want to transition your destination paths over to the new way, read on. Here are some "before and after" examples from rsnapshot.conf. Each one yields identical results on the filesystem. THE OLD WAY (rsnapshot 1.1.6 and before): backup /etc/ localhost/etc/ backup /home/ localhost/home/ backup /usr/local/ localhost/usr/local/ backup root@example.com:/etc/ example.com/etc/ backup root@example.com:/var/ example.com/var/ backup rsync://example.com:/pub/cvs/ example.com/pub/cvs/ THE NEW WAY (from rsnapshot 1.2.0 on): backup /etc/ localhost/ backup /home/ localhost/ backup /usr/local/ localhost/ backup root@example.com:/etc/ example.com/ backup root@example.com:/var/ example.com/ backup rsync://example.com:/pub/cvs/ example.com/pub/ But what happens when you had an entry like this? backup /var/qmail/ localhost/email/ As you can see, there is no direct mapping from the source path to the destination. You now have essentially four choices: 1. Manually change the backup directories for individual backup points inside the snapshot root. This is probably the best method for most people to follow. For example, take this entry: backup /var/qmail/ localhost/email/ For the conversion, we are going to change it to: backup /var/qmail/ localhost/ Assume the snapshot root is "/.snapshots/", and the smallest interval is "hourly". Under the old system, these files would be backed up in this location: /.snapshots/hourly.0/localhost/email/ After we change the config file over to use --relative in rsync_long_args, the same files will now get backed up here: /.snapshots/hourly.0/localhost/var/qmail/ To make the transition seamless, we need to move this directory inside the snapshot root, and create all the parent directories, if necessary. So in this example, we do: cd /.snapshots/hourly.0/localhost/ mkdir var/ mv email/ var/qmail/ If we map all the directories over in this way, we maintain all the hard links. The only real drawback is that users will have to learn the new locations of the files to restore them. 2. Keep rsync_long_args set to the old values. Backward compatibility is maintained, but you can't take advantage of the new features. 3. Specify rsync_long_args for a particular backup point where you want to use the old method. I.E.: backup /etc/ localhost/ backup /home/ localhost/ backup /var/qmail/ localhost/email/ rsync_long_args=--delete --numeric-ids This way you get the new features except where you need to override them for certain backup points. Be very careful here because it's easy to forget what's going on. 4. Delete the latest snapshot and do a full re-sync under the new system. This is the brute force "I don't care about my old backups anyway" method. If this interests you, then perform the following steps: A. Figure out where your snapshot root is located. B. Figure out what the smallest interval is (I.E. hourly). C. Modify the config file to change your paths over to the new system. D. Manually delete the most recent snapshot directory. Assuming your snapshot root is set to "/.snapshots/", and your smallest interval is "hourly", you would delete the following directory: rm -rf /.snapshots/hourly.0/ E. Manually run rsnapshot on the lowest interval to perform a full re-sync. rsnapshot -v hourly Aside from the extra time spent on the full re-sync, the other big drawback to this method is that your snapshots will now take up the space of TWO full backups, plus incrementals. If you liked this method and were more concerned with disk space than history, you could also conceivably just delete the entire snapshot root and start over as well. Obviously this is a tactic to be used as a last resort! Finally, be aware that the backup_script parameter does NOT follow these new rules. Backup scripts still drop their files right into the destination directory specified. This makes sense when you realize that since the files came from a script, they didn't really have a source path on the filesystem to begin with. Any backup_script parameters should remain unchanged from before. Additionally, new checks have been added to rsnapshot to prevent you from accidentally wiping out your backup points later with an incorrect backup_script destination. For instance, this would nuke your backups, except that rsnapshot won't let you do it: backup /etc/ localhost/etc/ backup_script /usr/local/bin/backup_pgsql.sh localhost/etc/ This won't work either, because the backup script destination is above the backup point: backup /etc/ localhost/etc/ backup_script /usr/local/bin/backup_pgsql.sh localhost/ The correct usage would be something like this: backup /etc/ localhost/etc/ backup_script /usr/local/bin/backup_pgsql.sh localhost/pgsql/ rsnapshot-1.3.1/Makefile.am0000644000000000000000000001145611031316777015544 0ustar rootroot00000000000000# $Id: Makefile.am,v 1.88 2008/06/28 02:02:14 djk20 Exp $ # # rsnapshot version VERSION = 1.3.1 # Where RPM files are built on this system RPM_BASE_DIR = /usr/src/redhat # update of spec file, within this rsnapshot version RPM_RELEASE = 1 doc: man html @echo "Documentation $(man_MANS) and rsnapshot.html are now up to date." @touch doc man: $(man_MANS) rsnapshot.1 : rsnapshot @# perl 5.8 for this /usr/bin/pod2man -c '' -n 'rsnapshot' -r '' rsnapshot > rsnapshot.1 rsnapshot-diff.1 : rsnapshot-diff @# perl 5.8 for this /usr/bin/pod2man -c '' -n 'rsnapshot-diff' -r '' rsnapshot-diff > rsnapshot-diff.1 html: rsnapshot.html rsnapshot.html: rsnapshot pod2html rsnapshot | grep -v 'link rev' > rsnapshot.html rm -f pod2htmd.* rm -f pod2htmi.* upgrade: @echo "" ${PERL} rsnapshot-program.pl -c ${sysconfdir}/rsnapshot.conf upgrade-config-file @echo "" clean: rm -rf rsnapshot-$(VERSION)/ rm -rf autom4te.cache rm -f rsnapshot-$(VERSION).tar.gz rm -f rsnapshot-$(VERSION)-$(RPM_RELEASE).noarch.rpm rm -f rsnapshot.conf.default rm -f rsnapshot.conf.default.in.redhat rm -f rsnapshot.html rm -f pod2htmd.* rm -f pod2htmi.* rm -f Makefile config.log config.status configure.lineno rsnapshot rsnapshot-diff -rm -f doc rpm-patch rpm tar rm -f t/*.t rm -f t/support/etc/*.conf rm -f t/support/files/a/{1,2} rm -rf t/support/snapshots/*.* rpm-patch: redhat/SOURCES/rsnapshot.patch @echo @touch rpm-patch redhat/SOURCES/rsnapshot.patch: rsnapshot.conf.default.in Makefile @echo building rpm config file patch $@ cp -p rsnapshot.conf.default.in rsnapshot.conf.default.in.redhat perl -pi -e 's/^\#\@CMD_CP\@/\@CMD_CP\@/' rsnapshot.conf.default.in.redhat perl -pi -e 's/^\#\@CMD_DU\@/\@CMD_DU\@/' rsnapshot.conf.default.in.redhat perl -pi -e 's/^\#logfile/logfile/' rsnapshot.conf.default.in.redhat perl -pi -e 's/^\#lockfile/lockfile/' rsnapshot.conf.default.in.redhat perl -pi -e 's%^\#cmd_rsnapshot_diff /usr/local/bin/rsnapshot-diff%cmd_rsnapshot_diff /usr/bin/rsnapshot-diff%' rsnapshot.conf.default.in.redhat @# diff doesn't return 0 diff -u rsnapshot.conf.default.in rsnapshot.conf.default.in.redhat > redhat/SOURCES/rsnapshot.patch || /bin/true rm -f rsnapshot.conf.default.in.redhat rpm: rsnapshot-$(VERSION)-$(RPM_RELEASE).noarch.rpm @touch rpm rsnapshot-$(VERSION)-$(RPM_RELEASE).noarch.rpm: tar redhat/SOURCES/rsnapshot.patch redhat/SPECS/rsnapshot.spec @echo building rpm file $@ @# build rpm file cp rsnapshot-$(VERSION).tar.gz $(RPM_BASE_DIR)/SOURCES/ cp redhat/SOURCES/rsnapshot.patch $(RPM_BASE_DIR)/SOURCES/ cp redhat/SPECS/rsnapshot.spec $(RPM_BASE_DIR)/SPECS/ rpmbuild -ba $(RPM_BASE_DIR)/SPECS/rsnapshot.spec cp -p $(RPM_BASE_DIR)/RPMS/noarch/rsnapshot-$(VERSION)-$(RPM_RELEASE).noarch.rpm . -cp -p $(RPM_BASE_DIR)/SRPMS/rsnapshot-$(VERSION)-$(RPM_RELEASE).src.rpm . @echo tar: rsnapshot-$(VERSION).tar.gz @touch tar rsnapshot-$(VERSION).tar.gz: $(man_MANS) rpm-patch Makefile $(bin_SCRIPTS) $(sysconf_DATA) @echo building tar file @# recommended to run make tar as root for the chown rm -f rsnapshot-$(VERSION).tar.gz @# core files mkdir rsnapshot-$(VERSION) cp -p rsnapshot-preamble.pl rsnapshot-program.pl rsnapshot-diff.pl rsnapshot.conf.default.in \ $(man_MANS) AUTHORS COPYING INSTALL README TODO NEWS ChangeLog \ rsnapshot-$(VERSION)/ @# documentation files cp -a docs rsnapshot-$(VERSION)/ @# autoconf files cp -p Makefile.am Makefile.in aclocal.m4 configure configure.ac config.guess config.sub \ install-sh missing mkinstalldirs rsnapshot-$(VERSION)/ @# redhat mkdir rsnapshot-$(VERSION)/redhat/ mkdir rsnapshot-$(VERSION)/redhat/SOURCES/ mkdir rsnapshot-$(VERSION)/redhat/SPECS/ cp -p redhat/README rsnapshot-$(VERSION)/redhat/ cp -p redhat/SOURCES/rsnapshot.patch rsnapshot-$(VERSION)/redhat/SOURCES/ cp -p redhat/SPECS/rsnapshot.spec rsnapshot-$(VERSION)/redhat/SPECS/ @# utils mkdir rsnapshot-$(VERSION)/utils/ cp -p utils/{*.sh,*.pl,README} rsnapshot-$(VERSION)/utils/ cp -p utils/{rsnaptar,rsnapshot-copy} rsnapshot-$(VERSION)/utils/ mkdir rsnapshot-$(VERSION)/utils/rsnapshotdb cp -p --parents utils/rsnapshotdb/*.* rsnapshot-$(VERSION)/ @# t - testing mkdir -p rsnapshot-$(VERSION)/t/support/etc mkdir rsnapshot-$(VERSION)/t/support/files mkdir rsnapshot-$(VERSION)/t/support/snapshots cp -a --parents t/*.t.in t/support/etc/*.in t/support/files rsnapshot-$(VERSION)/ @# remove CVS directories from t/support/files and docs. -find rsnapshot-$(VERSION)/ -depth -name CVS -exec rm -rf {} \; @# change ownership to root, and delete build dir -chown -R root:root rsnapshot-$(VERSION)/ tar czf rsnapshot-$(VERSION).tar.gz rsnapshot-$(VERSION)/ rm -rf rsnapshot-$(VERSION)/ @echo test: rsnapshot @PERL@ -MTest::Harness -e 'runtests(glob "t/*.t")'; bin_SCRIPTS = rsnapshot rsnapshot-diff man_MANS = rsnapshot.1 rsnapshot-diff.1 sysconf_DATA = rsnapshot.conf.default rsnapshot-1.3.1/Makefile.in0000644000000000000000000005472211056477150015560 0ustar rootroot00000000000000# Makefile.in generated by automake 1.9.2 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # $Id: Makefile.in,v 1.109 2008/08/31 10:48:47 djk20 Exp $ # srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = . am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = . DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/rsnapshot-diff.pl \ $(srcdir)/rsnapshot-preamble.pl $(srcdir)/rsnapshot-program.pl \ $(srcdir)/rsnapshot.conf.default.in $(top_srcdir)/configure \ $(top_srcdir)/t/configtest.t.in $(top_srcdir)/t/gnu_cp.t.in \ $(top_srcdir)/t/relative_delete_bugfix.t.in \ $(top_srcdir)/t/rsync.t.in \ $(top_srcdir)/t/support/etc/configtest.conf.in \ $(top_srcdir)/t/support/etc/gnu_cp.conf.in \ $(top_srcdir)/t/support/etc/relative_delete_bugfix.conf.in \ $(top_srcdir)/t/support/etc/rsync.conf.in AUTHORS COPYING \ ChangeLog INSTALL NEWS TODO config.guess config.sub install-sh \ missing mkinstalldirs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno configure.status.lineno mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_CLEAN_FILES = rsnapshot rsnapshot-diff rsnapshot.conf.default \ t/support/etc/configtest.conf t/support/etc/rsync.conf \ t/support/etc/gnu_cp.conf \ t/support/etc/relative_delete_bugfix.conf t/configtest.t \ t/rsync.t t/gnu_cp.t t/relative_delete_bugfix.t am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" \ "$(DESTDIR)$(sysconfdir)" binSCRIPT_INSTALL = $(INSTALL_SCRIPT) SCRIPTS = $(bin_SCRIPTS) SOURCES = DIST_SOURCES = man1dir = $(mandir)/man1 NROFF = nroff MANS = $(man_MANS) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; sysconfDATA_INSTALL = $(INSTALL_DATA) DATA = $(sysconf_DATA) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ { test ! -d $(distdir) \ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -fr $(distdir); }; } DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best distuninstallcheck_listfiles = find . -type f -print distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CMD_CP = @CMD_CP@ CMD_DU = @CMD_DU@ CMD_LOGGER = @CMD_LOGGER@ CMD_RM = @CMD_RM@ CMD_RSYNC = @CMD_RSYNC@ CMD_SSH = @CMD_SSH@ CP = @CP@ CWD = @CWD@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DU = @DU@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LOGGER = @LOGGER@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ RM = @RM@ RSYNC = @RSYNC@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SSH = @SSH@ STRIP = @STRIP@ TEST_CP = @TEST_CP@ TEST_DU = @TEST_DU@ TEST_LOGGER = @TEST_LOGGER@ TEST_RM = @TEST_RM@ TEST_SSH = @TEST_SSH@ # rsnapshot version VERSION = 1.3.1 ac_ct_STRIP = @ac_ct_STRIP@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ datadir = @datadir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ prefix = @prefix@ program_transform_name = @program_transform_name@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ # Where RPM files are built on this system RPM_BASE_DIR = /usr/src/redhat # update of spec file, within this rsnapshot version RPM_RELEASE = 1 bin_SCRIPTS = rsnapshot rsnapshot-diff man_MANS = rsnapshot.1 rsnapshot-diff.1 sysconf_DATA = rsnapshot.conf.default all: all-am .SUFFIXES: am--refresh: @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ cd $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) cd $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) rsnapshot: $(top_builddir)/config.status $(srcdir)/rsnapshot-preamble.pl $(srcdir)/rsnapshot-program.pl cd $(top_builddir) && $(SHELL) ./config.status $@ rsnapshot-diff: $(top_builddir)/config.status $(srcdir)/rsnapshot-preamble.pl $(srcdir)/rsnapshot-diff.pl cd $(top_builddir) && $(SHELL) ./config.status $@ rsnapshot.conf.default: $(top_builddir)/config.status $(srcdir)/rsnapshot.conf.default.in cd $(top_builddir) && $(SHELL) ./config.status $@ t/support/etc/configtest.conf: $(top_builddir)/config.status $(top_srcdir)/t/support/etc/configtest.conf.in cd $(top_builddir) && $(SHELL) ./config.status $@ t/support/etc/rsync.conf: $(top_builddir)/config.status $(top_srcdir)/t/support/etc/rsync.conf.in cd $(top_builddir) && $(SHELL) ./config.status $@ t/support/etc/gnu_cp.conf: $(top_builddir)/config.status $(top_srcdir)/t/support/etc/gnu_cp.conf.in cd $(top_builddir) && $(SHELL) ./config.status $@ t/support/etc/relative_delete_bugfix.conf: $(top_builddir)/config.status $(top_srcdir)/t/support/etc/relative_delete_bugfix.conf.in cd $(top_builddir) && $(SHELL) ./config.status $@ t/configtest.t: $(top_builddir)/config.status $(top_srcdir)/t/configtest.t.in cd $(top_builddir) && $(SHELL) ./config.status $@ t/rsync.t: $(top_builddir)/config.status $(top_srcdir)/t/rsync.t.in cd $(top_builddir) && $(SHELL) ./config.status $@ t/gnu_cp.t: $(top_builddir)/config.status $(top_srcdir)/t/gnu_cp.t.in cd $(top_builddir) && $(SHELL) ./config.status $@ t/relative_delete_bugfix.t: $(top_builddir)/config.status $(top_srcdir)/t/relative_delete_bugfix.t.in cd $(top_builddir) && $(SHELL) ./config.status $@ install-binSCRIPTS: $(bin_SCRIPTS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" @list='$(bin_SCRIPTS)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f $$d$$p; then \ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ echo " $(binSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(bindir)/$$f'"; \ $(binSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(bindir)/$$f"; \ else :; fi; \ done uninstall-binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(bin_SCRIPTS)'; for p in $$list; do \ f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ rm -f "$(DESTDIR)$(bindir)/$$f"; \ done uninstall-info-am: install-man1: $(man1_MANS) $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)" @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.1*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 1*) ;; \ *) ext='1' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \ done uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ for i in $$l2; do \ case "$$i" in \ *.1*) list="$$list $$i" ;; \ esac; \ done; \ for i in $$list; do \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 1*) ;; \ *) ext='1' ;; \ esac; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \ rm -f "$(DESTDIR)$(man1dir)/$$inst"; \ done install-sysconfDATA: $(sysconf_DATA) @$(NORMAL_INSTALL) test -z "$(sysconfdir)" || $(mkdir_p) "$(DESTDIR)$(sysconfdir)" @list='$(sysconf_DATA)'; for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ f=$(am__strip_dir) \ echo " $(sysconfDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(sysconfdir)/$$f'"; \ $(sysconfDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(sysconfdir)/$$f"; \ done uninstall-sysconfDATA: @$(NORMAL_UNINSTALL) @list='$(sysconf_DATA)'; for p in $$list; do \ f=$(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(sysconfdir)/$$f'"; \ rm -f "$(DESTDIR)$(sysconfdir)/$$f"; \ done tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) $(am__remove_distdir) mkdir $(distdir) $(mkdir_p) $(distdir)/. $(distdir)/t $(distdir)/t/support/etc @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r $(distdir) dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) dist dist-all: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir); chmod a+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && cd $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck $(am__remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}' distuninstallcheck: @cd $(distuninstallcheck_dir) \ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) $(MANS) $(DATA) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(sysconfdir)"; do \ test -z "$$dir" || $(mkdir_p) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: info: info-am info-am: install-data-am: install-man install-exec-am: install-binSCRIPTS install-sysconfDATA install-info: install-info-am install-man: install-man1 installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binSCRIPTS uninstall-info-am uninstall-man \ uninstall-sysconfDATA uninstall-man: uninstall-man1 .PHONY: all all-am am--refresh check check-am clean clean-generic dist \ dist-all dist-bzip2 dist-gzip dist-shar dist-tarZ dist-zip \ distcheck distclean distclean-generic distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-binSCRIPTS install-data \ install-data-am install-exec install-exec-am install-info \ install-info-am install-man install-man1 install-strip \ install-sysconfDATA installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \ uninstall-binSCRIPTS uninstall-info-am uninstall-man \ uninstall-man1 uninstall-sysconfDATA doc: man html @echo "Documentation $(man_MANS) and rsnapshot.html are now up to date." @touch doc man: $(man_MANS) rsnapshot.1 : rsnapshot @# perl 5.8 for this /usr/bin/pod2man -c '' -n 'rsnapshot' -r '' rsnapshot > rsnapshot.1 rsnapshot-diff.1 : rsnapshot-diff @# perl 5.8 for this /usr/bin/pod2man -c '' -n 'rsnapshot-diff' -r '' rsnapshot-diff > rsnapshot-diff.1 html: rsnapshot.html rsnapshot.html: rsnapshot pod2html rsnapshot | grep -v 'link rev' > rsnapshot.html rm -f pod2htmd.* rm -f pod2htmi.* upgrade: @echo "" ${PERL} rsnapshot-program.pl -c ${sysconfdir}/rsnapshot.conf upgrade-config-file @echo "" clean: rm -rf rsnapshot-$(VERSION)/ rm -rf autom4te.cache rm -f rsnapshot-$(VERSION).tar.gz rm -f rsnapshot-$(VERSION)-$(RPM_RELEASE).noarch.rpm rm -f rsnapshot.conf.default rm -f rsnapshot.conf.default.in.redhat rm -f rsnapshot.html rm -f pod2htmd.* rm -f pod2htmi.* rm -f Makefile config.log config.status configure.lineno rsnapshot rsnapshot-diff -rm -f doc rpm-patch rpm tar rm -f t/*.t rm -f t/support/etc/*.conf rm -f t/support/files/a/{1,2} rm -rf t/support/snapshots/*.* rpm-patch: redhat/SOURCES/rsnapshot.patch @echo @touch rpm-patch redhat/SOURCES/rsnapshot.patch: rsnapshot.conf.default.in Makefile @echo building rpm config file patch $@ cp -p rsnapshot.conf.default.in rsnapshot.conf.default.in.redhat perl -pi -e 's/^\#\@CMD_CP\@/\@CMD_CP\@/' rsnapshot.conf.default.in.redhat perl -pi -e 's/^\#\@CMD_DU\@/\@CMD_DU\@/' rsnapshot.conf.default.in.redhat perl -pi -e 's/^\#logfile/logfile/' rsnapshot.conf.default.in.redhat perl -pi -e 's/^\#lockfile/lockfile/' rsnapshot.conf.default.in.redhat perl -pi -e 's%^\#cmd_rsnapshot_diff /usr/local/bin/rsnapshot-diff%cmd_rsnapshot_diff /usr/bin/rsnapshot-diff%' rsnapshot.conf.default.in.redhat @# diff doesn't return 0 diff -u rsnapshot.conf.default.in rsnapshot.conf.default.in.redhat > redhat/SOURCES/rsnapshot.patch || /bin/true rm -f rsnapshot.conf.default.in.redhat rpm: rsnapshot-$(VERSION)-$(RPM_RELEASE).noarch.rpm @touch rpm rsnapshot-$(VERSION)-$(RPM_RELEASE).noarch.rpm: tar redhat/SOURCES/rsnapshot.patch redhat/SPECS/rsnapshot.spec @echo building rpm file $@ @# build rpm file cp rsnapshot-$(VERSION).tar.gz $(RPM_BASE_DIR)/SOURCES/ cp redhat/SOURCES/rsnapshot.patch $(RPM_BASE_DIR)/SOURCES/ cp redhat/SPECS/rsnapshot.spec $(RPM_BASE_DIR)/SPECS/ rpmbuild -ba $(RPM_BASE_DIR)/SPECS/rsnapshot.spec cp -p $(RPM_BASE_DIR)/RPMS/noarch/rsnapshot-$(VERSION)-$(RPM_RELEASE).noarch.rpm . -cp -p $(RPM_BASE_DIR)/SRPMS/rsnapshot-$(VERSION)-$(RPM_RELEASE).src.rpm . @echo tar: rsnapshot-$(VERSION).tar.gz @touch tar rsnapshot-$(VERSION).tar.gz: $(man_MANS) rpm-patch Makefile $(bin_SCRIPTS) $(sysconf_DATA) @echo building tar file @# recommended to run make tar as root for the chown rm -f rsnapshot-$(VERSION).tar.gz @# core files mkdir rsnapshot-$(VERSION) cp -p rsnapshot-preamble.pl rsnapshot-program.pl rsnapshot-diff.pl rsnapshot.conf.default.in \ $(man_MANS) AUTHORS COPYING INSTALL README TODO NEWS ChangeLog \ rsnapshot-$(VERSION)/ @# documentation files cp -a docs rsnapshot-$(VERSION)/ @# autoconf files cp -p Makefile.am Makefile.in aclocal.m4 configure configure.ac config.guess config.sub \ install-sh missing mkinstalldirs rsnapshot-$(VERSION)/ @# redhat mkdir rsnapshot-$(VERSION)/redhat/ mkdir rsnapshot-$(VERSION)/redhat/SOURCES/ mkdir rsnapshot-$(VERSION)/redhat/SPECS/ cp -p redhat/README rsnapshot-$(VERSION)/redhat/ cp -p redhat/SOURCES/rsnapshot.patch rsnapshot-$(VERSION)/redhat/SOURCES/ cp -p redhat/SPECS/rsnapshot.spec rsnapshot-$(VERSION)/redhat/SPECS/ @# utils mkdir rsnapshot-$(VERSION)/utils/ cp -p utils/{*.sh,*.pl,README} rsnapshot-$(VERSION)/utils/ cp -p utils/{rsnaptar,rsnapshot-copy} rsnapshot-$(VERSION)/utils/ mkdir rsnapshot-$(VERSION)/utils/rsnapshotdb cp -p --parents utils/rsnapshotdb/*.* rsnapshot-$(VERSION)/ @# t - testing mkdir -p rsnapshot-$(VERSION)/t/support/etc mkdir rsnapshot-$(VERSION)/t/support/files mkdir rsnapshot-$(VERSION)/t/support/snapshots cp -a --parents t/*.t.in t/support/etc/*.in t/support/files rsnapshot-$(VERSION)/ @# remove CVS directories from t/support/files and docs. -find rsnapshot-$(VERSION)/ -depth -name CVS -exec rm -rf {} \; @# change ownership to root, and delete build dir -chown -R root:root rsnapshot-$(VERSION)/ tar czf rsnapshot-$(VERSION).tar.gz rsnapshot-$(VERSION)/ rm -rf rsnapshot-$(VERSION)/ @echo test: rsnapshot @PERL@ -MTest::Harness -e 'runtests(glob "t/*.t")'; # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: rsnapshot-1.3.1/aclocal.m40000644000000000000000000006123611005052460015334 0ustar rootroot00000000000000# generated automatically by aclocal 1.9.2 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 # Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. # -*- Autoconf -*- # Copyright (C) 2002, 2003 Free Software Foundation, Inc. # Generated from amversion.in; do not edit by hand. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"]) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION so it can be traced. # This function is AC_REQUIREd by AC_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.9.2])]) # AM_AUX_DIR_EXPAND # Copyright (C) 2001, 2003 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to # `$srcdir', `$srcdir/..', or `$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is `.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # Do all the work for Automake. -*- Autoconf -*- # This macro actually does too much some checks are only needed if # your package does certain things. But this isn't really a big deal. # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 # Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # serial 11 # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.58])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl # test to see if srcdir already configured if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) AM_MISSING_PROG(AUTOCONF, autoconf) AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) AM_PROG_INSTALL_SH AM_PROG_INSTALL_STRIP AC_REQUIRE([AM_PROG_MKDIR_P])dnl # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES(CC)], [define([AC_PROG_CC], defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES(CXX)], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl ]) ]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $1 | $1:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. # Copyright (C) 2001, 2003 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl install_sh=${install_sh-"$am_aux_dir/install-sh"} AC_SUBST(install_sh)]) # -*- Autoconf -*- # Copyright (C) 2003 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # serial 1 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # -*- Autoconf -*- # Copyright (C) 1997, 1999, 2000, 2001, 2003 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # serial 3 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it supports --run. # If it does, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= AC_MSG_WARN([`missing' script is too old or missing]) fi ]) # AM_PROG_MKDIR_P # --------------- # Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise. # Copyright (C) 2003, 2004 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories # created by `make install' are always world readable, even if the # installer happens to have an overly restrictive umask (e.g. 077). # This was a mistake. There are at least two reasons why we must not # use `-m 0755': # - it causes special bits like SGID to be ignored, # - it may be too restrictive (some setups expect 775 directories). # # Do not use -m 0755 and let people choose whatever they expect by # setting umask. # # We cannot accept any implementation of `mkdir' that recognizes `-p'. # Some implementations (such as Solaris 8's) are not thread-safe: if a # parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c' # concurrently, both version can detect that a/ is missing, but only # one can create it and the other will error out. Consequently we # restrict ourselves to GNU make (using the --version option ensures # this.) AC_DEFUN([AM_PROG_MKDIR_P], [if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then # We used to keeping the `.' as first argument, in order to # allow $(mkdir_p) to be used without argument. As in # $(mkdir_p) $(somedir) # where $(somedir) is conditionally defined. However this is wrong # for two reasons: # 1. if the package is installed by a user who cannot write `.' # make install will fail, # 2. the above comment should most certainly read # $(mkdir_p) $(DESTDIR)$(somedir) # so it does not work when $(somedir) is undefined and # $(DESTDIR) is not. # To support the latter case, we have to write # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), # so the `.' trick is pointless. mkdir_p='mkdir -p --' else # On NextStep and OpenStep, the `mkdir' command does not # recognize any option. It will interpret all options as # directories to create, and then abort because `.' already # exists. for d in ./-p ./--version; do test -d $d && rmdir $d done # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. if test -f "$ac_aux_dir/mkinstalldirs"; then mkdir_p='$(mkinstalldirs)' else mkdir_p='$(install_sh) -d' fi fi AC_SUBST([mkdir_p])]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # serial 2 # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # ------------------------------ # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), 1)]) # _AM_SET_OPTIONS(OPTIONS) # ---------------------------------- # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # # Check to make sure that the build environment is sane. # # Copyright (C) 1996, 1997, 2000, 2001, 2003 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # serial 3 # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftest.file # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t $srcdir/configure conftest.file` fi rm -f conftest.file if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT(yes)]) # AM_PROG_INSTALL_STRIP # Copyright (C) 2001, 2003 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in `make install-strip', and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be `maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # serial 1 # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of `v7', `ustar', or `pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. AM_MISSING_PROG([AMTAR], [tar]) m4_if([$1], [v7], [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of `-'. for _am_tool in $_am_tools do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR rsnapshot-1.3.1/configure0000755000000000000000000030614311005052462015404 0ustar rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59 for rsnapshot 1.3.1. # # Report bugs to . # # Copyright (C) 2003 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` exec 6>&1 # # Initializations. # ac_default_prefix=/usr/local ac_config_libobj_dir=. cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. # This variable seems obsolete. It should probably be removed, and # only ac_max_sed_lines should be used. : ${ac_max_here_lines=38} # Identity of this package. PACKAGE_NAME='rsnapshot' PACKAGE_TARNAME='rsnapshot' PACKAGE_VERSION='1.3.1' PACKAGE_STRING='rsnapshot 1.3.1' PACKAGE_BUGREPORT='rsnapshot-discuss@lists.sourceforge.net' ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CWD PERL CMD_RSYNC RSYNC TEST_CP CP CMD_CP RM TEST_RM CMD_RM SSH TEST_SSH CMD_SSH LOGGER TEST_LOGGER CMD_LOGGER DU TEST_DU CMD_DU LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. ac_init_help= ac_init_version=false # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_option in -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir=$ac_optarg ;; -disable-* | --disable-*) ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` eval "enable_$ac_feature=no" ;; -enable-* | --enable-*) ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "enable_$ac_feature='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package| sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "with_$ac_package='$ac_optarg'" ;; -without-* | --without-*) ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/-/_/g'` eval "with_$ac_package=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) { echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` eval "$ac_envvar='$ac_optarg'" export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` { echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi # Be sure to have absolute paths. for ac_var in exec_prefix prefix do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* | NONE | '' ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # Be sure to have absolute paths. for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ localstatedir libdir includedir oldincludedir infodir mandir do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_confdir=`(dirname "$0") 2>/dev/null || $as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$0" : 'X\(//\)[^/]' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$0" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 { (exit 1); exit 1; }; } else { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi fi (cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 { (exit 1); exit 1; }; } srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` ac_env_build_alias_set=${build_alias+set} ac_env_build_alias_value=$build_alias ac_cv_env_build_alias_set=${build_alias+set} ac_cv_env_build_alias_value=$build_alias ac_env_host_alias_set=${host_alias+set} ac_env_host_alias_value=$host_alias ac_cv_env_host_alias_set=${host_alias+set} ac_cv_env_host_alias_value=$host_alias ac_env_target_alias_set=${target_alias+set} ac_env_target_alias_value=$target_alias ac_cv_env_target_alias_set=${target_alias+set} ac_cv_env_target_alias_value=$target_alias # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures rsnapshot 1.3.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] _ACEOF cat <<_ACEOF Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data [PREFIX/share] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --infodir=DIR info documentation [PREFIX/info] --mandir=DIR man documentation [PREFIX/man] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of rsnapshot 1.3.1:";; esac cat <<\_ACEOF Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-perl=PATH Specify the path to perl --with-rsync=PATH Specify the path to rsync --with-cp=PATH Specify the path to cp --with-rm=PATH Specify the path to rm --with-ssh=PATH Specify the path to ssh --with-logger=PATH Specify the path to logger --with-du=PATH Specify the path to du Report bugs to . _ACEOF fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. ac_popdir=`pwd` for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d $ac_dir || continue ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac cd $ac_dir # Check for guested configure; otherwise get Cygnus style configure. if test -f $ac_srcdir/configure.gnu; then echo $SHELL $ac_srcdir/configure.gnu --help=recursive elif test -f $ac_srcdir/configure; then echo $SHELL $ac_srcdir/configure --help=recursive elif test -f $ac_srcdir/configure.ac || test -f $ac_srcdir/configure.in; then echo $ac_configure --help else echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi cd $ac_popdir done fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF rsnapshot configure 1.3.1 generated by GNU Autoconf 2.59 Copyright (C) 2003 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit 0 fi exec 5>config.log cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by rsnapshot $as_me 1.3.1, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ _ACEOF { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` hostinfo = `(hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. echo "PATH: $as_dir" done } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_sep= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$ac_configure_args1 '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" # Get rid of the leading space. ac_sep=" " ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Be sure not to use single quotes in there, as some shells, # such as our DU 5.0 friend, will then `close' the trap. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, { (set) 2>&1 | case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in *ac_space=\ *) sed -n \ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" ;; *) sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------- ## ## Output files. ## ## ------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo sed "/^$/d" confdefs.h | sort echo fi test "$ac_signal" != 0 && echo "$as_me: caught signal $ac_signal" echo "$as_me: exit $exit_status" } >&5 rm -f core *.core && rm -rf conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo >confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then { echo "$as_me:$LINENO: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . $cache_file;; *) . ./$cache_file;; esac fi else { echo "$as_me:$LINENO: creating cache $cache_file" >&5 echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in `(set) 2>&1 | sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val="\$ac_cv_env_${ac_var}_value" eval ac_new_val="\$ac_env_${ac_var}_value" case $ac_old_set,$ac_new_set in set,) { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am__api_version="1.9" ac_aux_dir= for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do if test -f $ac_dir/install-sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f $ac_dir/install.sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f $ac_dir/shtool; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} { (exit 1); exit 1; }; } fi ac_config_guess="$SHELL $ac_aux_dir/config.guess" ac_config_sub="$SHELL $ac_aux_dir/config.sub" ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in ./ | .// | /cC/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi done done ;; esac done fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. We don't cache a # path for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the path is relative. INSTALL=$ac_install_sh fi fi echo "$as_me:$LINENO: result: $INSTALL" >&5 echo "${ECHO_T}$INSTALL" >&6 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo "$as_me:$LINENO: checking whether build environment is sane" >&5 echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6 # Just in case sleep 1 echo timestamp > conftest.file # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t $srcdir/configure conftest.file` fi rm -f conftest.file if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken alias in your environment" >&5 echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken alias in your environment" >&2;} { (exit 1); exit 1; }; } fi test "$2" = conftest.file ) then # Ok. : else { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! Check your system clock" >&5 echo "$as_me: error: newly created file is older than distributed files! Check your system clock" >&2;} { (exit 1); exit 1; }; } fi echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 test "$program_prefix" != NONE && program_transform_name="s,^,$program_prefix,;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s,\$,$program_suffix,;$program_transform_name" # Double any \ or $. echo might interpret backslashes. # By default was `s,x,x', remove it if useless. cat <<\_ACEOF >conftest.sed s/[\\$]/&&/g;s/;s,x,x,$// _ACEOF program_transform_name=`echo $program_transform_name | sed -f conftest.sed` rm conftest.sed # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} fi if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then # We used to keeping the `.' as first argument, in order to # allow $(mkdir_p) to be used without argument. As in # $(mkdir_p) $(somedir) # where $(somedir) is conditionally defined. However this is wrong # for two reasons: # 1. if the package is installed by a user who cannot write `.' # make install will fail, # 2. the above comment should most certainly read # $(mkdir_p) $(DESTDIR)$(somedir) # so it does not work when $(somedir) is undefined and # $(DESTDIR) is not. # To support the latter case, we have to write # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), # so the `.' trick is pointless. mkdir_p='mkdir -p --' else # On NextStep and OpenStep, the `mkdir' command does not # recognize any option. It will interpret all options as # directories to create, and then abort because `.' already # exists. for d in ./-p ./--version; do test -d $d && rmdir $d done # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. if test -f "$ac_aux_dir/mkinstalldirs"; then mkdir_p='$(mkinstalldirs)' else mkdir_p='$(install_sh) -d' fi fi for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_AWK+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then echo "$as_me:$LINENO: result: $AWK" >&5 echo "${ECHO_T}$AWK" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$AWK" && break done echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.make <<\_ACEOF all: @echo 'ac_maketemp="$(MAKE)"' _ACEOF # GNU make sometimes prints "make[1]: Entering...", which would confuse us. eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` if test -n "$ac_maketemp"; then eval ac_cv_prog_make_${ac_make}_set=yes else eval ac_cv_prog_make_${ac_make}_set=no fi rm -f conftest.make fi if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 SET_MAKE= else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # test to see if srcdir already configured if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} { (exit 1); exit 1; }; } fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='rsnapshot' VERSION='1.3.1' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} install_sh=${install_sh-"$am_aux_dir/install-sh"} # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_STRIP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then echo "$as_me:$LINENO: result: $STRIP" >&5 echo "${ECHO_T}$STRIP" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 echo "${ECHO_T}$ac_ct_STRIP" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi STRIP=$ac_ct_STRIP else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. AMTAR=${AMTAR-"${am_missing_run}tar"} am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.make <<\_ACEOF all: @echo 'ac_maketemp="$(MAKE)"' _ACEOF # GNU make sometimes prints "make[1]: Entering...", which would confuse us. eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` if test -n "$ac_maketemp"; then eval ac_cv_prog_make_${ac_make}_set=yes else eval ac_cv_prog_make_${ac_make}_set=no fi rm -f conftest.make fi if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 SET_MAKE= else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 SET_MAKE="MAKE=${MAKE-make}" fi # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in ./ | .// | /cC/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi done done ;; esac done fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. We don't cache a # path for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the path is relative. INSTALL=$ac_install_sh fi fi echo "$as_me:$LINENO: result: $INSTALL" >&5 echo "${ECHO_T}$INSTALL" >&6 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' ac_config_files="$ac_config_files Makefile" CWD=`eval echo \`pwd\`` CWD="$CWD" # Check whether --with-perl or --without-perl was given. if test "${with_perl+set}" = set; then withval="$with_perl" if test "x$withval" != "xno"; then if test -x "$withval"; then PERL=$withval else { { echo "$as_me:$LINENO: error: perl not found" >&5 echo "$as_me: error: perl not found" >&2;} { (exit 1); exit 1; }; } fi else { { echo "$as_me:$LINENO: error: perl is required" >&5 echo "$as_me: error: perl is required" >&2;} { (exit 1); exit 1; }; } fi fi; if test "$PERL" = ""; then # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_PERL+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $PERL in [\\/]* | ?:[\\/]*) ac_cv_path_PERL="$PERL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_path_PERL" && ac_cv_path_PERL="no" ;; esac fi PERL=$ac_cv_path_PERL if test -n "$PERL"; then echo "$as_me:$LINENO: result: $PERL" >&5 echo "${ECHO_T}$PERL" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test "$PERL" = "no"; then { { echo "$as_me:$LINENO: error: perl is required" >&5 echo "$as_me: error: perl is required" >&2;} { (exit 1); exit 1; }; } fi # Check whether --with-rsync or --without-rsync was given. if test "${with_rsync+set}" = set; then withval="$with_rsync" if test "x$withval" != "xno"; then if test -x "$withval"; then RSYNC=$withval CMD_RSYNC="cmd_rsync $RSYNC" else { { echo "$as_me:$LINENO: error: rsync not found" >&5 echo "$as_me: error: rsync not found" >&2;} { (exit 1); exit 1; }; } fi else { { echo "$as_me:$LINENO: error: rsync is required" >&5 echo "$as_me: error: rsync is required" >&2;} { (exit 1); exit 1; }; } fi fi; if test "$RSYNC" = ""; then # Extract the first word of "rsync", so it can be a program name with args. set dummy rsync; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_RSYNC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $RSYNC in [\\/]* | ?:[\\/]*) ac_cv_path_RSYNC="$RSYNC" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_RSYNC="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_path_RSYNC" && ac_cv_path_RSYNC="no" ;; esac fi RSYNC=$ac_cv_path_RSYNC if test -n "$RSYNC"; then echo "$as_me:$LINENO: result: $RSYNC" >&5 echo "${ECHO_T}$RSYNC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi RSYNC="$RSYNC" CMD_RSYNC="cmd_rsync $RSYNC" fi if test "$RSYNC" = "no"; then { { echo "$as_me:$LINENO: error: rsync is required" >&5 echo "$as_me: error: rsync is required" >&2;} { (exit 1); exit 1; }; } fi # Check whether --with-cp or --without-cp was given. if test "${with_cp+set}" = set; then withval="$with_cp" if test "x$withval" != "xno"; then if test -x "$withval"; then CP=$withval else { { echo "$as_me:$LINENO: error: cp not found" >&5 echo "$as_me: error: cp not found" >&2;} { (exit 1); exit 1; }; } fi else CP=no fi fi; TEST_CP="$CP" if test "$CP" != "no"; then if test "$CP" = ""; then # Extract the first word of "cp", so it can be a program name with args. set dummy cp; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_CP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $CP in [\\/]* | ?:[\\/]*) ac_cv_path_CP="$CP" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_CP="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_path_CP" && ac_cv_path_CP="no" ;; esac fi CP=$ac_cv_path_CP if test -n "$CP"; then echo "$as_me:$LINENO: result: $CP" >&5 echo "${ECHO_T}$CP" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi fi if test "$CP" = "no"; then CP=/bin/cp fi CMD_CP="cmd_cp $CP" # Check whether --with-rm or --without-rm was given. if test "${with_rm+set}" = set; then withval="$with_rm" if test "x$withval" != "xno"; then if test -x "$withval"; then RM=$withval else { { echo "$as_me:$LINENO: error: rm not found" >&5 echo "$as_me: error: rm not found" >&2;} { (exit 1); exit 1; }; } fi else RM=no fi fi; if test "$RM" != "no"; then if test "$RM" = ""; then # Extract the first word of "rm", so it can be a program name with args. set dummy rm; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_RM+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $RM in [\\/]* | ?:[\\/]*) ac_cv_path_RM="$RM" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_RM="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_path_RM" && ac_cv_path_RM="no" ;; esac fi RM=$ac_cv_path_RM if test -n "$RM"; then echo "$as_me:$LINENO: result: $RM" >&5 echo "${ECHO_T}$RM" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi fi TEST_RM="$RM" if test "$RM" = "no"; then RM=/bin/rm fi CMD_RM="cmd_rm $RM" # Check whether --with-ssh or --without-ssh was given. if test "${with_ssh+set}" = set; then withval="$with_ssh" if test "x$withval" != "xno"; then if test -x "$withval"; then SSH=$withval else { { echo "$as_me:$LINENO: error: ssh not found" >&5 echo "$as_me: error: ssh not found" >&2;} { (exit 1); exit 1; }; } fi else SSH=no fi fi; if test "$SSH" != "no"; then if test "$SSH" = ""; then # Extract the first word of "ssh", so it can be a program name with args. set dummy ssh; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_SSH+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $SSH in [\\/]* | ?:[\\/]*) ac_cv_path_SSH="$SSH" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_SSH="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_path_SSH" && ac_cv_path_SSH="no" ;; esac fi SSH=$ac_cv_path_SSH if test -n "$SSH"; then echo "$as_me:$LINENO: result: $SSH" >&5 echo "${ECHO_T}$SSH" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi fi TEST_SSH="$SSH" if test "$SSH" = "no"; then SSH=/path/to/ssh fi CMD_SSH="cmd_ssh $SSH" # Check whether --with-logger or --without-logger was given. if test "${with_logger+set}" = set; then withval="$with_logger" if test "x$withval" != "xno"; then if test -x "$withval"; then LOGGER=$withval else { { echo "$as_me:$LINENO: error: logger not found" >&5 echo "$as_me: error: logger not found" >&2;} { (exit 1); exit 1; }; } fi else LOGGER=no fi fi; if test "$LOGGER" != "no"; then if test "$LOGGER" = ""; then # Extract the first word of "logger", so it can be a program name with args. set dummy logger; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_LOGGER+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $LOGGER in [\\/]* | ?:[\\/]*) ac_cv_path_LOGGER="$LOGGER" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_LOGGER="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_path_LOGGER" && ac_cv_path_LOGGER="no" ;; esac fi LOGGER=$ac_cv_path_LOGGER if test -n "$LOGGER"; then echo "$as_me:$LINENO: result: $LOGGER" >&5 echo "${ECHO_T}$LOGGER" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi fi TEST_LOGGER="$LOGGER" if test "$LOGGER" = "no"; then LOGGER=/path/to/logger fi CMD_LOGGER="cmd_logger $LOGGER" # Check whether --with-du or --without-du was given. if test "${with_du+set}" = set; then withval="$with_du" if test "x$withval" != "xno"; then if test -x "$withval"; then DU=$withval else { { echo "$as_me:$LINENO: error: du not found" >&5 echo "$as_me: error: du not found" >&2;} { (exit 1); exit 1; }; } fi else DU=no fi fi; if test "$DU" != "no"; then if test "$DU" = ""; then # Extract the first word of "du", so it can be a program name with args. set dummy du; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_DU+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $DU in [\\/]* | ?:[\\/]*) ac_cv_path_DU="$DU" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_DU="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_path_DU" && ac_cv_path_DU="no" ;; esac fi DU=$ac_cv_path_DU if test -n "$DU"; then echo "$as_me:$LINENO: result: $DU" >&5 echo "${ECHO_T}$DU" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi fi TEST_DU="$DU" if test "$DU" = "no"; then DU=/path/to/du fi CMD_DU="cmd_du $DU" ac_config_files="$ac_config_files rsnapshot:rsnapshot-preamble.pl:rsnapshot-program.pl" ac_config_files="$ac_config_files rsnapshot-diff:rsnapshot-preamble.pl:rsnapshot-diff.pl" ac_config_files="$ac_config_files rsnapshot.conf.default:rsnapshot.conf.default.in" ac_config_files="$ac_config_files t/support/etc/configtest.conf:t/support/etc/configtest.conf.in" ac_config_files="$ac_config_files t/support/etc/rsync.conf:t/support/etc/rsync.conf.in" ac_config_files="$ac_config_files t/support/etc/gnu_cp.conf:t/support/etc/gnu_cp.conf.in" ac_config_files="$ac_config_files t/support/etc/relative_delete_bugfix.conf:t/support/etc/relative_delete_bugfix.conf.in" ac_config_files="$ac_config_files t/configtest.t:t/configtest.t.in" ac_config_files="$ac_config_files t/rsync.t:t/rsync.t.in" ac_config_files="$ac_config_files t/gnu_cp.t:t/gnu_cp.t.in" ac_config_files="$ac_config_files t/relative_delete_bugfix.t:t/relative_delete_bugfix.t.in" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. { (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote # substitution turns \\\\ into \\, and sed turns \\ into \). sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } | sed ' t clear : clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ : end' >>confcache if diff $cache_file confcache >/dev/null 2>&1; then :; else if test -w $cache_file; then test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" cat confcache >$cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/; s/:*\${srcdir}:*/:/; s/:*@srcdir@:*/:/; s/^\([^=]*=[ ]*\):*/\1/; s/:*$//; s/^[^=]*=[ ]*$//; }' fi # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then we branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. cat >confdef2opt.sed <<\_ACEOF t clear : clear s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g t quote s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g t quote d : quote s,[ `~#$^&*(){}\\|;'"<>?],\\&,g s,\[,\\&,g s,\],\\&,g s,\$,$$,g p _ACEOF # We use echo to avoid assuming a particular line-breaking character. # The extra dot is to prevent the shell from consuming trailing # line-breaks from the sub-command output. A line-break within # single-quotes doesn't work because, if this script is created in a # platform that uses two characters for line-breaks (e.g., DOS), tr # would break. ac_LF_and_DOT=`echo; echo .` DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` rm -f confdef2opt.sed ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_i=`echo "$ac_i" | sed 's/\$U\././;s/\.o$//;s/\.obj$//'` # 2. Add them. ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH exec 6>&1 # Open the log real soon, to keep \$[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. Logging --version etc. is OK. exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX } >&5 cat >&5 <<_CSEOF This file was extended by rsnapshot $as_me 1.3.1, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ _CSEOF echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 echo >&5 _ACEOF # Files that config.status was made for. if test -n "$ac_config_files"; then echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS fi if test -n "$ac_config_headers"; then echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS fi if test -n "$ac_config_links"; then echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS fi if test -n "$ac_config_commands"; then echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS fi cat >>$CONFIG_STATUS <<\_ACEOF ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ rsnapshot config.status 1.3.1 configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2003 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." srcdir=$srcdir INSTALL="$INSTALL" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "x$1" : 'x\([^=]*\)='` ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` ac_shift=: ;; -*) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; *) # This is not an option, so the user has probably given explicit # arguments. ac_option=$1 ac_need_defaults=false;; esac case $ac_option in # Handling of the options. _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --vers* | -V ) echo "$ac_cs_version"; exit 0 ;; --he | --h) # Conflict between --help and --header { { echo "$as_me:$LINENO: error: ambiguous option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; };; --help | --hel | -h ) echo "$ac_cs_usage"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift CONFIG_FILES="$CONFIG_FILES $ac_optarg" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" ac_need_defaults=false;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF if \$ac_cs_recheck; then echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_config_target in $ac_config_targets do case "$ac_config_target" in # Handling of arguments. "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; "rsnapshot" ) CONFIG_FILES="$CONFIG_FILES rsnapshot:rsnapshot-preamble.pl:rsnapshot-program.pl" ;; "rsnapshot-diff" ) CONFIG_FILES="$CONFIG_FILES rsnapshot-diff:rsnapshot-preamble.pl:rsnapshot-diff.pl" ;; "rsnapshot.conf.default" ) CONFIG_FILES="$CONFIG_FILES rsnapshot.conf.default:rsnapshot.conf.default.in" ;; "t/support/etc/configtest.conf" ) CONFIG_FILES="$CONFIG_FILES t/support/etc/configtest.conf:t/support/etc/configtest.conf.in" ;; "t/support/etc/rsync.conf" ) CONFIG_FILES="$CONFIG_FILES t/support/etc/rsync.conf:t/support/etc/rsync.conf.in" ;; "t/support/etc/gnu_cp.conf" ) CONFIG_FILES="$CONFIG_FILES t/support/etc/gnu_cp.conf:t/support/etc/gnu_cp.conf.in" ;; "t/support/etc/relative_delete_bugfix.conf" ) CONFIG_FILES="$CONFIG_FILES t/support/etc/relative_delete_bugfix.conf:t/support/etc/relative_delete_bugfix.conf.in" ;; "t/configtest.t" ) CONFIG_FILES="$CONFIG_FILES t/configtest.t:t/configtest.t.in" ;; "t/rsync.t" ) CONFIG_FILES="$CONFIG_FILES t/rsync.t:t/rsync.t.in" ;; "t/gnu_cp.t" ) CONFIG_FILES="$CONFIG_FILES t/gnu_cp.t:t/gnu_cp.t.in" ;; "t/relative_delete_bugfix.t" ) CONFIG_FILES="$CONFIG_FILES t/relative_delete_bugfix.t:t/relative_delete_bugfix.t.in" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason to put it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Create a temporary directory, and hook for its removal unless debugging. $debug || { trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./confstat$$-$RANDOM (umask 077 && mkdir $tmp) } || { echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # # CONFIG_FILES section. # # No need to generate the scripts if there are no CONFIG_FILES. # This happens for instance when ./config.status config.h if test -n "\$CONFIG_FILES"; then # Protect against being on the right side of a sed subst in config.status. sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF s,@SHELL@,$SHELL,;t t s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t s,@exec_prefix@,$exec_prefix,;t t s,@prefix@,$prefix,;t t s,@program_transform_name@,$program_transform_name,;t t s,@bindir@,$bindir,;t t s,@sbindir@,$sbindir,;t t s,@libexecdir@,$libexecdir,;t t s,@datadir@,$datadir,;t t s,@sysconfdir@,$sysconfdir,;t t s,@sharedstatedir@,$sharedstatedir,;t t s,@localstatedir@,$localstatedir,;t t s,@libdir@,$libdir,;t t s,@includedir@,$includedir,;t t s,@oldincludedir@,$oldincludedir,;t t s,@infodir@,$infodir,;t t s,@mandir@,$mandir,;t t s,@build_alias@,$build_alias,;t t s,@host_alias@,$host_alias,;t t s,@target_alias@,$target_alias,;t t s,@DEFS@,$DEFS,;t t s,@ECHO_C@,$ECHO_C,;t t s,@ECHO_N@,$ECHO_N,;t t s,@ECHO_T@,$ECHO_T,;t t s,@LIBS@,$LIBS,;t t s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t s,@INSTALL_DATA@,$INSTALL_DATA,;t t s,@CYGPATH_W@,$CYGPATH_W,;t t s,@PACKAGE@,$PACKAGE,;t t s,@VERSION@,$VERSION,;t t s,@ACLOCAL@,$ACLOCAL,;t t s,@AUTOCONF@,$AUTOCONF,;t t s,@AUTOMAKE@,$AUTOMAKE,;t t s,@AUTOHEADER@,$AUTOHEADER,;t t s,@MAKEINFO@,$MAKEINFO,;t t s,@install_sh@,$install_sh,;t t s,@STRIP@,$STRIP,;t t s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t s,@mkdir_p@,$mkdir_p,;t t s,@AWK@,$AWK,;t t s,@SET_MAKE@,$SET_MAKE,;t t s,@am__leading_dot@,$am__leading_dot,;t t s,@AMTAR@,$AMTAR,;t t s,@am__tar@,$am__tar,;t t s,@am__untar@,$am__untar,;t t s,@CWD@,$CWD,;t t s,@PERL@,$PERL,;t t s,@CMD_RSYNC@,$CMD_RSYNC,;t t s,@RSYNC@,$RSYNC,;t t s,@TEST_CP@,$TEST_CP,;t t s,@CP@,$CP,;t t s,@CMD_CP@,$CMD_CP,;t t s,@RM@,$RM,;t t s,@TEST_RM@,$TEST_RM,;t t s,@CMD_RM@,$CMD_RM,;t t s,@SSH@,$SSH,;t t s,@TEST_SSH@,$TEST_SSH,;t t s,@CMD_SSH@,$CMD_SSH,;t t s,@LOGGER@,$LOGGER,;t t s,@TEST_LOGGER@,$TEST_LOGGER,;t t s,@CMD_LOGGER@,$CMD_LOGGER,;t t s,@DU@,$DU,;t t s,@TEST_DU@,$TEST_DU,;t t s,@CMD_DU@,$CMD_DU,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t CEOF _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_lines=48 ac_sed_frag=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_lines # Line after last line for current file. ac_more_lines=: ac_sed_cmds= while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag else sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag fi if test ! -s $tmp/subs.frag; then ac_more_lines=false else # The purpose of the label and of the branching condition is to # speed up the sed processing (if there are no `@' at all, there # is no need to browse any of the substitutions). # These are the two extra sed commands mentioned above. (echo ':t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" else ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" fi ac_sed_frag=`expr $ac_sed_frag + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_lines` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi fi # test -n "$CONFIG_FILES" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_builddir$INSTALL ;; esac if test x"$ac_file" != x-; then { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} rm -f "$ac_file" fi # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ if test x"$ac_file" = x-; then configure_input= else configure_input="$ac_file. " fi configure_input=$configure_input"Generated from `echo $ac_file_in | sed 's,.*/,,'` by configure." # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo "$f";; *) # Relative if test -f "$f"; then # Build tree echo "$f" elif test -f "$srcdir/$f"; then # Source tree echo "$srcdir/$f" else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF sed "$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s,@configure_input@,$configure_input,;t t s,@srcdir@,$ac_srcdir,;t t s,@abs_srcdir@,$ac_abs_srcdir,;t t s,@top_srcdir@,$ac_top_srcdir,;t t s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t s,@builddir@,$ac_builddir,;t t s,@abs_builddir@,$ac_abs_builddir,;t t s,@top_builddir@,$ac_top_builddir,;t t s,@abs_top_builddir@,$ac_abs_top_builddir,;t t s,@INSTALL@,$ac_INSTALL,;t t " $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out rm -f $tmp/stdin if test x"$ac_file" != x-; then mv $tmp/out $ac_file else cat $tmp/out rm -f $tmp/out fi done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi # this is kludgy, but it works RSNAPSHOT_SYSCONFDIR=`eval echo ${sysconfdir}` if test -e "$RSNAPSHOT_SYSCONFDIR/rsnapshot.conf"; then RSNAPSHOT_OLD_VERSION=`$PERL rsnapshot-program.pl -c $RSNAPSHOT_SYSCONFDIR/rsnapshot.conf check-config-version` # figure out if this is a fresh install or an upgrade # advise the user accordingly if test "$RSNAPSHOT_OLD_VERSION" = "unknown"; then echo "" echo "+----------------------------------------------------------------------------+" echo "| A previous version of rsnapshot was detected. |" echo "| |" echo "| If you have not already done so, it is HIGHLY recommended that you upgrade |" echo "| your config file for compatibility with this release. |" echo "| |" echo "| If you don't upgrade your config file, rsnapshot will appear to work, but |" echo "| rearrange the relative paths to your backup files when you aren't looking. |" echo "| It would be a nasty surprise, which is why we're telling you about it now. |" echo "| |" echo "| If you would like to automatically upgrade your config file, just type: |" echo "| |" echo "| \"make upgrade\" |" echo "| |" echo "| After you have upgraded your config file, type \"make install\". |" echo "| |" echo "| For more information on the upgrade, read the INSTALL file that came with |" echo "| the program. |" echo "+----------------------------------------------------------------------------+" exit 0 fi # this is already the latest version. if test "$RSNAPSHOT_OLD_VERSION" = "1.2"; then echo "$RSNAPSHOT_SYSCONFDIR/rsnapshot.conf found, and is up to date." else echo "" echo "ERROR: $RSNAPSHOT_SYSCONFDIR/rsnapshot.conf is an unknown version." echo "Upgrading is not recommended until you figure out what's wrong." echo "" exit 1 fi fi echo "" echo "Now type \"make test\" to run the regression test suite." echo "Then type \"make install\" to install the program." echo "" if test ! -e "$RSNAPSHOT_SYSCONFDIR/rsnapshot.conf"; then echo "After rsnapshot is installed, don't forget to copy" echo "$RSNAPSHOT_SYSCONFDIR/rsnapshot.conf.default to $RSNAPSHOT_SYSCONFDIR/rsnapshot.conf" echo "" fi rsnapshot-1.3.1/configure.ac0000644000000000000000000002124711005052310015752 0ustar rootroot00000000000000dnl $Id: configure.ac,v 1.49 2008/04/27 10:23:58 djk20 Exp $ AC_INIT(rsnapshot, 1.3.1, rsnapshot-discuss@lists.sourceforge.net) AM_INIT_AUTOMAKE AC_PROG_MAKE_SET AC_PROG_INSTALL AC_CONFIG_FILES(Makefile) dnl dnl get the current working directory for the regression test suite dnl CWD=`eval echo \`pwd\`` AC_SUBST(CWD, "$CWD") dnl dnl PERL CHECK (required program) dnl dnl if the user specified a path, try that first AC_ARG_WITH(perl, [ --with-perl=PATH Specify the path to perl ], [ if test "x$withval" != "xno"; then if test -x "$withval"; then PERL=$withval else AC_MSG_ERROR(perl not found) fi else AC_MSG_ERROR(perl is required) fi ] ) dnl if the user didn't specify a path, hunt for it if test "$PERL" = ""; then AC_PATH_PROG(PERL, perl, no) fi dnl bail out if we can't find it if test "$PERL" = "no"; then AC_MSG_ERROR(perl is required) fi dnl dnl RSYNC CHECK (required program) dnl dnl if the user specified a path, try that first AC_ARG_WITH(rsync, [ --with-rsync=PATH Specify the path to rsync ], [ if test "x$withval" != "xno"; then if test -x "$withval"; then RSYNC=$withval AC_SUBST(CMD_RSYNC, "cmd_rsync $RSYNC") else AC_MSG_ERROR(rsync not found) fi else AC_MSG_ERROR(rsync is required) fi ] ) dnl if the user didn't specify a path, hunt for it if test "$RSYNC" = ""; then AC_PATH_PROG(RSYNC, rsync, no) AC_SUBST(RSYNC, "$RSYNC") AC_SUBST(CMD_RSYNC, "cmd_rsync $RSYNC") fi dnl bail out if we can't find it if test "$RSYNC" = "no"; then AC_MSG_ERROR(rsync is required) fi dnl dnl CP CHECK (optional program) dnl dnl if the user specified a path, try that first AC_ARG_WITH(cp, [ --with-cp=PATH Specify the path to cp ], [ if test "x$withval" != "xno"; then if test -x "$withval"; then CP=$withval else AC_MSG_ERROR(cp not found) fi else CP=no fi ] ) dnl save the program for testing AC_SUBST(TEST_CP, "$CP") dnl if the user didn't specify a path, hunt for it if test "$CP" != "no"; then if test "$CP" = ""; then AC_PATH_PROG(CP, cp, no) fi fi dnl if we couldn't find it, provide an example if test "$CP" = "no"; then CP=/bin/cp fi dnl either way, set the cmd_cp var AC_SUBST(CMD_CP, "cmd_cp $CP") dnl dnl RM CHECK (optional program) dnl dnl if the user specified a path, try that first AC_ARG_WITH(rm, [ --with-rm=PATH Specify the path to rm ], [ if test "x$withval" != "xno"; then if test -x "$withval"; then RM=$withval else AC_MSG_ERROR(rm not found) fi else RM=no fi ] ) dnl if the user didn't specify a path, hunt for it if test "$RM" != "no"; then if test "$RM" = ""; then AC_PATH_PROG(RM, rm, no) fi fi dnl save the program for testing AC_SUBST(TEST_RM, "$RM") dnl if we couldn't find it, provide an example if test "$RM" = "no"; then RM=/bin/rm fi dnl either way, set the cmd_rm var AC_SUBST(CMD_RM, "cmd_rm $RM") dnl dnl SSH CHECK (optional program) dnl dnl if the user specified a path, try that first AC_ARG_WITH(ssh, [ --with-ssh=PATH Specify the path to ssh ], [ if test "x$withval" != "xno"; then if test -x "$withval"; then SSH=$withval else AC_MSG_ERROR(ssh not found) fi else SSH=no fi ] ) dnl if the user didn't specify a path, hunt for it if test "$SSH" != "no"; then if test "$SSH" = ""; then AC_PATH_PROG(SSH, ssh, no) fi fi dnl save the program for testing AC_SUBST(TEST_SSH, "$SSH") dnl if we couldn't find it, provide an example if test "$SSH" = "no"; then SSH=/path/to/ssh fi dnl either way, set the cmd_ssh var AC_SUBST(CMD_SSH, "cmd_ssh $SSH") dnl dnl LOGGER CHECK (optional program) dnl dnl if the user specified a path, try that first AC_ARG_WITH(logger, [ --with-logger=PATH Specify the path to logger ], [ if test "x$withval" != "xno"; then if test -x "$withval"; then LOGGER=$withval else AC_MSG_ERROR(logger not found) fi else LOGGER=no fi ] ) dnl if the user didn't specify a path, hunt for it if test "$LOGGER" != "no"; then if test "$LOGGER" = ""; then AC_PATH_PROG(LOGGER, logger, no) fi fi dnl save the program for testing AC_SUBST(TEST_LOGGER, "$LOGGER") dnl if we couldn't find it, provide an example if test "$LOGGER" = "no"; then LOGGER=/path/to/logger fi dnl either way, set the cmd_logger var AC_SUBST(CMD_LOGGER, "cmd_logger $LOGGER") dnl dnl DU CHECK (optional program) dnl dnl if the user specified a path, try that first AC_ARG_WITH(du, [ --with-du=PATH Specify the path to du ], [ if test "x$withval" != "xno"; then if test -x "$withval"; then DU=$withval else AC_MSG_ERROR(du not found) fi else DU=no fi ] ) dnl if the user didn't specify a path, hunt for it if test "$DU" != "no"; then if test "$DU" = ""; then AC_PATH_PROG(DU, du, no) fi fi dnl save the program for testing AC_SUBST(TEST_DU, "$DU") dnl if we couldn't find it, provide an example if test "$DU" = "no"; then DU=/path/to/du fi dnl either way, set the cmd_ssh var AC_SUBST(CMD_DU, "cmd_du $DU") dnl Combine the preamble with a normal, working script AC_CONFIG_FILES(rsnapshot:rsnapshot-preamble.pl:rsnapshot-program.pl) dnl Combine the preamble with the rsnapshot-diff script to determine path to perl AC_CONFIG_FILES(rsnapshot-diff:rsnapshot-preamble.pl:rsnapshot-diff.pl) dnl try to find dependent programs for the config file AC_CONFIG_FILES(rsnapshot.conf.default:rsnapshot.conf.default.in) dnl config files for regression test scripts AC_CONFIG_FILES(t/support/etc/configtest.conf:t/support/etc/configtest.conf.in) AC_CONFIG_FILES(t/support/etc/rsync.conf:t/support/etc/rsync.conf.in) AC_CONFIG_FILES(t/support/etc/gnu_cp.conf:t/support/etc/gnu_cp.conf.in) AC_CONFIG_FILES(t/support/etc/relative_delete_bugfix.conf:t/support/etc/relative_delete_bugfix.conf.in) dnl regression test scripts AC_CONFIG_FILES(t/configtest.t:t/configtest.t.in) AC_CONFIG_FILES(t/rsync.t:t/rsync.t.in) AC_CONFIG_FILES(t/gnu_cp.t:t/gnu_cp.t.in) AC_CONFIG_FILES(t/relative_delete_bugfix.t:t/relative_delete_bugfix.t.in) AC_OUTPUT # this is kludgy, but it works RSNAPSHOT_SYSCONFDIR=`eval echo ${sysconfdir}` if test -e "$RSNAPSHOT_SYSCONFDIR/rsnapshot.conf"; then RSNAPSHOT_OLD_VERSION=`$PERL rsnapshot-program.pl -c $RSNAPSHOT_SYSCONFDIR/rsnapshot.conf check-config-version` # figure out if this is a fresh install or an upgrade # advise the user accordingly if test "$RSNAPSHOT_OLD_VERSION" = "unknown"; then echo "" echo "+----------------------------------------------------------------------------+" echo "| A previous version of rsnapshot was detected. |" echo "| |" echo "| If you have not already done so, it is HIGHLY recommended that you upgrade |" echo "| your config file for compatibility with this release. |" echo "| |" echo "| If you don't upgrade your config file, rsnapshot will appear to work, but |" echo "| rearrange the relative paths to your backup files when you aren't looking. |" echo "| It would be a nasty surprise, which is why we're telling you about it now. |" echo "| |" echo "| If you would like to automatically upgrade your config file, just type: |" echo "| |" echo "| \"make upgrade\" |" echo "| |" echo "| After you have upgraded your config file, type \"make install\". |" echo "| |" echo "| For more information on the upgrade, read the INSTALL file that came with |" echo "| the program. |" echo "+----------------------------------------------------------------------------+" exit 0 fi # this is already the latest version. if test "$RSNAPSHOT_OLD_VERSION" = "1.2"; then echo "$RSNAPSHOT_SYSCONFDIR/rsnapshot.conf found, and is up to date." else echo "" echo "ERROR: $RSNAPSHOT_SYSCONFDIR/rsnapshot.conf is an unknown version." echo "Upgrading is not recommended until you figure out what's wrong." echo "" exit 1 fi fi echo "" echo "Now type \"make test\" to run the regression test suite." echo "Then type \"make install\" to install the program." echo "" if test ! -e "$RSNAPSHOT_SYSCONFDIR/rsnapshot.conf"; then echo "After rsnapshot is installed, don't forget to copy" echo "$RSNAPSHOT_SYSCONFDIR/rsnapshot.conf.default to $RSNAPSHOT_SYSCONFDIR/rsnapshot.conf" echo "" fi rsnapshot-1.3.1/config.guess0000755000000000000000000012470210173414462016023 0ustar rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. timestamp='2004-11-12' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit 0 ;; amd64:OpenBSD:*:*) echo x86_64-unknown-openbsd${UNAME_RELEASE} exit 0 ;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; cats:OpenBSD:*:*) echo arm-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; luna88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; macppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvmeppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sgi:OpenBSD:*:*) echo mips64-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sun3:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit 0 ;; macppc:MirBSD:*:*) echo powerppc-unknown-mirbsd${UNAME_RELEASE} exit 0 ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit 0 ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit 0 ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit 0;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit 0 ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit 0 ;; *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit 0 ;; *:OS400:*:*) echo powerpc-ibm-os400 exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit 0;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit 0 ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7 && exit 0 ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit 0 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c \ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ && exit 0 echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit 0 ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit 0 ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit 0 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit 0 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit 0 ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit 0 ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit 0 ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:*:*) echo rs6000-ibm-aix exit 0 ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit 0 ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit 0 ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then # avoid double evaluation of $set_cc_for_build test -n "$CC_FOR_BUILD" || eval $set_cc_for_build if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit 0 ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit 0 ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:FreeBSD:*:*) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit 0 ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit 0 ;; x86:Interix*:[34]*) echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' exit 0 ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit 0 ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit 0 ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit 0 ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit 0 ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit 0 ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit 0 ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit 0 ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit 0 ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit 0 ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit 0 ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit 0 ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit 0 ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit 0 ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit 0 ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit 0 ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #ifdef __INTEL_COMPILER LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit 0 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit 0 ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit 0 ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit 0 ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit 0 ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit 0 ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit 0 ;; i*86:*:5:[78]*) case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit 0 ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; paragon:*:*:*) echo i860-intel-osf1 exit 0 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit 0 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit 0 ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit 0 ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit 0 ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4.3${OS_REL} && exit 0 /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit 0 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit 0 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit 0 ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit 0 ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit 0 ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit 0 ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit 0 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in *86) UNAME_PROCESSOR=i686 ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit 0 ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit 0 ;; *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit 0 ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit 0 ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit 0 ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit 0 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit 0 ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit 0 ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit 0 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit 0 ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit 0 ;; *:ITS:*:*) echo pdp10-unknown-its exit 0 ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit 0 ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit 0 ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms && exit 0 ;; I*) echo ia64-dec-vms && exit 0 ;; V*) echo vax-dec-vms && exit 0 ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit 0 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; c34*) echo c34-convex-bsd exit 0 ;; c38*) echo c38-convex-bsd exit 0 ;; c4*) echo c4-convex-bsd exit 0 ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: rsnapshot-1.3.1/config.sub0000755000000000000000000007535310173414462015475 0ustar rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. timestamp='2004-11-30' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | m32r | m32rle | m68000 | m68k | m88k | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | msp430 \ | ns16k | ns32k \ | openrisc | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv8 | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | msp430-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16c) basic_machine=cr16c-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; or32 | or32-*) basic_machine=or32-unknown os=-coff ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sh64) basic_machine=sh64-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: rsnapshot-1.3.1/install-sh0000755000000000000000000001273610175635176015523 0ustar rootroot00000000000000#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 rsnapshot-1.3.1/missing0000755000000000000000000002453310431356771015110 0ustar rootroot00000000000000#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2004-09-07.08 # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004 # Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case "$1" in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file tar try tar, gnutar, gtar, then tar without non-portable flags yacc create \`y.tab.[ch]', if possible, from existing .[ch] Send bug reports to ." exit 0 ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit 0 ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). case "$1" in lex|yacc) # Not GNU programs, they don't have --version. ;; tar) if test -n "$run"; then echo 1>&2 "ERROR: \`tar' requires --run" exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then exit 1 fi ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case "$1" in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case "$f" in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison|yacc) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.h fi ;; esac fi if [ ! -f y.tab.h ]; then echo >y.tab.h fi if [ ! -f y.tab.c ]; then echo 'main() { return 0; }' >y.tab.c fi ;; lex|flex) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if [ ! -f lex.yy.c ]; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` fi if [ -f "$file" ]; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit 1 fi ;; makeinfo) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` fi touch $file ;; tar) shift # We have already tried tar in the generic part. # Look for gnutar/gtar before invocation to avoid ugly error # messages. if (gnutar --version > /dev/null 2>&1); then gnutar "$@" && exit 0 fi if (gtar --version > /dev/null 2>&1); then gtar "$@" && exit 0 fi firstarg="$1" if shift; then case "$firstarg" in *o*) firstarg=`echo "$firstarg" | sed s/o//` tar "$firstarg" "$@" && exit 0 ;; esac case "$firstarg" in *h*) firstarg=`echo "$firstarg" | sed s/h//` tar "$firstarg" "$@" && exit 0 ;; esac fi echo 1>&2 "\ WARNING: I can't seem to be able to run \`tar' with the given arguments. You may want to install GNU tar or Free paxutils, or check the command line arguments." exit 1 ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: rsnapshot-1.3.1/mkinstalldirs0000755000000000000000000000133010175635202016277 0ustar rootroot00000000000000#! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Public domain # $Id: mkinstalldirs,v 1.2 2005/01/26 06:36:50 scubaninja Exp $ errstatus=0 for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr fi fi pathcomp="$pathcomp/" done done exit $errstatus # mkinstalldirs ends here rsnapshot-1.3.1/redhat/0000755000000000000000000000000011056477673014762 5ustar rootroot00000000000000rsnapshot-1.3.1/redhat/SOURCES/0000755000000000000000000000000011056477673016105 5ustar rootroot00000000000000rsnapshot-1.3.1/redhat/SOURCES/rsnapshot.patch0000644000000000000000000000211211056477477021145 0ustar rootroot00000000000000--- rsnapshot.conf.default.in 2008-04-27 20:26:16.000000000 +1000 +++ rsnapshot.conf.default.in.redhat 2008-08-31 21:23:43.000000000 +1000 @@ -41,7 +41,7 @@ # # See the README file or the man page for more details. # -#@CMD_CP@ +@CMD_CP@ # uncomment this to use the rm program instead of the built-in perl routine. # @@ -64,11 +64,11 @@ # If you have an older version of "du", you may also want to check the # "du_args" parameter below. # -#@CMD_DU@ +@CMD_DU@ # Uncomment this to specify the path to rsnapshot-diff. # -#cmd_rsnapshot_diff /usr/local/bin/rsnapshot-diff +cmd_rsnapshot_diff /usr/bin/rsnapshot-diff # Specify the path to a script (and any optional arguments) to run right # before rsnapshot syncs files @@ -113,7 +113,7 @@ # If you enable this, data will be written to the file you specify. The # amount of data written is controlled by the "loglevel" parameter. # -#logfile /var/log/rsnapshot +logfile /var/log/rsnapshot # If enabled, rsnapshot will write a lockfile to prevent two instances # from running simultaneously (and messing up the snapshot_root). rsnapshot-1.3.1/redhat/SPECS/0000755000000000000000000000000011056477673015637 5ustar rootroot00000000000000rsnapshot-1.3.1/redhat/SPECS/rsnapshot.spec0000644000000000000000000001111411031316777020520 0ustar rootroot00000000000000# $Id: rsnapshot.spec,v 1.58 2008/06/28 02:10:25 djk20 Exp $ Name: rsnapshot Summary: Local and remote filesystem snapshot utility Version: 1.3.1 Release: 1 BuildArch: noarch License: GPL URL: http://www.rsnapshot.org/ Group: Applications/System Source: http://www.rsnapshot.org/downloads/rsnapshot-%{version}.tar.gz Patch: rsnapshot.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Requires: perl, rsync BuildRequires: rsync AutoReqProv: no %description This is a remote backup program that uses rsync to take backup snapshots of filesystems. It uses hard links to save space on disk. For more details see http://www.rsnapshot.org/. %prep %setup %patch %build %configure \ --with-perl="%{__perl}" \ --with-rsync="%{_bindir}/rsync" \ --with-ssh="%{_bindir}/ssh" \ --with-logger="%{_bindir}/logger" \ --with-du="%{_bindir}/du" %install install -d $RPM_BUILD_ROOT/%{_bindir} install -m 755 rsnapshot $RPM_BUILD_ROOT/usr/bin/rsnapshot install -m 755 rsnapshot-diff $RPM_BUILD_ROOT/usr/bin/rsnapshot-diff install -m 755 utils/rsnapreport.pl $RPM_BUILD_ROOT/usr/bin/rsnapreport.pl install -d $RPM_BUILD_ROOT/%{_mandir}/man1 install -m 644 rsnapshot*.1* $RPM_BUILD_ROOT/usr/share/man/man1/ install -d $RPM_BUILD_ROOT/%{_sysconfdir} install -m 644 rsnapshot.conf.default $RPM_BUILD_ROOT/etc/rsnapshot.conf.default install -m 600 rsnapshot.conf.default $RPM_BUILD_ROOT/etc/rsnapshot.conf %post # # upgrade rsnapshot config file # RSNAPSHOT_CONFIG_VERSION=`%{_bindir}/rsnapshot check-config-version` if test $? != 0; then echo "Error upgrading %{_sysconfdir}/rsnapshot.conf" fi if test "$RSNAPSHOT_CONFIG_VERSION" = "1.2"; then # already latest version exit 0 fi if test "$RSNAPSHOT_CONFIG_VERSION" = "unknown"; then %{_bindir}/rsnapshot upgrade-config-file RETVAL=$? exit $RETVAL fi echo "Error upgrading %{_sysconfdir}/rsnapshot.conf. Config format unknown!" exit 1 %clean rm -rf $RPM_BUILD_ROOT rm -rf $RPM_BUILD_DIR/%{name}-%{version}/ %files %defattr(-,root,root) %doc AUTHORS COPYING ChangeLog README INSTALL TODO %doc docs/Upgrading_from_1.1 docs/HOWTOs/rsnapshot-HOWTO.en.html # rsnapshot.conf.default is replaceable - user is not supposed to edit it %config %{_sysconfdir}/rsnapshot.conf.default %config(noreplace) %verify(user group mode) %{_sysconfdir}/rsnapshot.conf %{_bindir}/rsnapshot %{_bindir}/rsnapshot-diff %{_bindir}/rsnapreport.pl %{_mandir}/man1/rsnapshot*.1* %changelog * Mon Apr 28 2008 David Keegel - 1.3.1-1 - Add "BuildRequires: rsync" as sugggested by Erik Logtenberg 28 Feb 2008. * Sat Oct 28 2006 David Keegel - 1.3.0-2 - Include rsnapshot-diff.1, by using rsnapshot*.1* for man page files. * Tue Oct 10 2006 David Keegel - 1.3.0-1 - Add docs: Upgrading_from_1.1 rsnapshot-HOWTO.en.html - Add rsnapreport.pl to files and install. * Sun Sep 24 2006 David Keegel - 1.3.0-1 - Update version number to 1.3.0 * Thu Jun 22 2006 David Keegel - 1.3.0-0 - Change BuildRoot to format recommended in Fedora Packaging Guidelines - Reformat description to fit in 80 columns, and add URL. - Add URL (www.rsnapshot.org) - Remove %verify on %files (except rsnapshot.conf). - Change rsnapshot.conf to %config(noreplace). - Add version numbers to my ChangeLog entries. * Thu May 18 2006 David Keegel - 1.2.9-1 - Update version number to 1.2.9 * Sun Feb 5 2006 David Keegel - 1.2.4-1 - Added rsnapshot-diff to %files - Update version number to 1.2.4 * Sat Apr 2 2005 Nathan Rosenquist - Added rsnapshot-diff to install * Sun Jan 29 2005 Nathan Rosenquist - Added upgrade script * Sat Jan 22 2005 Nathan Rosenquist - Added --with-du option * Thu Jan 15 2004 Nathan Rosenquist - Added "AutoReqProv: no" for SuSE compatibility * Fri Dec 26 2003 Nathan Rosenquist - Added util-linux dependency, and --with-logger= option * Fri Dec 19 2003 Nathan Rosenquist - now fully support autoconf * Tue Dec 16 2003 Nathan Rosenquist - changed rsnapshot.conf to rsnapshot.conf.default from the source tree * Wed Nov 05 2003 Nathan Rosenquist - Removed fileutils dependency, added verification info * Tue Nov 04 2003 Nathan Rosenquist - fixed anonymous rsync error * Thu Oct 30 2003 Nathan Rosenquist - update to 1.0.3 * Tue Oct 28 2003 Carl Wilhelm Soderstrom - created spec file rsnapshot-1.3.1/redhat/README0000644000000000000000000000076710174622172015636 0ustar rootroot00000000000000These are the necessary files to build an RPM file. "make rpm" will do this all for you if your system is set up just right. Copy the source code tarball to your SOURCES directory. Copy SOURCES/rsnapshot.patch to your SOURCES directory. Copy SPECS/rsnapshot.spec to your SPECS directory. rpmbuild -bb /path/to/your/SPECS/rsnapshot.spec rpm -ivh /path/to/your/RPMS/noarch/rsnapshot-1.x.x-0.noarch.rpm If you don't want to make an RPM, you can download the latest version at http://www.rsnapshot.org/ rsnapshot-1.3.1/utils/0000755000000000000000000000000011056477673014653 5ustar rootroot00000000000000rsnapshot-1.3.1/utils/backup_dpkg.sh0000755000000000000000000000115710223445642017452 0ustar rootroot00000000000000#!/bin/sh ############################################################################## # backup_dpkg.sh # # by Nathan Rosenquist # http://www.rsnapshot.org/ # # This script simply backs up a list of which Debian packages are installed. # Naturally, this only works on a Debian system. # # This script simply needs to dump a file into the current working directory. # rsnapshot handles everything else. ############################################################################## # $Id: backup_dpkg.sh,v 1.2 2005/04/02 07:37:06 scubaninja Exp $ /usr/bin/dpkg --get-selections > dpkg_selections rsnapshot-1.3.1/utils/backup_mysql.sh0000755000000000000000000000206711005052310017654 0ustar rootroot00000000000000#!/bin/sh ############################################################################## # backup_mysql.sh # # by Nathan Rosenquist # http://www.rsnapshot.org/ # # This is a simple shell script to backup a MySQL database with rsnapshot. # # The assumption is that this will be invoked from rsnapshot. Also, since it # will run unattended, the user that runs rsnapshot (probably root) should have # a .my.cnf file in their home directory that contains the password for the # MySQL root user. For example: # # /root/.my.cnf (chmod 0600) # [client] # user = root # password = thepassword # host = localhost # # This script simply needs to dump a file into the current working directory. # rsnapshot handles everything else. ############################################################################## # $Id: backup_mysql.sh,v 1.6 2007/03/22 02:50:21 drhyde Exp $ umask 0077 # backup the database /usr/bin/mysqldump --all-databases > mysqldump_all_databases.sql # make the backup readable only by root /bin/chmod 600 mysqldump_all_databases.sql rsnapshot-1.3.1/utils/backup_pgsql.sh0000755000000000000000000000177211005052310017637 0ustar rootroot00000000000000#!/bin/sh ############################################################################## # backup_pgsql.sh # # by Nathan Rosenquist # http://www.rsnapshot.org/ # # This is a simple shell script to backup a PostgreSQL database with rsnapshot. # # The assumption is that this will be invoked from rsnapshot. Also, since it # will run unattended, the user that runs rsnapshot (probably root) should have # a .pgpass file in their home directory that contains the password for the # postgres user. For example: # # /root/.pgpass (chmod 0600) # *:*:*:postgres:thepassword # # This script simply needs to dump a file into the current working directory. # rsnapshot handles everything else. ############################################################################## # $Id: backup_pgsql.sh,v 1.6 2007/03/22 02:50:21 drhyde Exp $ umask 0077 # backup the database /usr/local/pgsql/bin/pg_dumpall -Upostgres > pg_dumpall.sql # make the backup readable only by root /bin/chmod 600 pg_dumpall.sql rsnapshot-1.3.1/utils/backup_rsnapshot_cvsroot.sh0000755000000000000000000000160310223445643022322 0ustar rootroot00000000000000#!/bin/sh ############################################################################## # backup_rsnapshot_cvsroot.sh # # by Nathan Rosenquist # http://www.rsnapshot.org/ # # This is a simple shell script to backup the CVS tar/bz file from # SourceForge. # # The assumption is that this will be invoked from rsnapshot. Also, since it # will run unattended, the user that runs rsnapshot (probably root) should have # a .pgpass file in their home directory that contains the password for the # postgres user. # # This script simply needs to dump a file into the current working directory. # rsnapshot handles everything else. ############################################################################## # $Id: backup_rsnapshot_cvsroot.sh,v 1.3 2005/04/02 07:37:07 scubaninja Exp $ /usr/bin/wget http://cvs.sourceforge.net/cvstarballs/rsnapshot-cvsroot.tar.bz2 2>/dev/null rsnapshot-1.3.1/utils/backup_smb_share.sh0000755000000000000000000000306010223445643020464 0ustar rootroot00000000000000#!/bin/sh ############################################################################## # backup_smb_share.sh # # by Nathan Rosenquist # http://www.rsnapshot.org/ # # This is a simple shell script to backup an SMB share with rsnapshot. # # The assumption is that this will be invoked from rsnapshot. Also, for # security reasons, the authfile should be stored in a place where it is not # accessible by anyone other than the user running rsnapshot (probably root). # # This script simply needs to dump the contents of the SMB share into the # current working directory. rsnapshot handles everything else. # # Please note that because of cross-platform issues, the files archived will # be owned by the user running rsnapshot to make the backup, not by the # original owner of the files. Also, any ACL permissions that may have been # on the Windows machine will be lost. However, the data in the files will # be archived safely. ############################################################################## # $Id: backup_smb_share.sh,v 1.6 2005/04/02 07:37:07 scubaninja Exp $ # IP or hostname to backup over SMB SERVER=192.168.1.10 # The name of the share SHARE=home # The authfile is a file that contains the username and password to connect # with. man smbclient(1) for details on how this works. It's much more secure # than specifying the password on the command line directly. AUTHFILE=/path/to/authfile # connect to the SMB share using the authfile /usr/local/samba/bin/smbclient //${SERVER}/${SHARE} -A ${AUTHFILE} -Tc - 2>/dev/null | tar xf - rsnapshot-1.3.1/utils/debug_moving_files.sh0000755000000000000000000000231410223445643021024 0ustar rootroot00000000000000#!/bin/sh ############################################################################## # debug_moving_files.sh # # by Nathan Rosenquist # http://www.rsnapshot.org/ # # This is an abusive shell script designed to simulate users moving files # while a backup is occuring. Hopefully your users aren't this evil. # # The general idea is that you create an "abuse" directory, include it in your # backup points, run this script in one terminal window and rsnapshot in the # other. # # Most people will probably never need to use this unless they want to debug # "vanishing file" problems with rsync. ############################################################################## # $Id: debug_moving_files.sh,v 1.3 2005/04/02 07:37:07 scubaninja Exp $ # change this path to your liking DIRECTORY=/path/to/abuse/dir/ # be sure and create it or the script won't work cd $DIRECTORY || exit 1; # ready touch 0 1 2 3 4 5 6 7 8 9 rm *.tmp 2>/dev/null # set echo "STARTING ABUSE NOW..." # go while true; do # move them for i in `echo 0 1 2 3 4 5 6 7 8 9`; do echo mv $i $i.tmp mv $i $i.tmp done # move them back for i in `echo 0 1 2 3 4 5 6 7 8 9`; do echo mv $i.tmp $i mv $i.tmp $i done done rsnapshot-1.3.1/utils/make_cvs_snapshot.sh0000755000000000000000000000145710254703535020714 0ustar rootroot00000000000000#!/bin/sh ############################################################################## # make_cvs_snapshot.sh # # by Nathan Rosenquist # http://www.rsnapshot.org/ # # this script just does a find/replace in the source tree to change # the version number to CVS-$DATE # # this was done before manually, now it's automatic ############################################################################## # $Id: make_cvs_snapshot.sh,v 1.6 2005/06/18 02:30:53 scubaninja Exp $ if [ $PWD = "$HOME/projects/rsnapshot/rsnapshot" ]; then echo "This is not where you want to be. cp -r to a different directory first!" echo "Quitting now!" exit 1 fi VERSION=`./rsnapshot-program.pl version-only | sed s/\\\./\\\\\\\./g` DATE=`date +"%Y%m%d"` perl -pi -e s/$VERSION/CVS-$DATE/g `find . -type f` rsnapshot-1.3.1/utils/mkmakefile.sh0000755000000000000000000000123610516352557017312 0ustar rootroot00000000000000#! /bin/sh -xe # This mini script is to generate the Makefile for building rsnapshot. # # Usage: mkmakefile.sh [options to pass to ./configure] # # Example: mkmakefile.sh # Example: mkmakefile.sh --sysconfdir=/etc # # You can just re-run ./configure after running mkmakefile.sh to change the # options to ./configure. # # Inputs: Makefile.am configure.ac # Outputs: Makefile Makefile.in configure aclocal.m4 # # This script is executed with the sh -e flag, so that an error from # executing any command will cause the shell script to abort immediately. # trap "echo Previous command had error, mkmakefile.sh aborting." ERR # aclocal autoconf automake ./configure "$@" rsnapshot-1.3.1/utils/random_file_verify.sh0000755000000000000000000000407210270775653021054 0ustar rootroot00000000000000#!/bin/bash ############################################################################## # random_file_verify.sh # # by Sherman Boyd # http://www.rsnapshot.org/ # # This script generates a random test file to be backed up and # then tests it after the backup. It's a paranoid sanity check, I # suppose. The script then emails the results of the backup and check # to the admin. # # As it is currently implemented, it is a wrapper around an "rsnapshot daily" # command. It could probably be broken out into seperate preexec annd # postexec commands as well. # # Feel free to use and improve ... # ############################################################################## #Initialize echo "Started backup script on `date`"> /var/log/localbackup.log msubject="Local Backup SUCCESSFUL!" #Create random 100 byte file echo "Generating random test file.">> /var/log/localbackup.log dd if=/dev/urandom of=/path/to/files/you/are/backing/up/randomtestfile bs=1 count=100 if [ $? -eq 0 ] then echo "SUCCESS: Randomly generated test file created." >> /var/log/localbackup.log else echo "FAILED: Randomly generated test file not created." >> /var/log/localbackup.log msubject="Local Backup has ERRORS!" fi #Run Backup echo "Running rsnapshot backup.">> /var/log/localbackup.log rsnapshot daily if [ $? -eq 0 ] then echo "SUCCESS: Backup completed with no errors." >> /var/log/localbackup.log else echo "FAILED: Backup completed with some errors." >> /var/log/localbackup.log msubject="Local Backup has ERRORS!" fi #Test Random File echo "Comparing random file with the backup.">> /var/log/localbackup.log diff /path/to/files/you/are/backing/up/randomtestfile /path/to/your/rsnapshots/daily.0/localhost/randomtestfile > /dev/null if [ $? -eq 0 ] then echo "PASSED: Randomly generated test file is the same." >> /var/log/localbackup.log else echo "FAILED: Randomly generated test file differs." >> /var/log/localbackup.log msubject="Local Backup has ERRORS!" fi #Mail results mail -s "$msubject" your@email.com < /var/log/localbackup.log exit 0 rsnapshot-1.3.1/utils/rsnapshot_if_mounted.sh0000755000000000000000000000346510223445643021437 0ustar rootroot00000000000000#!/bin/sh ############################################################################## # rsnapshot_if_mounted.sh # # by Nathan Rosenquist # http://www.rsnapshot.org/ # ############################################################################## ############################################################################## ############################################################################## # # NOTE: THIS SCRIPT HAS BEEN SUPERCEDED BY THE "no_create_root" OPTION IN # rsnapshot. IT IS LEFT HERE JUST IN CASE ANYONE WANTS TO USE IT. # ############################################################################## ############################################################################## ############################################################################## # # This is a simple shell script to run rsnapshot only if the backup drive # is mounted. It is intended to be used when backups are made to removable # devices (such as FireWire drives). # # Usage: /path/to/rsnapshot_if_mounted.sh [options] interval # # Edit this script so it points to your rsnapshot program and snapshot root. # Then simply call this script instead of rsnapshot. # # Example: /usr/local/bin/rsnapshot_if_mounted.sh -v daily ############################################################################## # $Id: rsnapshot_if_mounted.sh,v 1.4 2005/04/02 07:37:07 scubaninja Exp $ # path to rsnapshot RSNAPSHOT=/usr/local/bin/rsnapshot # snapshot_root SNAPSHOT_ROOT=/.snapshots/; # external programs LS=/bin/ls HEAD=/usr/bin/head # check to see if the drive is mounted IS_MOUNTED=`$LS $SNAPSHOT_ROOT/ | $HEAD -1` > /dev/null 2>&1; # if the drive is mounted, run rsnapshot # otherwise refuse to run if [ $IS_MOUNTED ]; then $RSNAPSHOT $@ else echo "$SNAPSHOT_ROOT is not mounted, rsnapshot will not be run" fi rsnapshot-1.3.1/utils/rsnapshot_invert.sh0000755000000000000000000000174010607461656020617 0ustar rootroot00000000000000#!/bin/bash # $Id: rsnapshot_invert.sh,v 1.1 2007/04/12 16:51:58 drhyde Exp $ # This script takes one parameter, which should be your rsnapshot config # file. It will parse that file to find your snapshot_root, backup points, # and interval/retain values, and will create from those an inverted # directory structure of backup points containing daily.{0,1,2,3} etc # symlinks. Run it from a cron job to keep that structure up to date. # # There is minimal^Wno error checking, and the parsing is totally brain- # dead. SNAPSHOT_ROOT=`grep ^snapshot_root $1|awk '{print \$2}'` BACKUPS=`grep ^backup $1|awk '{print \$3}'` INTERVALS=`grep -E '^(interval|retain)' $1|awk '{print \$2}'` cd $SNAPSHOT_ROOT for i in $BACKUPS; do mkdir $i for j in $INTERVALS; do HOWMANY=`grep -E ^\(interval\|retain\).$j $1|awk '{print \$3}'` COUNT=0 while [[ $COUNT != $HOWMANY ]]; do ln -s $SNAPSHOT_ROOT/$j.$COUNT/$i $SNAPSHOT_ROOT/$i/$j.$COUNT COUNT=$(($COUNT + 1)) done done done rsnapshot-1.3.1/utils/sign_packages.sh0000755000000000000000000000146610434510430017771 0ustar rootroot00000000000000#!/bin/sh ############################################################################## # sign_packages.sh # # by Nathan Rosenquist # http://www.rsnapshot.org/ # # This is the script used to semi-automatically GPG sign rsnapshot releases ############################################################################## # $Id: sign_packages.sh,v 1.3 2005/04/02 07:37:07 scubaninja Exp $ for file in `/bin/ls *.tar.gz *.deb *.rpm | grep -v latest`; do # MD5 if [ ! -e "$file.md5" ]; then md5sum $file > $file.md5; echo "Created MD5 Hash for $file"; fi # SHA1 if [ ! -e "$file.sha1" ]; then sha1sum $file > $file.sha1; echo "Created SHA1 hash for $file"; fi # PGP if [ ! -e "$file.asc" ]; then gpg --armor --detach-sign $file; echo "Created PGP Signature for $file"; fi done rsnapshot-1.3.1/utils/mysqlbackup.pl0000644000000000000000000000546111056476666017552 0ustar rootroot00000000000000#!/usr/bin/perl =head1 Author: Anthony Ettinger License: GPL 2.0 URL: http://www.gnu.org/licenses/gpl.txt Notes: This script was originally written to function as a MySQL database backup script in conjunction with the open source Perl/rsync backup program "rsnapshot". rsnapshot can be found here: http://www.rsnapshot.org/ In order to backup a MySQL database remotely, the necessary database user must be able to connect remotely to the database server from your IP number (some ISPs only allow access from localhost - you may need to email your admin and ask for your ip to be given access) It is extremely important that you secure the /etc/mysqlbackup file so only YOU can read the file, 'chmod 0600 /etc/mysqlbackup', as it will store the database passwords in plain text format. =cut use warnings; use strict; use Data::Dumper; use DBI; use POSIX qw(strftime); ## WARNING: type 'chmod 0600 /etc/mysqlbackup' ## #file must contain 'username:password:host' #one entry per line. Functionality is similar to /etc/passwd, #however passwords are stored in plain text and NOT encrypted my $mysqlbackup_passwd = '/etc/mysqlbackup'; #location of 'mysqldump' program (required) my $mysqldump = '/usr/bin/mysqldump'; main(); sub main { #check mode of $mysqlbackup_passwd file my ($mode) = (stat($mysqlbackup_passwd))[2]; $mode = sprintf "%04o", $mode & 07777; unless (-o $mysqlbackup_passwd && $mode eq '0600') { die "Please secure '$mysqlbackup_passwd' file. Type 'chmod 0600 $mysqlbackup_passwd'.\n"; } #read in passwords from file read_passwd(); } sub read_passwd { open(PASSWD, $mysqlbackup_passwd) or die "$!"; while() { chomp; my ($user, $pass, $host) = split(/:/); #retrieve databases with this user's privileges show_databases($user, $pass, $host); } close(PASSWD); } sub show_databases { my ($user, $pass, $host) = @_; my $db_list = []; #arrayref to store list of databases my $dbh = DBI->connect("dbi:mysql:host=$host", $user, $pass) or die DBI->errstr; #execute show databases query my $sth = $dbh->prepare("SHOW DATABASES") or die $dbh->errstr; $sth->execute() or die $dbh->errstr; #fetch results from query while (my $db_row = $sth->fetch) { push(@{$db_list}, $db_row->[0]); } dump_databases($db_list, $user, $pass, $host); } sub dump_databases { my ($db_list, $user, $pass, $host) = @_; my $timestamp = strftime "%F-%H.%M", localtime; foreach my $db (@{$db_list}) { my $filename = "$host-$db-$timestamp"; my $dump_cmd = "$mysqldump -u $user -p$pass -h $host --opt $db > $filename.sql"; my $tar_cmd = "tar czf $filename.tar.gz $filename.sql"; my $rm_cmd = "rm $filename.sql"; #print "Backing up $db from $host\n"; system($dump_cmd) == 0 or die "$!"; system($tar_cmd) == 0 or die "$!"; system($rm_cmd) == 0 or die "$!"; #tar czf $db.$DATE.tar.gz $FILE } } rsnapshot-1.3.1/utils/rsnapreport.pl0000644000000000000000000001026611005052310017537 0ustar rootroot00000000000000#!/usr/bin/env perl # this script prints a pretty report from rsnapshot output # in the rsnapshot.conf you must set # verbose >= 3 # and add --stats to rsync_long_args # then setup crontab 'rsnapshot daily 2>&1 | rsnapreport.pl | mail -s"SUBJECT" backupadm@adm.com # don't forget the 2>&1 or your errors will be lost to stderr ################################ ## Copyright 2006 William Bear ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ################################ use strict; use warnings; use English '-no_match_vars'; my $bufsz = 2; my %bkdata=(); my @errors=(); sub pretty_print(){ my $ofh = select(STDOUT); $FORMAT_NAME="BREPORTBODY"; $FORMAT_TOP_NAME="BREPORTHEAD"; select($ofh); foreach my $source (sort keys %bkdata){ if($bkdata{$source} =~ /error/i) { print "ERROR $source $bkdata{$source}"; next; } my $files = $bkdata{$source}{'files'}; my $filest = $bkdata{$source}{'files_tran'}; my $filelistgentime = $bkdata{$source}{'file_list_gen_time'}; my $filelistxfertime = $bkdata{$source}{'file_list_trans_time'}; my $bytes= $bkdata{$source}{'file_size'}/1000000; # convert to MB my $bytest= $bkdata{$source}{'file_tran_size'}/1000000; # convert to MB $source =~ s/^[^\@]+\@//; # remove username format BREPORTHEAD = SOURCE TOTAL FILES FILES TRANS TOTAL MB MB TRANS LIST GEN TIME FILE XFER TIME -------------------------------------------------------------------------------------------------------------------- . format BREPORTBODY = @<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>>>>>>>>>> @>>>>>>>>>> @#########.## @########.## @>>>>>>>>>>>> @>>>>>>>>>>>>> $source, $files, $filest, $bytes, $bytest, $filelistgentime, $filelistxfertime . write STDOUT; } } sub nextLine($){ my($lines) = @_; my $line = <>; push(@$lines,$line); return shift @$lines; } my @rsnapout = (); # load readahead buffer for(my $i=0; $i < $bufsz; $i++){ $rsnapout[$i] = <>; } while (my $line = nextLine(\@rsnapout)){ if($line =~ /^[\/\w]+\/rsync/) { # find start rsync command line my @rsynccmd=(); while($line =~ /\s+\\$/){ # combine wrapped lines $line =~ s/\\$//g; $line .= nextLine(\@rsnapout); } push(@rsynccmd,split(/\s+/,$line)); # split into command components my $source = $rsynccmd[-2]; # count backwards: source always second to last #print $source; while($line = nextLine(\@rsnapout)){ # this means we are missing stats info if($line =~ /^[\/\w]+\/rsync/){ unshift(@rsnapout,$line); push(@errors,"$source NO STATS DATA"); last; } # stat record if($line =~ /^total size is\s+\d+/){ last; } # this ends the rsync stats record elsif($line =~ /Number of files:\s+(\d+)/){ $bkdata{$source}{'files'}=$1; } elsif($line =~ /Number of files transferred:\s+(\d+)/){ $bkdata{$source}{'files_tran'}=$1; } elsif($line =~ /Total file size:\s+(\d+)/){ $bkdata{$source}{'file_size'}=$1; } elsif($line =~ /Total transferred file size:\s+(\d+)/){ $bkdata{$source}{'file_tran_size'}=$1; } elsif($line =~ /File list generation time:\s+(.+)/){ $bkdata{$source}{'file_list_gen_time'}=$1; } elsif($line =~ /File list transfer time:\s+(.+)/){ $bkdata{$source}{'file_list_trans_time'}=$1; } elsif($line =~ /^(rsync error|ERROR): /){ push(@errors,"$source $line"); } # we encountered an rsync error } } elsif($line =~ /^(rsync error|ERROR): /){ push(@errors,$line); } # we encountered an rsync error } pretty_print(); if(scalar @errors > 0){ print "\nERRORS\n"; print join("\n",@errors); print "\n"; } rsnapshot-1.3.1/utils/README0000644000000000000000000000744311005052310015506 0ustar rootroot00000000000000The scripts in this folder are mostly quick and dirty examples of things that you may or may not find useful in conjunction with rsnapshot. rsnapshot-copy ------------------------------------------------------------------------------ rsnapshot-copy copies an rsnapshot snapshot root, preserving the intersnapshot hard links for unchanged files. You can use this if you want to copy/move your snapshot root to another place but find that rsync -aH on the lot is too slow (uses too much RAM). It copies intervals in chronological order using rsync --link-dest. rsnaptar ------------------------------------------------------------------------------ A script that can automatically tar up your latest snapshots and send you an e-mail when it's done. You may need to edit some of the variables by hand. backup_dpkg.sh ------------------------------------------------------------------------------ An example script to backup package info on a Debian system, to be invoked from rsnapshot using the "backup_script" parameter. If you have a Debian system, this will most likely work without changes. backup_mysql.sh ------------------------------------------------------------------------------ An example script to backup a MySQL database, to be invoked from rsnapshot using the "backup_script" parameter. You will probably need to modify this for your setup. backup_pgsql.sh ------------------------------------------------------------------------------ An example script to backup a PostgreSQL database, to be invoked from rsnapshot using the "backup_script" parameter. You will probably need to modify this for your setup. backup_rsnapshot_cvsroot.sh ------------------------------------------------------------------------------ An example script to backup the CVS repository for the rsnapshot project, which is hosted on SourceForge. This script is a good example of using the wget program to archive web content in your backups. This script is designed to be invoked from rsnapshot using the "backup_script" parameter. backup_smb_share.sh ------------------------------------------------------------------------------ An example script to backup a Microsoft SMB share, to be invoked from rsnapshot using the "backup_script" parameter. This requires the Samba program. You will definitely need to modify this for your system. debug_moving_files.sh ------------------------------------------------------------------------------ Debug script for rsync. Moves files around, so you can try backing them up to see what rsnapshot does. Only useful if you're having problems with vanishing files and want to have a known source of them. make_cvs_snapshot.sh ------------------------------------------------------------------------------ Quick and dirty shell script to find/replace "real" version numbers with a CVS-date version. ./rsnapshotdb ------------------------------------------------------------------------------ Directory containing rsnapshotDB.pl, a perl script with an XML configuration file for remote database backups. Please see ./rsnapshotdb/README.txt. rsnapshot_if_mounted.sh ------------------------------------------------------------------------------ Deprecated. A work-around for using removable drives as the snapshot root. Superceded by the "no_create_root" option in rsnapshot proper. rsnapreport.pl ------------------------------------------------------------------------------ This script just takes the output of rsnapshot using the rsync --stats option, and generates a pretty report, and tries to include errors at the bottom. sign_packages.sh ------------------------------------------------------------------------------ The shell script used to automate package signing for releases. rsnapshot-1.3.1/utils/rsnaptar0000755000000000000000000000374111005052310016403 0ustar rootroot00000000000000#!/bin/sh ############################################################################## # rsnaptar # by Nathan Rosenquist # # A quick hack of a shell script to tar up backup points from the rsnapshot # snapshot root. Sends an e-mail to an address specified on the command line # when finished. # # I set this up in cron to run once a week, take the tar files, # and make DVD-RW backups of the latest snapshot. Your mileage may vary. # # http://www.rsnapshot.org/ ############################################################################## # $Id: rsnaptar,v 1.11 2007/03/22 02:50:21 drhyde Exp $ umask 0077 # DIRECTORIES TAR_DIR="/var/dvd_backup" SNAPSHOT_DIR="/backup/private/snapshots/daily.0" # SHELL COMMANDS LS="/bin/ls" TAR="/bin/tar" CAT="/bin/cat" CHMOD="/bin/chmod" CHOWN="/bin/chown" MKDIR="/bin/mkdir" SENDMAIL="/usr/lib/sendmail -t -oi" HOSTNAME=`/bin/hostname` DATE=`/bin/date +%Y-%m-%d` # uncomment this to gpg encrypt files # the e-mail address the notification is being sent to must have their GPG key # in the public keyring of the user running this backup # GPG="/usr/bin/gpg" # GET E-MAIL ADDRESS if [ ! $1 ]; then echo "Usage: rsnaptar user@domain.com" exit 1 else TO_EMAIL=$1 fi # MAKE ONE TAR FILE FOR EACH BACKUP POINT ${MKDIR} -p ${TAR_DIR}/${DATE}/ cd ${SNAPSHOT_DIR} for BACKUP_POINT in `${LS} ${SNAPSHOT_DIR}`; do # GPG encrypt backups if $GPG is defined if test ${GPG}; then ${TAR} --numeric-owner -cf - ${BACKUP_POINT}/ | \ $GPG --encrypt -r $TO_EMAIL > ${TAR_DIR}/${DATE}/${BACKUP_POINT}.tar.gpg # just create regular tar files else ${TAR} -czf ${TAR_DIR}/${DATE}/${BACKUP_POINT}.tar.gz ${BACKUP_POINT}/ fi done cd - # there are probably sensitive files here, so use the strictest permissions ${CHMOD} -R 0600 ${TAR_DIR}/${DATE}/* ${CHMOD} 0700 ${TAR_DIR}/${DATE}/ ${CAT} <&2 Usage: rsnapshot-copy [--test] RSYNC-OPTION... SRC-SNAPSHOT-ROOT DEST-SNAPSHOT-ROOT rsnapshot-copy copies an rsnapshot snapshot root, preserving the intersnapshot hard links for unchanged files. It does so by copying one snapshot at a time with rsync, each time giving a --link-dest option for the previous snapshot. This technique uses less memory than others (such as plain rsync -H) that hold a list of all the files in the snapshot root in memory in order to preserve arbitrary hard links. As with an ordinary rsync command, either the source or the destination can be remote, but not both. The destination should be empty or nonexistent; rsnapshot-copy currently is not designed for incremental mirroring of a snapshot root (though an incremental mode may be added in the future). Each snapshot is copied using `rsync RSYNC-OPTION...', so you should probably pass -a and any other relevant rsync options used by your ordinary rsnapshot runs, such as --numeric-ids. --test: show the shell commands to be executed instead of executing them Written and maintained by Matt McCutchen . EOM } # To support remote src or dest, we must perform all filesystem access via rsync. set -e trap 'echo "Command failed!: $BASH_COMMAND" >&2' ERR set -o errtrace set -o pipefail testmode= if [ "$1" = "--test" ]; then testmode=1 shift fi # Test or execute a command as appropriate. function do_cmd { if [ $testmode ]; then (set -x; : "$@") else "$@" fi } if [ $# -lt 3 ]; then usage exit 1 fi rsync_opts=("${@:1:$#-2}") src="${@: -2:1}" dest="${@: -1:1}" # Ensure that the destination dir exists. (--exclude=* excludes everything else.) do_cmd rsync "${rsync_opts[@]}" --exclude=* "$src/" "$dest/" # Obtain a list of snapshot names in newest to oldest order. # List the src -> filter to `2008/04/09T17:59:43 hourly.0' format # -> sort newest to oldest -> read each line, ignoring the time. rsync "${rsync_opts[@]}" --list-only --no-r -d --no-l "$src/" \ | sed -nre 's,^d[^ ]+ +[^ ]+ (..../../..) (..:..:..) (.*\.[0-9]+)$,\1T\2 \3,p' \ | LC_ALL=C sort -r --key=1,1 | { # --link-dest option to use, if any ldo=() # Copy each snapshot while read st sn; do do_cmd rsync "${rsync_opts[@]}" "${ldo[@]}" "$src/$sn/" "$dest/$sn/" # The next snapshot should link from this one. ldo=(--link-dest="../$sn/") done } rsnapshot-1.3.1/utils/rsnapshotdb/0000755000000000000000000000000011056477673017202 5ustar rootroot00000000000000rsnapshot-1.3.1/utils/rsnapshotdb/CHANGES.txt0000644000000000000000000000155411005052310020763 0ustar rootroot0000000000000010/22/06 Removed requirement that a database password be present in rsnapshotDB.conf xml file. 8/16/06 Changed permission of log file /var/log/rsnapshotDB to 0600. When passwords are used to access the database, they are shown in the log file when verbosity is enabled. 1/22/06 Cleaned up code and removed password requirement for ssh server connection. Removed requirement of Net::SSH::Perl Speed optimization done with remote database dump and gzip compression before transfering file locally. 1/4/05 Switched to XML-based configuration file, and requirement of Net::SSH::Perl for more sophisticated ssh handling of database backups. Speed issue of remote database dumps should be slightly if not vastly more optimized in this release. Database tables were locking during a remote backup, which took down the web site temporarily ( ~ 30 mins on one forum I own). rsnapshot-1.3.1/utils/rsnapshotdb/INSTALL.txt0000644000000000000000000000342011056476666021051 0ustar rootroot00000000000000rsnapshotDB has a few necessary requirements pre-install, as follows Pre-install Requirements: 1) Perl v. 5.8.7+ 2) SSH with ssh-keygen 3) Unix commands: scp, rm, gzip, mysqldump/pg_dump, nice These need to be inplace on both the remote and/or local server. If using XML conf, then definitely on both servers for scp, rm, gzip, and 'nice'. The "dumper" programs can be only on the remote server since rsnapshotDB version: 1.2. 5) ssh-keygen public key on remote server Ideally, you would automate easily by having public/private ssh keys on your servers. See ~/.ssh and 'man ssh-keygen'. 6) local access to database server This would also negate the need of storing vital (ie - "password") info in the XML config file. Note: This hasn't been thoroughly tested yet! Please report any bugs to mailto:rsnapshot-discuss-request@lists.sf.net?subject=subscribe http://www.rsnapshot.org 7) Copy rsnapshotDB.conf.sample to /etc/rsnapshotDB.conf BASIC INSTALL: Place the rsnapshotDB.conf and rsnapshotDB.xsd in a safe location (typicall /etc/) then type $ chmod 600 rsnapshotDB.* Copy rsnapshotDB.pl into a good location, something like: /usr/local/bin/rsnapshotDB.pl Then call it from the rsnapshot.conf file as: backup_script /usr/local/bin/rsnapshotDB.pl database/ SECURITY: The best option is to use ssh keys and network-authenticated database users. ie (only connect from localhost or 192.168.x.x -> db server without password). This avoids having to store your db passwords in /etc/rsnapshotDB.conf NOTE: If you have not logged in via ssh and keys before, you will have to do so manually as the rsnapshot user (typically root). This is necessary in order to accept the host as an authorized host. Once you say "yes" to accepting the key/host, you should be able to login automatically. rsnapshot-1.3.1/utils/rsnapshotdb/LICENSE.txt0000644000000000000000000004313310360335625021014 0ustar rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. rsnapshot-1.3.1/utils/rsnapshotdb/README.txt0000644000000000000000000000066211056476666020705 0ustar rootroot00000000000000See LICENSE.txt for licensing information See INSTALL.txt for installation instructions See TODO.txt for more to come For latest documentation type: $ perldoc rsnapshotDB.pl or $ perldoc rsnapshotDB or $ perldoc /path/to/rsnapshotDB.pl Trouble Shooting: mailing list: rsnapshot-request@lists.sf.net subject: "subscribe" Other Info: Author: Anthony Ettinger Email: aettinger<-rm-@-spam->sdsualumni.org Blog: http://www.chovy.com rsnapshot-1.3.1/utils/rsnapshotdb/TODO.txt0000644000000000000000000000161211005052310020453 0ustar rootroot00000000000000TODO LIST: - as suggested by r00t in #bash, add option to split on tables instead of db. ie: ./hostname/database/table.tar.gz - enable split | gzip to get in under isp radar (cpu resource limits with I/O on large db's). - thoroughly test with postgresql, mysql on Linux only testing so far. 10/22/06 DONE - remove requirement for database password to be present in xml config file. 8/16/06 DONE - changed log file to 0600 permissions 1/22/06 DONE - Thoroughly test rewrite using ssh keys and tunneling. DONE - Optimize code efficiency, main reason I'm throwing this out on the web as GPL :-) - Decide whether to stop, or continue on errors/connectivity issues. Possibly throw an email/SMS at someone. Problem because assumption is that you're db's are being archived without error. DONE - remove support for unencrypted SSH passwords in rsnapshotDB.conf, should be supported with ssh keys instead. rsnapshot-1.3.1/utils/rsnapshotdb/rsnapshotDB.conf.sample0000644000000000000000000000336011056476666023563 0ustar rootroot00000000000000 mysql db.example.com user pass ssh2 foo.example.net admin StronglyEncryptedHash mysql db.example.org user2 #F0oB4r! mysql db.example.com me plain-text-password ssh2 www.example.com user optional rsnapshot-1.3.1/utils/rsnapshotdb/rsnapshotDB.pl0000755000000000000000000003422511056476666022000 0ustar rootroot00000000000000#!/usr/bin/perl =pod =head1 NAME: rsnapshotDB Web: http://www.rsnapshot.org Bugs: rsnapshot-discuss@lists.sf.net License: GPL http://www.gnu.org/licenses/gpl.txt Version: 1.2.1 =head1 AUTHOR: Anthony Ettinger Email: aettinger<--at-->sdsualumni<--dot-->org Blog: http://anthony.ettinger.name =head1 DESCRIPTION: This script was originally written to function as a MySQL database backup script in conjunction with the open source Perl/rsync backup program "rsnapshot". rsnapshot can be found at: http://www.rsnapshot.org/ In order to backup a database remotely, the necessary database user must be able to connect remotely to the database server from a trusted secure shell server. (some ISPs only allow access from an internal network - you may need to make sure you do have internal access from an internal ssh server to the database server). IF YOU DON'T HAVE SSH KEYS, this program isn't for you. (see:man ssh-keygen). It is extremely important that you secure the /etc/rsnapshotDB.conf file so only YOU (the user who's cronjob this is running from) can read the file, 'chmod 0600 /etc/rsnapshotDB.conf', as it will store the database passwords in plain text format. If you don't know who YOU are - type 'whoami' or ask a friend. For best results, configure and run this script from /etc/rsnapshot.conf. (see:'man rsnapshot', backup_script). =head2 SEE ALSO: INSTALL.txt, TODO.txt, CHANGES.txt =cut use warnings; use strict; use Cwd 'cwd'; use Data::Dumper; use DBI; use POSIX qw(strftime); =head3 WARNING: type 'chmod 0600 /etc/rsnapshotDB.conf' Currently 'dbtype' supported can be either 'mysql' or 'pgsql' Functionality is similar to /etc/DBPASSWD, however passwords are stored in plain text and NOT encrypted are allowed in the following file: Note: rsnapshotdb.list is deprecated in favor of XML config rsnapshotDB.conf and rsnapshotDB.xsd =cut my $dbpasswd = '/etc/rsnapshotDB.conf'; my $xsd = '/etc/rsnapshotDB.xsd'; #used to validate config file my $xmlUsage = 1; #0 if using flat-list configuation file (deprecated). my $verbose = 2; #0 for no warning/status messages, increase for more. =head2 WARNING: Setting the "temporary" directory: 1) the db dump might get left behind on error 2) the temp directory could fill up, depending on size of db and quota of user or directory =cut my $tmpDir = '$HOME/tmp'; #may want to change this^ my $niceness = '19'; #amount of CPU/Mem -20 high, 19 low priority. my $sshOption = '-o TCPKeepAlive=yes'; #keep ssh alive (avoid timeouts) =head2 DUMPERS: Location of "dumper" program(s) type 'which ' to find the path (ie - 'which mysqldump') Note: the hash key here must match 'dbtype' field in $dbpasswd file. =cut my $dbApp = { 'mysql' => { 'dumper' => { bin => 'mysqldump', opts => '--opt -C', user => '-u', pass => '-p', host => '-h', }, 'prompt' => { bin => 'mysql', opts => '-s', user => '-u', pass => '-p', host => '-h', }, }, 'pgsql' => { 'dumper' => { bin => 'pg_dump', opts => '', user => '-U', pass => '-p', host => '-h', }, 'prompt' => { bin => 'pgsql', opts => '', user => '-U', pass => '-p', host => '-h', }, }, }; init(); sub init { #check mode of $dbpasswd file my ($mode_dbpasswd) = (stat($dbpasswd))[2]; $mode_dbpasswd = sprintf "%04o", $mode_dbpasswd & 07777; my $localTmpDir = cwd(); unless (-o $dbpasswd && $mode_dbpasswd eq '0600') { die "Please secure '$dbpasswd' file. Type 'chmod 0600 $dbpasswd'.\n"; } unless ($xmlUsage && -f $xsd) { warn "You are not validating '$dbpasswd' against an XMLSchema file: '$xsd'. Defaulting to flat file format for '$dbpasswd'.\n"; } #read in passwords from file read_dbpasswd(); } sub read_dbpasswd { if ($xmlUsage) { my $xobj = rsnapshotDB->new( { 'dbpasswd' => $dbpasswd, 'xsd' => $xsd, 'dbApp' => $dbApp, 'tmpDir' => $tmpDir, 'verbose' => $verbose, } ); my $validity = $xobj->validateXML; #boolean test if ($validity) { #main module dump routine called within my $status = $xobj->parseXML(); } } else { die "flat list is deprecated, please see INSTALL.txt"; } } =pod =head1 END OF THE LINE: If you've gotten this far with no "die" errors, you should be good to go with XML config rsnapshotDB.conf vs. flat list rsnapshotdb.list Check the $localTmpDir or your /backups/.snapshot/foo/wherever you put your database backups using rsnapshot.conf. =cut package rsnapshotDB; =pod =head1 rsnapshotDB.pm =cut use strict; use Data::Dumper; use Cwd 'cwd'; use POSIX qw(strftime); use XML::Validator::Schema; use XML::Simple; sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = bless( {}, $class ); my $timestamp = localtime; my %data = ref($_[0]) eq 'HASH' ? %{$_[0]} : (@_); $self->_dbpasswd($data{'dbpasswd'}); $self->_xsd($data{'xsd'}); $self->_tmpDir($data{'tmpDir'}); $self->_verbose($data{'verbose'}); $self->_dbApp($data{'dbApp'}); $self->v("\n\nSTART TIME: $timestamp", 0); return $self; } sub validateXML { my $self = shift; my $xml = $self->_dbpasswd; my $xsd = $self->_xsd; my $validator = XML::Validator::Schema->new(file=> $xsd); my $parser = XML::SAX::ParserFactory->parser(Handler => $validator); $self->v("WAITING: validating xml...", 1); eval { $parser->parse_uri($xml) }; die "File failed validation: $@" if $@; $self->v("FINISH: validated '$xml' against '$xsd'.", 1); return $self; } =pod =head1 C Utitility to parse our XML file for values =cut sub parseXML { my $self = shift; #start xml parsing of conf file. my $xml = $self->_dbpasswd(); my $parser = XML::Simple->new(); #hardcoded xml tag names my $xmlRef = $parser->XMLin($xml, ForceArray => ['hostGroup', 'hostPair', 'databaseHost', 'defaultSSHHost'] ); #count hostGroup tags my $hostGroups = scalar(@{$xmlRef->{'hostGroup'}}); #process hostGroups for (my $i=0; $i<$hostGroups; $i++) { $self->v("START: hostGroup...", 1); #save default hostGroup ssh host my $defaultSSHHost = {}; #process hostPairs foreach my $hostPair (@{$xmlRef->{'hostGroup'}->[$i]->{'hostPair'}}) { $self->v("START: hostPair...", 1); #save databaseHost hashref my $databaseHost = $hostPair->{'databaseHost'}; if ( exists($hostPair->{'defaultSSHHost'}[0]->{'hostType'}) ) { #save default and continue to use it $defaultSSHHost = $hostPair->{'defaultSSHHost'}; } $self->showDB($defaultSSHHost, $databaseHost); $self->v("END: hostPair\n", 1); } $self->v("END: hostGroup\n", 1); } return $self; } =pod =head2 LOGIN REMOTELY: This is the section where you authenticate with the remote ssh server. I'm pretty sure, you can just leave off the password flags if you know what you're doing in the XML Config file rsnapshotDB.conf. Requirement: Net::SSH::Perl. If you don't have root, read about how to install a perl module as an under privileged user (it IS possible - /home/username/modules/). =head2 SHOW DATABASES: C<$self-\>showDB();> This should pull down the list of your database user's databases from the XML configuration file. Note: This is done on the remote SSH server with db access. Since we're not writing or reading there isn't a lock on the table. The one restriction here is that you can actually access your database server remotely from an internal ssh server via ssh tunneling. =head2 PATH: Make sure your prompt binary (ie - mysql) and dumper binary (ie - mysqldump) are in your default path for the ssh user. =cut sub showDB { my ($self, $sshHost, $dbHost) = @_; #ssh my $user = $sshHost->[0]->{'username'}; my $host = $sshHost->[0]->{'hostname'}; #db my $dbApp = $self->_dbApp(); my $dbType = $dbHost->[0]->{'dbType'}; my $dbuser = $dbHost->[0]->{'dbusername'}; my $dbpass = $dbHost->[0]->{'dbpassword'}; my $dbhost = $dbHost->[0]->{'dbhostname'}; #add dbApp binaries to you PATH on the server(s) my $dumper = $dbApp->{$dbType}->{'dumper'}->{'bin'}; my $prompt = $dbApp->{$dbType}->{'prompt'}->{'bin'}; my $dbNames = []; #results from SHOW DATABASES; my $dbpass_arg = defined($dbpass) ? "$dbApp->{$dbType}->{'prompt'}->{'pass'}$dbpass" : ''; #dbpass not required $self->v("START: showDB command...", 1); my $cmdShowDB = "ssh $sshOption $user\@$host \"echo -n 'SHOW DATABASES;' | \ $dbApp->{$dbType}->{'prompt'}->{'bin'} \ $dbApp->{$dbType}->{'prompt'}->{'opts'} \ $dbApp->{$dbType}->{'prompt'}->{'user'} $dbuser \ $dbpass_arg \ $dbApp->{$dbType}->{'prompt'}->{'host'} $dbhost\""; my $out = qx/$cmdShowDB/ or warn 'SHOW DATABASES failed...'; $self->v("CMD: $cmdShowDB -> $out.", 2); $self->v("DONE: showDB command.", 1); #fetch results from query push(@{$dbNames}, split(/\n/, $out)); $self->v(Dumper($dbNames), 2); $self->dumbDB($sshHost, $dbHost, $dbNames); return $self; } =pod =head2 DUMP DATABASE: This is the bulk of the app, via ssh tunneling, logs in to an internal ssh server with access to the database server. The main reason for speeding this application up was becauase a remote database pull is extremely inefficient directly over the internet. The idea here is to use ssh-keygen from this account to your remote ssh server, then do the database dump, and secure copy ('man scp') the file back here locally. The gained result here should be seconds vs. minutes. =cut sub dumbDB { my ($self, $sshHost, $dbHost, $dbNames) = @_; my $user = $sshHost->[0]->{'username'}; my $host = $sshHost->[0]->{'hostname'}; #db my $dbApp = $self->_dbApp(); my $dbType = $dbHost->[0]->{'dbType'}; my $dbuser = $dbHost->[0]->{'dbusername'}; my $dbpass = $dbHost->[0]->{'dbpassword'}; my $dbhost = $dbHost->[0]->{'dbhostname'}; #add dbApp binaries to you PATH on the server(s) my $dumper = $dbApp->{$dbType}->{'dumper'}->{'bin'}; my $prompt = $dbApp->{$dbType}->{'prompt'}->{'bin'}; my $tmpDir = $self->_tmpDir(); #remote tmp directory path my $localTmpDir = cwd(); #need by rsnapshot my $cmdRemoteTmpDir = "ssh $sshOption $user\@$host 'echo -n $tmpDir'"; $self->v("CMD: remote tmp dir '$cmdRemoteTmpDir'.", 2); my $remoteTmpDir = qx/$cmdRemoteTmpDir/ or warn "REMOTE TMP DIR failed..."; $self->v("SET: remote temp dir... '$remoteTmpDir'", 1); #dumper arguments my $dumpOptsArg = $dbApp->{$dbType}->{'dumper'}->{'opts'}; my $dumpHostArg = $dbApp->{$dbType}->{'dumper'}->{'host'}; my $dumpUserArg = $dbApp->{$dbType}->{'dumper'}->{'user'}; my $dumpPassArg = $dbApp->{$dbType}->{'dumper'}->{'pass'}; foreach my $dbName (@{$dbNames}) { my $ftimestamp = strftime "%F-%H.%M", localtime; $self->v("FTIMESTAMP: $ftimestamp", 1); my $file = join('--', $dbType, $dbhost, $dbName, $ftimestamp); my $cmdTestRTD = "ssh $sshOption $user\@$host 'test -d $remoteTmpDir'"; $self->v("CMD: $cmdTestRTD.", 2); my $out = qx/$cmdTestRTD/; if ($?) { $self->v("FAIL: $cmdTestRTD, $out.", 0); my $cmdCreateRTD = "ssh $sshOption TCPKeepAlive $user\@$host 'mkdir -m 0700 $remoteTmpDir'"; my $out = qx/$cmdCreateRTD/; $self->v("CMD: $cmdCreateRTD.", 2); $self->v("FAIL: $cmdCreateRTD, $out", 0) if $?; } else { my $cmdChmodRTD = "ssh $sshOption $user\@$host 'chmod 0700 $remoteTmpDir'"; my $out = qx/$cmdChmodRTD/; $self->v("FAIL: $cmdChmodRTD, $out.", 2) if $?; } #the actual .sql.gz remote file creation! my $cmdRemoteDump = "ssh $sshOption $user\@$host 'umask 0077;nice --adjustment=$niceness $dumper \ $dumpOptsArg $dumpUserArg $dbuser $dumpPassArg" . "$dbpass $dumpHostArg $dbhost \ $dbName > $remoteTmpDir/$file.sql'"; $self->v("WAITING: remote dump...", 1); $out = qx/$cmdRemoteDump/; $self->v("FAIL: $cmdRemoteDump, $out.", 0) if $?; $self->v("CMD: $cmdRemoteDump", 2); $self->v("FINISH: remote dump.", 1); my $cmdRemoteGZip = "ssh $sshOption $user\@$host 'nice --adjustment=$niceness gzip --fast $remoteTmpDir/$file.sql'"; $self->v("WAITING: remote gzip...", 1); $self->v("CMD: $cmdRemoteGZip", 2); $out = qx/$cmdRemoteGZip/; $self->v("FAIL: $cmdRemoteGZip, $out.", 0) if $?; $self->v("FINISH: remote gzip.", 1); my $cmdRemoteSCP = "scp $user\@$host:$remoteTmpDir/$file.sql.gz $localTmpDir"; $self->v("WAITING: remote scp...", 1); $self->v("CMD: $cmdRemoteSCP", 2); $out = qx/$cmdRemoteSCP/; $self->v("FAIL: $cmdRemoteSCP, $out.", 0) if $?; $self->v("FINISH: remote scp.", 1); my $cmdRemoteRM = "ssh $sshOption $user\@$host 'nice --adjustment=$niceness rm $remoteTmpDir/$file.sql.gz'"; $self->v("WAITING: remote remove...", 1); $self->v("CMD: $cmdRemoteRM", 2); $out = qx/$cmdRemoteRM/; $self->v("FAIL: $cmdRemoteRM, $out.", 0) if $?; $self->v("FINISH: remote remove.", 1); } } =pod =head2 SECURE COPY: At this point it's necessary to use ssh-keygen to connect to the server, the local command is using SSH tunneling. ARCHIVING: The move from $localTmpDir to '/backups/.snapshot/database' is determined in rsnapshot.conf and backup rsnapshotDB.pl option (see 'man rsnapshot' for script usage). VERBOSITY: Typically, you would first want to test rsnapshotDB with verbosity set to 1 in the rsnapshotdb.pl see:$verbose => 1. You can increase verbosity ie - 2 instead of 1. Typically, this will dump commands that are being execute remotely and/or locally. LOG FILE: /var/log/rsnapshotDB =cut sub v { my ($self, $msg, $level) = @_; open(LOG, ">>/var/log/rsnapshotDB") or warn "$!"; chmod 0600, "/var/log/rsnapshotDB"; if ($self->_verbose >= $level) { print LOG "$msg\n"; } close(LOG); return $self; } #Class::Accessors simulation sub _dbpasswd { my $self = shift; if (@_ == 0) { return $self->{'dbpasswd'}; } $self->{'dbpasswd'} = shift; return $self->{'dbpasswd'}; } sub _binPath { my $self = shift; if (@_ == 0) { return $self->{'binPath'}; } $self->{'_binPath'} = shift; return $self->{'_binPath'}; } sub _xsd { my $self = shift; if (@_ == 0) { return $self->{'xsd'}; } $self->{'xsd'} = shift; return $self->{'xsd'}; } sub _dbApp { my $self = shift; if (@_ == 0) { return $self->{'dbApp'}; } $self->{'dbApp'} = shift; return $self->{'dbApp'}; } sub _tmpDir { my $self = shift; if (@_ == 0) { return $self->{'tmpDir'}; } $self->{'tmpDir'} = shift; return $self->{'tmpDir'}; } sub _verbose { my $self = shift; if (@_ == 0) { return $self->{'verbose'}; } $self->{'verbose'} = shift; return $self->{'verbose'}; } 1; =pod =head1 MORE INFO: see README.txt =cut rsnapshot-1.3.1/utils/rsnapshotdb/rsnapshotDB.xsd0000644000000000000000000000465110360335625022142 0ustar rootroot00000000000000 test valid foo.xml The root node definition Primary use is for segregating hostPair definitions Used for pairing ssh host inside LAN to pull database backup from db server host Default ssh host to connect to in order to pull database backups. defaultSSHHost can be defined once database server from which you are pulling database backups. See defaultSSHHostType for pull location. rsnapshot-1.3.1/t/0000755000000000000000000000000011056477673013756 5ustar rootroot00000000000000rsnapshot-1.3.1/t/support/0000755000000000000000000000000011056477673015472 5ustar rootroot00000000000000rsnapshot-1.3.1/t/support/etc/0000755000000000000000000000000011056477673016245 5ustar rootroot00000000000000rsnapshot-1.3.1/t/support/etc/configtest.conf.in0000644000000000000000000000021710301774603021647 0ustar rootroot00000000000000config_version 1.2 snapshot_root @CWD@/t/support/snapshots/ cmd_rsync @RSYNC@ interval hourly 6 backup @CWD@/t/support/files/a/ localhost/ rsnapshot-1.3.1/t/support/etc/gnu_cp.conf.in0000644000000000000000000000023510301774603020755 0ustar rootroot00000000000000config_version 1.2 snapshot_root @CWD@/t/support/snapshots/ cmd_rsync @RSYNC@ cmd_cp @CP@ interval hourly 6 backup @CWD@/t/support/files/a/ localhost/ rsnapshot-1.3.1/t/support/etc/relative_delete_bugfix.conf.in0000644000000000000000000000021710301773361024203 0ustar rootroot00000000000000config_version 1.2 snapshot_root @CWD@/t/support/snapshots/ cmd_rsync @RSYNC@ interval hourly 6 backup @CWD@/t/support/files/a/ localhost/ rsnapshot-1.3.1/t/support/etc/rsync.conf.in0000644000000000000000000000021710301771423020635 0ustar rootroot00000000000000config_version 1.2 snapshot_root @CWD@/t/support/snapshots/ cmd_rsync @RSYNC@ interval hourly 6 backup @CWD@/t/support/files/a/ localhost/ rsnapshot-1.3.1/t/support/files/0000755000000000000000000000000011056477673016574 5ustar rootroot00000000000000rsnapshot-1.3.1/t/support/files/a/0000755000000000000000000000000011056477673017014 5ustar rootroot00000000000000rsnapshot-1.3.1/t/support/files/b/0000755000000000000000000000000011056477673017015 5ustar rootroot00000000000000rsnapshot-1.3.1/t/support/files/template/0000755000000000000000000000000011056477673020407 5ustar rootroot00000000000000rsnapshot-1.3.1/t/support/files/template/a/0000755000000000000000000000000011056477673020627 5ustar rootroot00000000000000rsnapshot-1.3.1/t/support/files/template/a/10000644000000000000000000000000310271105605020660 0ustar rootroot00000000000000a1 rsnapshot-1.3.1/t/support/files/template/a/20000644000000000000000000000000310271105605020661 0ustar rootroot00000000000000a2 rsnapshot-1.3.1/t/support/files/template/b/0000755000000000000000000000000011056477673020630 5ustar rootroot00000000000000rsnapshot-1.3.1/t/support/snapshots/0000755000000000000000000000000011056477673017514 5ustar rootroot00000000000000rsnapshot-1.3.1/t/configtest.t.in0000644000000000000000000000025210442457756016712 0ustar rootroot00000000000000#!/usr/bin/perl use strict; use Test::More tests => 1; # check for basic configtest ok(! `@PERL@ ./rsnapshot -c t/support/etc/configtest.conf configtest > /dev/null`); rsnapshot-1.3.1/t/gnu_cp.t.in0000644000000000000000000000036410442457756016024 0ustar rootroot00000000000000#!/usr/bin/perl use strict; use Test::More tests => 1; # check for GNU cp my @lines = `@CP@ --help | grep -i 'gnu'`; SKIP: { skip('GNU cp not found', 1) if (@lines == 0); ok(! `@PERL@ ./rsnapshot -c t/support/etc/gnu_cp.conf hourly`); } rsnapshot-1.3.1/t/relative_delete_bugfix.t.in0000644000000000000000000000153610442457756021254 0ustar rootroot00000000000000#!/usr/bin/perl use strict; use Test::More tests => 2; # copy files into place mkdir("t/support/files/a") unless -d "t/support/files/a"; `cp t/support/files/template/a/1 t/support/files/template/a/2 t/support/files/a/`; # run rsnapshot once to copy the files into the snapshot root `@PERL@ ./rsnapshot -c t/support/etc/rsync.conf hourly`; # now remove a file from the source `rm -f t/support/files/a/1`; # run rsnapshot again, it _should_ delete the "1" file `@PERL@ ./rsnapshot -c t/support/etc/relative_delete_bugfix.conf hourly`; my $pwd = `pwd`; chomp($pwd); my $path_to_check = $pwd . '/t/support/snapshots/hourly.0/localhost/' . $pwd . '/t/support/files/a/'; # make sure the file was --deleted ok( ! -e "$path_to_check/1" ); # make sure the other one is still there ok( -e "$path_to_check/2" ); `rm -f t/support/files/a/1 t/support/files/a/2`; rsnapshot-1.3.1/t/rsync.t.in0000644000000000000000000000047110442457756015706 0ustar rootroot00000000000000#!/usr/bin/perl use strict; use Test::More tests => 1; mkdir("t/support/files/a") unless -d "t/support/files/a"; `cp t/support/files/template/a/1 t/support/files/template/a/2 t/support/files/a/`; ok(! `@PERL@ ./rsnapshot -c t/support/etc/rsync.conf hourly`); `rm -f t/support/files/a/1 t/support/files/a/2`;