[csw-devel] SF.net SVN: gar:[7727] csw/mgar/gar/v2-checkpkg/bin/checkpkg.d

wahwah at users.sourceforge.net wahwah at users.sourceforge.net
Thu Dec 24 00:44:47 CET 2009


Revision: 7727
          http://gar.svn.sourceforge.net/gar/?rev=7727&view=rev
Author:   wahwah
Date:     2009-12-23 23:44:47 +0000 (Wed, 23 Dec 2009)

Log Message:
-----------
checkpkg.d: analyzing .so dependencies of single packages passes the smoke test (this time for real)

Modified Paths:
--------------
    csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg-libs.py
    csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg.py

Added Paths:
-----------
    csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg_test.py

Property Changed:
----------------
    csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg-libs.py

Modified: csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg-libs.py
===================================================================
--- csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg-libs.py	2009-12-23 23:40:15 UTC (rev 7726)
+++ csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg-libs.py	2009-12-23 23:44:47 UTC (rev 7727)
@@ -5,12 +5,198 @@
 # A check for dependencies between shared libraries.
 
 import checkpkg
+import os
 import os.path
+import copy
+import re
+import subprocess
+import logging
 
+DUMP_BIN = "/usr/ccs/bin/dump"
+NEEDED_SONAMES = "needed sonames"
+RUNPATH = "runpath"
+
 def main():
+  logging.basicConfig(level=logging.DEBUG)
   options, args = checkpkg.GetOptions()
-  pkgpath = os.path.join(options.extractdir, options.pkgname)
+  checker = checkpkg.CheckpkgBase(options.extractdir, options.pkgname)
+  binaries = checker.ListBinaries()
+  ws_re = re.compile(r"\s+")
 
+  # if [[ "$goodarch" = "yes" ]] ; then
+  #   # man ld.so.1 for more info on this hack
+  #   export LD_NOAUXFLTR=1
+  # 
+  #   listbinaries $EXTRACTDIR/$pkgname >$EXTRACTDIR/elflist
+  #   # have to do this for ldd to work. arrg.
+  #   if [ -s "$EXTRACTDIR/elflist" ] ; then
+  #     chmod 0755 `cat $EXTRACTDIR/elflist`
+  # 
+  #     cat $EXTRACTDIR/elflist| xargs dump -Lv |nawk '$2=="NEEDED"{print $3}' |
+  #       sort -u | egrep -v $EXTRACTDIR >$EXTRACTDIR/liblist
+  # 
+  #       
+  # 
+  #     print libraries used are:
+  #     cat $EXTRACTDIR/liblist
+  #     print "cross-referencing with depend file (May take a while)"
+  #   else
+  #     print No dynamic libraries in the package
+  #   fi
+  # fi
+   
+  env = copy.copy(os.environ)
+  env["LD_NOAUXFLTR"] = "1"
+  binaries_by_name = {}
+  # Assembling a data structure with the data about binaries.
+  # {
+  #   <binary1 name>: {NEEDED_SONAMES: [...],
+  #                   RUNPATH:     [...]},
+  #   <binary2 name>: ...,
+  #   ...
+  # }
+  #
+  for binary in binaries:
+    binary_base_name = binary.split("/")[-1]
+    if binary_base_name not in binaries_by_name:
+      binaries_by_name[binary_base_name] = {}
+    binary_data = binaries_by_name[binary_base_name]
+    args = [DUMP_BIN, "-Lv", binary]
+    dump_proc = subprocess.Popen(args, stdout=subprocess.PIPE)
+    stdout, stderr = dump_proc.communicate()
+    ret = dump_proc.wait()
+    for line in stdout.splitlines():
+      fields = re.split(ws_re, line)
+      logging.debug("%s says: %s", DUMP_BIN, fields)
+      if len(fields) < 3:
+        continue
+      if fields[1] == "NEEDED":
+        if NEEDED_SONAMES not in binary_data:
+          binary_data[NEEDED_SONAMES] = []
+        binary_data[NEEDED_SONAMES].append(fields[2])
+      elif fields[1] == "RUNPATH":
+        if RUNPATH not in binary_data:
+          binary_data[RUNPATH] = []
+        binary_data[RUNPATH].extend(fields[2].split(":"))
+        # Adding the default runtime path search option.
+        binary_data[RUNPATH].append("/usr/lib")
+  print binaries_by_name
 
