On Tue, Jun 24, 2003 at 08:47:53PM +1000, Daniel Stone wrote: > On Tue, Jun 24, 2003 at 08:29:05PM +1000, Martijn van Oosterhout wrote: > > Hey, how far along is this? I've been thinking that this would be very > > possible and very useful. Including having the result be an ISO image and > > combine with one of those autoinstall tools to automatically recreate a > > machine without intervention. Fill up any remaining space with a copy of > > base and any other large packages. > > > > Just dreaming, ok? :) > > It's still in the initial stages right now, but that could certainly be > very handy - maybe an external tool to automatically create the ISO? > Right now, it just spits out a tar file for debrestore to deal with - > containing one file with the package information, a directory for > conffiles, and stuff. I'm sure that could be burnt along with the ISO, > and then debrestore be automatically run ... > > Mmm, good ideas you have. :)
Here's a small script that I started to write a while back and never used for much. It reads a file list on stdin and filters out files which are unchanged from the packages available from apt. The idea would be to generate a list of files to be backed up, and pipe it through this program to reduce the size of the backup without losing local modifications. Maybe it will have some useful ideas for you. -- - mdz
#!/usr/bin/python import sys import os import md5 import apt_pkg import StringIO def log(msg): pass #print >>sys.stderr, msg def xargs_pipe(command, args): max = 1024 argswork = args[:] ret = '' while argswork: argstr = '' while len(argstr) < (len(command) + max) and argswork: argstr += ' ' + argswork.pop(0) cmd = os.popen(command + argstr) ret += cmd.read() return ret def set_intersect(one, two): one_hash = {} ret = [] for item in one: one_hash[one] = 1 for item in two: if item in one: ret.append(item) return ret def modified_conffile(conffiles, f): # maybe should remember the deletion of a conffile? dpkg cares... if f not in conffiles or not os.path.exists(f): return None dbhash = conffiles[f] hashcalc = md5.new() hashcalc.update(open(f).read()) return hashcalc.hexdigest() == dbhash def conffiles(packages): log("Reading conffile data...") conffiles = {} pkghash = {} for package in packages: pkghash[package] = 1 # XXX, dpkg internal interface parser = apt_pkg.ParseTagFile(open('/var/lib/dpkg/status')) while parser.Step() == 1: # This is potentially broken with respect to filenames with spaces, but # it emulates current dpkg (1.10.9) package, cfstanza = (parser.Section.get('Package'), parser.Section.get('Conffiles')) if package not in pkghash: continue if not cfstanza: continue cfentries = cfstanza.split() while cfentries: cfname = cfentries.pop(0) if not cfentries: # XXX broken continue cfhash = cfentries.pop(0) conffiles[cfname] = cfhash return conffiles def contents(packages): log("Reading package contents...") return xargs_pipe( "dpkg-query --listfiles ", packages ).split('\n') def installed_packages(): log("Reading installed package list...") installed = [] parser = apt_pkg.ParseTagFile(os.popen( "dpkg-query --show --showformat='Package: ${Package}\nVersion: ${Version}\nStatus: ${Status}\n\n'" )) while parser.Step() == 1: package, version = (parser.Section.get('Package'), parser.Section.get('Version')) desired, error, status = parser.Section.get('Status').split() if status == 'installed': installed.append((package,version)) return installed def available_packages(): log("Reading available package list...") available = [] parser = apt_pkg.ParseTagFile(os.popen("apt-cache dumpavail")) while parser.Step() == 1: available.append((parser.Section.get('Package'), parser.Section.get('Version'))) return available def alternatives(): log("Reading alternatives...") alternatives = [] # XXX, dpkg internal interface alternatives_dir = '/var/lib/dpkg/alternatives' for alt in os.listdir(alternatives_dir): lines = open(os.path.join(alternatives_dir,alt)).readlines() alternatives.append(lines[1][:-1]) return alternatives def diversions(): log("Reading diversions...") diversions = [] for line in os.popen("dpkg-divert --list '*'").readlines(): # diversion of /usr/bin/autoconf to /usr/bin/autoconf2.50 by autoconf2.13 diversions.append(line.split()[4]) return diversions def main(): action = sys.argv[1] if action == 'filter': available = {} for package in available_packages(): available[package] = 1 packages = [] for package in installed_packages(): if package in available: packages.append(package[0]) exclude_list = {} for f in alternatives(): exclude_list[f] = 1 for f in diversions(): exclude_list[f] = 1 cf = conffiles(packages) lastfile = None for f in contents(packages): if lastfile and f.startswith('locally diverted to: '): exclude_list[lastfile] -= 1 if modified_conffile(cf, f): continue exclude_list[f] = exclude_list.setdefault(f,0) + 1 lastfile = f for f in exclude_list.keys(): if exclude_list[f] < 1: del exclude_list[f] packages = None log("Ready to filter") while 1: line = sys.stdin.readline() if not line: break filename = line[:-1] if filename not in exclude_list: print filename else: sys.stderr.write('No action specified\n') sys.exit(1) if __name__ == '__main__': main()
pgphoi4NEQrFY.pgp
Description: PGP signature