dirvish-1.2.1/0040775000076400007640000000000010430420233012512 5ustar keithlkeithldirvish-1.2.1/loadconfig.pl0100664000076400007640000001165610205506717015176 0ustar keithlkeithl# Get patch level of loadconfig.pl in case exit codes # are needed. # $Id: loadconfig.pl,v 12.0 2004/02/25 02:42:15 jw Exp $ ######################################################################### # # # Copyright 2002 and $Date: 2004/02/25 02:42:15 $ # Pegasystems Technologies and J.W. Schultz # # # # Licensed under the Open Software License version 2.0 # # # ######################################################################### sub seppuku # Exit with code and message. { my ($status, $message) = @_; chomp $message; if ($message) { $seppuku_prefix and print STDERR $seppuku_prefix, ': '; print STDERR $message, "\n"; } exit $status; } sub slurplist { my ($key, $filename, $Options) = @_; my $f; my $array; $filename =~ m(^/) and $f = $filename; if (!$f && ref($$Options{vault}) ne 'CODE') { $f = join('/', $$Options{Bank}, $$Options{vault}, 'dirvish', $filename); -f $f or $f = undef; } $f or $f = "$CONFDIR/$filename"; open(PATFILE, "<$f") or seppuku 229, "cannot open $filename for $key list"; $array = $$Options{$key}; while() { chomp; length or next; push @{$array}, $_; } close PATFILE; } # loadconfig -- load configuration file # SYNOPSYS # loadconfig($opts, $filename, \%data) # # DESCRIPTION # load and parse a configuration file into the data # hash. If the filename does not contain / it will be # looked for in the vault if defined. If the filename # does not exist but filename.conf does that will # be read. # # OPTIONS # Options are case sensitive, upper case has the # opposite effect of lower case. If conflicting # options are given only the last will have effect. # # f Ignore fields in config file that are # capitalized. # # o Config file is optional, return undef if missing. # # R Do not allow recoursion. # # g Only load from global directory. # # # # LIMITATIONS # Only way to tell whether an option should be a list # or scalar is by the formatting in the config file. # # Options reqiring special handling have to have that # hardcoded in the function. # sub loadconfig { my ($mode, $configfile, $Options) = @_; my $confile = undef; my ($key, $val); my $CONFIG; ref($Options) or $Options = {}; my %modes; my ($conf, $bank, $k); $modes{r} = 1; for $_ (split(//, $mode)) { if (/[A-Z]/) { $_ =~ tr/A-Z/a-z/; $modes{$_} = 0; } else { $modes{$_} = 1; } } $CONFIG = 'CFILE' . scalar(@{$$Options{Configfiles}}); $configfile =~ s/^.*\@//; if($configfile =~ m[/]) { $confile = $configfile; } elsif($configfile ne '-') { if(!$modes{g} && $$Options{vault} && $$Options{vault} ne 'CODE') { if(!$$Options{Bank}) { my $bank; for $bank (@{$$Options{bank}}) { if (-d "$bank/$$Options{vault}") { $$Options{Bank} = $bank; last; } } } if ($$Options{Bank}) { $confile = join('/', $$Options{Bank}, $$Options{vault}, 'dirvish', $configfile); -f $confile || -f "$confile.conf" or $confile = undef; } } $confile ||= "$CONFDIR/$configfile"; } if($configfile eq '-') { open($CONFIG, $configfile) or seppuku 221, "cannot open STDIN"; } else { ! -f $confile && -f "$confile.conf" and $confile .= '.conf'; if (! -f "$confile") { $modes{o} and return undef; seppuku 222, "cannot open config file: $configfile"; } grep(/^$confile$/, @{$$Options{Configfiles}}) and seppuku 224, "ERROR: config file looping on $confile"; open($CONFIG, $confile) or seppuku 225, "cannot open config file: $configfile"; } push(@{$$Options{Configfiles}}, $confile); while(<$CONFIG>) { chomp; s/\s*#.*$//; s/\s+$//; /\S/ or next; if(/^\s/ && $key) { s/^\s*//; push @{$$Options{$key}}, $_; } elsif(/^SET\s+/) { s/^SET\s+//; for $k (split(/\s+/)) { $$Options{$k} = 1; } } elsif(/^UNSET\s+/) { s/^UNSET\s+//; for $k (split(/\s+/)) { $$Options{$k} = undef; } } elsif(/^RESET\s+/) { ($key = $_) =~ s/^RESET\s+//; $$Options{$key} = [ ]; } elsif(/^[A-Z]/ && $modes{f}) { $key = undef; } elsif(/^\S+:/) { ($key, $val) = split(/:\s*/, $_, 2); length($val) or next; $k = $key; $key = undef; if ($k eq 'config') { $modes{r} and loadconfig($mode . 'O', $val, $Options); next; } if ($k eq 'client') { if ($modes{r} && ref ($$Options{$k}) eq 'CODE') { loadconfig($mode . 'og', "$CONFDIR/$val", $Options); } $$Options{$k} = $val; next; } if ($k eq 'file-exclude') { $modes{r} or next; slurplist('exclude', $val, $Options); next; } if (ref ($$Options{$k}) eq 'ARRAY') { push @{$$Options{$k}}, $_; } else { $$Options{$k} = $val; } } } close $CONFIG; return $Options; } dirvish-1.2.1/install.sh0100755000076400007640000000746610205507255014541 0ustar keithlkeithl#!/bin/sh #KHL 2005-02-18 space removed from above #!/bin/sh 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 EXECUTABLES="dirvish dirvish-runall dirvish-expire dirvish-locate" MANPAGES="dirvish.8 dirvish-runall.8 dirvish-expire.8 dirvish-locate.8" MANPAGES="$MANPAGES dirvish.conf.5" while : do PERL=`which perl` if [ -z "$PERL" ] then PERL=/usr/bin/perl fi echo $ECHO_N "perl to use ($PERL) $ECHO_C" read ans if [ -n "$ans" ] then PERL="$ans" fi until [ -n "$PREFIX_OK" ] do EXECDIR="/usr/sbin" CONFDIR="/etc/dirvish" MANDIR="/usr/share/man" echo $ECHO_N "What installation prefix should be used? ($PREFIX) $ECHO_C" read ans if [ -n "$ans" ] then PREFIX="$ans" # KHL 2005-02-18 == changed to = in "if" below if [ "$PREFIX" = "/" ] then PREFIX="" fi fi if [ -n "$PREFIX" -a ! -d "$PREFIX" ] then echo $ECHO_N "$PREFIX doesn't exist, create it? (n) $ECHO_C" read ans if [ `expr "$ans" : '[yY]'` -ne 0 ] then CREATE_PREFIX="$PREFIX directory will be created" PREFIX_OK="yes" else continue fi else PREFIX_OK="yes" fi if [ -d "$PREFIX/sbin" ] then BINDIR=$PREFIX/sbin else BINDIR=$PREFIX/bin fi if [ -d "$PREFIX/share/man" ] then MANDIR=$PREFIX/share/man elif [ -d "$PREFIX/usr/share/man" ] then MANDIR=$PREFIX/usr/share/man elif [ -d "$PREFIX/usr/man" ] then MANDIR="$PREFIX/usr/man" ] else MANDIR=$PREFIX/man fi if [ `expr "$PREFIX" : '.*dirvish.*'` -gt 0 ] then CONFDIR="$PREFIX/etc" else CONFDIR="/etc/dirvish" fi done echo $ECHO_N "Directory to install executables? ($BINDIR) $ECHO_C" read ans if [ -n "$ans" ] then BINDIR="$ans" fi echo $ECHO_N "Directory to install MANPAGES? ($MANDIR) $ECHO_C" read ans if [ -n "$ans" ] then MANDIR="$ans" fi echo $ECHO_N "Configuration directory ($CONFDIR) $ECHO_C" read ans if [ -n "$ans" ] then CONFDIR="$ans" fi cat <$f cat $f.pl >>$f cat loadconfig.pl >>$f chmod 755 $f done echo echo "Executables created." echo echo $ECHO_N "Install executables and manpages? (no/yes) $ECHO_C" read ans if [ `expr "$ans" : '[yY]'` -ne 0 ] then echo if [ -n "$CREATE_PREFIX" ] then mkdir -p "$PREFIX" fi if [ ! -d $BINDIR ] then if [ -z "$CREATE_PREFIX" -o `expr "$BINDIR" : "$PREFIX"` -ne `expr "$PREFIX" : '.*'` ] then echo "$BINDIR doesn't exist, creating" fi mkdir -p "$BINDIR" fi if [ ! -d $MANDIR ] then if [ -z "$CREATE_PREFIX" -o `expr "$MANDIR" : "$PREFIX"` -ne `expr "$PREFIX" : '.*'` ] then echo "$MANDIR doesn't exist, creating" fi mkdir -p "$MANDIR" fi if [ ! -d "$CONFDIR" ] then mkdir -p "$CONFDIR" fi for f in $EXECUTABLES do echo "installing $BINDIR/$f" cp $f $BINDIR/$f chmod 755 $BINDIR/$f done for f in $MANPAGES do s=`expr "$f" : '.*\(.\)$'` if [ ! -d "$MANDIR/man$s" ] then mkdir -p "$MANDIR/man$s" fi echo "installing $MANDIR/man$s/$f" cp $f $MANDIR/man$s/$f chmod 644 $MANDIR/man$s/$f done echo echo "Installation complete" fi echo $ECHO_N "Clean installation directory? (no/yes) $ECHO_C" read ans if [ `expr "$ans" : '[yY]'` -ne 0 ] then for f in $EXECUTABLES do rm $f done echo "Install directory cleaned." fi dirvish-1.2.1/dirvish-locate.80100664000076400007640000000576410205506717015545 0ustar keithlkeithl.\" $Id: dirvish-locate.8,v 12.0 2004/02/25 02:42:14 jw Exp $ $Name: Dirvish-1_2 $ .ds d \-\^\- .ds o \fR[\fP .ds c \fR]\fP .ds | \fR|\fP .ds bank \fIbank\fP .ds vault \fIvault\fP .ds branch \fIbranch\fP .ds image \fIimage\fP .de D \\.B \*d\\$1 .. .de DR \\.BR \*d\\$1 \\$2 .. .de Bi \\.BI \\$1 " \\$2" .. .de DI \\.BI \*d\\$1 \\$2 .. .de Di \\.BI \*d\\$1 " \\$2" .. .de See See \fB\\$1\fP for details. .. .de SeeIn See \fB\\$1\fP in \fB\\$2\fP for details. .. .de multiple Multiple \fB\\$1:\fP values will accumulate. .. .de default Default value: \fB\\$1\fP .. .TH DIRVISH-LOCATE 8 .SH NAME dirvish\-locate \- locate file versions in dirvish images .SH SYNOPSIS .B dirvish\-locate .I vault\*o:branch\*c .I pattern .SH DESCRIPTION Locate versions of files in a dirvish vault The index of each image specified \*[vault] is searched for paths matching .IR pattern . Each path found matching the .I pattern will be reported followed by a modification time of each version of the file and all images having a link to it. The optional \*[branch] specification will restrict searching to the specified branch. Images with an error status will be skipped as will any without index files. The index file may be compressed by gzip or bzip2. See .B tree and .B index in .B dirvish.conf(5) for details. The .I pattern is a .B perl regular expression to match the final component of the path. Append .B .* to the end of the pattern if you wish to match any substring of the whole path or .B $ if you wish to anchor the pattern to the end of the path. .See perlre(1) Directories are excluded from matching as they would wind up matching every file within them anyway. Symlinks are also excluded from matching. If the .I pattern matches too many paths .B dirvish\-locate will only report the paths matched and not versions. As a sanity check if the number of matches is really excessive .B dirvish\-locate will limit the number of images searched. Excessive matches is an indication of an insufficiently specific .IR pattern . Use the resulting path list to compose a more specific one. .SH EXIT CODES To facilitate further automation and integration of .B dirvish-locate with other tools .B dirvish-locate provides rationalised exit codes. The exit codes are range based. While the code for a specific error may change from one version to another it will remain within the specified range. So don't test for specific exit codes but instead test for a range of values. To the degree possible higher value ranges indicate more severe errors. .TP 0 success 200-219 An error was encountered in loading a configuration file. .TP 220-254 An error was detected in the configuration. .TP 255 Incorrect usage. .SH FILES .TP .B /etc/dirvish/master.conf alternate master configuration file. .TP .B /etc/dirvish.conf master configuration file. .TP .IB bank/vault/image/ summary image creation summary. .TP .IB bank/vault/image/ index .TP .IB bank/vault/image/ index.gz .TP .IB bank/vault/image/ index.bz2 dirvish index file. .SH SEE ALSO .nf dirvish.conf(5) .SH BUGS dirvish-1.2.1/dirvish.pl0100664000076400007640000005552510205510551014533 0ustar keithlkeithl # $Id: dirvish.pl,v 12.0 2004/02/25 02:42:15 jw Exp $ $Name: Dirvish-1_2 $ $VERSION = ('$Name: Dirvish-1_2 $' =~ /Dirvish/i) ? ('$Name: Dirvish-1_2 $' =~ m/^.*:\s+dirvish-(.*)\s*\$$/i)[0] : '1.1.2 patch' . ('$Id: dirvish.pl,v 12.0 2004/02/25 02:42:15 jw Exp $' =~ m/^.*,v(.*:\d\d)\s.*$/)[0]; $VERSION =~ s/_/./g; ######################################################################### # # # Copyright 2002 and $Date: 2004/02/25 02:42:15 $ # Pegasystems Technologies and J.W. Schultz # # # # Licensed under the Open Software License version 2.0 # # # # This program is free software; you can redistribute it # # and/or modify it under the terms of the Open Software # # License, version 2.0 by Lauwrence E. Rosen. # # # # 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 Open Software License for details. # # # ######################################################################### ######################################################### # EXIT CODES # # 0 success # 1-19 warnings # 20-39 finalization error # 40-49 post-* error # 50-59 post-client error code % 10forwarded # 60-69 post-server error code % 10forwarded # 70-79 pre-* error # 80-89 pre-server error code % 10 forwarded # 90-99 pre-client error code % 10 forwarded # 100-149 non-fatal error # 150-199 fatal error # 200-219 loadconfig error. # 220-254 configuration error # 255 usage error use POSIX qw(strftime); use Getopt::Long; use Time::ParseDate; use Time::Period; @rsyncargs = qw(-vrltH --delete); %RSYNC_CODES = ( 0 => [ 'success', "No errors" ], 1 => [ 'fatal', "syntax or usage error" ], 2 => [ 'fatal', "protocol incompatibility" ], 3 => [ 'fatal', "errors selecting input/output files, dirs" ], 4 => [ 'fatal', "requested action not supported" ], 5 => [ 'fatal', "error starting client-server protocol" ], 10 => [ 'error', "error in socket IO" ], 11 => [ 'error', "error in file IO" ], 12 => [ 'check', "error in rsync protocol data stream" ], 13 => [ 'check', "errors with program diagnostics" ], 14 => [ 'error', "error in IPC code" ], 20 => [ 'error', "status returned when sent SIGUSR1, SIGINT" ], 21 => [ 'error', "some error returned by waitpid()" ], 22 => [ 'error', "error allocating core memory buffers" ], 23 => [ 'error', "partial transfer" ], #KHL 2005/02/18: rsync code 24 changed from 'error' to 'warning' 24 => [ 'warning', "file vanished on sender" ], 30 => [ 'error', "timeout in data send/receive" ], 124 => [ 'fatal', "remote shell failed" ], 125 => [ 'error', "remote shell killed" ], 126 => [ 'fatal', "command could not be run" ], 127 => [ 'fatal', "command not found" ], ); @BOOLEAN_FIELDS = qw( permissions checksum devices init numeric-ids sparse stats whole-file xdev zxfer ); %RSYNC_OPT = ( # simple options permissions => '-pgo', devices => '-D', sparse => '-S', checksum => '-c', 'whole-file' => '-W', xdev => '-x', zxfer => '-z', stats => '--stats', 'numeric-ids' => '--numeric-ids', ); %RSYNC_POPT = ( # parametered options 'password-file' => '--password-file', 'rsync-client' => '--rsync-path', ); sub errorscan; sub logappend; sub scriptrun; sub seppuku; sub usage { my $message = shift(@_); length($message) and print STDERR $message, "\n\n"; $! and exit(255); # because getopt seems to send us here for death print STDERR < join(' ', @ARGV), 'numeric-ids' => 1, 'devices' => 1, permissions => 1, 'stats' => 1, exclude => [ ], 'expire-rule' => [ ], 'rsync-option' => [ ], bank => [ ], 'image-default' => '%Y%m%d%H%M%S', rsh => 'ssh', summary => 'short', config => sub { loadconfig('f', $_[1], $Options); }, client => sub { $$Options{$_[0]} = $_[1]; loadconfig('fog', "$CONFDIR/$_[1]", $Options); }, branch => sub { if ($_[1] =~ /:/) { ($$Options{vault}, $$Options{branch}) = split(/:/, $_[1]); } else { $$Options{$_[0]} = $_[1]; } loadconfig('f', "$$Options{branch}", $Options); }, vault => sub { if ($_[1] =~ /:/) { ($$Options{vault}, $$Options{branch}) = split(/:/, $_[1]); loadconfig('f', "$$Options{branch}", $Options); } else { $$Options{$_[0]} = $_[1]; loadconfig('f', 'default.conf', $Options); } }, reset => sub { $$Options{$_[1]} = ref($$Options{$_[1]}) eq 'ARRAY' ? [ ] : undef; }, version => sub { print STDERR "dirvish version $VERSION\n"; exit(0); }, help => \&usage, }; if ($CONFDIR =~ /dirvish$/ && -f "$CONFDIR.conf") { loadconfig('f', "$CONFDIR.conf", $Options); } elsif (-f "$CONFDIR/master.conf") { loadconfig('f', "$CONFDIR/master.conf", $Options); } elsif (-f "$CONFDIR/dirvish.conf") { seppuku 250, < 1, NOW => $n); if (!$now) { $now = parsedate($$Options{'image-time'}, NOW => $n); $now > $n && $$Options{'image-time'} !~ /\+/ and $now -= 24*60*60; } $now or seppuku 222, "ERROR: image-time unparseable: $$Options{'image-time'}"; } $$Options{'Image-now'} = strftime('%Y-%m-%d %H:%M:%S', localtime($now)); $$Options{Image} =~ /%/ and $$Options{Image} = strftime($$Options{Image}, localtime($now)); $image =~ /%/ and $image = strftime($image, localtime($now)); !$$Options{branch} || ref($$Options{branch}) and $$Options{branch} = $$Options{'branch-default'} || 'default'; $seppuku_prefix = join(':', $$Options{vault}, $$Options{branch}, $image); if (-d "$vault/$$Options{'image-temp'}" && $image eq $$Options{'image-temp'}) { my $iinfo; $iinfo = loadconfig('R', "$vault/$image/summary"); $$iinfo{Image} or seppuku 223, "cannot cope with existing $image"; if ($$Options{'no-run'}) { print "ACTION: rename $vault/$image $vault/$$iinfo{Image}\n\n"; $have_temp = 1; } else { rename ("$vault/$image", "$vault/$$iinfo{Image}"); } } -d "$vault/$$Options{Image}" and seppuku 224, "ERROR: image $$Options{Image} already exists in $vault"; -d "$vault/$image" && !$have_temp and seppuku 225, "ERROR: image $image already exists in $vault"; $$Options{Reference} = $$Options{reference} || $$Options{branch}; if (!$$Options{init} && -f "$vault/dirvish/$$Options{Reference}.hist") { my (@images, $i, $s); open(IMAGES, "$vault/dirvish/$$Options{Reference}.hist"); @images = ; close IMAGES; while ($i = pop(@images)) { $i =~ s/\s.*$//s; -d "$vault/$i/tree" or next; $$Options{Reference} = $i; last; } } $$Options{init} || -d "$vault/$$Options{Reference}" or seppuku 227, "ERROR: no images for branch $$Options{branch} found"; if(!$$Options{expire} && $$Options{expire} !~ /never/i && scalar(@{$$Options{'expire-rule'}})) { my ($rule, $p, $t, $e); my @cron; my @pnames = qw(min hr md mo wd); for $rule (reverse(@{$$Options{'expire-rule'}})) { if ($rule =~ /\{.*\}/) { ($p, $e) = $rule =~ m/^(.*\175)\s*([^\175]*)$/; } else { @cron = split(/\s+/, $rule, 6); $e = $cron[5] || ''; $p = ''; for ($t = 0; $t < @pnames; $t++) { $cron[$t] eq '*' and next; ($p .= "$pnames[$t] { $cron[$t] } ") =~ tr/,/ /; } } if (!$p) { $$Options{'Expire-rule'} = $rule; $$Options{Expire} = $e; last; } $t = inPeriod($now, $p); if ($t == 1) { $e ||= 'Never'; $$Options{'Expire-rule'} = $rule; $$Options{Expire} = $e; last; } $t == -1 and printf STDERR "WARNING: invalid expire rule %s\n", $rule; next; } } else { $$Options{Expire} = $$Options{expire}; } $$Options{Expire} ||= $$Options{'expire-default'}; if ($$Options{Expire} && $$Options{Expire} !~ /Never/i) { $$Options{Expire} .= strftime(' == %Y-%m-%d %H:%M:%S', localtime(parsedate($$Options{Expire}, NOW => $now))); } else { $$Options{Expire} = 'Never'; } #+SIS: KHL 2005-02-18 SpacesInSource fix #-SIS: ($srctree, $aliastree) = split(/\s+/, $$Options{tree}) ($srctree, $aliastree) = split(/[^\\]\s+/, $$Options{tree}) or seppuku 228, "ERROR: no source tree defined"; $srctree =~ s(\\ )( )g; #+SIS $srctree =~ s(/+$)(); $aliastree =~ s(/+$)(); $aliastree ||= $srctree; $destree = join("/", $vault, $image, 'tree'); $reftree = join('/', $vault, $$Options{Reference}, 'tree'); $err_temp = join("/", $vault, $image, 'rsync_error.tmp'); $err_file = join("/", $vault, $image, 'rsync_error'); $log_file = join("/", $vault, $image, 'log'); $log_temp = join("/", $vault, $image, 'log.tmp'); $exl_file = join("/", $vault, $image, 'exclude'); $fsb_file = join("/", $vault, $image, 'fsbuffer'); while (($k, $v) = each %RSYNC_OPT) { $$Options{$k} and push @rsyncargs, $v; } while (($k, $v) = each %RSYNC_POPT) { $$Options{$k} and push @rsyncargs, $v . '=' . $$Options{$k}; } $$Options{'speed-limit'} and push @rsyncargs, '--bwlimit=' . $$Options{'speed-limit'} * 100; scalar @{$$Options{'rsync-option'}} and push @rsyncargs, @{$$Options{'rsync-option'}}; scalar @{$$Options{exclude}} and push @rsyncargs, '--exclude-from=' . $exl_file; if (!$$Options{'no-run'}) { mkdir "$vault/$image", 0700 or seppuku 230, "mkdir $vault/$image failed"; mkdir $destree, 0755; open(SUMMARY, ">$vault/$image/summary") or seppuku 231, "cannot create $vault/$image/summary"; } else { open(SUMMARY, ">-"); } $Set = $Unset = ''; for (@BOOLEAN_FIELDS) { $$Options{$_} and $Set .= $_ . ' ' or $Unset .= $_ . ' '; } @summary_fields = qw( client tree rsh Server Bank vault branch Image image-temp Reference Image-now Expire Expire-rule exclude rsync-option Enabled ); $summary_reset = 0; for $key (@summary_fields, 'RESET', sort(keys(%$Options))) { if ($key eq 'RESET') { $summary_reset++; $Set and print SUMMARY "SET $Set\n"; $Unset and print SUMMARY "UNSET $Unset\n"; print SUMMARY "\n"; $$Options{summary} ne 'long' && !$$Options{'no-run'} and last; next; } grep(/^$key$/, @BOOLEAN_FIELDS) and next; $summary_reset && grep(/^$key$/, @summary_fields) and next; $val = $$Options{$key}; if(ref($val) eq 'ARRAY') { my $v; scalar(@$val) or next; print SUMMARY "$key:\n"; for $v (@$val) { printf SUMMARY "\t%s\n", $v; } } ref($val) and next; $val or next; printf SUMMARY "%s: %s\n", $key, $val; } $$Options{init} or push @rsyncargs, "--link-dest=$reftree"; $rclient = undef; $$Options{client} ne $$Options{Server} and $rclient = $$Options{client} . ':'; $ENV{RSYNC_RSH} = $$Options{rsh}; @cmd = ( ($$Options{rsync} ? $$Options{rsync} : 'rsync'), @rsyncargs, $rclient . $srctree . '/', $destree ); printf SUMMARY "\n%s: %s\n", 'ACTION', join (' ', @cmd); $$Options{'no-run'} and exit 0; printf SUMMARY "%s: %s\n", 'Backup-begin', strftime('%Y-%m-%d %H:%M:%S', localtime); $env_srctree = $srctree; #+SIS: $env_srctree =~ s/ /\\ /g; #+SIS: $WRAPPER_ENV = sprintf (" %s=%s" x 5, 'DIRVISH_SERVER', $$Options{Server}, 'DIRVISH_CLIENT', $$Options{client}, #-SIS: 'DIRVISH_SRC', $srctree, 'DIRVISH_SRC', $env_srctree, #+SIS: 'DIRVISH_DEST', $destree, 'DIRVISH_IMAGE', join(':', $$Options{vault}, $$Options{branch}, $$Options{Image}), ); if(scalar @{$$Options{exclude}}) { open(EXCLUDE, ">$exl_file"); for (@{$$Options{exclude}}) { print EXCLUDE $_, "\n"; } close(EXCLUDE); $ENV{DIRVISH_EXCLUDE} = $exl_file; } if ($$Options{'pre-server'}) { $status{'pre-server'} = scriptrun( lable => 'Pre-Server', cmd => $$Options{'pre-server'}, now => $now, log => $log_file, dir => $destree, env => $WRAPPER_ENV, ); if ($status{'pre-server'}) { my $s = $status{'pre-server'} >> 8; printf SUMMARY "pre-server failed (%d)\n", $s; printf STDERR "%s:%s pre-server failed (%d)\n", $$Options{vault}, $$Options{branch}, $s; exit 80 + ($s % 10); } } if ($$Options{'pre-client'}) { $status{'pre-client'} = scriptrun( lable => 'Pre-Client', cmd => $$Options{'pre-client'}, now => $now, log => $log_file, dir => $srctree, env => $WRAPPER_ENV, shell => (($$Options{client} eq $$Options{Server}) ? undef : "$$Options{rsh} $$Options{client}"), ); if ($status{'pre-client'}) { my $s = $status{'pre-client'}; printf SUMMARY "pre-client failed (%d)\n", $s; printf STDERR "%s:%s pre-client failed (%d)\n", $$Options{vault}, $$Options{branch}, $s; ($$Options{'pre-server'}) && scriptrun( lable => 'Post-Server', cmd => $$Options{'post-server'}, now => $now, log => $log_file, dir => $destree, env => $WRAPPER_ENV . ' DIRVISH_STATUS=fail', ); exit 90 + ($s % 10); } } # create a buffer to allow logging to work after full fileystem open (FSBUF, ">$fsb_file"); print FSBUF " \n" x 6553; close FSBUF; for ($runloops = 0; $runloops < 5; ++$runloops) { logappend($log_file, sprintf("\n%s: %s\n", 'ACTION', join(' ', @cmd))); # create error file and connect rsync STDERR to it. # preallocate 64KB so there will be space if rsync # fills the filesystem. open (INHOLD, "<&STDIN"); open (ERRHOLD, ">&STDERR"); open (STDERR, ">$err_temp"); print STDERR " \n" x 6553; seek STDERR, 0, 0; open (OUTHOLD, ">&STDOUT"); open (STDOUT, ">$log_temp"); $status{code} = (system(@cmd) >> 8) & 255; open (STDERR, ">&ERRHOLD"); open (STDOUT, ">&OUTHOLD"); open (STDIN, "<&INHOLD"); open (LOG_FILE, ">>$log_file"); open (LOG_TEMP, "<$log_temp"); while () { chomp; m(/$) and next; m( [-=]> ) and next; print LOG_FILE $_, "\n"; } close (LOG_TEMP); close (LOG_FILE); unlink $log_temp; $status{code} and errorscan(\%status, $err_file, $err_temp); $status{warning} || $status{error} and logappend($log_file, sprintf( "RESULTS: warnings = %d, errors = %d", $status{warning}, $status{error} ) ); if ($RSYNC_CODES{$status{code}}[0] eq 'check') { $status{fatal} and last; $status{error} or last; } else { $RSYNC_CODES{$status{code}}[0] eq 'fatal' and last; $RSYNC_CODES{$status{code}}[0] eq 'error' or last; } } scalar @{$$Options{exclude}} && unlink $exl_file; -f $fsb_file and unlink $fsb_file; if ($status{code}) { if ($RSYNC_CODES{$status{code}}[0] eq 'check') { if ($status{fatal}) { $Status = 'fatal'; } elsif ($status{error}) { $Status = 'error'; } elsif ($status{warning}) { $Status = 'warning'; } $Status_msg = sprintf "%s (%d) -- %s", ($Status eq 'fatal' ? 'fatal error' : $Status), $status{code}, $status{message}{$Status}; } elsif ($RSYNC_CODES{$status{code}}[0] eq 'fatal') { $Status_msg = sprintf "fatal error (%d) -- %s", $status{code}, $RSYNC_CODES{$status{code}}[1]; } if (!$Status_msg) { $RSYNC_CODES{$status{code}}[0] eq 'fatal' and $Status = 'fatal'; $RSYNC_CODES{$status{code}}[0] eq 'error' and $Status = 'error'; $RSYNC_CODES{$status{code}}[0] eq 'warning' and $Status = 'warning'; $RSYNC_CODES{$status{code}}[0] eq 'check' and $Status = 'unknown'; exists $RSYNC_CODES{$status{code}} or $Status = 'unknown'; $Status_msg = sprintf "%s (%d) -- %s", ($Status eq 'fatal' ? 'fatal error' : $Status), $status{code}, $RSYNC_CODES{$status{code}}[1]; } if ($Status eq 'fatal' || $Status eq 'error' || $status eq 'unknown') { printf STDERR "dirvish %s:%s %s\n", $$Options{vault}, $$Options{branch}, $Status_msg; } } else { $Status = $Status_msg = 'success'; } $WRAPPER_ENV .= ' DIRVISH_STATUS=' . $Status; if ($$Options{'post-client'}) { $status{'post-client'} = scriptrun( lable => 'Post-Client', cmd => $$Options{'post-client'}, now => $now, log => $log_file, dir => $srctree, env => $WRAPPER_ENV, shell => (($$Options{client} eq $$Options{Server}) ? undef : "$$Options{rsh} $$Options{client}"), ); if ($status{'post-client'}) { my $s = $status{'post-client'} >> 8; printf SUMMARY "post-client failed (%d)\n", $s; printf STDERR "%s:%s post-client failed (%d)\n", $$Options{vault}, $$Options{branch}, $s; } } if ($$Options{'post-server'}) { $status{'post-server'} = scriptrun( lable => 'Post-Server', cmd => $$Options{'post-server'}, now => $now, log => $log_file, dir => $destree, env => $WRAPPER_ENV, ); if ($status{'post-server'}) { my $s = $status{'post-server'} >> 8; printf SUMMARY "post-server failed (%d)\n", $s; printf STDERR "%s:%s post-server failed (%d)\n", $$Options{vault}, $$Options{branch}, $s; } } if($status{fatal}) { system ("rm -rf $destree"); unlink $err_temp; printf SUMMARY "%s: %s\n", 'Status', $Status_msg; exit 199; } else { unlink $err_temp; -z $err_file and unlink $err_file; } printf SUMMARY "%s: %s\n", 'Backup-complete', strftime('%Y-%m-%d %H:%M:%S', localtime); printf SUMMARY "%s: %s\n", 'Status', $Status_msg; # We assume warning and unknown produce useful results $Status eq 'warning' || $Status eq 'unknown' and $Status = 'success'; if ($Status eq 'success') { -s "$vault/dirvish/$$Options{branch}.hist" or $newhist = 1; if (open(HIST, ">>$vault/dirvish/$$Options{branch}.hist")) { $newhist == 1 and printf HIST ("#%s\t%s\t%s\t%s\n", qw(IMAGE CREATED REFERECE EXPIRES)); printf HIST ("%s\t%s\t%s\t%s\n", $$Options{Image}, strftime('%Y-%m-%d %H:%M:%S', localtime), $$Options{Reference} || '-', $$Options{Expire} ); close (HIST); } } else { printf STDERR "dirvish error: branch %s:%s image %s failed\n", $vault, $$Options{branch}, $$Options{Image}; } length($$Options{'meta-perm'}) and chmod oct($$Options{'meta-perm'}), "$vault/$image/summary", "$vault/$image/rsync_error", "$vault/$image/log"; $Status eq 'success' or exit 149; $$Options{log} =~ /.*(gzip)|(bzip2)/ and system "$$Options{log} $vault/$image/log"; if ($$Options{index} && $$Options{index} !~/^no/i) { open(INDEX, ">$vault/$image/index"); open(FIND, "find $destree -ls|") or seppuku 21, "dirvish $vault:$image cannot build index"; while () { s/ $destree\// $aliastree\//g; print INDEX $_ or seppuku 22, "dirvish $vault:$image error writing index"; } close FIND; close INDEX; length($$Options{'meta-perm'}) and chmod oct($$Options{'meta-perm'}), "$vault/$image/index"; $$Options{index} =~ /.*(gzip)|(bzip2)/ and system "$$Options{index} $vault/$image/index"; } chmod oct($$Options{'image-perm'}) || 0755, "$vault/$image"; exit 0; sub errorscan { my ($status, $err_file, $err_temp) = @_; my $err_this_loop = 0; my ($action, $pattern, $severity, $message); my @erraction = ( [ 'fatal', '^ssh:.*nection refused', ], [ 'fatal', '^\S*sh: .* No such file', ], [ 'fatal', '^ssh:.*No route to host', ], [ 'error', '^file has vanished: ', ], [ 'warning', 'readlink .*: no such file or directory', ], [ 'fatal', 'failed to write \d+ bytes:', 'write error, filesystem probably full' ], [ 'fatal', 'write failed', 'write error, filesystem probably full' ], [ 'error', 'error: partial transfer', 'partial transfer' ], [ 'error', 'error writing .* exiting: Broken pipe', 'broken pipe' ], ); open (ERR_FILE, ">>$err_file"); open (ERR_TEMP, "<$err_temp"); while () { chomp; s/\s+$//; length or next; if (!$err_this_loop) { printf ERR_FILE "\n\n*** Execution cycle %d ***\n\n", $runloops; $err_this_loop++ } print ERR_FILE $_, "\n"; $$status{code} or next; for $action (@erraction) { ($severity, $pattern, $message) = @$action; /$pattern/ or next; ++$$status{$severity}; $msg = $message || $_; $$status{message}{$severity} ||= $msg; logappend($log_file, $msg); $severity eq 'fatal' and printf STDERR "dirvish %s:%s fatal error: %s\n", $$Options{vault}, $$Options{branch}, $msg; last; } if (/No space left on device/) { $msg = 'filesystem full'; $$status{message}{fatal} eq $msg and next; -f $fsb_file and unlink $fsb_file; ++$$status{fatal}; $$status{message}{fatal} = $msg; logappend($log_file, $msg); printf STDERR "dirvish %s:%s fatal error: %s\n", $$Options{vault}, $$Options{branch}, $msg; } if (/error: error in rsync protocol data stream/) { ++$$status{error}; $msg = $message || $_; $$status{message}{error} ||= $msg; logappend($log_file, $msg); } } close ERR_TEMP; close ERR_FILE; } sub logappend { my ($file, @messages) = @_; my $message; open (LOGFILE, '>>' . $file) or seppuku 20, "cannot open log file $file"; for $message (@messages) { print LOGFILE $message, "\n"; } close LOGFILE; } sub scriptrun { my (%A) = @_; my ($cmd, $rcmd, $return); $A{now} ||= time; $A{log} or seppuku 229, "must specify logfile for scriptrun()"; ref($A{cmd}) and seppuku 232, "$A{lable} option specification error"; $cmd = strftime($A{cmd}, localtime($A{now})); #KHL 2005-02-18 BadShellCommandCWD: fix inverted logic # if ($A{dir} =~ /^:/) if ($A{dir} !~ /^:/) { $rcmd = sprintf ("%s 'cd %s; %s %s' >>%s", ("$A{shell}" || "/bin/sh -c"), $A{dir}, $A{env}, $cmd, $A{log} ); } else { $rcmd = sprintf ("%s '%s %s' >>%s", ("$A{shell}" || "/bin/sh -c"), $A{env}, $cmd, $A{log} ); } $A{lable} =~ /^Post/ and logappend($A{log}, "\n"); logappend($A{log}, "$A{lable}: $cmd"); $return = system($rcmd); $A{lable} =~ /^Pre/ and logappend($A{log}, "\n"); return $return; } dirvish-1.2.1/dirvish.conf.50100664000076400007640000005175010430420106015200 0ustar keithlkeithl.\" $Id: dirvish.conf.5,v 12.0 2004/02/25 02:42:15 jw Exp $ $Name: Dirvish-1_2 $ .ds d \-\^\- .ds o \fR[\fP .ds c \fR]\fP .ds | \fR|\fP .ds bank \fIbank\fP .ds vault \fIvault\fP .ds branch \fIbranch\fP .ds image \fIimage\fP .de D \\.B \*d\\$1 .. .de Dr \\.BR \*d\\$1 \\$2 .. .de Bi \\.BI \\$1 " \\$2" " \fR\\$3" .. .de Br \\.BR "\\$1" " \\$2" .. .de DI \\.BI \*d\\$1 \\$2 .. .de Di \\.BI \*d\\$1 " \\$2" .. .de See See \fB\\$1\fP for more details. .. .de SeeIn See \fB\\$1\fP in \fB\\$2\fP for more details. .. .de multiple Multiple \fB\\$1:\fP values will accumulate. .. .de default Default value: \fB\\$1\fP .. .de usedefault Setting this in a config file may cause the command line option to be overridden. Use \fB\\$1\-default:\fP instead. .. .TH DIRVISH.CONF 5 .SH NAME dirvish.conf \- dirvish configuration file. .SH DESCRIPTION The dirvish.conf file provides configuration information and default values for dirvish. The file format is fairly simple. Each option requires either a single-value or a list of values and unless otherwise indicated must be specified according to its expected type. Single value options are specified by lines of the form .BR "option: value" . Options expecting list must be specified in a multi-line format as shown here where the lines specifying values are indented by any kind of whitespace even if only one value is being specified. .br \fB .in +.5i .nf option: .in +.5i value1 value2 \&. \&. \&. valueN .br .fi .in -1i \fR Each value must be provided on its own line. Any leading and trailing whitespace is discarded. Options whose names with an initial capital (ex: Foo) are discarded by dirvish itself but may be used by support utilities. Blank lines are ignored. While this simplistic format may allow for configuration errors it allows arbitrary options to be declared that custom support scripts could use. A .B # introduces a comment to the end of the line. On startup the dirvish utilities will first load a master dirvish.conf file. .B /etc/dirvish.conf will be tried first but if not present .B /etc/dirvish/master.conf will be tried. During installation dirvish may have been configured expect the system-wide configuration files in some location other than /etc/dirvish. Multiple configuration files will be loaded by the .DR config , .D vault and .D branch command-line options as well as the .B config: and .B client: configuration parameters. To prevent looping each configuration file can only be loaded once. .SH DIRVISH OPTIONS Like the command line each option may be specified any number of times. Those options that expect lists will accumulate all of their arguments and for single value options each specification will override the ones before. Boolean values need to specified as .B 1 or .B 0 or may be specified using .B SET or .BR UNSET . Some Boolean values are set by default and must be explicitly unset if unwanted. Each option is marked here with one of (B) for Boolean, (S) single value, (L) list or (0) other. .TP .Bi SET "option option ..." (O) .TP .Bi UNSET "option option ..." (O) Set or unset one or more boolean options. NOTE: The SET and UNSET directives do not use colons <:>. .TP .Bi RESET option (O) Reset a list option so that it contains no values. This may be used to start specification of the option. NOTE: The RESET directive does not use a colon <:>. .TP .Br bank: (L) Specify paths to directories containing vaults. A \*[bank] is a directory containing one or more \*[vault]s. The system supports multiple \*[bank]s so that filesystem mount-points can be managed more effectively. When a \*[vault] is specified the \*[bank]s will be searched in list order until the \*[vault] is found. This way \*[vault]s can be moved between \*[bank]s or added without having to update a master index. .multiple bank .TP .Bi branch: branch_name (S) Specify a \*[branch] to use. A \*[branch] is a sequence of \*[image]s. This also specifies a default value for .BR reference: . .usedefault branch .TP .Bi branch\-default: branch_name (S) Specify a default \*[branch] to use. .TP .Bi client: \*ousername@\*cclient_name (S) specify a client to back up. Setting this to the same value as hostname will cause dirvish to do a local copy and stay off the network. This automatically invokes \fBwhole\-file\fP. The first time this parameter is set .B /etc/dirvish/\fIclient_name\fP or .B /etc/dirvish/\fIclient_name\fP.conf will be loaded. .TP .Br checksum: (B) Force the checksum comparison of file contents even when the inode fails to indicate a change has occurred. .default 0 .TP .Bi config: filename (S) Load configuration file. Similar to #include, .I filename or .IB filename .conf will be loaded immediately. If .I filename is a relative path it will be looked for in the vault and then the system-wide configuration directories. .TP .Br devices: (B) If this is unset device special files will be excluded from backups. This may need to be unset when doing backups of where the client OS uses device numbers or types unsupported by the server OSs or where the presence of device nodes in the vault present a security issue. .TP .Br exclude: (L) Specify a filename patterns to exclude. Patterns are based on shell glob with some enhancements. .See rsync(1) .multiple exclude .TP .Bi file\-exclude: filename (S) Load a set of patterns from a file. If .I filename is a relative path it will be looked for in the vault and then the system-wide configuration directories. .TP .Bi expire: expire_date (S) Specify a time for the \*[image] to expire. This does not actually expire anything. What it does do is add an .B Expire: option to the \*[image] summary file with the absolute time appended so that .B dirvish\-expire can automate old \*[image] removal. .usedefault "expire\-rule: \fRand\fP expire" .See Time::ParseDate(3pm) .TP .Bi expire\-default: expire_date (S) Specify a default expiration time. This value will only be used if expire is not set and expire\-rule doesn't have a match. .TP .Br expire\-rule: (L) specify rules for expiration. Rules are specified similar to crontab or in .BR Time::Period format . .See "EXPIRE RULES" .multiple expire\-rule .TP .Bi image: image_name (S) Specify a name for the \*[image]. .I image_name is passed through .B POSIX::strftime .usedefault image .See strftime(3) .TP .Bi image\-default: image_name (S) Set the default .IR image_name . This value will only be used if .B image: is not set. .TP .Bi image\-perm: octal_mode (S) Set the permissions for the \*[image]. While the \*[image] is being created the \*[image] directory permissions will be .BR 0700 . After completion it will be changed to .I octal_mode or .BR 0755 . .See "chmod(1) and umask(2)" .TP .Bi image\-time: parsedate_expression (S) Time to use when creating the \*[image] name. If an absolute time without a date is provided it will be forced into the past. If this isn't set the current time will be used. .See Time::ParseDate(3pm) .TP .Bi image\-temp: dirname (S) Temporary directory name to use for new \*[image]. This allows you to have \*[image]s created with the same directory name each run so that automatic processes can access them. The next time an image is made on the \*[branch] this option will cause the directory to be renamed to its official name. .TP .B "index: none\*|text\*|gzip\*|bzip2" (S) Create an index file listing all files in the \*[image]. The index file will be created using .B "find -ls" so the list will be in the same format as .BR ls -dils with paths converted to reflect the source location. If index is set to bzip2 or gzip or a path to one the index file will be compressed accordingly. This index will be used by .B dirvish\-locate to locate versions of files. .See dirvish\-locate(8) .TP .Br init: (B) Create an initial \*[image]. Turning this on will prevent backups from being incremental. .TP .B "log: text\*|gzip\*|bzip2" (S) Specify format for the image log file. If .B log is set to bzip2 or gzip or a path to one the log file will be compressed accordingly. .TP .Bi meta\-perm: octal\-mode (S) Set the permissions for the \*[image] meta-data files. If this value is set the permissions of the meta-data files in the \*[image] will be changed after the \*[image] is created. Otherwise the active umask will prevail. SECURITY NOTE: The log, index, and error files contain lists of files. It may be possible that filenames themselves may be or contain confidential information so uncontrolled access may constitute a security weakness. .See "chmod(1) and umask(2)" .TP .Br numeric\-ids: (B) Use numeric uid/gid values instead of looking up user/group names for setting permissions. .See rsync(1) .default 1 .TP .Bi password\-file: filepath (S) Specify file containing password for connection to an .B rsync daemon on backup client. This is not useful for remote shell passwords. .SeeIn \*dpassword\-file rsync(1) .TP .Br permissions: (B) Preserve file permissions. If this is unset permissions will not be checked or preserved. With rsync version 2.5.6 not preserving permissions will break the linking. Only unset this if you are running a later version of rsync. .See rsync(1) .default 1 .TP .Bi pre\-server: shell_command (S) .TP .Bi pre\-client: shell_command (S) .TP .Bi post\-client: shell_command (S) .TP .Bi post\-server: shell_command (S) Execute .I shell_command on client or server before or after making backup. The client commands are run on the client system using the remote shell command (see the \fBrsh\fR: parameter). The order of execution is .BR pre\-server , .BR pre\-client , .BR rsync , .BR post\-client , .BR post\-server . The .I shell_command will be passed through .B strftime(3) to allow date strings to be expanded. Each pre or post .IR shell_command s will be run with these environment variables .BR DIRVISH_SERVER , .BR DIRVISH_CLIENT, .BR DIRVISH_SRC , .B DIRVISH_DEST and .B DIRVISH_IMAGE set. The current directory will be .B DIRVISH_SRC on the client and .B DIRVISH_DEST on the server. If there are any exclude patterns defined the .B pre\-server shell command will also have the exclude file's path in .B DIRVISH_EXCLUDE so it may read or modify the exlude list. .SM STDOUT from each .I shell_command will be written to the \*[image] log file. The exit status of each script will be checked. Non-zero values will be recognised as failure and logged. Failure of the .B pre\-server command will halt all further action. Failure of the .B pre\-client command will prevent the rsync from running and the .B post\-server command, if any, will be run. Post .IR shell_command s will also have .B DIRVISH_STATUS set to .BR success , .BR warning , .BR error , or .BR "fatal error" . This is useful for multiple things. The client .IR shell_command s can be used to stop and start services so their files can be backed up safely. You might use .B post\-server: to schedule replication or a tape backup of the new \*[image]. Use your imagination. .TP .Bi reference: branch_name\*|image_name (S) Specify an existing \*[image] or a \*[branch] from which to create the new \*[image]. If a .I branch_name is specified, the last existing \*[image] from its history file will be used. A \*[branch] will take precedence over an \*[image] of the same name. If this isn't specified the \*[branch] name will be used as a default value. .TP .Bi rsh: command (S) Remote shell utility. This can be used to specify the location of .B ssh or .B rsh and/or to provide addition options for said utility such as .Bi \-p port for .B ssh to use an alternate port number. If not specified .B ssh will be used. This remote shell command will be used not only as the default rsync transport but also for any .B pre\-client and .B post\-client commands. .TP .Bi rsync: command (S) Path to rsync executable on the server. .TP .Bi rsync\-client: command (S) Path to rsync executable on the client. .TP .Br rsync\-option: (L) Specify additional options for the rsync command. Only one option per list item is supported. This allows you to use rsync features that are not directly supported by .BR dirvish . Where .B dirvish does support an rsync feature it is probably better to use the the .B dirvish supplied mechanism for setting it. .multiple rsync\-options .TP .Br sparse: (B) Try to handle sparse files efficiently so they take up less space in the \*[vault]. NOTE: Some filesystem types may have problems seeking over null regions. .TP .Bi speed\-limit: Mbps (S) Specify a maximum transfer rate. This allows you to limit the network bandwidth consumed. The value is specified in approximate Mega-bits per second which correlates to network transport specifications. An adaptive algorithm is used so the actual bandwidth usage may exceed .I Mbps occasionally. .SeeIn --bwlimit rsync(1) .TP .Br stats: (B) Have rsync report transfer statistics. .See rsync(1) .default 1 .TP .Br "summary: short\*|long" (S) Specify summary format. A short summary will only include final used values. A long summary will include all configuration values. With long format you custom options in the configuration files will appear in the summary. The default is short. .TP .Bi tree: "path [alias]" (S) Specify a directory path on the client to backup. If .I path is prefixed with a colon the transfer will be done from an .B rsync daemon on the client otherwise the transfer will be done through a remote shell process. The optional .I alias specifies the path that should appear in the index so .B dirvish\-locate will report paths consistant with common usage. This can help reduce confusion when dealing with users unfamiliar with the physical topology of their network provided files. .TP .Br no\-run: (B) Don't actually do anything. Process all configuration files, options and tests then produce a summary/configuration file on standard output and exit. I can't think why you would do this in a configuration file but if you want to shoot yourself in the foot, be my guest. .TP .Bi vault: vault (S) Specify the \*[vault] to store the \*[image] in. Although multiple \*[vault]s may share a filesystem a given \*[vault] cannot span filesystems. For filesystem purposes the \*[vault] is the level of atomicity. This will seldom be specified in a configuration file. .TP .Br whole\-file: (B) Transfer whole files instead of just the parts that have changed. This may be slightly faster for files that have more changed than left the same such as compressed or encrypted files. In most cases this will be slower when transferring over the network but will use less CPU resources. This will be faster if the transfers are not over the network or when the network is faster than the destination disk subsystem. .TP .Br xdev: (B) Do not cross mount-points when traversing the tree on the client. .TP .Br zxfer: (B) Enable compression on data-transfer. .SH SCHEDULING OPTIONS .TP .Bi Dirvish: path (S) Location of dirvish executable. If not set defaults to .BR dirvish . .if 0 \{ \" parameters for dirvish-sched .TP .Bi Frequency: parsedate_expression (S) How often this backup is allowed to run. If the time the last \*[image] of this \*[branch] was created is more than parsedate_expression old and we are within a time Window it may commence a backup. .TP .Bi Load: load_units (S) Set a relative load value for a job. The load that a job places on the server will vary depending on the frequency of file changes, end-to-end network bandwidth (and .BR speed\-limit ), and the processing speed of the client. .TP .Bi Load\-default: load_units (S) Set the default value for Load. This option can only be set in the master configuration file and if left unset will default to .BR 100 . .TP .Bi Max\-jobs: count (S) Set the maximum number of simultaneous jobs permitted. When set in the master configuration file this applies to the server. When set in the client config file this will limit only limit the number of simultaneous jobs on that client. .TP .Bi Max\-load: load_units (S) Set the maximum load permitted. The total load_units of all jobs running will not exceed this value. If not set no load limiting will be done. When set in the master configuration file this applies to the server. hen set in the client config file this will limit only limit the load of simultaneous jobs on that client. .TP .Bi Priority: priority (S) Set a priority value for a job. Relative priorities will be used in scheduling jobs. \} .TP .Br Runall: (L) Specify \*[branch]es to be scheduled for automated backups. Each value is specified in the form .ti +.5i .br vault:branch [image_time] .br If image_time is set here it will be used. This option can only be set in the master configuration file and multiple values will accumulate. .if 0 \{ \" parameters for dirvish-sched .TP .Bi Schedule: vault:branch (L) Specify \*[branch]es to be scheduled for automated backups. This option can only be set in the master configuration file and multiple \*[branch]es will accumulate. .TP .Bi Window: time_pattern (L) time pattern expression for scheduling backups. The time_patterns will be tested and if any one matches the current time and the last \*[image] is old enough it may commence a backup. See EXPIRE RULES for details of time_pattern expressions. Multiple patterns will accumulate so if a client or \*[branch] requires more restrictive windows use RESET. \} .SH EXPIRE RULES Expire rules is a list of rules used to determine an expiration time for an \*[image]. The last rule that matches will apply so list order is significant. This allows rules to be set in client, \*[vault] and \*[branch] configuration files to override rules set in the master configuration file without having to use .BR RESET . In most cases it is better to use a .B expire\-default: value than to define a rule that matches all possible times. Each rule has an pattern expression against which the current time is compared followed by a date specifier in .B Time::ParseDate format. .See Time::ParseDate(3pm) A matching rule with an empty/missing date specifier or specifying .B never will result in no expiration. The time pattern expression may be in either .B crontab or in .B Time::Period format. .See "crontab(5) and Time::Period(3pm)" The crontab formated patterns are converted to .B Time::Period format so the limitations and extensions for the specification of option values of .B Time::Period apply to the .B crontab format as well. Most notable is that the days of the week are numbered \fB1\fP\-\fB7\fP for \fBsun\fP\-\fBsat\fP so .B 0 is not a valid wday but .B sat is. Here are two equivalent examples of an expire\-rule list. .nf .ft CR .ta .5i T 6m expire\-default: +5 weeks expire\-rule: #MIN HR DOM MON DOW EXPIRE * * * * 1 +3 months * * 1\-7 * su +1 year * * 1\-7 1,4,7,10 1 never * 10\-20 * * * +10 days or: .ta +.5i +36m wd { sun } +3 months wd { sun } md { 1\-7 } +1 year wd { 1 } md { 1\-7 } mo { 1,4,7,10 } never hr { 10\-20 } +10 days .ft R .fi This describes is an aggressive retention schedule. If the nightly backup is made dated the 1st Sunday of each quarter it is is kept forever, the 1st Sunday of any other month is kept for 1 year, all other Sunday's are kept for 3 months, the remaining nightlies are kept for 5 weeks. In addition, if the backup is made between 10AM and 8PM it will expire after 10 days. This would be appropriate for someone with a huge backup server who is so paranoid he makes two backups per day. The other possibility for the hour spec would be for ad-hoc special backups to have a default that differs from the normal dailies. It should be noted that all expiration rules will do is to cause dirvish to put an .B Expire: option in the summary file. The .B dirvish\-expire utility will have to be run to actually delete any expired \*[image]s. .SH FILES .TP .B /etc/dirvish/master.conf alternate master configuration file. .TP .B /etc/dirvish.conf master configuration file. .TP .B /etc/dirvish/\fIclient\fP[.conf] client configuration file. .TP .IB bank/vault/ dirvish/default[.conf] default vault configuration file. .TP .IB bank/vault/\fBdirvish\fP/branch [.conf] branch configuration file. .TP .IB bank/vault/\fBdirvish\fP/branch .hist branch history file. .TP .IB bank/vault/image/ summary image creation summary. .TP .IB bank/vault/image/ log image creation log. .TP .IB bank/vault/image/ tree actual image of source directory tree. .TP .IB bank/vault/image/ rsync_error Error output from rsync if errors or warnings were detected. .SH SEE ALSO .nf dirvish(8) dirvish\-expire(8) dirvish\-runall(8) dirvish\-locate(8) ssh(1), rsync(1) Time::ParseDate(3pm) strftime(3) .SH AUTHOR Dirvish was created by J.W. Schultz of Pegasystems Technologies. .SH BUGS Rsync version 2.5.6 has a bug so that unsetting the .B perms option will not disable testing for permissions. Disabling perms will break image linking. Options set in configuration files will override command line options that have been set before the file is read. This behaviour while consistent may confuse users. For this reason the more frequently used command line options have options paired with a .I default option so the order of specification will be more forgiving. It is recommended that where such default options exist in configuration files they should be preferred over the primary option. It is possible to specify almost any command line option as a option. Some of them just don't make sense to use here. dirvish-1.2.1/RELEASE.html0100664000076400007640000000204310205544474014472 0ustar keithlkeithl DIRVISH RELEASE NOTES