+  # Building indexes
+  runpath_by_needed_soname = {}
+  # {"foo.so": ["/opt/csw/lib/gcc4", "/opt/csw/lib", ...],
+  #  ...
+  # }
+  needed_sonames = set()
+  binaries_by_soname = {}
+  for binary_name, data in binaries_by_name.iteritems():
+    for soname in data[NEEDED_SONAMES]:
+      needed_sonames.add(soname)
+      if soname not in runpath_by_needed_soname:
+        runpath_by_needed_soname[soname] = []
+      runpath_by_needed_soname[soname].extend(data[RUNPATH])
+      if soname not in binaries_by_soname:
+        binaries_by_soname[soname] = []
+      binaries_by_soname[soname].append(binary_name)
+
+  pkgmap = checkpkg.SystemPkgmap()
+  paths_by_soname = pkgmap.paths_by_soname
+
+  logging.debug("Determining soname-file relationships.")
+  # lines by soname is an equivalent of $EXTRACTDIR/shortcatalog
+  lines_by_soname = {}
+  for soname in needed_sonames:
+    if soname in paths_by_soname:
+      logging.debug("%s found", repr(soname))
+      # Finding the first matching path
+      for runpath in runpath_by_needed_soname[soname]:
+        if runpath in paths_by_soname[soname]:
+          logging.debug("%s found in %s", runpath, paths_by_soname[soname])
+          logging.debug("line found: %s", repr(paths_by_soname[soname][runpath]))
+          lines_by_soname[soname] = paths_by_soname[soname][runpath]
+          break
+    else:
+      logging.debug("%s not found in the soname list!", soname)
+  for soname in needed_sonames:
+    if soname in binaries:
+    	print "%s is provided by the package itself" % soname
+    elif soname in lines_by_soname:
+      print ("%s is required by %s and provided by %s" 
+             % (soname,
+                binaries_by_soname[soname],
+                repr(lines_by_soname[soname])))
+    else:
+    	print ("%s is required by %s, but we don't know what provides it."
+    	       % (soname, binaries_by_soname[soname]))
+
+  # for lib in `cat $EXTRACTDIR/liblist` ; do
+  #   grep "[/=]$lib[ =]" $EXTRACTDIR/$pkgname/pkgmap
+  #   if [[ $? -eq 0 ]] ; then
+  #     echo $lib provided by package itself
+  #     continue
+  #   else
+  #       grep "[/=]$lib[ =]" $SETLIBS
+  #       if [[ $? -eq 0 ]]; then
+  #     echo "$lib provided by package set being evaluated."
+  #     continue
+  #       fi
+  #   fi
+  # 
+  #   libpkg=`grep /$lib $EXTRACTDIR/shortcatalog |
+  #         sed 's/^.* \([^ ]*\)$/\1/' |sort -u`
+  # 
+  #   if [[ -z "$libpkg" ]] ; then
+  #     echo "$lib $pkgname" >> $SETLIBS.missing
+  #     print Cannot find package providing $lib.  Storing for delayed validation.
+  #   else
+  #     print $libpkg | fmt -1 >>$EXTRACTDIR/libpkgs
+  #   fi
+  # done
+  # 
+  # sort -u $EXTRACTDIR/libpkgs >$EXTRACTDIR/libpkgs.x
+  # mv $EXTRACTDIR/libpkgs.x $EXTRACTDIR/libpkgs
+  # 
+  # diff $EXTRACTDIR/deppkgs $EXTRACTDIR/libpkgs >/dev/null
+  # if [[ $? -ne 0 ]] ; then
+  #   print SUGGESTION: you may want to add some or all of the following as depends:
+  #   print '   (Feel free to ignore SUNW or SPRO packages)'
+  #   diff $EXTRACTDIR/deppkgs $EXTRACTDIR/libpkgs | fgrep '>'
+  # fi
+  # 
+  # 
+  # 
+  # if [[ "$basedir" != "" ]] ; then
+  #   print
+  #   if [[ -f $EXTRACTDIR/elflist ]] ; then
+  #     print "Checking relocation ability..."
+  #     xargs strings < $EXTRACTDIR/elflist| grep /opt/csw
+  #     if [[ $? -eq 0 ]] ; then
+  #       errmsg package build as relocatable, but binaries have hardcoded /opt/csw paths in them
+  #     else
+  #       print trivial check passed
+  #     fi
+  #   else
+  #     echo No relocation check done for non-binary relocatable package.
+  #   fi
+  # fi
+  #
+  # ...
+  # 
+  # if [ -s $SETLIBS.missing ]; then
+  #     print "Doing late evaluations of package library dependencies."
+  #     while read ldep; do
+  #   lib=`echo $ldep | nawk '{print $1}'`
+  #         [ "$lib" = "libm.so.2" ] && continue
+  #   pkg=`echo $ldep | nawk '{print $2}'`
+  #   /usr/bin/grep "[/=]$lib[ =]" $SETLIBS >/dev/null
+  #   if [ $? -ne 0 ]; then
+  #       errmsg "Couldn't find a package providing $lib"
+  #   else
+  #       print "A package in the set being evaluated provides $lib"
+  #   fi
+  #     done < $SETLIBS.missing
+  # fi
+
+
 if __name__ == '__main__':
