-#!/usr/bin/python -O
+#!/usr/bin/python -bbO
+# Copyright 2005-2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
-import sys, os
-from optparse import OptionParser, OptionValueError
-if not hasattr(__builtins__, "set"):
- from sets import Set as set
-import re
-try:
- import portage
-except ImportError:
- from os import path as osp
- sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
- import portage
-
-import portage.const, portage.exception
-class WorldHandler(object):
-
- def name():
- return "world"
- name = staticmethod(name)
-
- def __init__(self):
- self.invalid = []
- self.not_installed = []
- self.invalid_category = []
- self.okay = []
- self.world_file = os.path.join("/", portage.const.WORLD_FILE)
- self.found = os.access(self.world_file, os.R_OK)
-
- def _check_world(self, onProgress):
- categories = set(portage.settings.categories)
- myroot = portage.settings["ROOT"]
- vardb = portage.db[myroot]["vartree"].dbapi
-
- world_atoms = open(self.world_file).read().split()
- maxval = len(world_atoms)
- if onProgress:
- onProgress(maxval, 0)
- for i, atom in enumerate(world_atoms):
- if not portage.isvalidatom(atom):
- self.invalid.append(atom)
- if onProgress:
- onProgress(maxval, i+1)
- continue
- okay = True
- if not vardb.match(atom):
- self.not_installed.append(atom)
- okay = False
- if portage.catsplit(atom)[0] not in categories:
- self.invalid_category.append(atom)
- okay = False
- if okay:
- self.okay.append(atom)
- if onProgress:
- onProgress(maxval, i+1)
-
- def check(self, onProgress=None):
- self._check_world(onProgress)
- errors = []
- if self.found:
- errors += map(lambda x: "'%s' is not a valid atom" % x, self.invalid)
- errors += map(lambda x: "'%s' is not installed" % x, self.not_installed)
- errors += map(lambda x: "'%s' has a category that is not listed in /etc/portage/categories" % x, self.invalid_category)
- else:
- errors.append(self.world_file + " could not be opened for reading")
- return errors
-
- def fix(self, onProgress=None):
- self._check_world(onProgress)
- errors = []
- try:
- portage.write_atomic(self.world_file, "\n".join(self.okay))
- except portage.exception.PortageException:
- errors.append(self.world_file + " could not be opened for writing")
- return errors
-
-class VdbKeyHandler(object):
- def name():
- return "vdbkeys"
- name = staticmethod(name)
-
- def __init__(self):
- self.list = portage.db["/"]["vartree"].dbapi.cpv_all()
- self.missing = []
- self.keys = ["HOMEPAGE", "SRC_URI", "KEYWORDS", "DESCRIPTION"]
-
- for p in self.list:
- mydir = os.path.join(os.sep, portage.settings["ROOT"], portage.const.VDB_PATH, p)+os.sep
- ismissing = True
- for k in self.keys:
- if os.path.exists(mydir+k):
- ismissing = False
- break
- if ismissing:
- self.missing.append(p)
-
- def check(self):
- return ["%s has missing keys" % x for x in self.missing]
-
- def fix(self):
-
- errors = []
-
- for p in self.missing:
- mydir = os.path.join(os.sep, portage.settings["ROOT"], portage.const.VDB_PATH, p)+os.sep
- if not os.access(mydir+"environment.bz2", os.R_OK):
- errors.append("Can't access %s" % (mydir+"environment.bz2"))
- elif not os.access(mydir, os.W_OK):
- errors.append("Can't create files in %s" % mydir)
- else:
- env = os.popen("bzip2 -dcq "+mydir+"environment.bz2", "r")
- envlines = env.read().split("\n")
- env.close()
- for k in self.keys:
- s = [l for l in envlines if l.startswith(k+"=")]
- if len(s) > 1:
- errors.append("multiple matches for %s found in %senvironment.bz2" % (k, mydir))
- elif len(s) == 0:
- s = ""
- else:
- s = s[0].split("=",1)[1]
- s = s.lstrip("$").strip("\'\"")
- s = re.sub("(\\\\[nrt])+", " ", s)
- s = " ".join(s.split()).strip()
- if s != "":
- try:
- keyfile = open(mydir+os.sep+k, "w")
- keyfile.write(s+"\n")
- keyfile.close()
- except (IOError, OSError), e:
- errors.append("Could not write %s, reason was: %s" % (mydir+k, e))
-
- return errors
-
-def emaint_main(myargv):
-
- # TODO: Create a system that allows external modules to be added without
- # the need for hard coding.
- modules = {"world" : WorldHandler}
-
- module_names = modules.keys()
- module_names.sort()
- module_names.insert(0, "all")
-
- def exclusive(option, *args, **kw):
- var = kw.get("var", None)
- if var is None:
- raise ValueError("var not specified to exclusive()")
- if getattr(parser, var, ""):
- raise OptionValueError("%s and %s are exclusive options" % (getattr(parser, var), option))
- setattr(parser, var, str(option))
+"""System health checks and maintenance utilities.
+"""
+from __future__ import print_function
- usage = "usage: emaint [options] " + " | ".join(module_names)
-
- usage+= "\n\nCurrently emaint can only check and fix problems with one's world\n"
- usage+= "file. Future versions will integrate other portage check-and-fix\n"
- usage+= "tools and provide a single interface to system health checks."
-
-
- parser = OptionParser(usage=usage)
- parser.add_option("-c", "--check", help="check for problems",
- action="callback", callback=exclusive, callback_kwargs={"var":"action"})
- parser.add_option("-f", "--fix", help="attempt to fix problems",
- action="callback", callback=exclusive, callback_kwargs={"var":"action"})
- parser.action = None
-
-
- (options, args) = parser.parse_args(args=myargv)
- if len(args) != 1:
- parser.error("Incorrect number of arguments")
- if args[0] not in module_names:
- parser.error("%s target is not a known target" % args[0])
-
- if parser.action:
- action = parser.action
- else:
- print "Defaulting to --check"
- action = "-c/--check"
-
- if args[0] == "all":
- tasks = modules.values()
- else:
- tasks = [modules[args[0]]]
+import sys
+import errno
+# This block ensures that ^C interrupts are handled quietly.
+try:
+ import signal
+ def exithandler(signum, _frame):
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
+ sys.exit(128 + signum)
- if action == "-c/--check":
- status = "Checking %s for problems"
- func = "check"
- else:
- status = "Attempting to fix %s"
- func = "fix"
+ signal.signal(signal.SIGINT, exithandler)
+ signal.signal(signal.SIGTERM, exithandler)
+ signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+except KeyboardInterrupt:
+ sys.exit(1)
- for task in tasks:
- print status % task.name()
- inst = task()
- result = getattr(inst, func)()
- if result:
- print
- print "\n".join(result)
- print "\n"
+from os import path as osp
+pym_path = osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")
+sys.path.insert(0, pym_path)
+import portage
+portage._internal_caller = True
+from portage.emaint.main import emaint_main
- print "Finished"
-
-if __name__ == "__main__":
+try:
emaint_main(sys.argv[1:])
+except IOError as e:
+ if e.errno == errno.EACCES:
+ print("\nemaint: Need superuser access")
+ sys.exit(1)
+ else:
+ raise