DIRVISH RELEASE NOTES

Dirvish version 1.2.1 released 18 February 2005

  • Corrected a logic inversion bug in pre-client and post-client that resulted in the wrong working directory.
  • Changed rsync code 24 from error to warning.
  • Changed == to = in the install script.
  • Allow the use of spaces protected by a backslash in the source tree name.

Dirvish version 1.2 released 24 February 2004

Dirvish version 1.1.2 released 15 July 2003

Dirvish version 1.1.1 released 26 May 2003

No issues

Dirvish version 1.1 released 17 May 2003

  • The master and default config files have been renamed.
    /etc/dirvish/dirvish.conf --> /etc/dirvish/master.conf
    $VAULT/dirvish/dirvish.conf --> $VAULT/dirvish/default.conf
    

  • The rsync-options: option has been replaced with rsync-option: which only accepts one option per specification.
dirvish-1.2.1/CHANGELOG0100664000076400007640000011431610430416201013727 0ustar keithlkeithl2005/03/31 dirvish.pl 12.1 dirvish-1.2.1 INSTALL 12.1 dirvish-1.2.1 install.sh 12.1 dirvish-1.2.1 RELEASE.html 12.1 dirvish-1.2.1 Changed by hand by Keith Lofstrom - haven't learned how to write one of these things from Subversion yet (and we don't have jw's original cvs tree, sigh). See the release notes for more info. 2004/02/25 dirvish.conf.5 12.0 Dirvish-1.2 dirvish.pl 12.0 Dirvish-1.2 install.sh 12.0 Dirvish-1.2 loadconfig.pl 12.0 Dirvish-1.2 RELEASE.html 12.0 Dirvish-1.2 TODO.html 12.0 Dirvish-1.2 dirvish-expire.8 12.0 Dirvish-1.2 dirvish-expire.pl 12.0 Dirvish-1.2 dirvish-locate.8 12.0 Dirvish-1.2 dirvish-locate.pl 12.0 Dirvish-1.2 dirvish-runall.8 12.0 Dirvish-1.2 dirvish-runall.pl 12.0 Dirvish-1.2 dirvish.8 12.0 Dirvish-1.2 COPYING 12.0 Dirvish-1.2 FAQ.html 12.0 Dirvish-1.2 INSTALL 12.0 Dirvish-1.2 RELEASE.html 11.7 FAQ.html 11.8 Preparing to tag 1.2.0 Note license change and prep for 1.2 Update license note. 2004/02/23 dirvish.pl 11.27 install.sh 11.3 Set --delete on rsync so retries will delete deleted files. (Thanks to Nathan Hunsperger) Allow installs to existing install dir with missing subdirs. 2004/01/20 FAQ.html 11.7 Removed banner reference. 2004/01/19 FAQ.html 11.6 dirvish.pl 11.26 Reordered chmod operations on image. thanks to Nathan Hunsperger 2003/12/21 dirvish.pl 11.25 Better handling of vanished files on sender. 2003/12/17 TODO.html 11.16 file security check added to wish list 2003/12/15 dirvish.pl 11.24 Added recognition for vanishing (unexpected EOF) files on client. This happens due to a file being deleted or truncated between file scan and send. 2003/12/11 FAQ.html 11.5 11.4 Fixed html tag typo -- Frank de Jong 2003/12/08 dirvish.pl 11.23 Fix permissions of rsync-error file. Thanks to Nathan Hunsperger 2003/12/06 INSTALL 11.4 Change to reflect rsync's 2.5.7 security release and plan for post 2.5.6 CVS HEAD to be 2.6.0 2003/12/03 dirvish.conf.5 11.12 fixed some references to expire-rules (wrong plural) and expire_rules (underscore) 2003/11/26 dirvish.conf.5 11.11 dirvish.pl 11.22 11.21 TODO.html 11.15 Added a devices option (default yes) to allow excluding devices from backups. Fixed problems with expire-default and expire rules that assume never. 2003/10/25 dirvish-expire.pl 11.12 Allow a vault named dirvish. A vault named "tree" will still be skipped. 2003/09/17 dirvish.conf.5 11.10 fix typo 2003/09/14 dirvish.pl 11.20 loadconfig.pl 11.13 TODO.html 11.14 Check to be sure that pre and post scripts are specified correctly (single value) in config file. Added whitespace after seppuku_prefix 2003/09/01 TODO.html 11.13 dirvish-expire.pl 11.11 fixed dirvish-expire --vault so it works Still need major rework. 2003/08/30 TODO.html 11.12 2003/08/29 dirvish.pl 11.19 11.18 loadconfig.pl 11.12 TODO.html 11.11 INSTALL 11.3 FAQ.html 11.3 dirvish.conf.5 11.9 Fix seppuku prefix so it is $vault:$branch:$image Added seppuku prefix variable so error messages will be suitably marked with the vault: Better reflect filesystem requirements in INSTALL and FAQ. 2003/08/03 dirvish-expire.pl 11.10 dirvish-locate.pl 11.9 dirvish-runall.pl 11.9 dirvish.pl 11.17 loadconfig.pl 11.11 COPYING 11.5 11.4 dirvish-expire.pl 11.9 dirvish-locate.pl 11.8 dirvish-runall.pl 11.8 dirvish.pl 11.16 loadconfig.pl 11.10 COPYING 11.3 Upgraded license to OSL 2.0 Changed License to OSL 1.1 2003/08/02 TODO.html 11.10 11.9 dirvish.8 11.5 dirvish.pl 11.15 Restructured TODO list so TODO items are grouped by program. Trim down on the documented command-line options. Just leave the ones that are specific to command-line usage or actually make sense on the command-line. 2003/08/01 TODO.html 11.8 dirvish-runall.pl 11.7 dirvish-runall.8 11.3 dirvish.8 11.4 dirvish-expire.8 11.3 dirvish-locate.8 11.4 TODO.html 11.7 dirvish-expire.pl 11.8 dirvish-locate.pl 11.7 dirvish-runall.pl 11.6 dirvish.pl 11.14 loadconfig.pl 11.9 Make exit code reflect number of failed jobs. Document exit code rationalisation. Added seppuku function so scripts may honorably pass after failure. It is a little like die() except it explicity sets the exit code and doesn't present debugging info. Rationalized exit codes. 2003/07/29 dirvish.pl 11.13 Eliminated the last '|| die' 2003/07/27 dirvish-expire.pl 11.7 dirvish-locate.pl 11.6 dirvish-runall.pl 11.5 dirvish.pl 11.12 loadconfig.pl 11.8 TODO.html 11.6 When looking for files use -f to test for their existance instead of -r. We are more likely to hit a directory with the same name than a file that isn't readable. 2003/07/25 dirvish.pl 11.11 Identified another "filesystem full" error message. 2003/07/18 TODO.html 11.5 2003/07/17 RELEASE.html 11.6 11.5 dirvish-runall.pl 11.4 dirvish.pl 11.10 dirvish-expire.pl 11.6 dirvish-locate.pl 11.5 RELEASE.html 11.4 dirvish.conf.5 11.8 Bring release notes up-to-date with (pre|post)-client logic inversion fix. 2003/07/16 dirvish.pl 11.9 TODO.html 11.4 install.sh 11.2 Dirvish-1.1.2 loadconfig.pl 11.7 Dirvish-1.1.2 COPYING 11.2 Dirvish-1.1.2 FAQ.html 11.2 Dirvish-1.1.2 INSTALL 11.2 Dirvish-1.1.2 RELEASE.html 11.3 Dirvish-1.1.2 TODO.html 11.3 Dirvish-1.1.2 dirvish-expire.8 11.2 Dirvish-1.1.2 dirvish-expire.pl 11.5 Dirvish-1.1.2 dirvish-locate.8 11.3 Dirvish-1.1.2 dirvish-locate.pl 11.4 Dirvish-1.1.2 dirvish-runall.8 11.2 Dirvish-1.1.2 dirvish-runall.pl 11.3 Dirvish-1.1.2 dirvish.8 11.3 Dirvish-1.1.2 dirvish.conf.5 11.7 Dirvish-1.1.2 dirvish.pl 11.8 Dirvish-1.1.2 Fix pre- and post-client. Had inverted logic regarding whether to use ssh or local shell. tagging 1.1.2 2003/07/15 dirvish.conf.5 11.6 loadconfig.pl 11.6 dirvish.conf.5 11.5 dirvish.pl 11.7 loadconfig.pl 11.5 Removed duplicate pre-server: entry Record actual config files loaded in summary, not aliases. Change loadconfig so that if filename is a relative path it will be looked for in the vault and then the system-wide configuration directories but not current working directory. This should make things a little more cron-friendly. 2003/07/10 dirvish.conf.5 11.4 loadconfig.pl 11.4 dirvish.8 11.2 loadconfig.pl 11.3 dirvish.pl 11.6 dirvish.conf.5 11.3 enhanced file-exclude to search config dirs if relative path is used. Fixed loadconfig recursion control. STDio filehandle redirect fixed. 2003/06/18 dirvish.pl 11.5 dirvish.conf.5 11.2 dirvish-expire.pl 11.4 Made the exclude file available to pre-server (James Neal) Improved error message. 2003/05/27 install.sh 11.1 Dirvish-1.1.1 loadconfig.pl 11.2 Dirvish-1.1.1 COPYING 11.1 Dirvish-1.1.1 FAQ.html 11.1 Dirvish-1.1.1 INSTALL 11.1 Dirvish-1.1.1 RELEASE.html 11.2 Dirvish-1.1.1 TODO.html 11.2 Dirvish-1.1.1 dirvish-expire.8 11.1 Dirvish-1.1.1 dirvish-expire.pl 11.3 Dirvish-1.1.1 dirvish-locate.8 11.2 Dirvish-1.1.1 dirvish-locate.pl 11.3 Dirvish-1.1.1 dirvish-runall.8 11.1 Dirvish-1.1.1 dirvish-runall.pl 11.2 Dirvish-1.1.1 dirvish.8 11.1 Dirvish-1.1.1 dirvish.conf.5 11.1 Dirvish-1.1.1 dirvish.pl 11.4 Dirvish-1.1.1 Dirvish 1.1.1 2003/05/22 dirvish.pl 11.3 TODO.html 11.1 Fixed meta-perm error resulting in perms of 000. 2003/05/20 loadconfig.pl 11.1 dirvish-expire.pl 11.2 dirvish.pl 11.2 Cleaned up warnings and error in file-exclude. 2003/05/19 dirvish-locate.8 11.1 dirvish-locate.pl 11.2 RELEASE.html 11.1 Changed pattern handling to make more intuitive and flexible. 2003/05/18 dirvish-expire.pl 11.1 dirvish-locate.pl 11.1 dirvish-runall.pl 11.1 dirvish.pl 11.1 install.sh 11.0 Dirvish-1.1 loadconfig.pl 11.0 Dirvish-1.1 RELEASE.html 11.0 Dirvish-1.1 TODO.html 11.0 Dirvish-1.1 dirvish-expire.8 11.0 Dirvish-1.1 dirvish-expire.pl 11.0 Dirvish-1.1 dirvish-locate.8 11.0 Dirvish-1.1 dirvish-locate.pl 11.0 Dirvish-1.1 dirvish-runall.8 11.0 Dirvish-1.1 dirvish-runall.pl 11.0 Dirvish-1.1 dirvish.8 11.0 Dirvish-1.1 dirvish.conf.5 11.0 Dirvish-1.1 dirvish.pl 11.0 Dirvish-1.1 COPYING 11.0 Dirvish-1.1 FAQ.html 11.0 Dirvish-1.1 INSTALL 11.0 Dirvish-1.1 Fixed version info on patches. Tagging 1.1 release 2003/05/06 dirvish-runall.pl 1.16 Dirvish-1.1rc2 dirvish.8 1.12 Dirvish-1.1rc2 dirvish.conf.5 1.34 Dirvish-1.1rc2 dirvish.pl 1.51 Dirvish-1.1rc2 install.sh 1.9 Dirvish-1.1rc2 loadconfig.pl 1.6 Dirvish-1.1rc2 COPYING 1.4 Dirvish-1.1rc2 FAQ.html 1.17 Dirvish-1.1rc2 INSTALL 1.13 Dirvish-1.1rc2 RELEASE.html 1.4 Dirvish-1.1rc2 TODO.html 1.36 Dirvish-1.1rc2 dirvish-expire.8 1.9 Dirvish-1.1rc2 dirvish-expire.pl 1.20 Dirvish-1.1rc2 dirvish-locate.8 1.3 Dirvish-1.1rc2 dirvish-locate.pl 1.3 Dirvish-1.1rc2 dirvish-runall.8 1.7 Dirvish-1.1rc2 description 1.7 TODO.html 1.35 Tagging 1.1rc2 Dropped the description file. Internally split the TODO list into TODO and wish lists. 2003/05/02 TODO.html 1.34 dirvish-locate.8 1.2 dirvish.pl 1.50 TODO.html 1.33 dirvish-locate.pl 1.2 dirvish.conf.5 1.33 Implemented tree aliases. 2003/05/01 dirvish.pl 1.49 Fixed typos in error message. 2003/04/30 FAQ.html 1.16 Tightened wording in section one of the FAQ. 2003/04/28 dirvish.conf.5 1.32 install.sh 1.8 FAQ.html 1.15 TODO.html 1.32 dirvish-locate.8 1.1 dirvish-locate.pl 1.1 dirvish.8 1.11 dirvish.conf.5 1.31 Typo in dirvish.conf.5 Created the dirvish-locate command. Dirvish-locate scans the index files to locate matching paths and displays their history. Very helpful for restores. 2003/04/24 dirvish.conf.5 1.30 dirvish.pl 1.48 Added log: option to allow compression of image logs. 2003/04/23 install.sh 1.7 1.6 INSTALL 1.12 Provide non-zero exit on error. typos in install.sh 2003/04/19 dirvish-expire.8 1.8 dirvish-runall.8 1.6 dirvish.conf.5 1.29 INSTALL 1.11 Dirvish-1.1rc1 RELEASE.html 1.3 Dirvish-1.1rc1 TODO.html 1.31 Dirvish-1.1rc1 description 1.6 Dirvish-1.1rc1 dirvish-expire.8 1.7 Dirvish-1.1rc1 dirvish-expire.pl 1.19 Dirvish-1.1rc1 dirvish-runall.8 1.5 Dirvish-1.1rc1 dirvish-runall.pl 1.15 Dirvish-1.1rc1 dirvish.8 1.10 Dirvish-1.1rc1 dirvish.conf.5 1.28 Dirvish-1.1rc1 dirvish.pl 1.47 Dirvish-1.1rc1 install.sh 1.5 Dirvish-1.1rc1 loadconfig.pl 1.5 Dirvish-1.1rc1 COPYING 1.3 Dirvish-1.1rc1 FAQ.html 1.14 Dirvish-1.1rc1 loadconfig.pl 1.4 COPYING 1.2 FAQ.html 1.13 INSTALL 1.10 RELEASE.html 1.2 TODO.html 1.30 description 1.5 dirvish-expire.8 1.6 dirvish-expire.pl 1.18 dirvish-runall.8 1.4 dirvish-runall.pl 1.14 dirvish.8 1.9 dirvish.conf.5 1.27 dirvish.pl 1.46 install.sh 1.4 INSTALL 1.9 RELEASE 1.4 RELEASE.html 1.1 TODO.html 1.29 dirvish.conf.5 1.26 Spelling fixes. Fix version stuff for 1.1rc2 Tagging 1.1rc1 fix errors in INSTALL instructions. Convert release notes to html. Manpage rephrasing 2003/04/16 dirvish.pl 1.45 1.44 1.43 Report failure to write to index. Bug fix: remove known bools from discrete summary. Report errors, not just fatal ones. 2003/04/10 dirvish.pl 1.42 Moved permissions option to top of boolean list. 2003/04/09 dirvish.pl 1.41 more status adjustments? 2003/04/08 dirvish-expire.pl 1.17 dirvish.pl 1.40 INSTALL 1.8 install.sh 1.3 dirvish.pl 1.39 dirvish.conf.5 1.25 RELEASE 1.3 dirvish.conf.5 1.24 dirvish.pl 1.38 loadconfig.pl 1.3 FAQ.html 1.12 Small change in status 20 install.sh is a little more verbose and cleans up if asked. Added perms option to support non-POSIX clients. Isolated stats into its own option to allow users to disable them. The rsync command is now invoked as an array for better argument passing. Clarity and typo fixes in FAQ. 2003/04/07 dirvish.pl 1.37 get fatal error messages to stderr to indicate branch. 2003/04/04 FAQ.html 1.11 TODO.html 1.28 dirvish.conf.5 1.23 dirvish.pl 1.36 loadconfig.pl 1.2 dirvish-expire.pl 1.16 dirvish.conf.5 1.22 dirvish-expire.pl 1.15 dirvish-runall.pl 1.13 dirvish.8 1.8 dirvish.conf.5 1.21 dirvish.pl 1.35 install.sh 1.2 loadconfig.pl 1.1 Added the SET and UNSET config directives for booleans added dry-run alias for no-run Better description of list vs scalar config format. laodconfig has been consolidated. 2003/04/03 dirvish-expire.pl 1.14 dirvish-runall.pl 1.12 dirvish.pl 1.34 dirvish-expire.pl 1.13 dirvish-runall.pl 1.11 dirvish.pl 1.33 INSTALL 1.7 TODO.html 1.27 dirvish-expire.pl 1.12 dirvish-runall.pl 1.10 dirvish.pl 1.32 install.sh 1.1 Try again Fixing permissions. First version of install.sh 2003/04/02 dirvish-runall.pl 1.9 dirvish-expire.pl 1.11 dirvish.pl 1.31 dirvish-expire 1.12 dirvish-runall 1.10 dirvish 1.32 renaming to *.pl for source consolidation by linking with make Renameing to *.pl support source code consolidation with make. 2003/03/29 dirvish 1.31 1.30 Print to stderr on non-check fatal errors. Vastly improved error handling. Now have some recognition of exit codes from rsync. 2003/03/28 dirvish 1.29 Fixed rsync options handling error. 2003/03/25 RELEASE 1.2 dirvish 1.28 dirvish-expire 1.11 dirvish-expire.8 1.5 dirvish-runall 1.9 dirvish-runall.8 1.3 dirvish.8 1.7 dirvish.conf.5 1.20 RELEASE 1.1 TODO.html 1.26 Restructured config file nameing. The master config file is now /etc/dirvish/master.conf and the config file used if a vault is specified without a branch is default.conf. Added release notes file. 2003/03/22 dirvish 1.27 dirvish.conf.5 1.19 Fixed (hopfully) pre-client and post-client to allow client to be on the same server. Check status of pre and post scripts and handle failure appropriately. 2003/03/20 dirvish 1.26 TODO.html 1.25 dirvish 1.25 dirvish.conf.5 1.18 TODO.html 1.24 dirvish.conf.5 1.17 Numeric IDs are now optional Changed documentation to reflect list/scalar limitation of loadconfig. 2003/03/17 dirvish.conf.5 1.16 TODO.html 1.23 dirvish.conf.5 1.15 Client same as server note. Added to BUGS the single/multi value parser bug. meta-perm security note. 2003/03/16 INSTALL 1.6 FAQ.html 1.10 Reflect changes in install procedure. Minor fixes to FAQ including... mbox vs. maildir and logfile rotation NFS over UDP error rates spelling adjustments (brit vs US?) punctuation and grammer fixes. 2003/01/28 FAQ.html 1.9 INSTALL 1.5 TODO.html 1.22 rsync 2.5.6 is released and fully supports dirvish without patches. 2002/12/28 dirvish-expire 1.10 Fixed sort order. 2002/11/27 dirvish 1.24 remove --force Doesn't apply because we aren't doing an rsync in-place. 2002/11/20 dirvish 1.23 Added --force to the default rsync options to deal with directories replaced by symlinks. 2002/11/12 FAQ.html 1.8 TODO.html 1.21 dirvish.conf.5 1.14 Minor documentation updates 2002/10/29 TODO.html 1.20 dirvish 1.22 dirvish-expire 1.9 dirvish-runall 1.8 dirvish 1.21 1.20 dirvish-expire 1.8 dirvish-runall 1.7 TODO.html 1.19 added $SYSCONFDIR to specify /etc location. Corrected "image already exists" error message. Stop printing line numbers when dying. User feedback and a couple of other ideas added to TODO 2002/09/27 description 1.4 FAQ.html 1.7 1.6 Enlarged disclaimer Documentation updates. link-dest option now in rsync CVS. 2002/09/24 dirvish 1.19 fixed bug in image-temp renameing. 2002/08/08 TODO.html 1.18 dirvish 1.18 TODO.html 1.17 dirvish 1.17 dirvish-runall.8 1.2 pre/post client scripts won't try to cd srctree if using rsyncd on client. Relocated vault:branch processing to getopt anon functions. 2002/05/15 TODO.html 1.16 dirvish 1.16 dirvish.conf.5 1.13 Added rsync-options field Fixed typos and older perl compatability issues. 2002/05/14 TODO.html 1.15 dirvish 1.15 dirvish.conf.5 1.12 If rsync errors are detected they will accumulate in rsync_error for each run. Added password-file field to dirvish.conf for rsyncd based transfer and enhanced tree: documentation to indicate support for same. 2002/05/07 TODO.html 1.14 dirvish-runall 1.6 dirvish-runall.8 1.1 Added commandline processing to dirvish-runall so it can now read Runall: parameter from an arbitrary file. Documented dirvish-runall 2002/05/01 TODO.html 1.13 dirvish 1.14 dirvish-expire 1.7 dirvish-expire.8 1.4 dirvish.8 1.6 dirvish.conf.5 1.11 Added nroff formatting to manpages. Small fixes. 2002/04/28 TODO.html 1.12 dirvish 1.13 dirvish-expire 1.6 dirvish-expire.8 1.3 dirvish-runall 1.5 dirvish.conf.5 1.10 dirvish 1.12 TODO.html 1.11 dirvish 1.11 dirvish-expire changes: added Status field in summary so dirvish can tell if an image is good. Added logic to dirvish-expire so that it won't delete last good image on a branch. Without this if backups fail for several days in a row it could get sticky doing a restore and you would have to rerun dirvish --init which is expensive. ... now handling errors with network failure. Fixed infinite loop around error retries. now handles 2002/04/27 TODO.html 1.10 dirvish 1.10 dirvish-expire 1.5 dirvish.8 1.5 dirvish.conf.5 1.9 Changed calculated values in summary to have initcap lables. WARNING: This breaks backward compatability for dirvish-expire. WARNING: expire: and image: have been changed to Expire: and Image: Added "summary" option to allow short or long summaries with @summary_fields holding list of ordered fields to be in short summaries. Added new summary fields "Enabled" and "Disabled" to report switch values. 2002/04/25 INSTALL 1.4 TODO.html 1.9 dirvish 1.9 dirvish.8 1.4 dirvish.conf.5 1.8 added rsh: parameter. 2002/04/24 TODO.html 1.8 dirvish 1.8 dirvish.conf.5 1.7 added index: configuration parameter. 2002/04/22 FAQ.html 1.5 INSTALL 1.3 TODO.html 1.7 description 1.3 dirvish 1.7 dirvish-expire 1.4 dirvish-runall 1.4 dirvish.conf.5 1.6 minor tweaks for expire: field in summary files spellcheck on docs and some updates to INSTALL and description to reflect changes. Note: Changes to TODO and FAQ and some other documentation are not recorded in changelogs. 2002/04/20 TODO.html 1.6 dirvish 1.6 dirvish.conf.5 1.5 Added config: parameter to loadconfig. loadconfig now checks for config file loops. 2002/04/19 TODO.html 1.5 dirvish 1.5 dirvish-expire 1.3 expire: in summary file now has two parts preserving intent. 2002/04/18 FAQ.html 1.4 TODO.html 1.4 description 1.2 dirvish 1.4 dirvish-runall 1.3 dirvish.8 1.3 dirvish.conf.5 1.4 Added loop structure around rsync execution. Now it can loop for correctable errors. Cleanup of pre and post script using runscript(). renamed dirvish.runall to dirvish-runall, Added Runall: parameter to global conf. 2002/04/14 FAQ.html 1.3 TODO.html 1.3 dirvish 1.3 dirvish.conf.5 1.3 added pre-server, pre-client, post-client, post-server config fields. added ID keywords branches: 1.1.1; Initial revision Dirvish backup system dirvish-1.2.1/dirvish-locate.pl0100664000076400007640000001244110205506717015777 0ustar keithlkeithl# $Id: dirvish-locate.pl,v 12.0 2004/02/25 02:42:14 jw Exp $ $Name: Dirvish-1_2 $ $VERSION = ('$Name: Dirvish-1_2 $' =~ /Dirvish/i) ? ('$Name: Dirvish-1_2 $' =~ m/^.*:\s+dirvish-(.*)\s*\$$/i)[0] : '1.1.2 patch' . ('$Id: dirvish-locate.pl,v 12.0 2004/02/25 02:42:14 jw Exp $' =~ m/^.*,v(.*:\d\d)\s.*$/)[0]; $VERSION =~ s/_/./g; ######################################################################### # # # Copyright 2003 and $Date: 2004/02/25 02:42:14 $ # Pegasystems Technologies and J.W. Schultz # # # # Licensed under the Open Software License version 2.0 # # # # This program is free software; you can redistribute it # # and/or modify it under the terms of the Open Software # # License, version 2.0 by Lauwrence E. Rosen. # # # # 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 Open Software License for details. # # # ######################################################################### use Time::ParseDate; use POSIX qw(strftime); use File::Find; use Getopt::Long; sub loadconfig; sub check_expire; sub findop; sub imsort; sub seppuku; $KILLCOUNT = 1000; $MAXCOUNT = 100; sub usage { my $message = shift(@_); length($message) and print STDERR $message, "\n\n"; print STDERR < \&usage, version => sub { print STDERR "dirvish version $VERSION\n"; exit(0); }, }; if ($CONFDIR =~ /dirvish$/ && -f "$CONFDIR.conf") { loadconfig(undef, "$CONFDIR.conf", $Options); } elsif (-f "$CONFDIR/master.conf") { loadconfig(undef, "$CONFDIR/master.conf", $Options); } elsif (-f "$CONFDIR/dirvish.conf") { seppuku 250, < $imdir, image => $$conf{Image}, branch => $$conf{branch}, created => $$conf{'Backup-complete'}, } } for $image (sort(imsort @images)) { $imdir = $$image{imdir}; $index = undef; -f "$imdir/index.bz2" and $index = "bzip2 -d -c $imdir/index.bz2|"; -f "$imdir/index.gz" and $index = "gzip -d -c $imdir/index|"; -f "$imdir/index" and $index = "<$imdir/index"; $index or next; ++$imagecount; open INDEX, $index or next; while () { chomp; m($partpattern) or next; # this parse operation is too slow. It might be faster as a # split with trimmed leading whitespace and remerged modtime $f = { image => $image }; ( $$f{inode}, $$f{blocks}, $$f{perms}, $$f{links}, $$f{owner}, $$f{group}, $$f{bytes}, $$f{mtime}, $path ) = m<^ \s*(\S+) # inode \s+(\S+) # block count \s+(\S+) # perms \s+(\S+) # link count \s+(\S+) # owner \s+(\S+) # group \s+(\S+) # byte count \s+(\S+\s+\S+\s+\S+) # date \s+(\S.*) # path $>x; $$f{perms} =~ /^[dl]/ and next; $path =~ m($fullpattern) or next; exists($match{$path}) or ++$pathcount; push @{$match{$path}}, $f; } if ($pathcount >= $KILLCOUNT) { printf "dirvish-locate: too many paths match pattern, interupting search\n"; last; } } printf "%d matches in %d images\n", $pathcount, $imagecount; $pathcount >= $MAXCOUNT and printf "Pattern '%s' too vague, listing paths only.\n", $Pattern; for $path (sort(keys(%match))) { $last = undef; print $path; if ($pathcount >= $MAXCOUNT) { print "\n"; next; } for $hit (@{$match{$path}}) { $inode = $$hit{inode}; $mtime = $$hit{mtime}; $image = $$hit{image}{image}; if ($inode ne $last) { $linesize = 5 + length($mtime) + length($image); printf "\n %s %s", $mtime, $image; } else { $linesize += length($image) + 2; if ($linesize > 78) { $linesize = 5 + length($mtime) + length($image); print "\n", " " x (5 + length($mtime)), $image; } else { printf ", %s", $$hit{image}{image}; } } $last = $inode; } print "\n\n"; } exit 0; sub imsort { $$a{branch} cmp $$b{branch} || $$b{created} cmp $$a{created}; } dirvish-1.2.1/TODO.html0100664000076400007640000001536110430416036014156 0ustar keithlkeithl Dirvish ToDo List

