diff options
-rw-r--r-- | .SRCINFO | 27 | ||||
-rw-r--r-- | PKGBUILD | 36 | ||||
-rw-r--r-- | exclude.patch | 263 | ||||
-rwxr-xr-x | lb.cron | 5 | ||||
-rw-r--r-- | lb.exclude | 33 | ||||
-rw-r--r-- | link-backup.install | 51 | ||||
-rw-r--r-- | root-src-fix.patch | 22 | ||||
-rw-r--r-- | shebang.patch | 8 |
8 files changed, 445 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO new file mode 100644 index 000000000000..8aaab28208ab --- /dev/null +++ b/.SRCINFO @@ -0,0 +1,27 @@ +pkgbase = link-backup + pkgdesc = Intelligent backup utility that handles renames, moves, duplicate files + pkgver = 0.8 + pkgrel = 5 + url = http://www.scottlu.com/Content/Link-Backup.html + install = link-backup.install + arch = i686 + arch = x86_64 + license = unknown + depends = python + depends = openssh + depends = rsync + source = http://www.scottlu.com/files/lb.py + source = lb.cron + source = lb.exclude + source = shebang.patch + source = exclude.patch + source = root-src-fix.patch + md5sums = 4acd3ea00da33ef14a87410cfcc7c987 + md5sums = 79b92199173c8895f828b9839c88ce62 + md5sums = 67548d6c7e00a8dab1c562e7735b93f9 + md5sums = 8fd3cc50efd4d83db0220ad3c5f4cbac + md5sums = b2ed3a9cb520e52a18ca37d8d7558557 + md5sums = 21b1e3f881038f173efcde1fa432d6ec + +pkgname = link-backup + diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 000000000000..a6fd310877eb --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,36 @@ +# Contributor: Sorin Ionescu <sorin.ionescu@gmail.com> +pkgname=link-backup +pkgver=0.8 +pkgrel=5 +pkgdesc="Intelligent backup utility that handles renames, moves, duplicate files" +arch=('i686' 'x86_64') +depends=('python' 'openssh' 'rsync') +url="http://www.scottlu.com/Content/Link-Backup.html" +license=('unknown') +install=link-backup.install +source=(http://www.scottlu.com/files/lb.py + lb.cron + lb.exclude + shebang.patch + exclude.patch + root-src-fix.patch) + +md5sums=('4acd3ea00da33ef14a87410cfcc7c987' + '79b92199173c8895f828b9839c88ce62' + '67548d6c7e00a8dab1c562e7735b93f9' + '8fd3cc50efd4d83db0220ad3c5f4cbac' + 'b2ed3a9cb520e52a18ca37d8d7558557' + '21b1e3f881038f173efcde1fa432d6ec') + +build() +{ + cd $startdir/src + patch -p0 -i $startdir/src/shebang.patch || return 1 + patch -p0 -i $startdir/src/exclude.patch || return 1 + patch -p0 -i $startdir/src/root-src-fix.patch || return 1 + install -D -m 755 lb.py $startdir/pkg/usr/bin/lb || return 1 + install -D -m 755 lb.cron $startdir/pkg/usr/share/lb/lb.cron || return 1 + install -D -m 644 lb.exclude $startdir/pkg/usr/share/lb/lb.exclude || return 1 +} + +# vim:set ts=2 sw=2 et: diff --git a/exclude.patch b/exclude.patch new file mode 100644 index 000000000000..9afa7a664ce8 --- /dev/null +++ b/exclude.patch @@ -0,0 +1,263 @@ +--- lb.py~ 2008-03-04 19:14:37.000000000 -0500 ++++ lb.py 2008-05-13 22:05:54.000000000 -0400 +@@ -6,7 +6,7 @@ + of backed-up trees, and intelligently handles renames, moves, and + duplicate files without additional storage or transfer. + +-Transfer occurs over standard i/o locally or remotely between a client and ++Transfer occurs over standard I/O locally or remotely between a client and + server instance of this script. Remote backups rely on the secure remote + shell program ssh. + +@@ -28,18 +28,21 @@ + + Options: + +- --verify Run rsync with --dry-run to cross-verify +- --numeric-ids Keep uid/gid values instead of mapping; requires root +- --minutes <mins> Only run for <mins> minutes. Incremental backup. +- --showfiles Don't backup, only list relative path files needing +- backup +- --catalogonly Update catalog only +- --filelist <- or file> Specify filelist. Files relative to srcdir. +- --lock Ensure only one backup to a given dest will run at a time +- --verbose Show what is happening +- --ssh-i <file> Select id file to use for authentication (ssh -i) +- --ssh-C Use ssh compression (ssh -C) +- --ssh-p <port> ssh port on remote host (ssh -p) ++ --catalogonly Update catalog only ++ --exclude <file> Exclude paths matching the regexp rules in file ++ --filelist <- or file> Specify filelist. Files relative to srcdir. ++ --lock Ensure only one backup to a given dest will run at ++ a time ++ --minutes <mins> Only run for <mins> minutes. Incremental backup ++ --numeric-ids Keep uid/gid values instead of mapping; ++ requires root ++ --showfiles Don't backup, only list relative path files needing ++ backup ++ --ssh-C Use ssh compression (ssh -C) ++ --ssh-i <file> Select id file to use for authentication (ssh -i) ++ --ssh-p <port> ssh port on remote host (ssh -p) ++ --verbose Show what is happening ++ --verify Run rsync with --dry-run to cross-verify + + Comments: + +@@ -69,19 +72,19 @@ + + Example 1: + +-python lb.py pictures pictures-backup ++lb pictures pictures-backup + + Makes a new backup of pictures in pictures-backup. + + Example 2: + +-python lb.py pictures me@fluffy:~/pictures-backup ++lb pictures me@fluffy:~/pictures-backup + + Backs up on remote machine fluffy instead of locally. + + Example 3: + +-python lb.py --minutes 240 pictures me@remote:~/pictures-backup ++lb --minutes 240 pictures me@remote:~/pictures-backup + + Same as above except for 240 minutes only. This is useful if backing up over + the internet only during specific times (at night for example). Does what it +@@ -89,22 +92,22 @@ + hardlinked to the catalog. + + Example 4: +-python lb.py --showfiles pictures pictures-backup | \ +-python lb.py --filelist - pictures pictures-backup ++lb --showfiles pictures pictures-backup | \ ++lb --filelist - pictures pictures-backup + + Same as example #1. + + Example 5: + + 1) +-python lb.py --showfiles pictures me@remote:~/pictures-backup | \ +-python lb.py --filelist - pictures me@laptop:~/pictures-transfer ++lb --showfiles pictures me@remote:~/pictures-backup | \ ++lb --filelist - pictures me@laptop:~/pictures-transfer + + 2) +-python lb.py --catalogonly pictures-transfer me@remote:~/pictures-backup ++lb --catalogonly pictures-transfer me@remote:~/pictures-backup + + 3) +-python lb.py pictures me@remote:~/pictures-backup ++lb pictures me@remote:~/pictures-backup + + If the difference between pictures and pictures-backup (for example) is too + large for internet backup, the steps above can be used. Step 1 transfers only +@@ -118,11 +121,11 @@ + since only the catalog is being updated (however it would be a speedup). + + History: +- ++ + v 0.8 12/23/2006 scottlu +- - allow backups to occur while files are changing +- - minor --verify command bug +- - added --verbose logging to tree building ++ - Allow backups to occur while files are changing ++ - Minor --verify command bug ++ - Added --verbose logging to tree building + + v 0.7 09/02/2006 scottlu + - Ignore pipe, socket, and device file types +@@ -159,14 +162,14 @@ + - Added backup stat query methods + - Changed log file format + - Added viewlb.cgi, a web interface for viewing backups +- - added gzip compression of filemap +- - added --numeric-ids ++ - Added gzip compression of filemap ++ - Added --numeric-ids + + v 0.2 8/28/2004 scottlu +- - filemap format change +- - added --rmempty +- - added --verify to run rsync in verify mode +- - added uid/gid mapping by default unless --numeric-ids is specified ++ - Filemap format change ++ - Added --rmempty ++ - Added --verify to run rsync in verify mode ++ - Added uid/gid mapping by default unless --numeric-ids is specified + + v 0.1 8/19/2004 scottlu + - Fully working backup, hardlinking between trees +@@ -747,55 +750,68 @@ + if stat.S_ISSOCK(mode): + return False + return True ++ ++def is_excluded(filepath, exclude_rules): ++ exclude_filepath = False ++ if exclude_rules: ++ for rule in exclude_rules: ++ if rule.search(filepath): ++ exclude_filepath = True ++ break ++ return exclude_filepath + +-def build_filelist_from_tree(treepath): ++def build_filelist_from_tree(treepath, exclude_rules): + class ListBuilder: + def __init__(self, basepath): + self.lenbase = len('%s%s' % (basepath, os.sep)) + + def callback(self, arg, dirpath, filelist): + for file in filelist: +- # Sometimes a stat may fail, like if there are broken +- # symlinks in the file system +- try: +- # Collect stat values instead of stat objects. It's 6 +- # times smaller (measured) and mutuable +- # (for uid/gid mapping at the dest) +- filepath = join(dirpath, file) +- s = os.stat(filepath) +- if not is_mode_ok(s.st_mode): +- continue +- arg.append((filepath[self.lenbase:], [s.st_mode, s.st_size, s.st_mtime, s.st_uid, s.st_gid])) +- except: +- pass ++ # Sometimes a stat may fail, like if there are broken ++ # symlinks in the file system ++ try: ++ # Collect stat values instead of stat objects. It's 6 ++ # times smaller (measured) and mutuable ++ # (for uid/gid mapping at the dest) ++ filepath = join(dirpath, file) ++ if is_excluded(filepath, exclude_rules): ++ continue ++ s = os.stat(filepath) ++ if not is_mode_ok(s.st_mode): ++ continue ++ arg.append((filepath[self.lenbase:], [s.st_mode, s.st_size, s.st_mtime, s.st_uid, s.st_gid])) ++ except: ++ pass + + treepath_abs = os.path.abspath(treepath) + filelist = [] + os.path.walk(treepath_abs, ListBuilder(treepath_abs).callback, filelist) + return filelist + +-def build_filelist_from_file(treepath, file): ++def build_filelist_from_file(treepath, file, exclude_rules): + filelist = [] + for line in file.readlines(): + filepath_rel = line.rstrip('\n') ++ if is_excluded(filepath_rel, exclude_rules): ++ continue + s = os.stat(join(treepath, filepath_rel)) + if not is_mode_ok(s.st_mode): + continue + filelist.append((filepath_rel, [s.st_mode, s.st_size, s.st_mtime, s.st_uid, s.st_gid])) + return filelist + +-def build_filelist(treepath): ++def build_filelist(treepath, exclude_rules): + verbose_log('building filelist...') + for n in xrange(len(sys.argv)): + if sys.argv[n] == '--filelist': + if sys.argv[n + 1] == '-': +- return build_filelist_from_file(treepath, sys.stdin) ++ return build_filelist_from_file(treepath, sys.stdin, exclude_rules) + else: + file = open(sys.argv[n + 1]) +- filelist = build_filelist_from_file(treepath, file) ++ filelist = build_filelist_from_file(treepath, file, exclude_rules) + file.close() + return filelist +- return build_filelist_from_tree(treepath) ++ return build_filelist_from_tree(treepath, exclude_rules) + + def build_uidgidmap(filelist): + """Build a map of uid's to names and gid's to names +@@ -973,7 +989,7 @@ + if not treepath_last: + verbose_log('tree not equal: no last tree!') + return False +- filelist_old = build_filelist_from_tree(treepath_last) ++ filelist_old = build_filelist_from_tree(treepath_last, None) + if len(filelist) != len(filelist_old): + verbose_log('tree not equal: filelists different sizes!') + return False +@@ -1006,9 +1022,29 @@ + if is_source: + # Sending side + # Create filelist, calc name map, send both +- ++ ++ exclude_rules_file_path = None ++ exclude_rules = None ++ for n in xrange(len(sys.argv)): ++ if sys.argv[n] == '--exclude': ++ exclude_rules_file_path = sys.argv[n + 1] ++ break ++ if exclude_rules_file_path: ++ if os.path.isfile(exclude_rules_file_path): ++ exclude_rules_file = open(exclude_rules_file_path, "r") ++ try: ++ exclude_rules = [] ++ for rule in exclude_rules_file: ++ exclude_rules.append(re.compile(rule.strip(), re.UNICODE)) ++ except IOError, e: ++ error('an error occured while reading the excludes file') ++ finally: ++ exclude_rules_file.close() ++ else: ++ error('excludes file "' + exclude_rules_file_path + '" not found') ++ + srcpath = os.path.abspath(os.path.expanduser(src['path'])) +- filelist = build_filelist(srcpath) ++ filelist = build_filelist(srcpath, exclude_rules) + send_object(filelist) + idname_map = build_uidgidmap(filelist) + send_object(idname_map) diff --git a/lb.cron b/lb.cron new file mode 100755 index 000000000000..4ef100b6c373 --- /dev/null +++ b/lb.cron @@ -0,0 +1,5 @@ +#!/bin/sh + +if [ -x /usr/bin/lb ]; then + nice -n 19 /usr/lib/lb --lock --ssh-C --numeric-ids --exclude /etc/lb.exclude / root@machine:/destination +fi diff --git a/lb.exclude b/lb.exclude new file mode 100644 index 000000000000..737138768484 --- /dev/null +++ b/lb.exclude @@ -0,0 +1,33 @@ +^/dev/.+ +^/media/.+ +^/mnt/.+ +^/proc/.+ +^/sys/.+ +^/tmp/.+ +^/var/log/gdm/.+ +^/var/log/.+ +^/var/tmp/.+ +.*/lost+found +.*\.tmp +^/home/.*/\.Trash +^/home/.*/\.Trash +^/home/.*/\.Trash-Root +^/home/.*/\.beagle +^/home/.*/\.cache +^/home/.*/\.dbus +^/home/.*/\.emerald/themecache +^/home/.*/\.fontconfig/.*\.cache/.* +^/home/.*/\.grails/.*/scriptCache +^/home/.*/\.java/deployment/cache +^/home/.*/\.liferea/.*/cache +^/home/.*/\.liferea/.*/mozilla/liferea/Cache +^/home/.*/\.local/share/Trash +^/home/.*/\.macromedia +^/home/.*/\.metacity +^/home/.*/\.mozilla/firefox/.*/Cache +^/home/.*/\.nautilus/saved-.* +^/home/.*/\.openoffice\.org2/user/registry/cache +^/home/.*/\.openoffice\.org2/user/uno_packages/cache +^/home/.*/\.thumbnails +^/home/sorin/Downloads +^/home/sorin/Packages/abs/.*?/.*(pkg|src|\.bz2|\.gz|\.zip) diff --git a/link-backup.install b/link-backup.install new file mode 100644 index 000000000000..bdaccc23be62 --- /dev/null +++ b/link-backup.install @@ -0,0 +1,51 @@ +# arg 1: the new package version +post_install() +{ + cat << _EOF + + Link-Backup is a backup utility that creates hard links between a + series of backed-up trees, and intelligently handles renames, moves, + and duplicate files without additional storage or transfer. + + Transfer occurs over standard i/o locally or remotely between a client + and server instance of this script. Remote backups rely on the secure + remote shell program ssh. + + NOTE: Open /usr/bin/lb in a text editor to read the documentation. + + To install the cron job script, issue: + cp /usr/share/lb/lb.cron /etc/cron.daily/lb + + To install the sample exclude rules file, issue: + cp /usr/share/lb/lb.exclude /etc/lb.exclude + + For additional information and a CGI script to view the backups see: + http://www.scottlu.com/Content/Link-Backup.html + +_EOF +} + +post_upgrade() +{ + post_install +} + +post_remove() { + cat << _EOF + + NOTE: You will have to manually take care of a number of + steps such as removing the cron job script, removing the + exclude rules file if you have chosen to use them. + + To remove the cron job script, issue: + rm /etc/cron.daily/lb + + To remove the exclude rules file, issue: + rm /etc/lb.exclude + +_EOF +} + +op=$1 +shift +$op $* diff --git a/root-src-fix.patch b/root-src-fix.patch new file mode 100644 index 000000000000..a822ef61f029 --- /dev/null +++ b/root-src-fix.patch @@ -0,0 +1,22 @@ +--- lb.py~ 2008-05-13 22:56:36.000000000 -0400 ++++ lb.py 2008-05-13 22:56:55.000000000 -0400 +@@ -281,6 +281,8 @@ + """ + def __init__(self, path): + self.path = os.path.abspath(path) ++ if self.path == os.sep: ++ self.path = "" + self.lenbase = len('%s%s' % (self.path, os.sep)) + self.logpath = join(self.path, 'log') + if not os.path.exists(self.path): +@@ -751,7 +753,9 @@ + def build_filelist_from_tree(treepath): + class ListBuilder: + def __init__(self, basepath): +- self.lenbase = len('%s%s' % (basepath, os.sep)) ++ if basepath == os.sep: ++ basepath = "" ++ self.lenbase = len('%s%s' % (basepath, os.sep)) + + def callback(self, arg, dirpath, filelist): + for file in filelist: diff --git a/shebang.patch b/shebang.patch new file mode 100644 index 000000000000..9e60be920f20 --- /dev/null +++ b/shebang.patch @@ -0,0 +1,8 @@ +--- lb.py~ 2008-05-13 10:52:51.000000000 -0400 ++++ lb.py 2008-05-13 10:55:27.000000000 -0400 +@@ -1,3 +1,5 @@ ++#!/usr/bin/python ++ + """Link-Backup + Copyright (c) 2004 Scott Ludwig + http://www.scottlu.com |