From bfffbf4a58a9dcd1a302879f5000f03ecfc473bd Mon Sep 17 00:00:00 2001 From: yusuf Date: Thu, 20 Aug 2015 15:05:01 +0300 Subject: [PATCH] opps --- checkelf | 580 ------------------------------------------------------- 1 file changed, 580 deletions(-) delete mode 100755 checkelf diff --git a/checkelf b/checkelf deleted file mode 100755 index 18d6e2f7..00000000 --- a/checkelf +++ /dev/null @@ -1,580 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# Copyright (C) 2009-2010 TUBITAK/UEKAE -# -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free -# Software Foundation; either version 2 of the License, or (at your option) -# any later version. - -# For more information execute run with '--help' -# -# A detailed documentation about checkelf can be found on: -# http://developer.pardus.org.tr/guides/packaging/checkelf.html - -import os -import re -import sys -import glob -import pisi -import magic -import shutil -import fnmatch -import tempfile -import optparse -import itertools -import subprocess - -FILESDB = pisi.db.filesldb.FilesLDB() -INSTALLDB = pisi.db.installdb.InstallDB() -CONSTANTS = pisi.constants.Constants() -CMPFILTR = re.compile("(.*?)(\s*\((base|devel)\)\s*)$") - -def process_ldd(objdump_needed, ldd_output, ldd_unused, ldd_undefined): - '''Process the ldd outputs. And return a simple path only lists''' - result_unused = [] - result_undefined = [] - result_broken = [] - result_main_ldd = {} - result_needed = [] - - for line in ldd_unused.replace("\t", "").split("\n"): - if not line == "" and not "Unused" in line: - result_unused.append(line.strip()) - - for line in ldd_undefined.replace("\t", "").split("\n"): - if line.startswith("undefined symbol:"): - result_undefined.append(re.sub("^undefined symbol: (.*)\((.*)\)$", "\\1", line)) - - for line in ldd_output: - if "=>" in line: - # Filter these special objects - if "linux-gate" in line or \ - "ld-linux" in line or "linux-vdso" in line: - continue - - so_name, so_path = line.split("=>") - if "not found" in so_path: - # One of the dynamic dependencies is missing - result_broken.append(so_name.strip()) - else: - result_main_ldd[so_name.strip()] = so_path.split(" (")[0].strip() - - for obj in objdump_needed: - # Find the absolute path of libraries from their SONAME's - if result_main_ldd.has_key(obj): - result_needed.append(os.popen("readlink -f %s" % result_main_ldd[obj]).read().strip()) - else: - result_needed.append(obj) - - # result_needed = (all shared libary dependencies) - (needed shared library gathered from objdump) - # result_broken = broken libraries that are not available at their place - # result_unused = unused direct dependencies - # result_undefined = undefined symbol errors - return (result_needed, result_broken, result_unused, result_undefined) - -found_objdump = [] -def check_objdump(processed_needed, package_elf_files, package_name): - '''check the objdump needed libraries with the ldd libraries - the libraries that are needed can be used for dependencies''' - result_needed = [] - # check if the libraries are shipped with the package - # then associate each library(with his package_name) with the given elf_file - for objdump_needed in processed_needed: - if objdump_needed in package_elf_files: - # file is shipped within this package - dependency_name = package_name - else: - # search for the package name (i.e: pisi sf /usr/lib/*.so ) - # the library may not exist, thus adding an exception is welcome - if objdump_needed.startswith("/"): objdump_needed = objdump_needed[1:] - if objdump_needed in found_objdump: continue - try: - dependency_name = FILESDB.search_file(objdump_needed)[0][0] - found_objdump.extend([x.path for x in INSTALLDB.get_files(dependency_name).list]) - except IndexError: - dependency_name = "broken" - #print "%s (probably broken dependency)" % needed - result_needed.append((objdump_needed, dependency_name)) - return result_needed - -found_pc_files = [] -def check_pc_files(pc_file): - '''check for .pc files created by pkgconfig and shipped with the package - these .pc files have requirements tags that can be used for dependencies''' - result_needed = [] - requires = set(os.popen("pkg-config --print-requires --print-requires-private %s | gawk '{ print $1 }'" % \ - os.path.basename(pc_file).replace(".pc", "")).read().split("\n")[:-1]) - - for require in requires: - require_file = "usr/share/pkgconfig/%s.pc" % require - - if not os.path.exists("/%s" % require_file): - require_file = "usr/lib/pkgconfig/%s.pc" % require - if require_file in found_pc_files: continue - try: - dependency_name = FILESDB.search_file(require_file)[0][0] - found_pc_files.extend([x.path for x in INSTALLDB.get_files(dependency_name).list]) - except IndexError: - dependency_name = "broken" - - result_needed.append((require_file, dependency_name)) - - return result_needed - -def check_intersections(result_dependencies, package_deps, package_name, systembase, systemdevel): - '''eliminate system base and system devel packages and self written deps''' - - # get system.base and system.devel packages - systembase_packages = [] - systemdevel_packages= [] - cdb = pisi.db.componentdb.ComponentDB() - for repo in pisi.db.repodb.RepoDB().list_repos(): - for component in cdb.list_components(repo): - if component == "system.base": - systembase_packages.extend(cdb.get_packages('system.base', repo)) - if component == "system.devel": - systemdevel_packages.extend(cdb.get_packages('system.devel', repo)) - - # look for packages that are system.base but are written as dependency - # mark them with "*" - result_must_removed = list(set(package_deps) & set(systembase_packages)) - for deps in package_deps: - if deps in result_must_removed: - package_deps[package_deps.index(deps)] = "%s (base)" % deps - - # look for packages that are system.devel but are written as dependency - # mark them with "*" - result_must_removed = list(set(package_deps) & set(systemdevel_packages)) - for deps in package_deps: - if deps in result_must_removed: - package_deps[package_deps.index(deps)] = "%s (devel)" % deps - - # extract the dependency package names and store them in result_deps - # dependencies tagged as broken or given itself are eliminated - dependencies = set() - result_deps = [] - for elf_files, paths_and_deps in result_dependencies.items(): - for data in paths_and_deps: - if not data[1] == "broken" and not data[1] == package_name and not data[1].replace("32-bit", "") == "glibc": - if (data[1].startswith("xorg-video-nvidia") or data[1].startswith("xorg-video-fglrx")) \ - and not (package_name.startswith("xorg-video-nvidia") or package_name.startswith("xorg-video-fglrx")): - result_deps.append("mesa") - else: - result_deps.append(data[1]) - - # remove packages that belong to system.base component - # when -s is used, systembase is set to true - # using set removes also duplicates in result_deps - # mark packages that are common to system.base and result_deps with * - if not systembase: - result_deps = list(set(result_deps) - set(systembase_packages)) - if not systemdevel and package_name.endswith('-devel'): - result_deps = list(set(result_deps) - set(systemdevel_packages)) - if systemdevel or systembase: - result_must_removed = list(set(result_deps) & set(systembase_packages)) - for deps in result_deps: - if deps in result_must_removed: - result_deps[result_deps.index(deps)] = "%s (base)" % deps - result_must_removed = list(set(result_deps) & set(systemdevel_packages)) - for deps in result_deps: - if deps in result_must_removed: - result_deps[result_deps.index(deps)] = "%s (devel)" % deps - result_deps = list(set(result_deps)) - - # remove packages that already are written in metadata.xml (runtime dependencies written in pspec.xml) - #result_section = list(set(result_deps) - set(package_deps)) - result_section = list(set([re.sub(CMPFILTR, r"\1", x) for x in result_deps]) - set([re.sub(CMPFILTR, r"\1", x) for x in package_deps])) - - # create a sorted iteration object of the final results variables - # the lists may have variable lengths, thus we fill the smallers one with empty strings. - # at the end all the lists are in the same length. This makes it easy to print it like a table - #cmp_func = lambda x, y: len(x) - len(y) - cmp_func = lambda x, y: len(re.sub(CMPFILTR, r"\1", x)) - len(re.sub(CMPFILTR, r"\1", y)) - result_lists = itertools.izip_longest(sorted(sorted(list(set(package_deps))), cmp=cmp_func), - sorted(sorted(result_deps), cmp=cmp_func), - sorted(sorted(result_section), cmp=cmp_func), - fillvalue="") - return result_lists - -def output_result(package_name, package_dir): - '''execute ldd on elf files and returns them''' - #Initialize magic for using "file" in python - magic_db = magic.open(magic.MAGIC_NONE) - magic_db.load() - - package_elf_files = [] - - # Two options are available. Checking for a pisi file or an installed package in the database - if package_dir: - package_files = os.popen("find %s" % package_dir).read().strip().split("\n") - package_pc_files = glob.glob("%s/usr/*/pkgconfig/*.pc" % package_dir) - else: - package_files = set(["/%s" % file_name.path \ - for file_name in INSTALLDB.get_files(package_name).list]) - package_pc_files = set([os.path.realpath("/%s" % file_name.path) \ - for file_name in INSTALLDB.get_files(package_name).list \ - if fnmatch.fnmatch(file_name.path, "*/pkgconfig/*.pc")]) - - for package_file in package_files: - package_file_info = magic_db.file(package_file) #Return file type - if re.search("LSB\s+shared object", package_file_info): - package_elf_files.append(os.path.realpath(package_file)) - elif re.search("LSB\s+executable", package_file_info): - package_elf_files.append(package_file) - - #There maybe more than one elf file, check for each one - result_dependencies = {} - result_unused = {} - result_undefined = {} - result_broken = None - result_runpath = {} - ld_library_paths = set() - - # Add library paths for unpacked pisi files - if package_dir: - for elf_file in package_elf_files: - if elf_file.endswith(".so") or ".so." in elf_file: - ld_library_paths.add(os.path.dirname(elf_file)) - os.environ.update({'LD_LIBRARY_PATH': ":".join(ld_library_paths)}) - - for elf_file in package_elf_files: - ldd_output = subprocess.Popen(["ldd", elf_file], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - env = os.environ).communicate()[0].strip().split("\n") - - ldd_unused, ldd_undefined = subprocess.Popen(["ldd", "-u", "-r", elf_file], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - env = os.environ).communicate() - - runpath = subprocess.Popen(["chrpath", "-l", elf_file], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - env = os.environ).communicate()[0].strip().split(": ") - - objdump_needed = [line.strip().split()[1] for line in \ - os.popen("objdump -p \"%s\" | grep 'NEEDED'" % elf_file).readlines()] - - - # Process the various ldd and objdump outputs - processed_needed, processed_broken, processed_unused, processed_undefined = \ - process_ldd(objdump_needed, ldd_output, ldd_unused, ldd_undefined) - - # association with each single elf file - result_unused.update(dict([(elf_file, processed_unused)])) - result_undefined.update(dict([(elf_file, processed_undefined)])) - result_runpath.update(dict([(elf_file, runpath)])) - result_broken = processed_broken - result_dependencies[elf_file] = check_objdump(processed_needed, package_elf_files, package_name) - - # Check for .pc files - for pc_file in package_pc_files: - result_dependencies[pc_file] = check_pc_files(pc_file) - - return (result_dependencies, result_broken, result_unused, result_undefined, result_runpath) - -def colorize(msg, color, nocolor=False): - """Colorizes the given message.""" - # The nocolor is added to shut off completely. You may ask the point of this - # someone want to pipe the output, but the asci characters will also printed - if nocolor: - return msg - else: - colors = {'green' : '\x1b[32;01m%s\x1b[0m', - 'red' : '\x1b[31;01m%s\x1b[0m', - 'yellow' : '\x1b[33;01m%s\x1b[0m', - 'bold' : '\x1b[1;01m%s\x1b[0m', - 'none' : '\x1b[0m%s\x1b[0m', - } - return colors[color if sys.stdout.isatty() else 'none'] % msg - -def main(arg): - '''Initialize packages and get the results. Prints them out ''' - # This is of type dictionary, it includes all the - # options from the parser such as option.directory, etc. - option = arg[0] - - # Arguments are stored here, - # such as the path of -d, or the pisi file. - packages = arg[1] - - # checklib is executed plain only, no packages are - # defined. It will look for pisi files inside that directory - # where checklib is executed - if not packages: - pisi_files = glob.glob("*.pisi") - if pisi_files: - packages.extend(pisi_files) - - # If directory is used as option - if option.directory: - if option.recursive: - for root, dirs, files in os.walk(option.directory): - for data in files: - if data.endswith(".pisi"): - packages.append(os.path.join(root, data)) - else: - # No recursion is used, just get the pisi - # files from directory specified with -d - pisi_files = glob.glob("%s/*.pisi" % option.directory) - packages.extend(pisi_files) - - # check for components, like system.base, tex.language, etc. - if option.component: - cdb = pisi.db.componentdb.ComponentDB() - for repo in pisi.db.repodb.RepoDB().list_repos(): - if cdb.has_component(option.component): - packages.extend(cdb.get_packages(option.component, repo)) - - # check for all packages installed on the machine - if option.installedlist: - packages.extend(INSTALLDB.list_installed()) - - used_pisi = False # Do not check for a pisi binary file and for a package installed on the system - for package in packages: - # Check loop for .pisi files - if package.endswith(".pisi"): - used_pisi = True - package_pisi = pisi.package.Package(package) - package_meta = package_pisi.get_metadata() - package_name = package_meta.package.name - - # Gather runtime dependencies directly from the metadata.xml - package_deps = [dep.name() for dep in package_meta.package.runtimeDependencies()] - - # Contains extracted package content - package_tempdir = tempfile.mkdtemp(prefix=os.path.basename(sys.argv[0]) + '-') - package_pisi.extract_install(package_tempdir) - - # Get results from objdump,ldd,etc... - result_dependencies, result_broken, result_unused, result_undefined, result_runpath = \ - output_result(package_name, package_tempdir) - - # Look for intersections of the packages(i.e. do not include system.base packages) - # result_lists is a iteration object which contains tuples of length 3 - # this tuple makes it easy to print the missing dependencies. look for print_results() - result_lists = check_intersections(result_dependencies, package_deps, package_name, option.systembase, option.systemdevel) - - # Print the results in a fancy output - print_results(result_broken, result_unused, result_undefined, result_lists, result_runpath, package_name, option) - - # Delet the created temporary directory - if package_tempdir.startswith("/tmp/"): - shutil.rmtree(package_tempdir) - - # Check for a installed package in the system - elif package in INSTALLDB.list_installed(): - if used_pisi: - print "You've checked for a pisi file before\nPlease do not check for a installed package and pisi file at the same time" - sys.exit(1) - else: - package_name = package - - # Gather runtime dependencies directly from the database of installed packages - package_deps = [dep.name() for dep in INSTALLDB.get_package(package).runtimeDependencies()] - package_tempdir = False # There is no need of temporary directory, hence we look for files that are installed - - # Same functions in the above part. You can read them - result_dependencies, result_broken, result_unused, result_undefined, result_runpath = \ - output_result(package_name, package_tempdir) - - result_lists = check_intersections(result_dependencies, package_deps, package_name, option.systembase, option.systemdevel) - print_results(result_broken, result_unused, result_undefined, result_lists, result_runpath, package_name, option) - - else: - print "Error: '%s' is not a valid .pisi file or an installed package\nPlease use -d option for a directory" % package - -def print_results(result_broken, result_unused, result_undefined, result_lists, result_runpath, package_name, option): - '''Print the final results in fancy colors''' - - def print_header(title, nocolor, color): - print colorize("\n%s" % title, color , nocolor) - print colorize("%s" % (len(title) * '-'), color, nocolor) - - def print_unused(result_unused, result_broken): - header_dumped = False - - # Mark broken libs - for elf_file, libs in result_unused.items(): - result_unused[elf_file] = map(lambda x: ("%s (broken)" % x) if x in result_broken else x, libs) - - for elf_file, libs in result_unused.items(): - if libs: - if not header_dumped: - print_header("Unused direct dependency analysis", option.nocolor, 'green') - header_dumped = True - print colorize(elf_file, 'red', option.nocolor) - for data in libs: - print " ", data - - def print_undefined(result_undefined): - header_dumped = False - for elf_file, libs in result_undefined.items(): - if libs: - if not header_dumped: - print_header("Undefined symbol analysis", option.nocolor, 'green') - header_dumped = True - print colorize(elf_file, 'red', option.nocolor) - for data in libs: - print " ", data - - def print_runpath(result_runpath): - header_dumped = False - for elf_file, libs in result_runpath.items(): - if libs: - if "RPATH" in libs[1]: - if not header_dumped: - print_header("Runpath analysis", option.nocolor, 'green') - header_dumped = True - print colorize(elf_file, 'red', option.nocolor) - print " ", libs[1] - - def print_dependencies(result_lists): - print colorize("\nWritten dependencies Detected dependencies Missing dependencies", 'green', option.nocolor) - print colorize("----------------------------------------------------------------------------------", 'green', option.nocolor) - - for tuple_deps in result_lists: - for deps in tuple_deps: - if "(base)" in deps: - print "%s" % colorize(deps.ljust(30), 'red', option.nocolor), - elif "(devel)" in deps: - print "%s" % colorize(deps.ljust(30), 'yellow', option.nocolor), - else: - print deps.ljust(30), - print - - def print_missing(result_lists, plain_list): - if not plain_list: - print_header("Missing dependencies", option.nocolor, 'green') - - for tuple_deps in result_lists: - pkg = tuple_deps[2] - if "(base)" in pkg: - print "%s" % colorize(pkg, 'red', option.nocolor) - elif pkg: - print pkg - - if not option.plain_list: - print_header("Package: %s" % package_name, option.nocolor, 'bold') - - # This part is for the behavior of checklib argument parsing - # If no options are used at all, than we show all options - # If any of the other options is used, only the choosen ones are showed - if not option.unused and not option.undefined and not option.dependencies \ - and not option.runpath and not option.missing: - print_unused(result_unused, result_broken) - print_undefined(result_undefined) - print_runpath(result_runpath) - #print set(result_lists) - print_dependencies(result_lists) - - else: - if option.unused: - print_unused(result_unused, result_broken) - if option.undefined: - print_undefined(result_undefined) - if option.runpath: - print_runpath(result_runpath) - if option.dependencies: - print_dependencies(result_lists) - if option.missing: - print_missing(result_lists, option.plain_list) - -def argument(): - '''Command line argument parsing''' - # TODO: use argparse() in the future - - parser = optparse.OptionParser(usage="Usage: %prog [options] foo.pisi foo2.pisi \n \t%prog [options] -d \n \t%prog [options]\n \t%prog [options] foo", - version="%prog 0.1") - - # Group options - # check_options = optparse.OptionGroup(parser, "Check Options") - - parser.add_option("-n", "--no-color", - action="store_true", - dest="nocolor", - default=False, - help="Do not colorize the output (useful for piping the output)") - - parser.add_option("-l", "--plain-list", - action="store_true", - dest="plain_list", - default=False, - help="Don't prettify the outputs, only a list of packages") - - parser.add_option("-u", "--unused", - action="store_true", - dest="unused", - default=False, - help="Show only unused direct dependencies") - - parser.add_option("-f", "--undefined", - action="store_true", - dest="undefined", - default=False, - help="Show only undefined symbols") - - parser.add_option("-m", "--missing", - action="store_true", - dest="missing", - default=False, - help="Show only missing dependencies") - - parser.add_option("-t", "--dependencies", - action="store_true", - dest="dependencies", - default=False, - help="Show dependencies in a table") - - parser.add_option("-p", "--runpath", - action="store_true", - dest="runpath", - default=False, - help="Show RPATH status") - - parser.add_option("-s", "--systembase", - action="store_true", - dest="systembase", - default=False, - help="Don't hide system.base dependencies") - - parser.add_option("-x", "--systemdevel", - action="store_true", - dest="systemdevel", - default=False, - help="Show(colorize) system.devel dependencies") - - parser.add_option("-c", "--component", - action="store", - dest="component", - type="string", - help="Check a whole component") - - parser.add_option("-a", "--all", - action="store_true", - dest="installedlist", - default=False, - help="Check all installed packages") - - parser.add_option("-d", "--directory", - action="store", - dest="directory", - type="string", - metavar="", - help="Specify a folder to check") - - parser.add_option("-r", "--recursive", - action="store_true", - dest="recursive", - default=False, - help="Check recursively in the specified folder") - - return parser.parse_args() - -if __name__ == "__main__": - args = argument() - sys.exit(main(args)) -