diff options
Diffstat (limited to 'support')
-rwxr-xr-x | support/cvs2includes | 85 | ||||
-rwxr-xr-x | support/files-to-excludes | 58 | ||||
-rwxr-xr-x | support/idmap | 45 | ||||
-rwxr-xr-x | support/json-rsync-version | 2 | ||||
-rwxr-xr-x | support/mapfrom | 15 | ||||
-rwxr-xr-x | support/mapto | 15 | ||||
-rwxr-xr-x | support/mnt-excl | 48 | ||||
-rwxr-xr-x | support/rrsync | 4 | ||||
-rw-r--r-- | support/rrsync.1.md | 7 |
9 files changed, 172 insertions, 107 deletions
diff --git a/support/cvs2includes b/support/cvs2includes index fc7f78f..4a0d1d8 100755 --- a/support/cvs2includes +++ b/support/cvs2includes @@ -1,42 +1,63 @@ -#!/usr/bin/env perl -# +#!/usr/bin/env python3 # This script finds all CVS/Entries files in the current directory and below # and creates a local .cvsinclude file with non-inherited rules including each # checked-in file. Then, use this option whenever using --cvs-exclude (-C): # -# -f ': .cvsinclude' +# -f ': .cvsinclude' # # That ensures that all checked-in files/dirs are included in the transfer. # (You could alternately put ": .cvsinclude" into an .rsync-filter file and # use the -F option, which is easier to type.) # # The downside is that you need to remember to re-run cvs2includes whenever -# you add a new file to the project. -use strict; - -open(FIND, 'find . -name CVS -type d |') or die $!; -while (<FIND>) { - chomp; - s#^\./##; - - my $entries = "$_/Entries"; - s/CVS$/.cvsinclude/; - my $filter = $_; - - open(ENTRIES, $entries) or die "Unable to open $entries: $!\n"; - my @includes; - while (<ENTRIES>) { - push(@includes, $1) if m#/(.+?)/#; - } - close ENTRIES; - if (@includes) { - open(FILTER, ">$filter") or die "Unable to write $filter: $!\n"; - print FILTER map "+ /$_\n", @includes; - close FILTER; - print "Updated $filter\n"; - } elsif (-f $filter) { - unlink($filter); - print "Removed $filter\n"; - } -} -close FIND; +# CVS gets an added or removed file. Maybe just run it before every copy. + +import os, argparse + +INC_NAME = '.cvsinclude' + +def main(): + if args.dir: + os.chdir(args.dir) + + cvs_includes = set() + for root, dirs, files in os.walk('.'): + if INC_NAME in files: + cvs_includes.add((root + '/' + INC_NAME)[2:]) + if root.endswith('/CVS') and 'Entries' in files: + entries = root[2:] + '/Entries' + includes = [ ] + with open(entries) as fh: + for line in fh: + if line.startswith(('/', 'D/')): + includes.append(line.split('/', 2)[1]) + if includes: + inc = root[2:-3] + INC_NAME + cvs_includes.discard(inc) + try: + with open(inc) as fh: + old_txt = fh.read() + except OSError: + old_txt = '' + txt = ''.join(f"+ /{x}\n" for x in includes) + if txt == old_txt: + print("Unchanged", inc) + else: + print("Updating", inc) + with open(inc, 'w') as fh: + fh.write(txt) + dirs.sort() + + for inc in sorted(cvs_includes): + print("Removing", inc) + os.unlink(inc) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description=f"Transform CVS/Entries into {INC_NAME} files.", add_help=False) + parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.") + parser.add_argument("dir", nargs='?', help="The top CVS dir. Defaults to the current directory.") + args = parser.parse_args() + main() + +# vim: sw=4 et diff --git a/support/files-to-excludes b/support/files-to-excludes index a28955c..a47d7f8 100755 --- a/support/files-to-excludes +++ b/support/files-to-excludes @@ -1,27 +1,37 @@ -#!/usr/bin/env perl -# This script takes an input of filenames and outputs a set of -# include/exclude directives that can be used by rsync to copy -# just the indicated files using an --exclude-from=FILE option. -use strict; +#!/usr/bin/env python3 +# This script takes an input of filenames and outputs a set of include/exclude +# directives that can be used by rsync to copy just the indicated files using +# an --exclude-from=FILE or -f'. FILE' option. To be able to delete files on +# the receiving side, either use --delete-excluded or change the exclude (-) +# rules to hide filter rules (H) that only affect the sending side. -my %hash; +import os, fileinput, argparse -while (<>) { - chomp; - s#^/+##; - my $path = '/'; - while (m#([^/]+/)/*#g) { - $path .= $1; - print "+ $path\n" unless $hash{$path}++; - } - if (m#([^/]+)$#) { - print "+ $path$1\n"; - } else { - delete $hash{$path}; - } -} +def main(): + paths = set() + for line in fileinput.input(args.files): + dirs = line.strip().lstrip('/').split('/') + if not dirs: + continue + for j in range(1, len(dirs)): + if dirs[j] == '': + continue + path = '/' + '/'.join(dirs[:j]) + '/' + if path not in paths: + print('+', path) + paths.add(path) + print('+', '/' + '/'.join(dirs)) -foreach (sort keys %hash) { - print "- $_*\n"; -} -print "- /*\n"; + for path in sorted(paths): + print('-', path + '*') + print('-', '/*') + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description="Transform a list of files into a set of include/exclude rules.", add_help=False) + parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.") + parser.add_argument("files", metavar="FILE", default='-', nargs='*', help="The file(s) that hold the pathnames to translate. Defaults to stdin.") + args = parser.parse_args() + main() + +# vim: sw=4 et diff --git a/support/idmap b/support/idmap new file mode 100755 index 0000000..b212aaf --- /dev/null +++ b/support/idmap @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# This helper script makes it easy to use a passwd or group file to map values +# in a LOCAL transfer. For instance, if you mount a backup that does not have +# the same passwd setup as the local machine, you can do a copy to/from the +# backup area as follows and get the differing ID values mapped just like a +# remote transfer to/from the backed-up machine would do: +# +# rsync -av --usermap=`idmap --to /mnt/backup/etc/passwd` \ +# --groupmap=`idmap --to /mnt/backup/etc/group` \ +# /some/src/ /mnt/backup/some/dest/ +# +# rsync -av --usermap=`idmap --from /mnt/backup/etc/passwd` \ +# --groupmap=`idmap --from /mnt/backup/etc/group` \ +# /mnt/backup/some/src/ /some/dest/ + +import re, fileinput, argparse + +NAME_ID_RE = re.compile(r'^(\w+):[^:]+:(\d+)') + +def main(): + maps = [ ] + for line in fileinput.input(args.files): + m = NAME_ID_RE.match(line) + if not m: + continue + if args.to: + pair = (m[1], m[2]) + else: + pair = (m[2], m[1]) + maps.append(':'.join(pair)) + print(','.join(maps)) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description="Output usermap or groupmap args for rsync.", add_help=False) + action = parser.add_argument_group() + action = parser.add_mutually_exclusive_group(required=True) + action.add_argument("--from", action="store_true", help="Output the map for use on the sending side.") + action.add_argument("--to", action="store_true", help="Output the map for use on the receiving side.") + parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.") + parser.add_argument("files", metavar="FILE", default='-', nargs='*', help="The file(s) that hold the name & id pairs. Defaults to stdin.") + args = parser.parse_args() + main() + +# vim: sw=4 et diff --git a/support/json-rsync-version b/support/json-rsync-version index 31fed7f..b01e1e4 100755 --- a/support/json-rsync-version +++ b/support/json-rsync-version @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import sys, argparse, subprocess, json diff --git a/support/mapfrom b/support/mapfrom deleted file mode 100755 index 88946bc..0000000 --- a/support/mapfrom +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env perl -# This helper script makes it easy to use a passwd or group file to map -# values in a LOCAL transfer. For instance, if you mount a backup that -# does not have the same passwd setup as the local machine, you can do -# a copy FROM the backup area as follows and get the differing ID values -# mapped just like a remote transfer FROM the backed-up machine would do: -# -# rsync -av --usermap=`mapfrom /mnt/backup/etc/passwd` \ -# --groupmap=`mapfrom /mnt/backup/etc/group` \ -# /mnt/backup/some/src/ /some/dest/ - -while (<>) { - push @_, "$2:$1" if /^(\w+):[^:]+:(\d+)/; -} -print join(',', @_), "\n"; diff --git a/support/mapto b/support/mapto deleted file mode 100755 index 9588752..0000000 --- a/support/mapto +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env perl -# This helper script makes it easy to use a passwd or group file to map -# values in a LOCAL transfer. For instance, if you mount a backup that -# does not have the same passwd setup as the local machine, you can do -# a copy TO the backup area as follows and get the differing ID values -# mapped just like a remote transfer TO the backed-up machine would do: -# -# rsync -av --usermap=`mapto /mnt/backup/etc/passwd` \ -# --groupmap=`mapto /mnt/backup/etc/group` \ -# /some/src/ /mnt/backup/some/dest/ - -while (<>) { - push @_, "$1:$2" if /^(\w+):[^:]+:(\d+)/; -} -print join(',', @_), "\n"; diff --git a/support/mnt-excl b/support/mnt-excl index ed7b49b..bc8b5bc 100755 --- a/support/mnt-excl +++ b/support/mnt-excl @@ -1,4 +1,4 @@ -#!/usr/bin/env perl +#!/usr/bin/env python3 # This script takes a command-line arg of a source directory # that will be passed to rsync, and generates a set of excludes # that will exclude all mount points from the list. This is @@ -27,23 +27,33 @@ # awk '{print $2}' /proc/mounts | grep -v '^/$' | \ # rsync -avf 'merge,/- -' /dir host:/dest/ -use strict; -use warnings; -use Cwd 'abs_path'; +import os, argparse -my $file = '/proc/mounts'; -my $dir = shift || '/'; -my $trailing_slash = $dir =~ m{./$} ? '/' : ''; -$dir = abs_path($dir) . $trailing_slash; -$dir =~ s{([^/]*)$}{}; -my $trailing = $1; -$trailing = '' if $trailing eq '.' || !-d "$dir$trailing"; -$trailing .= '/' if $trailing ne ''; +MNT_FILE = '/proc/mounts'; -open(IN, $file) or die "Unable to open $file: $!\n"; -while (<IN>) { - $_ = (split)[1]; - next unless s{^\Q$dir$trailing\E}{}o && $_ ne ''; - print "- /$trailing$_\n"; -} -close IN; +def main(): + trailing_slash = '/' if args.path.endswith(('/', '/.')) and args.path != '/' else '' + args.path = os.path.realpath(args.path) + trailing_slash + parent_dir = os.path.dirname(args.path) + trailing = os.path.basename(args.path) + if not os.path.isdir(args.path): + trailing = '' + elif trailing != '': + trailing += '/' + want_path = os.path.join(parent_dir, trailing) + wp_len = len(want_path) + + with open(MNT_FILE) as fh: + for line in fh: + mnt_path = line.split()[1] + if mnt_path.startswith(want_path) and mnt_path != want_path: + print(f"- /{trailing}{mnt_path[wp_len:]}") + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description="Output mount points as rsync excludes.", add_help=False) + parser.add_argument("--help", "-h", action="help", help="Output this help message and exit.") + parser.add_argument('path', metavar='PATH', nargs='?', default='/', help="Limit output to those within the PATH hierarchy.") + args = parser.parse_args() + main() + +# vim: sw=4 et diff --git a/support/rrsync b/support/rrsync index 94c85f5..4b4b87c 100755 --- a/support/rrsync +++ b/support/rrsync @@ -258,6 +258,9 @@ def main(): if args.munge: rsync_opts.append('--munge-links') + + if args.no_overwrite: + rsync_opts.append('--ignore-existing') if not rsync_args: rsync_args = [ '.' ] @@ -364,6 +367,7 @@ if __name__ == '__main__': arg_parser.add_argument('-munge', action='store_true', help="Enable rsync's --munge-links on the server side.") arg_parser.add_argument('-no-del', action='store_true', help="Disable rsync's --delete* and --remove* options.") arg_parser.add_argument('-no-lock', action='store_true', help="Avoid the single-run (per-user) lock check.") + arg_parser.add_argument('-no-overwrite', action='store_true', help="Prevent overwriting existing files by enforcing --ignore-existing") arg_parser.add_argument('-help', '-h', action='help', help="Output this help message and exit.") arg_parser.add_argument('dir', metavar='DIR', help="The restricted directory to use.") args = arg_parser.parse_args() diff --git a/support/rrsync.1.md b/support/rrsync.1.md index 98f2cab..2489290 100644 --- a/support/rrsync.1.md +++ b/support/rrsync.1.md @@ -5,7 +5,7 @@ rrsync - a script to setup restricted rsync users via ssh logins ## SYNOPSIS ``` -rrsync [-ro|-rw] [-munge] [-no-del] [-no-lock] DIR +rrsync [-ro|-rw] [-munge] [-no-del] [-no-lock] [-no-overwrite] DIR ``` The single non-option argument specifies the restricted _DIR_ to use. It can be @@ -85,6 +85,11 @@ The remainder of this manpage is dedicated to using the rrsync script. Avoid the single-run (per-user) lock check. Useful with [`-munge`](#opt). +0. `-no-overwrite` + + Enforce `--ignore-existing` on the server. Prevents overwriting existing + files when the server is the receiver. + 0. `-help`, `-h` Output this help message and exit. |