Dirvish ToDo List

List items are not in a prioritised order.

List item marks designate some intent.

  • to be done before next version.
  • normal.
  • ongoing.

dirvish

  • Allow vault[:branch] as an argument so --vault and --branch options aren't needed.
  • Enhance the password-file: parameter so that if given a relative path use the config-file search function (when written).
  • Add a --retry option for retrying a failed dirvish image.

    This would require pre-existance of destination image.

    Moves summary, log and rsync_error files into try.# directories.

  • Add a meta-owner parameter like meta-perm to specify a owner:group for meta-files in images.
  • Enhance recognition and assessment of rsync errors and warnings.

dirvish-expire

  • Allow vault[:branch] as an argument so --vault option isn't needed.
  • Move non-expiration notices to bottom of dirvish-expire output.
  • Put functionality for doing cleanups of hist files to deal with deleted backups somewhere in dirvish-expire. A possible approach would be for --histck to remove hist entries having no matching images on disk. --hist might remove hist entry during expiration but that would complicate things.
  • Rework to eliminate the internal find. Have dirvish-expire walk the vaults like dirvish-locate.
  • Improve internal logic to handle failed images better. Instead of using just sort order it should track a latest successful image to keep. Preferring an unexpired, but saving an expired one if no unexpired available.

dirvish-locate

  • Improve the performance of index file parsing.
  • Report all file dates with year even those without year in index.

