#!/usr/bin/perl # This script outputs data for rsyncdb --mounts. It must output a complete # list of the mounts for the current host in a strict format -- 2 fields # with a Tab between: $MOUNT_UNIQ\t$PATH # # The list of mounts MUST NOT contain any entry that has the same devnum # (st_dev) as any other entry in the list (as checked via its PATH). # # MOUNT_UNIQ is a unique string that identifies the mount on this host. # This cannot be the devnum (st_dev) because that can vary depending on the # mount order or be reused for different mounts if they are not mounted at # the same time. Ideally this would be its UUID value, if that is available # on this OS. This script looks in /dev/disk/by-uuid for the current UUID # mappings). If the UUID is not found, the fallback default is the string # "Mount of $devname", which should be adequate for situations that don't # use removable media (though you may need to take steps to weed-out removable # mounts). # # You can override the MOUNT_UNIQ value by putting a .rsyncdb_mount_uniq # file in the root directory of any mount, at which point it is up to you # to make sure that the value stays unique (note that all sequences of # whitespace are transformed into a single space, and leading/trailing # whitespace is removed). # # MOUNT_UNIQ may never contain a Tab but it would be legal for PATH to have # a Tab (just really weird). Neither may have a CR or LF in it. # # The maximum size for MOUNT_UNIQ is 256 characters. # # If this script doesn't meet your needs, feel free to edit/replace it and # choose some other method of finding a unique value for each mount. If you # come up with a good idiom that might be useful to others, please share it # with the rsync mailing list. use strict; use warnings; use Cwd 'abs_path'; my @MOUNT_FILES = qw( /proc/mounts /etc/mtab ); my $VALID_DEVICE_REGEX = qr{^/dev|^rootfs$}; my $UUID_DIR = '/dev/disk/by-uuid'; my $OVERRIDE_FILE = '.rsyncdb_mount_uniq'; my (%hash, %uuid); if (-d $UUID_DIR) { foreach my $uuid (glob "$UUID_DIR/*") { my $lnk = readlink($uuid); if ($lnk !~ m{^/}) { $lnk = abs_path("$UUID_DIR/$lnk"); } $uuid =~ s{.*/}{}; $uuid{$lnk} = $uuid; } } foreach my $mount_file (@MOUNT_FILES) { if (open MOUNTS, $mount_file) { while () { my ($devname, $path) = (split)[0,1]; next unless $devname =~ /$VALID_DEVICE_REGEX/; my ($devno) = (stat($path))[0]; next unless defined $devno; # Skip if mount is invalid. next if $hash{$devno}++; # SKip if we've seen this devno earlier. my $mount_uniq = $uuid{$devname} ? $uuid{$devname} : "Mount of $devname"; if (open UNIQ, '<', "$path/$OVERRIDE_FILE") { $mount_uniq = ; close UNIQ; $mount_uniq =~ s/\s+/ /g; # This ensures no tab, CR, nor LF. $mount_uniq =~ s/^ | $//g; # .. and no leading or trailing whitespace. } print $mount_uniq, "\t", $path, "\n"; } close MOUNTS; exit; } } die "Failed to to open any mount files: @MOUNT_FILES\n";