-	main()
+  main()


Property changes on: csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg-libs.py
___________________________________________________________________
Added: svn:executable
   + *

Modified: csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg.py
===================================================================
--- csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg.py	2009-12-23 23:40:15 UTC (rev 7726)
+++ csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg.py	2009-12-23 23:44:47 UTC (rev 7727)
@@ -1,22 +1,125 @@
-# This is a checkpkg library, common for all checkpkg tests written in Python.
+# $Id$
+#
+# This is the checkpkg library, common for all checkpkg tests written in
+# Python.
 
 import optparse
+import os
+import os.path
+import logging
+import subprocess
+import cPickle
+import re
 
+SYSTEM_PKGMAP = "/var/sadm/install/contents"
+
 class Error(Exception):
   pass
 
+
 class ConfigurationError(Error):
   pass
 
+
+class PackageError(Error):
+  pass
+
+
 def GetOptions():
   parser = optparse.OptionParser()
   parser.add_option("-e", dest="extractdir",
                     help="The directory into which the package has been extracted")
   parser.add_option("-p", dest="pkgname",
                     help="The pkgname, e.g. CSWfoo")
+  parser.add_option("-d", "--debug", dest="debug",
+                    default=False, action="store_true",
+                    help="Turn on debugging messages")
   (options, args) = parser.parse_args()
   if not options.extractdir:
     raise ConfigurationError("ERROR: -e option is missing.")
   if not options.pkgname:
     raise ConfigurationError("ERROR: -p option is missing.")
   return options, args
