#! /usr/bin/python ### ### Report on available package updates, including security updates. import time as T import os as OS import errno as E import apt_pkg as APT import apt.cache as AC ###-------------------------------------------------------------------------- ### Some utility functions. def cache_up_to_date_p(): """Answer whether the cache is up-to-date.""" ## I use the same stamp file as APT's standard periodic update service. ## This needs prodding via a hook in the APT configuration. now = T.time() try: last = OS.path.getmtime('/var/lib/apt/periodic/update-stamp') except OSError, err: if err.errno == E.ENOENT: return False return now - last < 86400 def upgradable_packages(): """Return a list of packages for which updates are available.""" cache = AC.Cache() return [pkg for pkg in cache if pkg.is_upgradable] def security_updates_p(pkg): """Answer whether any update for PKG is security-relevant.""" ## There doesn't seem to be a good way of doing this. For distributions ## like `testing', security updates are folded into the main distribution ## after the usual triage process, so they stop looking like security ## updates. Worse, for `unstable' there aren't distinct security updates ## anyway: they're all just thrown into the mixer. The good way to tell ## would be to fetch the changelog and look for urgent changes. Debian's ## Aptitude checks explicitly for `security.debian.org'. This check at ## least also captures Ubuntu. for v in pkg.versions: if v < pkg.installed: continue for o in v.origins: if o.site.startswith('security.'): return True return False ###-------------------------------------------------------------------------- ### Main program. if not cache_up_to_date_p(): print 'W: package cache is more than 24 hours of date' updates = upgradable_packages() if updates: plural = len(updates) != 1 print 'I: updates available for %d %s' % \ (len(updates), plural and 'packages' or 'package') sec = [pkg for pkg in updates if security_updates_p(pkg)] if sec: plural = len(sec) != 1 print 'W: security updates available for %d %s' % \ (len(sec), plural and 'packages' or 'package') ###----- That's all, folks --------------------------------------------------