aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'pym/gentoolkit/equery/check.py')
-rw-r--r--pym/gentoolkit/equery/check.py232
1 files changed, 232 insertions, 0 deletions
diff --git a/pym/gentoolkit/equery/check.py b/pym/gentoolkit/equery/check.py
new file mode 100644
index 0000000..ffddf72
--- /dev/null
+++ b/pym/gentoolkit/equery/check.py
@@ -0,0 +1,232 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2
+#
+# $Header: $
+
+"""Check timestamps and MD5sums for files owned by a given installed package"""
+
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import os
+import sys
+from getopt import gnu_getopt, GetoptError
+
+try:
+ import portage.checksum as checksum
+except ImportError:
+ import portage_checksum as checksum
+
+import gentoolkit.pprinter as pp
+from gentoolkit.equery import format_options, mod_usage, Config
+from gentoolkit.helpers2 import do_lookup
+
+# =======
+# Globals
+# =======
+
+QUERY_OPTS = {
+ "categoryFilter": None,
+ "includeInstalled": False,
+ "includeOverlayTree": False,
+ "includePortTree": False,
+ "checkMD5sum": True,
+ "checkTimestamp" : True,
+ "isRegex": False,
+ "matchExact": True,
+ "printMatchInfo": False,
+ "showSummary" : True,
+ "showPassedFiles" : False,
+ "showFailedFiles" : True
+}
+
+# =========
+# Functions
+# =========
+
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print __doc__.strip()
+ print
+
+ # Deprecation warning added by djanderson, 12/2008
+ pp.print_warn("Default action for this module has changed in Gentoolkit 0.3.")
+ pp.print_warn("Use globbing to simulate the old behavior (see man equery).")
+ pp.print_warn("Use '*' to check all installed packages.")
+ print
+
+ print mod_usage(mod_name="check")
+ print
+ print pp.command("options")
+ print format_options((
+ (" -h, --help", "display this help message"),
+ (" -c, --category CAT", "only check files from packages in CAT"),
+ (" -f, --full-regex", "query is a regular expression"),
+ ))
+
+
+def parse_module_options(module_opts):
+ """Parse module options and update GLOBAL_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ posargs = (x[1] for x in module_opts)
+ for opt, posarg in zip(opts, posargs):
+ if opt in ('-h', '--help'):
+ print_help()
+ sys.exit(0)
+ elif opt in ('-c', '--category'):
+ QUERY_OPTS['categoryFilter'] = posarg
+ elif opt in ('-f', '--full-regex'):
+ QUERY_OPTS['isRegex'] = True
+
+
+def run_checks(files):
+ """Run some basic sanity checks on a package's contents.
+
+ If the file type (ftype) is not a directory or symlink, optionally
+ verify MD5 sums or mtimes via verify_obj().
+
+ @see: gentoolkit.packages.get_contents()
+ @type files: dict
+ @param files: in form {'PATH': ['TYPE', 'TIMESTAMP', 'MD5SUM']}
+ @rtype: tuple
+ @return:
+ passed (int): number of files that passed all checks
+ checked (int): number of files checked
+ errs (list): check errors' descriptions
+ """
+
+ checked = 0
+ passed = 0
+ errs = []
+ for cfile in files:
+ checked += 1
+ ftype = files[cfile][0]
+ if not os.path.exists(cfile):
+ errs.append("%s does not exist" % cfile)
+ continue
+ elif ftype == "dir":
+ if not os.path.isdir(cfile):
+ err = "%(cfile)s exists, but is not a directory"
+ errs.append(err % locals())
+ continue
+ elif ftype == "obj":
+ new_errs = verify_obj(files, cfile, errs)
+ if new_errs != errs:
+ errs = new_errs
+ continue
+ elif ftype == "sym":
+ target = files[cfile][2].strip()
+ if not os.path.islink(cfile):
+ err = "%(cfile)s exists, but is not a symlink"
+ errs.append(err % locals())
+ continue
+ tgt = os.readlink(cfile)
+ if tgt != target:
+ err = "%(cfile)s does not point to %(target)s"
+ errs.append(err % locals())
+ continue
+ else:
+ err = "%(cfile)s has unknown type %(ftype)s"
+ errs.append(err % locals())
+ continue
+ passed += 1
+
+ return passed, checked, errs
+
+
+def verify_obj(files, cfile, errs):
+ """Verify the MD5 sum and/or mtime and return any errors."""
+
+ if QUERY_OPTS["checkMD5sum"]:
+ md5sum = files[cfile][2]
+ try:
+ cur_checksum = checksum.perform_md5(cfile, calc_prelink=1)
+ except IOError:
+ err = "Insufficient permissions to read %(cfile)s"
+ errs.append(err % locals())
+ return errs
+ if cur_checksum != md5sum:
+ err = "%(cfile)s has incorrect MD5sum"
+ errs.append(err % locals())
+ return errs
+ if QUERY_OPTS["checkTimestamp"]:
+ mtime = int(files[cfile][1])
+ st_mtime = os.lstat(cfile).st_mtime
+ if st_mtime != mtime:
+ err = "%(cfile)s has wrong mtime (is %(st_mtime)d, " + \
+ "should be %(mtime)d)"
+ errs.append(err % locals())
+ return errs
+
+ return errs
+
+
+def main(input_args):
+ """Parse input and run the program"""
+
+ short_opts = "hac:f"
+ long_opts = ('help', 'all', 'category=', 'full-regex')
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError, err:
+ pp.print_error("Module %s" % err)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries and not QUERY_OPTS["includeInstalled"]:
+ print_help()
+ sys.exit(2)
+ elif queries and not QUERY_OPTS["includeInstalled"]:
+ QUERY_OPTS["includeInstalled"] = True
+ elif QUERY_OPTS["includeInstalled"]:
+ queries = ["*"]
+
+ #
+ # Output
+ #
+
+ first_run = True
+ for query in queries:
+ if not first_run:
+ print
+
+ matches = do_lookup(query, QUERY_OPTS)
+
+ if not matches:
+ pp.print_error("No package found matching %s" % query)
+
+ matches.sort()
+
+ for pkg in matches:
+ if not Config["piping"] and Config["verbosityLevel"] >= 3:
+ print "[ Checking %s ]" % pp.cpv(pkg.cpv)
+ else:
+ print "%s:" % pkg.cpv
+
+ passed, checked, errs = run_checks(pkg.get_contents())
+
+ if not Config["piping"] and Config["verbosityLevel"] >= 3:
+ for err in errs:
+ pp.print_error(err)
+
+ passed = pp.number(str(passed))
+ checked = pp.number(str(checked))
+ info = " * %(passed)s out of %(checked)s files passed"
+ print info % locals()
+
+ first_run = False