dirvish-runall

  • Allow an optional timespec like expire-rule to make runall stansas conditional.

in general

  • Allow config-file search that searches bank/vault/dirvish/ also search /etc/dirvish/vault/ for files.
    Do this with a new function that can also be called for other file-based looking.
  • Add command-line options for non-interactive install.sh runs.
  • Add the ability to create an initial set of configs to install.sh.

Dirvish Wish List

These items are low-priority. It is recognised that they have merit and they have been given some thought but are, at present, not considered sufficiently important to invest the needed time. If a paying client wished one of them the priority would change but until that happens or the author's requirements change they are shelved.

  • Add a mechanism for dirvish and dirvish-expire to log their activity.

    This would probably a config parameter where you could either specify a file name or a syslog "facility" such as daemon or local3.

  • Create a dirvish-sync utility that could syncronize with a remote vault.

    Useful for secondary backup servers and removable hard drives used for offsites.

    This would examine the images in the specified vault. Remove those images from the destination that are not in the source. For each new image in creation order rsync the whole image with the best available reference image for the link-dest. Finish by rsyncing the dirvish directory if any.

  • Add option to run arbitrary command instead of rsync.

    This would allow dirvish to schedule jobs that don't involve rsync but belong under the same process management as the main backups. Having to maintain multiple backup systems and schedulers can be a pain.

  • Extend EXPIRE-RULES to support multi-stage actions

    The date specifier of an expire rule would contain a designator set elsewhere in the config file. The value of the designator (expire action) would be a list of date-specs and actions to be done.

    For example:

    expire-rule
    	wd { sun } md { 1-7 }               expire-monthly
    
    expire-monthly
    	+1 month	clean-tree clean_list
    	+6 months	delete-tree
    	+1 year		delete-image
    

    The actual format will probably differ and the image manager (dirvish-expire) will need to know what to do with the actions and record completion in the summary file to prevent repeats.

    Probable actions would be:
    delete-image delete whole image including metadata.
    delete-tree delete image tree leaving metadata.
    compress-tree create a compressed archive of the tree (tree.cpio.gz) and delete the tree.
    clean-tree lean the image tree by deleting files that match patterns in a file.
    run run an executable/script.

  • Add --replace and --inplace to config to allow overwriting of an existing image.

    If reference == image don't delete tree and don't use --link-dest.

    If reference != image and --replace, delete image before reuse because the delta from the reference image is most likely less than the reused image But if --inplace specified don't delete even if reference != image. Inplace is especially useful if the backup is incomplete and you wish to re-run it manually.

  • Create the scheduler.

    Most of the functionality is already documented in dirvish.conf(5) as comments not visible to man.

    The scheduler would generate a priority ordered run queue of jobs that can be run and launch as many would be permitted by the Max-jobs and Max-load limits. When a job completes recalculate whether any jobs still on the queue can run (window and limits) and launch them. If the queue is empty rescan for jobs that may now be runnable. Exit when there are no running or runnable jobs.

    The scheduler would use a /var/run/dirvish.pid file to prevent multiple dirvish-sched processes from running at once. The scheduler could be launched by cron at intervals.

  • Create a file security like facility

    This would examine the xfer log and report changed files after running them through a filter using include/exclude patterns or rules in a config file to eliminate expected changes. Excluded files (ones expected to change) might still be reported if they are suid/sgid.

    Deletes would not be detected this way because dirvish doesn't see them.

