Print (1) packages used by a binary, and (2) the list of installed patches related to these packages. If you have a binary that works with Solaris 10 update N, but doesn't with Solaris 10 update N-2, run this script on both platform and it will help you to find the patches you're looking for.
(1) is retrieved:
- By using pldd(pid) on the process you want to trace to get a list of loaded shared library
- By retrieving in the main /var/sadm/install/contents database the list of package related to these shared libraries
(2) is retrieved by parsing the output of the showrev -p command, given as input of this script
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 137 138 139 140 141 | #!/usr/bin/env python
'''
== Infos ==
Print (1) packages used by a binary, and (2) the list of installed patches
related to these packages. If you have a binary that works with Solaris 10 update N, but doesn't with Solaris 10 update N-2, run this script on both platform and it will help you to find the patches you're looking for.
(1) is retrieved:
* By using pldd(pid) on the process you want to trace to get a list of loaded
shared library
* By retrieving in the main /var/sadm/install/contents database
the list of package related to these shared libraries
(2) is retrieved by parsing the output of the showrev -p command, given as
input of this script
Requires Python 2.3 (Set module usage)
== Usage ==
Use the -h / --help switch for options.
# give it a pid
$ pldd2pkg.py -p `pgrep dtexec`
# give it a file (offline)
$ pldd 732 > /tmp/foobar
$ pldd2pkg.py -l /tmp/foobar
Written by Benjamin Sergeant: bsergean@gmail.com
'''
import sys
from optparse import OptionParser
from sets import Set
from commands import getoutput
from cStringIO import StringIO
def uniq(alist): # Fastest order preserving
''' Helper from comments in http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 '''
set = {}
return [set.setdefault(e,e) for e in alist if e not in set]
def package_info(p):
'''
$ pkginfo SUNWglrt
application SUNWglrt Sun OpenGL for Solaris Runtime Libraries
'''
output = getoutput('pkginfo %s' % p)
return (' ').join(output.split()[2:])
def showrev_minus_p():
print 'Get a list of patches installed on the system with `showrev -p`'
return getoutput('showrev -p')
def pldd(pid):
return getoutput('pldd %s' % pid)
def main(pldd_fo):
# Read list of libraries from pldd output
# First name is name of binary
binaries = pldd_fo.read().splitlines()
shared_libraries = binaries[1:]
executable = binaries[0]
# Create a map between files and SVR4 packages
map_files_package = {}
map_files_package_lines = open('/var/sadm/install/contents').read().splitlines()
for l in map_files_package_lines:
tokens = l.split()
# we are only interested in regular files
if tokens[1] == 'f':
fn, pkg = tokens[0], tokens[-1]
map_files_package[fn] = pkg
# Output
print executable
for f in shared_libraries:
if f in map_files_package:
print '\t', f, ' -> ', map_files_package[f]
else:
print '\t', f, ' -> ', '(Not found)'
print
print 'package used:'
pkg_used = [map_files_package[f] for f in shared_libraries if f in map_files_package]
pkg_used = uniq(pkg_used)
pkg_used_set = Set(pkg_used)
for p in pkg_used:
print '\t', p, ' -> ', package_info(p)
print
# Create a map between patch and SVR4 packages
map_patch_package = {}
showrev_fo = StringIO(showrev_minus_p())
map_patch_package_lines = showrev_fo.read().splitlines()
for l in map_patch_package_lines:
# Patch: 108806-17 Obsoletes: Requires: Incompatibles: Packages: SUNWqfed, SUNWqfedu
patch = l.split()[1]
tokens = l.split(':')
packages = [p.strip() for p in tokens[5].split(',')]
packages_set = Set(packages)
if packages_set & pkg_used_set:
map_patch_package[patch] = packages
# Output used patch / per patch
print 'patch related to package used:'
for k, v in map_patch_package.iteritems():
print '\t', k, ' -> ', (', ').join(v)
print
# Output used patch / per package
print 'patch related to package used:'
for p in pkg_used:
print '\t', p, ' -> ', package_info(p)
patches = [k for k, v in map_patch_package.iteritems() if p in v]
patches.sort()
for p in patches:
print '\t\t', p
print
if __name__ == "__main__":
# parse args
parser = OptionParser(usage = "usage: %prog <options>")
parser.add_option("-p", "--pid", dest="pid", default='',
help="The pid of the process to analyse")
parser.add_option("-l", "--pldd-file", dest="pldd_fn", default='',
help="offline: The file captured output of the pldd pid command")
options, args = parser.parse_args()
if options.pldd_fn:
pldd_fo = open(options.pldd_fn)
elif options.pid:
pldd_fo = StringIO(pldd(options.pid))
main(pldd_fo)
|