~ubuntu-security/ubuntu-cve-tracker/master

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/python

# Author: Jamie Strandboge <jamie@ubuntu.com>
# Copyright (C) 2012 Canonical Ltd.
#
# This script is distributed under the terms and conditions of the GNU General
# Public License, Version 2 or later. See http://www.gnu.org/copyleft/gpl.html
# for details.

import cPickle
import optparse
import os
import pprint
import signal
import subprocess
import tempfile
import sys

# TODO: use usn_lib.py
def load_database(db_filename):
    '''Load usn database'''
    print >>sys.stderr, "INFO: Loading %s..." % (db_filename)
    filename = os.path.expanduser(db_filename)
    if not os.path.isfile(filename):
        return {}
    return cPickle.load(open(filename))

def get_norm_db_as_str(db):
    '''Print the db in a normalized format, that can be used to compare'''
    return pprint.pformat(db)

def subprocess_setup():
    # Python installs a SIGPIPE handler by default. This is usually not what
    # non-Python subprocesses expect.
    signal.signal(signal.SIGPIPE, signal.SIG_DFL)

def cmd(command, input = None, stderr = subprocess.STDOUT, stdout = subprocess.PIPE, stdin = None, timeout = None):
    '''Try to execute given command (array) and return its stdout, or return
    a textual error if it failed.'''

    try:
        sp = subprocess.Popen(command, stdin=stdin, stdout=stdout, stderr=stderr, close_fds=True, preexec_fn=subprocess_setup)
    except OSError, e:
        return [127, str(e)]

    out, outerr = sp.communicate(input)
    # Handle redirection of stdout
    if out == None:
        out = ''
    # Handle redirection of stderr
    if outerr == None:
        outerr = ''
    return [sp.returncode,out+outerr]

def diff_db(db1, db2):
    '''Compare two databases'''
    tmpdir = tempfile.mkdtemp(prefix='usndb-tool-')

    fn1 = os.path.join(tmpdir, "db1")
    print >>sys.stderr, "INFO: Formatting %s..." % (os.path.basename(fn1))
    open(fn1,'w').write(get_norm_db_as_str(db1))

    fn2 = os.path.join(tmpdir, "db2")
    print >>sys.stderr, "INFO: Formatting %s..." % (os.path.basename(fn2))
    open(fn2,'w').write(get_norm_db_as_str(db2))

    print >>sys.stderr, "INFO: diffing %s %s..." % (os.path.basename(fn1), os.path.basename(fn2))
    rc, report = cmd(['diff', '-u', fn1, fn2])

    os.unlink(fn1)
    os.unlink(fn2)
    os.rmdir(tmpdir)

    return report

#
# main
#
if __name__ == "__main__":
    parser = optparse.OptionParser()
    parser.add_option("--db", help="database file", metavar="FILE")
    parser.add_option("--db2", help="database file", metavar="FILE")
    parser.add_option("--diff", help="Perform diff on files", action='store_true', default=False)
    parser.add_option("--dump", help="Dump the specified db to stdout", action='store_true', default=False)
    (opt, args) = parser.parse_args()

    if not opt.db:
        print >>sys.stderr, "Must specify --db"
        sys.exit(1)
    elif not opt.diff and not opt.dump:
        print >>sys.stderr, "Must specify one of --diff or --dump"
        sys.exit(1)
    elif opt.diff and not opt.db2:
        print >>sys.stderr, "Must specify --db2"
        sys.exit(1)
    elif opt.db and not os.path.isfile(opt.db):
        print >>sys.stderr, "'%s' is not a file" % opt.db
        sys.exit(1)
    elif opt.db2 and not os.path.isfile(opt.db2):
        print >>sys.stderr, "'%s' is not a file" % opt.db2
        sys.exit(1)

    db = load_database(opt.db)
    if opt.db2:
        db2 = load_database(opt.db2)

    if opt.diff:
        diff = diff_db(db, db2)
        if diff != "":
            print diff_db(db, db2)
    elif opt.dump:
        print get_norm_db_as_str(db)
    else:
        print >>sys.stderr, "Unrecognized command"
        sys.exit(1)
    sys.exit(0)