dirvish-1.2.1/INSTALL0100664000076400007640000000654210205510455013555 0ustar keithlkeithl INSTALLATION and GETTING STARTED #KHL 2005-02-18 removed "exclude core" error PREREQUISITES rsync version 2.5.6 or higher. rsync version 2.6.0 or higher may be needed if backing up windows. perl5 and these perl modules (if you aren't familiar with perl see CPAN(3pm)). POSIX Getopt::Long Time::ParseDate Time::Period by Patric Ryan Lots of empty disk space. I recommend using volume management (see lvm(8)). Ssh configured so root on the backup server can use ssh non-interactively to the backup clients. This does not necessarily mean it has to be able to be root on those clients. INSTALL Execute the install script "sh install.sh" from inside the unpack/download directory. The script will ask where to install the various pieces. Be sure you have write permissions for the installation directories. CONFIGURATION Dirvish will store the backup images in "vault"s. Plan on one vault per backup set. Create one or more directories as "bank"s in which to place the vaults. You can create a large filesystem for each bank but it is usually better to create a filesystem for each vault. Inside the banks create one mount-point directory (vault) for each backup set (ex: home). Start by making each filesystem about 1.5 times the size of the filesystem or directory tree it will be used to back up. Mount 'em up. The FAQ has additional details about how these filesystems should be built. create the file /etc/dirvish/master.conf on your backup server. It might look something like this: bank: /e/backup1 /e/backup2 exclude: lost+found/ *~ .nfs* Runall: app 22:00 data 22:00 home 22:00 site 22:00 expire-default: +15 days expire-rule: # MIN HR DOM MON DOW STRFTIME_FMT * * * * 1 +3 months * * 1-7 * 1 +1 year * * 1-7 1,4,7,10 1 * 10-20 * * * +4 days In each vault create a dirvish subdirectory. In the dirvish subdirectory of each vault create config files. To keep it simple here we will assume will only have one branch per vault and use the default configfile name; so create $BANK/$VAULT/dirvish/default.conf files. Here is an example from my home vault: client: leto tree: /e/home /home branch-default: daily exclude: /**/.*/**/*cache/ /**/.*/*cache/ /**/.*/**/*Cache/ .kde/share/thumbnails/ Now that you are configured create an initial image by running dirvish on the backup server like so: root# dirvish --vault home --init If you add the --no-run option you will see what it will try to do. To do a regular backup you now only would need to execute "dirvish --vault home" After you create your image you can look at the log and summary files to see what was done. I strongly recommend reading the dirvish and dirvish.conf manpages. Work on your exclude lists and have fun. dirvish.runall will run dirvish on all of the vault[:branch]s listed in the Runall list in /etc/dirvish.conf Because dirvish handles calculating expiration dates automatically you need only add two entries to crontab to completely automate your dirvish backups. 10 03 * * * root /site/sbin/dirvish-expire --quiet 18 03 * * * root /site/sbin/dirvish-runall --quiet Note that both dirvish-runall and dirvish-expire are scheduled after 22:00 as specified in the Runall: parameter. dirvish-1.2.1/dirvish-expire.pl0100664000076400007640000001302410205506717016022 0ustar keithlkeithl # $Id: dirvish-expire.pl,v 12.0 2004/02/25 02:42:14 jw Exp $ $Name: Dirvish-1_2 $ $VERSION = ('$Name: Dirvish-1_2 $' =~ /Dirvish/i) ? ('$Name: Dirvish-1_2 $' =~ m/^.*:\s+dirvish-(.*)\s*\$$/i)[0] : '1.1.2 patch' . ('$Id: dirvish-expire.pl,v 12.0 2004/02/25 02:42:14 jw Exp $' =~ m/^.*,v(.*:\d\d)\s.*$/)[0]; $VERSION =~ s/_/./g; ######################################################################### # # # Copyright 2002 and $Date: 2004/02/25 02:42:14 $ # Pegasystems Technologies and J.W. Schultz # # # # Licensed under the Open Software License version 2.0 # # # # This program is free software; you can redistribute it # # and/or modify it under the terms of the Open Software # # License, version 2.0 by Lauwrence E. Rosen. # # # # 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 Open Software License for details. # # # ######################################################################### use Time::ParseDate; use POSIX qw(strftime); use File::Find; use Getopt::Long; sub loadconfig; sub check_expire; sub findop; sub imsort; sub seppuku; sub usage { my $message = shift(@_); length($message) and print STDERR $message, "\n\n"; print STDERR < \&usage, version => sub { print STDERR "dirvish version $VERSION\n"; exit(0); }, }; if ($CONFDIR =~ /dirvish$/ && -f "$CONFDIR.conf") { loadconfig(undef, "$CONFDIR.conf", $Options); } elsif (-f "$CONFDIR/master.conf") { loadconfig(undef, "$CONFDIR/master.conf", $Options); } elsif (-f "$CONFDIR/dirvish.conf") { seppuku 250, < $expire_time and return 0; return 1; } sub findop { if ($_ eq 'tree') { $File::Find::prune = 1; return 0; } if ($_ eq 'summary') { my $summary; my ($etime, $path); $path = $File::Find::dir; $summary = loadconfig('R', $File::Find::name); $status = check_expire($summary, $expire_time); $status < 0 and return; $$summary{vault} && $$summary{branch} && $$summary{Image} or return; if ($status == 0) { $$summary{Status} =~ /^success/ && -d ($path . '/tree') and ++$unexpired{$$summary{vault}}{$$summary{branch}}; return; } -d ($path . ($$Options{tree} ? '/tree': undef)) or return; push (@expires, { vault => $$summary{vault}, branch => $$summary{branch}, client => $$summary{client}, tree => $$summary{tree}, image => $$summary{Image}, created => $$summary{'Backup-complete'}, expire => $$summary{Expire}, status => $$summary{Status}, path => $path, } ); } } ## WARNING: don't mess with the sort order, it is needed so that if ## WARNING: all images are expired the newest will be retained. sub imsort { $$a{vault} cmp $$b{vault} || $$a{branch} cmp $$b{branch} || $$a{created} cmp $$b{created}; } dirvish-1.2.1/dirvish-expire.80100664000076400007640000000647310205506717015570 0ustar keithlkeithl.\" $Id: dirvish-expire.8,v 12.0 2004/02/25 02:42:14 jw Exp $ $Name: Dirvish-1_2 $ .ds d \-\^\- .ds o \fR[\fP .ds c \fR]\fP .ds | \fR|\fP .ds bank \fIbank\fP .ds vault \fIvault\fP .ds branch \fIbranch\fP .ds image \fIimage\fP .de D \\.B \*d\\$1 .. .de DR \\.BR \*d\\$1 \\$2 .. .de Bi \\.BI \\$1 " \\$2" .. .de DI \\.BI \*d\\$1 \\$2 .. .de Di \\.BI \*d\\$1 " \\$2" .. .de See See \fB\\$1\fP for more details. .. .de SeeIn See \fB\\$1\fP in \fB\\$2\fP for more details. .. .de multiple Multiple \fB\\$1:\fP values will accumulate. .. .de default Default value: \fB\\$1\fP .. .TH DIRVISH-EXPIRE 8 .SH NAME dirvish\-expire \- delete expired dirvish images .SH SYNOPSIS .BI dirvish\-expire [OPTIONS] .SH DESCRIPTION Delete dirvish image trees or whole images that have expired. Each image .B summary file is checked for the .B Expire: field. If that field indicates the image has expired .B dirvish\-expire will delete that image from the vault. By default all subdirectories of all banks will be treated as vaults and all directories therein except the one named .B dirvish will be checked for summary files. The removal of an image will have no effect on other images. .B Dirvish\-expire will not delete an image unless it finds at least one image in that branch that has an intact image tree and .B "Status: success" in the summary that is not expired. .SH OPTIONS Each option on the command line may be specified any number of times. Those options that support lists in the config files will accumulate all of their arguments otherwise each specification will override the ones before. Each option may be unambiguously abbreviated. .TP .Di time time_expression Execute as though .I time_expression were the current time. .I Time_expression is processed by .B Time::Parsedate(3pm) so relative time and date strings are permitted. .See Time::Parsedate(3pm) .TP .D tree Only delete the image tree, leave in place the rest of the image directory with summary, log and any other image administrative files. .TP .Di vault vault Restrict expiration to the specified .IR vault . .TP .D no\-run Don't actually do anything. Just display what would have happened. .TP .D quiet Run quietly, only report errors. Normally .B dirvish\-expire will report the images deleted. .SH EXIT CODES To facilitate further automation and integration of .B dirvish-expire with other tools .B dirvish-expire provides rationalised exit codes. The exit codes are range based. While the code for a specific error may change from one version to another it will remain within the specified range. So don't test for specific exit codes but instead test for a range of values. To the degree possible higher value ranges indicate more severe errors. .TP 0 success .TP 200-219 An error was encountered in loading a configuration file. .TP 220-254 An error was detected in the configuration. .TP 255 Incorrect usage. .SH FILES .TP .B /etc/dirvish/master.conf alternate master configuration file. .TP .B /etc/dirvish.conf master configuration file. .TP .IB bank/vault/image/ summary image creation summary. .TP .IB bank/vault/image/ tree actual image of source directory tree. .SH SEE ALSO .nf dirvish.conf(5) Time::ParseDate(3pm) .SH BUGS .B Dirvish\-expire will walk the file hierarchy of all banks or the specified vault looking for summary files. Anything non-dirvish in there may cause excess file-walking. dirvish-1.2.1/COPYING0100664000076400007640000002326610205506717013567 0ustar keithlkeithlThe Open Software License v. 2.0 This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following notice immediately following the copyright notice for the Original Work: Licensed under the Open Software License version 2.0 1) Grant of Copyright License. Licensor hereby grants You a world-wide, royalty-free, non-exclusive, perpetual, sublicenseable license to do the following: a) to reproduce the Original Work in copies; b) to prepare derivative works ("Derivative Works") based upon the Original Work; c) to distribute copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute shall be licensed under the Open Software License; d) to perform the Original Work publicly; and e) to display the Original Work publicly. 2) Grant of Patent License. Licensor hereby grants You a world-wide, royalty-free, non-exclusive, perpetual, sublicenseable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, to make, use, sell and offer for sale the Original Work and Derivative Works. 3) Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor hereby agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work, and by publishing the address of that information repository in a notice immediately following the copyright notice that applies to the Original Work. 4) Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior written permission of the Licensor. Nothing in this License shall be deemed to grant any rights to trademarks, copyrights, patents, trade secrets or any other intellectual property of Licensor except as expressly stated herein. No patent license is granted to make, use, sell or offer to sell embodiments of any patent claims other than the licensed claims defined in Section 2. No right is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under different terms from this License any Original Work that Licensor otherwise would have a right to license. 5) External Deployment. The term "External Deployment" means the use or distribution of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether the Original Work or Derivative Works are distributed to those persons or made available as an application intended for use over a computer network. As an express condition for the grants of license hereunder, You agree that any External Deployment by You of a Derivative Work shall be deemed a distribution and shall be licensed to all under the terms of this License, as prescribed in section 1(c) herein. 6) Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. 7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately proceeding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to Original Work is granted hereunder except under this disclaimer. 8) Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to any person for any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to liability for death or personal injury resulting from Licensor's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. 9) Acceptance and Termination. If You distribute copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. Nothing else but this License (or another written agreement between Licensor and You) grants You permission to create Derivative Works based upon the Original Work or to exercise any of the rights granted in Section 1 herein, and any attempt to do so except under the terms of this License (or another written agreement between Licensor and You) is expressly prohibited by U.S. copyright law, the equivalent laws of other countries, and by international treaty. Therefore, by exercising any of the rights granted to You in Section 1 herein, You indicate Your acceptance of this License and all of its terms and conditions. This License shall terminate immediately and you may no longer exercise any of the rights granted to You by this License upon Your failure to honor the proviso in Section 1(c) herein. 10) Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, for patent infringement (i) against Licensor with respect to a patent applicable to software or (ii) against any entity with respect to a patent applicable to the Original Work (but excluding combinations of the Original Work with other software or hardware). 11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of the U.S. Copyright Act, 17 U.S.C. § 101 et seq., the equivalent laws of other countries, and international treaty. This section shall survive the termination of this License. 12) Attorneys Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. 13) Miscellaneous. This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. 14) Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 15) Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. This license is Copyright (C) 2003 Lawrence E. Rosen. All rights reserved. Permission is hereby granted to copy and distribute this license without modification. This license may not be modified without the express written permission of its copyright owner. dirvish-1.2.1/dirvish-runall.80100664000076400007640000000445610205506717015570 0ustar keithlkeithl.\" $Id: dirvish-runall.8,v 12.0 2004/02/25 02:42:14 jw Exp $ $Name: Dirvish-1_2 $ .ds d \-\^\- .ds o \fR[\fP .ds c \fR]\fP .ds | \fR|\fP .ds bank \fIbank\fP .ds vault \fIvault\fP .ds branch \fIbranch\fP .ds image \fIimage\fP .de D \\.B \*d\\$1 .. .de DR \\.BR \*d\\$1 \\$2 .. .de Bi \\.BI \\$1 " \\$2" .. .de DI \\.BI \*d\\$1 \\$2 .. .de Di \\.BI \*d\\$1 " \\$2" .. .de See See \fB\\$1\fP for more details. .. .de SeeIn See \fB\\$1\fP in \fB\\$2\fP for more details. .. .de multiple Multiple \fB\\$1:\fP values will accumulate. .. .de default Default value: \fB\\$1\fP .. .TH DIRVISH-RUNALL 8 .SH NAME dirvish\-runall \- run a set of dirvish backup jobs. .SH SYNOPSIS .BI dirvish\-runall [OPTIONS] .SH DESCRIPTION Run all the jobs specified in the .B Runall field of the dirvish master configuration file. .SH OPTIONS Each option may be unambiguously abbreviated. .TP .Di config configfile Read .I configfile for the .B Runall: field. By default .B dirvish\-runall will use the .B Runall: field from the master configuration file. This will only be used by .B dirvish-runall itself and not be propagated to the .B dirvish processes. .See dirvish.conf(5) .TP .D no\-run .TP .D dry\-run Don't actually do anything. Just display what would have happened. .TP .D quiet Run quietly, only report errors. Normally .B dirvish\-runall will report the dirvish commands invoked with timestamps. .TP .D version Print the version information and exit. .SH EXIT CODES To facilitate further automation and integration of .B dirvish-runall with other tools .B dirvish-runall provides rationalised exit codes. The exit codes are range based. While the code for a specific error may change from one version to another it will remain within the specified range. So don't test for specific exit codes but instead test for a range of values. To the degree possible higher value ranges indicate more severe errors. .TP 0 success .TP 1-199 Number of .B dirvish jobs that failed. If more than 199 jobs failed 199 will be the exit code. .TP 200-219 An error was encountered in loading a configuration file. .TP 220-254 An error was detected in the configuration. .TP 255 Incorrect usage. .SH FILES .TP .B /etc/dirvish/master.conf alternate master configuration file. .TP .B /etc/dirvish.conf master configuration file. .SH SEE ALSO .nf dirvish.conf(5) .SH BUGS dirvish-1.2.1/FAQ.html0100664000076400007640000005175110205506717014031 0ustar keithlkeithl Dirvish FAQ