+
+
+class CheckpkgBase(object):
+
+  def __init__(self, extractdir, pkgname):
+    self.extractdir = extractdir
+    self.pkgname = pkgname
+    self.pkgpath = os.path.join(self.extractdir, self.pkgname)
+
+  def ListBinaries(self):
+    # #########################################
+    # # find all executables and dynamic libs,and list their filenames.
+    # listbinaries() {
+    # 	if [ ! -d $1 ] ; then
+    # 		print errmsg $1 not a directory
+    # 		rm -rf $EXTRACTDIR
+    # 		exit 1
+    # 	fi
+    # 
+    # 	find $1 -print | xargs file |grep ELF |nawk -F: '{print $1}'
+    # }
+    find_tmpl = "find %s -print | xargs file | grep ELF | nawk -F: '{print $1}'"
+    if not os.path.isdir(self.pkgpath):
+    	raise PackageError("%s does not exist or is not a directory"
+    	                   % self.pkgpath)
+    find_proc = subprocess.Popen(find_tmpl % self.pkgpath,
+                                 shell=True, stdout=subprocess.PIPE)
+    stdout, stderr = find_proc.communicate()
+    ret = find_proc.wait()
+    if ret:
+    	logging.error("The find command returned an error.")
+    return stdout.splitlines()
+
+class SystemPkgmap(object):
+  """A class to hold and manipulate the /var/sadm/install/contents file."""
+  
+  PICKLE_NAME = "var-sadm-install-contents.pickle"
+  WS_RE = re.compile(r"\s+")
+  def __init__(self):
+    """There is no need to re-parse it each time.
+
+    Read it slowly the first time and cache it for later."""
+    self.checkpkg_dir = os.path.join(os.environ["HOME"], ".checkpkg")
+    self.pickle_path = os.path.join(self.checkpkg_dir, self.PICKLE_NAME)
+    if os.path.exists(self.pickle_path):
+    	logging.debug("Unpickling %s, please wait.", self.pickle_path)
+    	pickle_fd = open(self.pickle_path, "r")
+    	self.paths_by_soname = cPickle.load(pickle_fd)
+    	pickle_fd.close()
+    else:
+      # The original checkpkg code to port is in the comments.
+      #
+      # egrep -v 'SUNWbcp|SUNWowbcp|SUNWucb' /var/sadm/install/contents |
+      #     fgrep -f $EXTRACTDIR/liblist >$EXTRACTDIR/shortcatalog
+      stop_pkgs = ["SUNWbcp", "SUNWowbcp", "SUNWucb"] 
+      system_pkgmap_fd = open(SYSTEM_PKGMAP, "r")
+
+      stop_re = re.compile("(%s)" % "|".join(stop_pkgs))
+
+      # Creating a data structure:
+      # soname - {<path1>: <line1>, <path2>: <line2>, ...}
+      logging.debug("Building in-memory data structure for the %s file",
+                    SYSTEM_PKGMAP)
+      paths_by_soname = {}
+      for line in system_pkgmap_fd:
+        if stop_re.search(line):
+          continue
+        fields = re.split(self.WS_RE, line)
+        pkgmap_entry_path = fields[0].split("=")[0]
+        pkgmap_entry_dir, pkgmap_entry_base_name = os.path.split(pkgmap_entry_path)
+        if pkgmap_entry_base_name not in paths_by_soname:
+          paths_by_soname[pkgmap_entry_base_name] = {}
+        paths_by_soname[pkgmap_entry_base_name][pkgmap_entry_dir] = line
+      logging.debug("The data structure contains %s files",
+                    len(paths_by_soname))
+      self.paths_by_soname = paths_by_soname
+      if not os.path.exists(self.checkpkg_dir):
+      	logging.debug("Creating %s", self.checkpkg_dir)
+      	os.mkdir(self.checkpkg_dir)
+      logging.debug("Pickling to %s", self.pickle_path)
+      pickle_fd = open(self.pickle_path, "w")
+      cPickle.dump(self.paths_by_soname, pickle_fd)
+      pickle_fd.close()

Added: csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg_test.py
===================================================================
--- csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg_test.py	                        (rev 0)
+++ csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg_test.py	2009-12-23 23:44:47 UTC (rev 7727)
@@ -0,0 +1,8 @@
+#!/opt/csw/bin/python2.6
+
+import unittest
+
+
+
+if __name__ == '__main__':
+	unittest.main()


Property changes on: csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg_test.py
___________________________________________________________________
Added: svn:keywords
   + Id


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.



More information about the devel mailing list