#!/bin/env python # This program installs a set of Solaris patches on top # of a directory of binaries that might not have been installed # with pkgadd. This is useful if you download the tarball # version of some software, but you still want to apply # patches to it. Or if you made your own copy of some software # as a backup, or if you want to apply the patches over NFS without # logging into the server. Of course, you need to know that the tarball # is the right set of "Base files" that the patches were intended # for. import sys,os,tempfile,shutil,getopt,re,time # copied this code from the "Python Cookbook" to get # the 'set' implementation regardless of whether I'm using # python 2.3 or 2.4 try: set except NameError: from sets import Set as set # This controls the 'mode'. Either "check mode" or "install mode". G_check=0 # Remove a leading slash if any def abs_to_rel(p): if p[0] == '/': return p[1:] return p # short hand alias for joining elements into a directory path def j(*l): return os.path.join(*l) # Need to collect list of parent directories so that we # don't do lots of duplicate mkdirs. Should use "mkdir -p" instead? # But permissions might not be correct on intermediate directories? def add_parent_dirs(path, setvar): p = path # only SPROsslnk has absolute paths p = abs_to_rel(p) # as long as the remaining path contains a slash... # should use os.sys.path to do this ... while p.find('/') != -1: p = os.path.dirname(p) setvar.add(p) # Common wrapper for running commands. Enable the print # line to help you debug this script. def cmd(c): # print c os.system(c) # This function is called once for each "sparse package" in a patch def do_patch_sparse_pkg(basedir, pkgdir): # print "do_patch_sparse_pkg %s %s" % (basedir, pkgdir) filelist = [] fileperms = [] linklist = [] linktargs = [] dirset = set() # Scan through the pkgmap file, which lists the # contents of the sparse package, and sort them # into different lists for taking action on in # the loops below. for ln in open(j(pkgdir,"pkgmap"),"r").readlines(): items = ln.split(' ') if len(items) < 2: continue if items[1] == "f": filelist.append(items[3]) fileperms.append(items[4]) add_parent_dirs(items[3], dirset) if items[1] == "s": x = items[3].split("=") linklist.append(x[0]) linktargs.append(x[1].rstrip()) add_parent_dirs(x[0], dirset) if items[1] == "d": add_parent_dirs(j(items[3], "foo"), dirset) # Create/check any new directories that are needed. for d in dirset: d=abs_to_rel(d) dir = j(basedir,d) if G_check: if not os.path.exists(dir): print "Dir doesn't exist: %s" % dir else: cmd("mkdir -p %s" % dir) cmd("chmod 755 %s" % dir) # create/overwrite or check files for i in range(len(filelist)): f = filelist[i] f=abs_to_rel(f) p1 = j(pkgdir,"reloc",f) p2 = j(basedir,f) if G_check: cmd("cmp %s %s" % (p1, p2)) else: cmd("rm -f %s" % p2) cmd("cp %s %s" % (p1, p2)) cmd("chmod %s %s" % (fileperms[i], p2)) print p2 # overwrite or test any symbolic links in the package for i in range(len(linklist)): lk=linklist[i] ltarg=linktargs[i] lk=abs_to_rel(lk) link=j(basedir,lk) if G_check: if not os.path.exists(link): print "Link doesn't exist: %s -> %s" % \ (ltarg, link) else: # assume it's a link... l1 = os.readlink(link) if not l1 == ltarg: print "Link points differently:",\ l1, " should be: ", ltarg else: cmd("rm -f %s" % link) cmd("ln -s %s %s" % (ltarg, link)) print link, "(link)" # This function is called once for each expanded patch directory def do_patch_dir(basedir, patchdir): # print "do_patch_dir %s %s" % (basedir, patchdir) elts = os.listdir(patchdir) for f in elts: dir=j(patchdir,f) # print dir if os.path.exists(j(dir,"pkgmap")): do_patch_sparse_pkg(basedir, dir) # This function is called once for each patch (either zip or directory) def do_patch(basedir, patch): # print "do_patch %s %s" % (basedir, patch) if not os.path.exists(patch): print "Patch on command line doesn't exist: %s" % patch return tmpdir="" try: patchdir=patch if not os.path.isdir(patch): tmpdir = tempfile.mktemp() cmd("unzip %s -d %s > /dev/null" % (patch, tmpdir)) pnumdir=os.listdir(tmpdir)[0] patchdir=j(tmpdir,pnumdir) do_patch_dir(basedir, patchdir) # if we unzipped into a temporary directory, # remove the temp directory except: if not tmpdir == "": shutil.rmtree(tmpdir) raise if not tmpdir == "": shutil.rmtree(tmpdir) ############ # main program starts here ############ # Two ways to use this: # # patchraw -n DIR PATCH PATCH .... # This checks if any patches look like they're not applied. # # patchraw DIR PATCH PATCH ... # This installs all files in all patches # args = sys.argv if args[1] == "-n": G_check=1 args=args[1:] if len(args) < 3: print "Usage: unpkg [-n] ..." sys.exit(1) ARG_basedir = args[1] ARG_patchlist = args[2:] if not os.path.isdir(ARG_basedir): print "Destination directory doesn't exist: %s" % ARG_basedir sys.exit(1) for pt in ARG_patchlist: do_patch(ARG_basedir, pt)