Dirvish FAQ

General Questions

Is "Dirvish" an acronym?

No.

If you want to pretend it stands for Directory Virtual Storage Host or anything else you can invent go right ahead. I won't issue a fatwah.

back to top

Why the name?

Because what makes this backup system distinct is that it writes to spinning media. That reminded me of the whirling dervishes.

At first I rejected this for several reasons but I finally decided that it was just too anti-PC and anti-(so-called)-multi-cultural to resist.

Think it of a fast rotating backup system and take it for a spin.

back to top

Is there an dirvish icon or logo?

Not yet. I am not an artist. If you are and have an idea for one I'll be glad to consider it. While I won't pay you for your contribution I would give credit where due.

back to top

What is different about dirvish?

Dirvish uses cheap disk space to maintain the appearance of multiple copies of source file trees. Traditional backup systems write to tape.

back to top

What about disk mirrors?

Disk mirroring (RAID-1) and RAID-5 (not really mirroring) are good at protecting you from certain kinds of disk failure. Unfortunately they can't protect the data from human error, OS and hardware induced filesystem corruption, or anything that destroys the computer. For that you need a copy of the data that is isolated from the cause of failure.

Ideally the backup server should be in a different building.

back to top

What about backups on tape?

Look at the price of tape drives, robots and blank media. If you are already doing backups to tape, When was the last time a tape or tape drive failed? Compare that with the price and longevity of disk space, case and controllers.

