aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/pstage-scanner
blob: 4a27aa5d262b2b9dd4d7a1b6cf726c28938d4a75 (plain)
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/usr/bin/env python

##
## This script will scan all of the packages in PSTAGE_DIR (or argv[1])
## in search of packages which install files outside of their native sysroot
##

import os, sys, tarfile, shutil
import subprocess as sub

logf = ""
pcount = 0
ecount = 0

def main():
    """Generate a list of pstage packages and scan them for badness"""
    package_list = []

    try:
        path = sysv.arg[1]
    except:
        # Assume pstage is a child of tmp, Poky's default
        tmpdir = None
        sub.Popen(["bitbake", "-e"], stdout=sub.PIPE,stderr=sub.PIPE)
        err, out = p.communicate()
        if (!out):
            print("bitbake not in your environment, try pstage-scanner /some/path/to/pstage")
            exit
        for line in out:
            if line.find("PSTAGE_DIR=") != -1:
                tmpdir = line.partition("=")[2].strip("\"")
                break

    if len(path) < 1 or not os.path.exists(path):
        print ("No path defined and bitbake not in your environment, try pstage-scanner /some/path/to/pstage")
        exit
    
    global logf
    try:
        logf = sys.argv[2]
    except:
        logf = os.path.join(path, "pstage-scanner.log")

    ## Create a working directory
    tempdir = os.path.join(path, "tmp")
    os.mkdir(tempdir)

    ## Iterate each child of the target directory looking for .ipk files and
    ## building a list of files to process
    for root, dirs, files in os.walk(path):
        for d in dirs:
            for f in os.listdir(os.path.join(root,d)):
                if os.path.splitext(f)[1] == ".ipk" and f.find("native") == -1 and f.find("cross") == -1:
                    package_list.append(os.path.join(root,d,f))

    ## Next we iterate our built list of files and process each package
    for pkg in package_list:
        tmp = os.path.join(tempdir, os.path.splitext(os.path.split(pkg)[1])[0])
        os.mkdir(tmp)
        scan_package(pkg, tmp)

    ## Tidy up working directory
    shutil.rmtree(tempdir)

    ## Report a summary
    log("Finished scanning packaged staging. Scanned %i packages with %i errors" % (pcount, ecount))

def scan_package(filepath, parentdir):
    """Helper method to do bookkeeping, passes all installable directories to
    scan_dir which does the actual scanning."""
    os.chdir(parentdir)

    ## increment the package count, for the summary
    global pcount
    pcount += 1
    
    ## An ipk file is an ar archive containing two gzipped tarball directories
    ## data.tar.gz is inflated to / and contains the actual files
    ## control.tar.gz is metadata and scripts for the package
    ## The archive also contains a file, debian binary, which is unused
    ## Python can't handle ar archives ootb. So we cheat and inflate with
    ## the ar program on the host
    sub.call(["ar", "x", filepath])
    
    ## The things we care about are in data.tar.gz
    tgz = tarfile.open(os.path.join(parentdir, "data.tar.gz"))
    dest = os.path.join(parentdir, "inflate")
    os.mkdir(dest)
    tgz.extractall(dest)

    ## We want to know the target arch so that we can ensure the package is
    ## only installing into its target sysroot
    arch =  os.path.splitext(os.path.basename(filepath))[0].split("_")[-1]
    if arch == "64":
        arch = "x86_64"

    ## The ignored list contains directories we don't care to scan
    ignored = ["pkgdata", "stamps", "deploy"]

    ## Scan the package for badness
    pname = os.path.split(filepath)[1]
    for di in os.listdir(dest):
        if di not in ignored:
            scan_dir(os.path.join(dest, di), arch, pname)

def scan_dir (directory, arch, package_name):
    """Scan the contents of directory for things installing outside of native
    sysroot"""

    global ecount
    msg = ""

    head, tail = os.path.split(directory)
    if not tail == "sysroots":
        msg += "Tsk tsk, installing to " + tail + "\n"
        for d in os.listdir(directory):
            msg += "Installing %s in %s" % (d, tail) + "\n"
            ecount += 1
    else:
        for d in os.listdir(directory):
            if not d.startswith(arch) and d.find("fixmepath") == -1:
                msg += "Tsk tsk, installing into non-native sysroot " + os.path.join(directory, d)
                ecount += 1

    if len(msg) > 0:
        log("Scanning package " + package_name  + "\n" + msg)

def log (message):
    global logf
    logfile = open (logf, 'a+')
    logfile.write(message + "\n")
    print "LOG: " + message
    logfile.close()

if __name__ == "__main__":
    main()