#!/usr/bin/env python # verify.py Version 0.1 2009-10-18 # # under the WTFPL. see http://sam.zoy.org/wtfpl/ # # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE # Version 2, December 2004 # # Copyright (C) 2006 solsTiCe d'Hiver # Everyone is permitted to copy and distribute verbatim or modified # copies of this license document, and changing it is allowed as long # as the name is changed. # # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION # # 0. You just DO WHAT THE FUCK YOU WANT TO. '''a python script that compare the files in a package tarball and the files installed on the system: It reports changed files, missing files''' import tarfile import hashlib from sys import argv, exit, stderr, stdin from os import listdir from os.path import exists, basename from glob import glob DB = '/var/lib/pacman' CACHE = '/var/cache/pacman/pkg' # TODO: use logging module ? def error(s): stderr.write('Error: %s\n' % s) def warning(s): stderr.write('Warning: %s\n' % s) def getpkgname(pkgfile): '''return package name from its pkgfilename''' pkg = basename(pkgfile.rstrip('.pkg.tar.gz')) pkg = pkg[:pkg.rfind('-')] return pkg def ispkginstalled(pkgfile): '''return wether or not a package is installed''' return exists('/'.join([DB, 'local', getpkgname(pkgfile)])) def checkpkg(pkgfile): '''check if the installed files of a package have changed compared to the files in the package tarball''' missing = 0 changed = 0 md5s = md5pkg(pkgfile) for filename,md5 in md5s.items(): ff = '/' + filename if exists(ff): try: with open(ff) as g: if hashlib.md5(g.read()).hexdigest() != md5: warning('%s has changed' % ff) changed += 1 except IOError as e: error('%s: %s ' % (e.strerror, filename)) continue else: warning('%s has not been found' % ff) missing += 1 return (len(md5s), changed, missing) def listpkg(): '''return a list of all isntalled pkg''' return sorted(listdir('/'.join([DB, 'local']))) def findpkg(s, dbpkg): '''look for an installed pkg matching s and return the path of tarball in the cache''' candidates = [p for p in dbpkg if p.startswith(s)] found = False for i in candidates: pkgname = '-'.join(i.split('-')[:-2]) if pkgname == s: found = True break if found: res = glob('/'.join([CACHE, i+'*'])) if len(res) == 1: return res[0] return None def md5pkg(pkgfile): '''return a dictionary of filename and md5 of the package''' tf = tarfile.open(pkgfile, 'r') md5s = {} for ti in tf: if ti.isfile() and ti.name not in ('.PKGINFO', '.INSTALL', '.CHANGELOG'): f = tf.extractfile(ti) md5s[ti.name] = hashlib.md5(f.read()).hexdigest() f.close() tf.close() return md5s if __name__ == '__main__': dbpkg = listpkg() try: if len(argv) == 1: # try to use stdin if no argument pkglist = stdin.readlines() pkglist = [i.strip() for i in pkglist] else: pkglist = argv[1:] for pkg in pkglist: if exists(pkg): if not ispkginstalled(pkg): error('%s is not installed' % getpkgname(pkg)) continue else: # if we do not find the archive pkg, then look for a package with # that name in the db of pacman p = findpkg(pkg, dbpkg) if p != None: # strange but it works pkg = p else: error('%s not found' % pkg) continue # finaly check the tarball pkg (n,c,m) = checkpkg(pkg) print '%s: %d files, %d changed, %d missing' % (getpkgname(pkg), n, c, m) except KeyboardInterrupt: pass