summaryrefslogtreecommitdiff
path: root/support/atomic-rsync
diff options
context:
space:
mode:
authorWayne Davison <wayned@samba.org>2005-01-06 17:13:31 +0000
committerWayne Davison <wayned@samba.org>2005-01-06 17:13:31 +0000
commitfa170b2e5a684891e6b31f7fcf31b545f5db2fcf (patch)
treeea377b316b6dc1faffbda847dc2a945a157ca133 /support/atomic-rsync
parentc61ba345f25c053377b42c49d84a535b0b1af393 (diff)
downloadrsync-fa170b2e5a684891e6b31f7fcf31b545f5db2fcf.tar.gz
rsync-fa170b2e5a684891e6b31f7fcf31b545f5db2fcf.tar.bz2
rsync-fa170b2e5a684891e6b31f7fcf31b545f5db2fcf.zip
A perl script to effect an atomic transfer of a set of files.
Diffstat (limited to 'support/atomic-rsync')
-rwxr-xr-xsupport/atomic-rsync74
1 files changed, 74 insertions, 0 deletions
diff --git a/support/atomic-rsync b/support/atomic-rsync
new file mode 100755
index 00000000..4173abe9
--- /dev/null
+++ b/support/atomic-rsync
@@ -0,0 +1,74 @@
+#!/usr/bin/perl
+
+use strict;
+use Cwd 'abs_path';
+
+my $RSYNC = '/usr/bin/rsync';
+
+my $dest_dir = $ARGV[-1];
+usage(1) if $dest_dir eq '' || $dest_dir =~ /^--/;
+
+if (!-d $dest_dir) {
+ print STDERR "$dest_dir is not a directory.\n\n";
+ usage(1);
+}
+
+if (@_ = grep(/^--(link|compare)-dest/, @ARGV)) {
+ $_ = join(' or ', @_);
+ print STDERR "You may not use $_ as an rsync option.\n\n";
+ usage(1);
+}
+
+$dest_dir = abs_path($dest_dir);
+if ($dest_dir eq '/') {
+ print STDERR 'You must not use "/" as the destination directory.', "\n\n";
+ usage(1);
+}
+
+my $old_dir = "$dest_dir~old~";
+my $new_dir = $ARGV[-1] = "$dest_dir~new~";
+
+if (-d $old_dir) {
+ rename($old_dir, $new_dir) or die "Unable to rename $old_dir to $new_dir: $!";
+}
+
+if (system($RSYNC, "--link-dest=$dest_dir", @ARGV)) {
+ if ($? == -1) {
+ print "failed to execute $RSYNC: $!\n";
+ } elsif ($? & 127) {
+ printf "child died with signal %d, %s coredump\n",
+ ($? & 127), ($? & 128) ? 'with' : 'without';
+ } else {
+ printf "child exited with value %d\n", $? >> 8;
+ }
+ exit $?;
+}
+
+rename($dest_dir, $old_dir) or die "Unable to rename $new_dir to $old_dir: $!";
+rename($new_dir, $dest_dir) or die "Unable to rename $new_dir to $dest_dir: $!";
+
+exit;
+
+
+sub usage
+{
+ my($ret) = @_;
+ my $fh = $ret ? *STDERR : *STDOUT;
+ print $fh <<EOT;
+Usage: atomic-rsync [RSYNC-OPTIONS] HOST:SOURCE DEST
+
+This script allows you to pull some files into DEST on the local system
+(which must exist) in an atomic manner. It does this by first pulling
+files to DEST~new~ (using hard-links to unchanged files in order to keep
+the space requirements down), and then, at the end of the transfer, it
+renames DEST to DEST~old~ and renames DEST~new~ to DEST to effect the
+atomic update. The DEST~old~ hierarchy will be preserved until the next
+run of this script, at which point it will be renamed to DEST~new~ and
+used in the copy.
+
+See the "rsync" command for its list of options. You may not use the
+--link-dest or --compare-dest options (since this script uses --link-dest
+to effect the atomic transfer). Also, DEST cannot be "/".
+EOT
+ exit $ret;
+}