diff options
Diffstat (limited to 'portage_with_autodep/bin/glsa-check')
-rwxr-xr-x | portage_with_autodep/bin/glsa-check | 196 |
1 files changed, 107 insertions, 89 deletions
diff --git a/portage_with_autodep/bin/glsa-check b/portage_with_autodep/bin/glsa-check index a840c32..7fa3688 100755 --- a/portage_with_autodep/bin/glsa-check +++ b/portage_with_autodep/bin/glsa-check @@ -1,81 +1,79 @@ #!/usr/bin/python -# Copyright 2008-2011 Gentoo Foundation +# Copyright 2008-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 from __future__ import print_function import sys +import codecs -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 - +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 import os -from portage.output import * - -from optparse import OptionGroup, OptionParser +from portage.output import green, red, nocolor, white +from portage.util._argparse import ArgumentParser __program__ = "glsa-check" __author__ = "Marius Mauch <genone@gentoo.org>" __version__ = "1.0" -def cb_version(*args, **kwargs): - """Callback for --version""" - sys.stderr.write("\n"+ __program__ + ", version " + __version__ + "\n") - sys.stderr.write("Author: " + __author__ + "\n") - sys.stderr.write("This program is licensed under the GPL, version 2\n\n") - sys.exit(0) - # option parsing -parser = OptionParser(usage="%prog <option> [glsa-list]", - version="%prog "+ __version__) -parser.epilog = "glsa-list can contain an arbitrary number of GLSA ids," \ +epilog = "glsa-list can contain an arbitrary number of GLSA ids," \ " filenames containing GLSAs or the special identifiers" \ " 'all', 'new' and 'affected'" +parser = ArgumentParser(usage=__program__ + " <option> [glsa-list]", + epilog=epilog) -modes = OptionGroup(parser, "Modes") -modes.add_option("-l", "--list", action="store_const", +modes = parser.add_argument_group("Modes") +modes.add_argument("-l", "--list", action="store_const", const="list", dest="mode", help="List all unapplied GLSA") -modes.add_option("-d", "--dump", action="store_const", +modes.add_argument("-d", "--dump", action="store_const", const="dump", dest="mode", help="Show all information about the given GLSA") -modes.add_option("", "--print", action="store_const", +modes.add_argument("--print", action="store_const", const="dump", dest="mode", help="Alias for --dump") -modes.add_option("-t", "--test", action="store_const", +modes.add_argument("-t", "--test", action="store_const", const="test", dest="mode", help="Test if this system is affected by the given GLSA") -modes.add_option("-p", "--pretend", action="store_const", +modes.add_argument("-p", "--pretend", action="store_const", const="pretend", dest="mode", help="Show the necessary commands to apply this GLSA") -modes.add_option("-f", "--fix", action="store_const", +modes.add_argument("-f", "--fix", action="store_const", const="fix", dest="mode", help="Try to auto-apply this GLSA (experimental)") -modes.add_option("-i", "--inject", action="store_const", dest="mode", - help="Inject the given GLSA into the checkfile") -modes.add_option("-m", "--mail", action="store_const", +modes.add_argument("-i", "--inject", action="store_const", + const="inject", dest="mode", + help="inject the given GLSA into the glsa_injected file") +modes.add_argument("-m", "--mail", action="store_const", const="mail", dest="mode", help="Send a mail with the given GLSAs to the administrator") -parser.add_option_group(modes) -parser.remove_option("--version") -parser.add_option("-V", "--version", action="callback", - callback=cb_version, help="Some information about this tool") -parser.add_option("-v", "--verbose", action="store_true", dest="verbose", +parser.add_argument("-V", "--version", action="store_true", + help="Some information about this tool") +parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", help="Print more information") -parser.add_option("-n", "--nocolor", action="callback", - callback=lambda *args, **kwargs: nocolor(), +parser.add_argument("-n", "--nocolor", action="store_true", help="Disable colors") -parser.add_option("-e", "--emergelike", action="store_false", dest="least_change", +parser.add_argument("-e", "--emergelike", action="store_false", dest="least_change", help="Do not use a least-change algorithm") -parser.add_option("-c", "--cve", action="store_true", dest="list_cve", +parser.add_argument("-c", "--cve", action="store_true", dest="list_cve", help="Show CAN ids in listing mode") -options, params = parser.parse_args() +options, params = parser.parse_known_args() + +if options.nocolor: + nocolor() + +if options.version: + sys.stderr.write("\n"+ __program__ + ", version " + __version__ + "\n") + sys.stderr.write("Author: " + __author__ + "\n") + sys.stderr.write("This program is licensed under the GPL, version 2\n\n") + sys.exit(0) mode = options.mode least_change = options.least_change @@ -101,7 +99,8 @@ elif mode == "list" and not params: params.append("new") # delay this for speed increase -from portage.glsa import * +from portage.glsa import (Glsa, GlsaTypeException, GlsaFormatException, + get_applied_glsas, get_glsa_list) eroot = portage.settings['EROOT'] vardb = portage.db[eroot]["vartree"].dbapi @@ -117,7 +116,7 @@ glsalist = [] if "new" in params: glsalist = todolist params.remove("new") - + if "all" in params: glsalist = completelist params.remove("all") @@ -142,8 +141,17 @@ for p in params[:]: glsalist.extend([g for g in params if g not in glsalist]) -def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr): - fd2.write(white("[A]")+" means this GLSA was already applied,\n") +def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr, encoding="utf-8"): + # Get to the raw streams in py3k before wrapping them with an encoded writer + # to avoid writing bytes to a text stream (stdout/stderr are text streams + # by default in py3k) + if hasattr(fd1, "buffer"): + fd1 = fd1.buffer + if hasattr(fd2, "buffer"): + fd2 = fd2.buffer + fd1 = codecs.getwriter(encoding)(fd1) + fd2 = codecs.getwriter(encoding)(fd2) + fd2.write(white("[A]")+" means this GLSA was marked as applied (injected),\n") fd2.write(green("[U]")+" means the system is not affected and\n") fd2.write(red("[N]")+" indicates that the system might be affected.\n\n") @@ -155,7 +163,7 @@ def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr): if verbose: fd2.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e))) continue - if myglsa.isApplied(): + if myglsa.isInjected(): status = "[A]" color = white elif myglsa.isVulnerable(): @@ -186,7 +194,7 @@ def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr): fd1.write(")") if list_cve: fd1.write(" "+(",".join([r[:13] for r in myglsa.references if r[:4] in ["CAN-", "CVE-"]]))) - fd1.write("\n") + fd1.write("\n") return 0 if mode == "list": @@ -204,39 +212,46 @@ if mode in ["dump", "fix", "inject", "pretend"]: if mode == "dump": myglsa.dump() elif mode == "fix": - sys.stdout.write("fixing "+myid+"\n") - mergelist = myglsa.getMergeList(least_change=least_change) - for pkg in mergelist: - sys.stdout.write(">>> merging "+pkg+"\n") - # using emerge for the actual merging as it contains the dependency - # code and we want to be consistent in behaviour. Also this functionality - # will be integrated in emerge later, so it shouldn't hurt much. - emergecmd = "emerge --oneshot " + portage.settings["EMERGE_OPTS"] + " =" + pkg - if verbose: - sys.stderr.write(emergecmd+"\n") - exitcode = os.system(emergecmd) - # system() returns the exitcode in the high byte of a 16bit integer - if exitcode >= 1<<8: - exitcode >>= 8 - if exitcode: - sys.exit(exitcode) - myglsa.inject() + sys.stdout.write("Fixing GLSA "+myid+"\n") + if not myglsa.isVulnerable(): + sys.stdout.write(">>> no vulnerable packages installed\n") + else: + mergelist = myglsa.getMergeList(least_change=least_change) + if mergelist == []: + sys.stdout.write(">>> cannot fix GLSA, no unaffected packages available\n") + sys.exit(2) + for pkg in mergelist: + sys.stdout.write(">>> merging "+pkg+"\n") + # using emerge for the actual merging as it contains the dependency + # code and we want to be consistent in behaviour. Also this functionality + # will be integrated in emerge later, so it shouldn't hurt much. + emergecmd = "emerge --oneshot " + " =" + pkg + if verbose: + sys.stderr.write(emergecmd+"\n") + exitcode = os.system(emergecmd) + # system() returns the exitcode in the high byte of a 16bit integer + if exitcode >= 1<<8: + exitcode >>= 8 + if exitcode: + sys.exit(exitcode) + if len(mergelist): + sys.stdout.write("\n") elif mode == "pretend": sys.stdout.write("Checking GLSA "+myid+"\n") - mergelist = myglsa.getMergeList(least_change=least_change) - if mergelist: - sys.stdout.write("The following updates will be performed for this GLSA:\n") - for pkg in mergelist: - oldver = None - for x in vardb.match(portage.cpv_getkey(pkg)): - if vardb.aux_get(x, ["SLOT"]) == portdb.aux_get(pkg, ["SLOT"]): - oldver = x - if oldver == None: - raise ValueError("could not find old version for package %s" % pkg) - oldver = oldver[len(portage.cpv_getkey(oldver))+1:] - sys.stdout.write(" " + pkg + " (" + oldver + ")\n") + if not myglsa.isVulnerable(): + sys.stdout.write(">>> no vulnerable packages installed\n") else: - sys.stdout.write("Nothing to do for this GLSA\n") + mergedict = {} + for (vuln, update) in myglsa.getAffectionTable(least_change=least_change): + mergedict.setdefault(update, []).append(vuln) + + sys.stdout.write(">>> The following updates will be performed for this GLSA:\n") + for pkg in mergedict: + if pkg != "": + sys.stdout.write(" " + pkg + " (vulnerable: " + ", ".join(mergedict[pkg]) + ")\n") + if "" in mergedict: + sys.stdout.write("\n>>> For the following packages, no upgrade path exists:\n") + sys.stdout.write(" " + ", ".join(mergedict[""])) elif mode == "inject": sys.stdout.write("injecting " + myid + "\n") myglsa.inject() @@ -268,9 +283,9 @@ if mode == "test": # mail mode as requested by solar if mode == "mail": import portage.mail, socket - from io import StringIO + from io import BytesIO from email.mime.text import MIMEText - + # color doesn't make any sense for mail nocolor() @@ -278,7 +293,7 @@ if mode == "mail": myrecipient = portage.settings["PORTAGE_ELOG_MAILURI"].split()[0] else: myrecipient = "root@localhost" - + if "PORTAGE_ELOG_MAILFROM" in portage.settings: myfrom = portage.settings["PORTAGE_ELOG_MAILFROM"] else: @@ -287,11 +302,13 @@ if mode == "mail": mysubject = "[glsa-check] Summary for %s" % socket.getfqdn() # need a file object for summarylist() - myfd = StringIO() - myfd.write("GLSA Summary report for host %s\n" % socket.getfqdn()) - myfd.write("(Command was: %s)\n\n" % " ".join(sys.argv)) + myfd = BytesIO() + line = "GLSA Summary report for host %s\n" % socket.getfqdn() + myfd.write(line.encode("utf-8")) + line = "(Command was: %s)\n\n" % " ".join(sys.argv) + myfd.write(line.encode("utf-8")) summarylist(glsalist, fd1=myfd, fd2=myfd) - summary = str(myfd.getvalue()) + summary = myfd.getvalue().decode("utf-8") myfd.close() myattachments = [] @@ -302,16 +319,17 @@ if mode == "mail": if verbose: sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e))) continue - myfd = StringIO() + myfd = BytesIO() myglsa.dump(outstream=myfd) - myattachments.append(MIMEText(str(myfd.getvalue()), _charset="utf8")) + attachment = myfd.getvalue().decode("utf-8") + myattachments.append(MIMEText(attachment, _charset="utf8")) myfd.close() - + mymessage = portage.mail.create_message(myfrom, myrecipient, mysubject, summary, myattachments) portage.mail.send_mail(portage.settings, mymessage) - + sys.exit(0) - + # something wrong here, all valid paths are covered with sys.exit() sys.stderr.write("nothing more to do\n") sys.exit(2) |