By putting your dirvish server in a separate location from your production servers it becomes an off-site backup.

That said, you may still want to make tapes. With dirvish you can relegate tapes to off-site storage and long-term archive so you will make far fewer of them. And you can make the tapes from your backup server during working hours with no down-time.

back to top

What about network load?

If you have used network backup systems you may have seen the backups saturate your network. I know I have. Dirvish shouldn't do that.

Dirvish uses rsync for network transfer. Where an incremental tape backup requires only requires transmitting the changed files, dirvish only requires transmitting the changed parts of the changed files. So while the result is full backups every time, the volume of data sent is even less than incremental tape backups.

In fact the volume of data transferred can be sufficiently low that backups over the internet are feasible.

In some cases the network will actually be faster than the disk subsystems. When that is the case the whole-file parameter will actually improve overall performance at the expense of network load.

back to top

Why so many images, don't I only need one?

In an ideal world you wouldn't need any backups. I don't always know that I need a given file restored on the day it gets trashed. Often it will take several days before I even notice it. Most users are much worse. Someone deletes or modifies a file or deletes a whole directory and it turns out a few weeks later that someone else still needed it. One or two versions just don't cut it.

back to top

What does dirvish cost and how is it licensed?

Dirvish is free. The license is OSL.

I would like to know if dirvish is helping so if you are using it please let me know. Also let me know about any bugs you find or improvements you might come up with. I would be particularly interested in getting statistics on real-world capacity requirements.

