Add error-code ignoring options to atomic-rsync.

This commit is contained in:
Wayne Davison
2021-12-30 12:29:14 -08:00
parent 8e77ece0ee
commit 13cfe6406f
2 changed files with 45 additions and 21 deletions

13
NEWS.md
View File

@@ -97,7 +97,7 @@
- More ASM optimizations from Shark64.
- Transformed rrsync into a python script with improvements:
- Transformed support/rrsync into a python script with improvements:
- Security has been beefed up.
- The known rsync options were updated to include recent additions.
- Make rrsync reject `-L`, `-K`, & `-k` by default to make it harder to
@@ -112,6 +112,17 @@
and to output the command executed as a tuple (making the args clearer).
- An rrsync.1 manpage was added.
- Added options to support/lsh to allow the rrsync script to be easily tested.
- Transformed support/atomic-rsync into a python script and added the ability
to ignore one or more non-zero exit codes. By default, it now ignores code
24 (file vanished).
- Improved support/rsync-no-vanished wrapper script to not join stdout &
stderr together.
- Transformed support/munge-symlinks into a python script.
- Work around a glibc bug where lchmod() breaks in a chroot w/o /proc mounted.
- Some manpage improvements.

View File

@@ -29,6 +29,13 @@ def main():
if bad_args:
die("You cannot use the", ' or '.join(bad_args), "option with atomic-rsync.\nUse --help for help.")
# We ignore exit-code 24 (file vanished) by default.
allowed_exit_codes = '0 ' + os.environ.get('ATOMIC_RSYNC_OK_CODES', '24')
try:
allowed_exit_codes = set(int(num) for num in re.split(r'[, ]+', allowed_exit_codes) if num != '')
except ValueError:
die('Invalid integer in ATOMIC_RSYNC_OK_CODES:', allowed_exit_codes[2:])
symlink_content = os.readlink(dest_dir) if os.path.islink(dest_dir) else None
dest_arg = dest_dir
@@ -55,14 +62,18 @@ def main():
if os.path.isdir(new_dir):
shutil.rmtree(new_dir)
subprocess.run([RSYNC_PROG, '--link-dest=' + dest_dir, *cmd_args], check=True)
child = subprocess.run([RSYNC_PROG, '--link-dest=' + dest_dir, *cmd_args])
if child.returncode not in allowed_exit_codes:
die('The rsync copy failed with code', child.returncode, exitcode=child.returncode)
if not os.path.isdir(new_dir):
die('The rsync copy failed to create:', new_dir)
if old_dir is None:
atomic_symlink(symlink_content, dest_arg)
return
os.rename(dest_dir, old_dir)
os.rename(new_dir, dest_dir)
else:
os.rename(dest_dir, old_dir)
os.rename(new_dir, dest_dir)
def atomic_symlink(target, link):
@@ -89,22 +100,24 @@ to a local directory, and that directory must already exist. For example:
ln -s files-1 /local/files
atomic-rsync -aiv host:/remote/files/ /local/files/
If /local/files is a symlink to a directory that ends in -1 or -2, the
copy will go to the alternate suffix and the symlink will be changed to
point to the new dir. This is a fully atomic update. If the destination
is not a symlink (or not a symlink to a *-1 or a *-2 directory), this
will instead create a directory with "~new~" suffixed, move the current
directory to a name with "~old~" suffixed, and then move the ~new~
directory to the original destination name (this double rename is not
fully atomic, but is rapid). In both cases, the prior destintaion
directory will be preserved until the next update, at which point it
will be deleted.
If /local/files is a symlink to a directory that ends in -1 or -2, the copy
will go to the alternate suffix and the symlink will be changed to point to
the new dir. This is a fully atomic update. If the destination is not a
symlink (or not a symlink to a *-1 or a *-2 directory), this will instead
create a directory with "~new~" suffixed, move the current directory to a
name with "~old~" suffixed, and then move the ~new~ directory to the original
destination name (this double rename is not fully atomic, but is rapid). In
both cases, the prior destintaion directory will be preserved until the next
update, at which point it will be deleted.
In all likelihood, you do NOT want to specify this command:
By default, rsync exit-code 24 (file vanished) is allowed without halting the
atomic update. If you want to change that, specify the environment variable
ATOMIC_RSYNC_OK_CODES with numeric values separated by spaces and/or commas.
Specify an empty string to only allow a successful copy. An override example:
atomic-rsync -aiv host:/remote/files /local/
ATOMIC_RSYNC_OK_CODES='23 24' atomic-rsync -aiv host:src/ dest/
... UNLESS you want the entire /local dir to be swapped out!
See the errcode.h file for a list of all the exit codes.
See the "rsync" command for its list of options. You may not use the
--link-dest, --compare-dest, or --copy-dest options (since this script
@@ -114,9 +127,9 @@ uses --link-dest to make the transfer efficient).
sys.exit(1 if use_stderr else 0)
def die(*args):
def die(*args, exitcode=1):
print(*args, file=sys.stderr)
sys.exit(1)
sys.exit(exitcode)
if __name__ == '__main__':