Welcome, guest | Sign In | My Account | Store | Cart

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

Python, 141 lines
  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)