back to top

Where can I get dirvish?

The dirvish home is http://www.pegasys.ws/dirvish. Questions, patches, feedback etc can be sent to dirvish@pegasys.ws. At this time there is no mailing list but if you let me know you are using it i can add your email address to a confidential list and notify you of any bug fixes, security issues and upgrades.

back to top

Capacity Questions

How much space do I need for dirvish?

A reasonable rotation program should need about one and half to three times the space of the original filesystem. This is very dependant on the rate of change for a given directory tree and the number and age-range of images in the rotation.

Consideration should be given to the nature and probable change rates of a given backup area and the value of older data. Project areas and home directories may have relatively low rates of change but are subject to sudden spikes and their data is important enough to retain for extended periods. Conversely /var has a high change rate but the data is really only valuable for one or two days. So a vault for /home might want thrice the space of the production area to hold images ranging from one to three months or longer while /var may only need fifty percent more space in it's vault and be expired after 2 or three days.

back to top

How should I build the filesystems for dirvish?

Dirvish can back up almost any filesystem. Only the vaults on the backup server have any specific requirements.

Only regular files will be shared between images. Device nodes, symlinks, directories and other file types will be recreated for each image. This means that there will be a lot more inodes used in a vault than the source filesystem.

The best filesystem type for dirvish would be one that doesn't set a fixed number of inodes at build time. The vaults will also need to be built with a filesystem type that supports hard links.

While a journaling filesystem is a recommended the journals can have an adverse affect on performance. Dirvish and dirvish-expire do a lot of filesystem meta-data changes. This will stress the journal which in some cases is not as well optimized as one would like. Experience has shown that some journaling filesystems perform extremely poorly under dirvish. While no benchmarks have been made the difference in speed has been as high as 10:1. I would not recommend data journaling.

Using a filesystem type that allows resizing makes it much easier to adapt to the real world requirements of each backup set.

If you are building filesystems with a fixed number of inodes such as UFS or ext2 you should create the filesystem with a bytes per inode value that is half or even just a quarter of what you would normally. Because directories will not be shared it may be good to use a smaller block or fragment size to reduce internal fragmentation.

I would also recommend using RAID-5 arrays for the vaults. You are going to have a great deal of important data here and disk-fault tolerance is a good idea. RAID-5 isn't nearly as expensive as mirroring and should be more than fast enough. Logical Volume management is also a good idea for the vaults as you will probably wish to resize some of them over time.

back to top

With so many images, won't it use too much disk?

Because dirvish shares unchanged files between images the actual disk space used is considerably less than you might think. For most filesystems only a small percentage of files will change over a period of time.

The dirvish-expire utility will automatically delete old images based on their assigned expiration date. If you execute this regularly (see cron) each vault will soon reach a steady state where it grows very slowly in response to the growth of the clients.

back to top

Could linking between images be limited by a maximum link count?

Yes. But you are unlikely to ever come close to the limits.

Linux Filesystem
link limits

126xenix
126sysv
250minix
10,000coherent
32,000ufs
32,000ext2
64,535reiserfs
65,530minix2
65,535jfs
65,535
2,147,483,647
xfs
   I can remember a version of UFS that had a link count limit of 1023 but I doubt current versions are so limited. I haven't checked the commercial UNIXes but an examination of the 2.4 Linux kernel source shows that link counts are stored in an unsigned short so in theory would be limited to 65535. The 2.6 kernel is expected to raise this limit and use unsigned long (32 bit). Each filesystem type has it's own limit as shown in the table. Performing a quick test I determined that indeed I could create exactly 32000 hard links of a file on ext2.

What this means is that on most of the filesystems even if you had a file with 100 hard links (busybox perhaps) you could still support over 300 images sharing those links.

In the event you are using a filesystem type that has a risk of hitting the limit you could change hard links on the client to symlinks. None of these filesystems have limits lower than 126.

back to top

How can I save space?

First make sure you aren't backing up useless files. The exclude patterns can help there.

Look at the dirvish logs. They will show you what is changing. When I first started using dirvish I found web browser caches were a constant source of change. There was no reason to back them up so I added exclude patterns to block them. Spool areas are similar sources of waste.

Set reasonable expire-rules in the configuration files.

Some applications provide choices regarding file layout. A particularly good example is email. Because a changed file is not shared large mbox mail folders that change daily can be responsible for a considerable amount of backup space. Transitioning to maildir format means more small files but those files can be shared across images as long as they remain in the same status and folder. Such applications often have global configuration files in which system administrator can set a desired default that most users will not override. Similarly there can be an advantage to rotating log files more often.

Examine the logs. Some services will create log files in places you don't expect. Adding them to the exclude list is a workaround. Moving them to /var will correct the problem and make your system more robust.

back to top

Why would dirvish suddenly need more space?

Because dirvish saves space by sharing unchanged files across multiple images changing many files will cause dirvish's disk usage to spike.

Some of the things that can cause this are:

  • updating a software package.
  • restoring a directory tree without preserving timestamps and permissions.
  • recursive chown, chgrp or chmod.
  • sometimes users will update lots of files all at once.
  • relocating or renaming a directory.
  • leaving a temporary file around overnight.
It really is a good idea to have enough free space to weather a usage spike.

back to top

I'm running out of space what do I do?

Delete images.

Usually it is the same files that change over and over. Because of this deleting intermediate images may save nearly as much space as deleting old images.

Really old images can be archived to removable media and then deleted.

Sometimes the pressure is transient. A spike may be the result of one image having captured a temporary file such as a web download. In such a case the spike will go away with that one image. If someone recently changed a large number of files that will cause a spike in the disk usage. Such a spike will form a new plateau until the older images are expired.

If your rotation just won't fit examine your exclude lists, expiration rules and consider adding backup space.

back to top

What about compression?

Compression is a wonderful thing but one of dirvish's primary goals is transparency. If dirvish compressed files you couldn't do a transparent restore.

Because of the file sharing between images compressing individual images into compressed archives is unlikely to save you space and will break the transparency. Experience has shown that the disk usage of dirvish is vastly less than that of compressed snapshots.

It may be worthwhile to use a filesystem that supports transparent compression such as e2compr for some vaults.

It is worth remembering that more and more applications are storing their data in compressed formats such as jpg, ogg, mpeg and gzip'ed XML (office suites). If the files are already compressed it won't save space storing them on a compressed filesystem or compressing them externally. These compressed format files will also defeat the hardware compression found on tape drives.

back to top

What will dirvish do if it runs out of space?

Dirvish will output a message to STDERR that it thinks it may have run out of space and will remove the incomplete destination tree. The meta-data including log files will be left to assist with debugging.

back to top

What should I do if dirvish runs out of space?

First, delete any failed image. If dirvish actually runs out of space and cannot complete a backup image that image should be deleted. It will be missing files and have other problems that would cause successive images to not share correctly.

You may wish to delete some of your images or enlarge your vault filesystem. That is of course your call.

See the section on running out of space

back to top

Questions about use

How much maintenance does dirvish require?

Very little.

Dirvish, dirvish-runall and dirvish-expire will report errors when detected. Running them under cron, even in quiet mode will still cause email notification on error.

Dirvish-expire will use the expire options to manage the rotation of images automatically. That mainly just leaves monitoring the disk space to ensure that you don't run out of room and making archives.

back to top

How do I restore from dirvish?

Each image is a complete copy of what existed at the time it was made so all that is needed to restore from an image is to copy the files. It is essential to preserve ownership, permissions and modification time of restored files.

Rsync is a very good way but scp or streaming tar or cpio archives from the backup server will work as well.

It is also possible to do a read-only export of a dirvish vault using a network file system such as NFS or CIFS/SMB. This or network mounting the source directories on the backup server will allow the use of a simple copy command to restore files. It should be remembered that NFS over UDP does have a measurable error rate so exercise caution doing large restores over NFS. The permissions of all the files in a vault are the same as the source location so there is little security risk to doing so. It might however be better not to give users access to this as it will encourage lazy habits.

back to top

How can I find what versions of my files exist?

That is the purpose of the dirvish-locate command.

You first need to identify the file you are looking for. Examine the source tree or one of the dirvish indexes (you instructed dirvish to create indexes, right?). Optimally you want a perl regex pattern that will only find the file you want.

Let us suppose i'm looking for a version of my .muttrc file. I would use the pattern /jw/.muttrc The slashes have no special meaning and the pattern is anchored the at the end so this won't match a .muttrc.orig file. The dirvish-locate command would look like this:

# dirvish-locate home '/jw/.muttrc'
2 matches in 29 images
/e/home/jw/.muttrc
    Apr  9 18:38 030427, 030426, 030425, 030424, 030423, 030422, 030421
                 030420, 030419, 030418, 030417, 030416, 030415, 030414
                 030413
    Mar 26 22:24 030406
    Mar 26 22:24 030403, 030330
    Mar 15 06:09 030323, 030316
    Mar  9 17:26 030309
    Jan 14 21:46 030223, 030216, 030209, 030202
    Oct  5 18:20 030105, 021103
    Oct  5 18:20 021006
    Aug 17 20:15 020901
From this we can see a partial history of that file. Now i don't have to look in every image to find the version i want. I can either pick a version or look at one image per version to decide which one i really want to restore.

back to top

How can I make archives from dirvish?

You can use any utility that will make an archive from a directory. Feel free to use tar, cpio or dump. It is even reasonable to burn CDs or DVDs if your data will fit. The nice thing is that this won't interact with the production systems so you can do this during working hours.

back to top

Does dirvish support database backups?

Dirvish supports arbitrary pre and post processing commands on the client and server. This means that you can pause a database during backups or have dirvish create a database dump just prior to backing up the dump directory.

back to top

What do I need to run dirvish?

  • Unix or Linux server
  • Perl 5 and these perl modules
    • File::Find
    • Getopt::Long
    • POSIX
    • Time::ParseDate
    • Time::Period
  • rsync version 2.5.6 or higher.

back to top

Can i use an rsync daemon?

Dirvish can connect to an rsync daemon running on the clients just fine. Specifying the tree parameter with a colon prefix will direct the dirvish to connect to a rsync daemon.

back to top dirvish-1.2.1/dirvish-runall.pl0100664000076400007640000000601010205506717016020 0ustar keithlkeithl # $Id: dirvish-runall.pl,v 12.0 2004/02/25 02:42:14 jw Exp $ $Name: Dirvish-1_2 $ $VERSION = ('$Name: Dirvish-1_2 $' =~ /Dirvish/i) ? ('$Name: Dirvish-1_2 $' =~ m/^.*:\s+dirvish-(.*)\s*\$$/i)[0] : '1.1.2 patch' . ('$Id: dirvish-runall.pl,v 12.0 2004/02/25 02:42:14 jw Exp $' =~ m/^.*,v(.*:\d\d)\s.*$/)[0]; $VERSION =~ s/_/./g; ######################################################################### # # # Copyright 2002 and $Date: 2004/02/25 02:42:14 $ # Pegasystems Technologies and J.W. Schultz # # # # Licensed under the Open Software License version 2.0 # # # # This program is free software; you can redistribute it # # and/or modify it under the terms of the Open Software # # License, version 2.0 by Lauwrence E. Rosen. # # # # 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 Open Software License for details. # # # ######################################################################### use Time::ParseDate; use POSIX qw(strftime); use Getopt::Long; sub loadconfig; sub seppuku; sub usage { my $message = shift(@_); length($message) and print STDERR $message, "\n\n"; $! and exit(255); # because getopt seems to send us here for death print STDERR < sub { print STDERR "dirvish version $VERSION\n"; exit(0); }, help => \&usage, }; GetOptions($Options, qw( config=s quiet no-run|dry-run version help )) or usage; if ($$Options{config}) { $Config = loadconfig(undef, $$Options{config}) } elsif ($CONFDIR =~ /dirvish$/ && -f "$CONFDIR.conf") { $Config = loadconfig(undef, "$CONFDIR.conf"); } elsif (-f "$CONFDIR/master.conf") { $Config = loadconfig(undef, "$CONFDIR/master.conf"); } elsif (-f "$CONFDIR/dirvish.conf") { seppuku 250, <