12538Sesaxe#!/usr/sfw/bin/python 22538Sesaxe# 32538Sesaxe# CDDL HEADER START 42538Sesaxe# 52538Sesaxe# The contents of this file are subject to the terms of the 62538Sesaxe# Common Development and Distribution License (the "License"). 72538Sesaxe# You may not use this file except in compliance with the License. 82538Sesaxe# 92538Sesaxe# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 102538Sesaxe# or http://www.opensolaris.org/os/licensing. 112538Sesaxe# See the License for the specific language governing permissions 122538Sesaxe# and limitations under the License. 132538Sesaxe# 142538Sesaxe# When distributing Covered Code, include this CDDL HEADER in each 152538Sesaxe# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 162538Sesaxe# If applicable, add the following below this CDDL HEADER, with the 172538Sesaxe# fields enclosed by brackets "[]" replaced with your own identifying 182538Sesaxe# information: Portions Copyright [yyyy] [name of copyright owner] 192538Sesaxe# 202538Sesaxe# CDDL HEADER END 212538Sesaxe# 222538Sesaxe# Copyright 2006 Sun Microsystems, Inc. All rights reserved. 232538Sesaxe# Use is subject to license terms. 242538Sesaxe# 252538Sesaxe#ident "%Z%%M% %I% %E% SMI" 262538Sesaxe 272538Sesaxe# 282538Sesaxe# wsdiff(1) is a tool that can be used to determine which compiled objects 292538Sesaxe# have changed as a result of a given source change. Developers backporting 302538Sesaxe# new features, RFEs and bug fixes need to be able to identify the set of 312538Sesaxe# patch deliverables necessary for feature/fix realization on a patched system. 322538Sesaxe# 332538Sesaxe# The tool works by comparing objects in two trees/proto areas (one build with, 342538Sesaxe# and without the source changes. 352538Sesaxe# 362538Sesaxe# Using wsdiff(1) is fairly simple: 372538Sesaxe# - Bringover to a fresh workspace 382538Sesaxe# - Perform a full non-debug build (clobber if workspace isn't fresh) 392538Sesaxe# - Move the proto area aside, call it proto.old, or something. 402538Sesaxe# - Integrate your changes to the workspace 412538Sesaxe# - Perform another full non-debug clobber build. 422538Sesaxe# - Use wsdiff(1) to see what changed: 432538Sesaxe# $ wsdiff proto.old proto 442538Sesaxe# 452538Sesaxe# By default, wsdiff will print the list of changed objects / deliverables to 462538Sesaxe# stdout. If a results file is specified via -r, the list of differing objects, 472538Sesaxe# and details about why wsdiff(1) thinks they are different will be logged to 482538Sesaxe# the results file. 492538Sesaxe# 502538Sesaxe# By invoking nightly(1) with the -w option to NIGHTLY_FLAGS, nightly(1) will use 512538Sesaxe# wsdiff(1) to report on what objects changed since the last build. 522538Sesaxe# 532538Sesaxe# For patch deliverable purposes, it's advised to have nightly do a clobber, 542538Sesaxe# non-debug build. 552538Sesaxe# 562538Sesaxe# Think about the results. Was something flagged that you don't expect? Go look 572538Sesaxe# at the results file to see details about the differences. 582538Sesaxe# 592538Sesaxe# Use the -i option in conjunction with -v and -V to dive deeper and have wsdiff(1) 602538Sesaxe# report with more verbosity. 612538Sesaxe# 622538Sesaxe# Usage: wsdiff [-vVt] [-r results ] [-i filelist ] old new 632538Sesaxe# 642538Sesaxe# Where "old" is the path to the proto area build without the changes, and 652538Sesaxe# "new" is the path to the proto area built with the changes. The following 662538Sesaxe# options are supported: 672538Sesaxe# 682538Sesaxe# -v Do not truncate observed diffs in results 692538Sesaxe# -V Log *all* ELF sect diffs vs. logging the first diff found 702538Sesaxe# -t Use onbld tools in $SRC/tools 712538Sesaxe# -r Log results and observed differences 722538Sesaxe# -i Tell wsdiff which objects to compare via an input file list 732538Sesaxe 742538Sesaxeimport datetime, fnmatch, getopt, profile, os, popen2, commands 752538Sesaxeimport re, select, string, struct, sys, tempfile, time 762538Sesaxefrom stat import * 772538Sesaxe 782538Sesaxe# Human readable diffs truncated by default if longer than this 792538Sesaxe# Specifying -v on the command line will override 802538Sesaxediffs_sz_thresh = 4096 812538Sesaxe 822538Sesaxe# Default search path for wsdiff 832538Sesaxewsdiff_path = [ "/usr/bin", 842538Sesaxe "/usr/ccs/bin", 852538Sesaxe "/lib/svc/bin", 862538Sesaxe "/opt/onbld/bin" ] 872538Sesaxe 882538Sesaxe# These are objects that wsdiff will notice look different, but will not report. 892538Sesaxe# Existence of an exceptions list, and adding things here is *dangerous*, 902538Sesaxe# and therefore the *only* reasons why anything would be listed here is because 912538Sesaxe# the objects do not build deterministically, yet we *cannot* fix this. 922538Sesaxe# 932538Sesaxe# These perl libraries use __DATE__ and therefore always look different. 942538Sesaxe# Ideally, we would purge use the use of __DATE__ from the source, but because 952538Sesaxe# this is source we wish to distribute with Solaris "unchanged", we cannot modify. 962538Sesaxe# 972538Sesaxewsdiff_exceptions = [ "usr/perl5/5.8.4/lib/sun4-solaris-64int/CORE/libperl.so.1", 982538Sesaxe "usr/perl5/5.6.1/lib/sun4-solaris-64int/CORE/libperl.so.1", 992538Sesaxe "usr/perl5/5.8.4/lib/i86pc-solaris-64int/CORE/libperl.so.1", 1002538Sesaxe "usr/perl5/5.6.1/lib/i86pc-solaris-64int/CORE/libperl.so.1" 1012538Sesaxe ] 1022538Sesaxe 1032538Sesaxe##### 1042538Sesaxe# Logging routines 1052538Sesaxe# 1062538Sesaxe 1072538Sesaxe# Informational message to be printed to the screen, and the log file 1082538Sesaxedef info(msg) : 1092538Sesaxe 1102538Sesaxe print >> sys.stdout, msg 1112538Sesaxe if logging : 1122538Sesaxe print >> log, msg 1132538Sesaxe sys.stdout.flush() 1142538Sesaxe 1152538Sesaxe# Error message to be printed to the screen, and the log file 1162538Sesaxedef error(msg) : 1172538Sesaxe 1182538Sesaxe print >> sys.stderr, "ERROR:", msg 1192538Sesaxe sys.stderr.flush() 1202538Sesaxe if logging : 1212538Sesaxe print >> log, "ERROR:", msg 1222538Sesaxe log.flush() 1232538Sesaxe 1242538Sesaxe# Informational message to be printed only to the log, if there is one. 1252538Sesaxedef v_info(msg) : 1262538Sesaxe 1272538Sesaxe if logging : 1282538Sesaxe print >> log, msg 1292538Sesaxe log.flush() 1302538Sesaxe 1312538Sesaxe# 1322538Sesaxe# Flag a detected file difference 1332538Sesaxe# Display the fileName to stdout, and log the difference 1342538Sesaxe# 1352538Sesaxedef difference(f, dtype, diffs) : 1362538Sesaxe 1372538Sesaxe if f in wsdiff_exceptions : 1382538Sesaxe return 1392538Sesaxe 1402538Sesaxe print >> sys.stdout, f 1412538Sesaxe sys.stdout.flush() 1422538Sesaxe 1432538Sesaxe log_difference(f, dtype, diffs) 1442538Sesaxe 1452538Sesaxe# 1462538Sesaxe# Do the actual logging of the difference to the results file 1472538Sesaxe# 1482538Sesaxedef log_difference(f, dtype, diffs) : 1492538Sesaxe if logging : 1502538Sesaxe print >> log, f 1512538Sesaxe print >> log, "NOTE:", dtype, "difference detected." 1522538Sesaxe 1532538Sesaxe difflen = len(diffs) 1542538Sesaxe if difflen > 0 : 1552538Sesaxe print >> log 1562538Sesaxe 1572538Sesaxe if not vdiffs and difflen > diffs_sz_thresh : 1582538Sesaxe print >> log, diffs[:diffs_sz_thresh] 1592538Sesaxe print >> log, \ 1602538Sesaxe "... truncated due to length: " \ 1612538Sesaxe "use -v to override ..." 1622538Sesaxe else : 1632538Sesaxe print >> log, diffs 1642538Sesaxe print >> log, "\n" 1652538Sesaxe log.flush() 1662538Sesaxe 1672538Sesaxe 1682538Sesaxe##### 1692538Sesaxe# diff generating routines 1702538Sesaxe# 1712538Sesaxe 1722538Sesaxe# 1732538Sesaxe# Return human readable diffs from two temporary files 1742538Sesaxe# 1752538Sesaxedef diffFileData(tmpf1, tmpf2) : 1762538Sesaxe 1772538Sesaxe # Filter the data through od(1) if the data is detected 1782538Sesaxe # as being binary 1792538Sesaxe if isBinary(tmpf1) or isBinary(tmpf2) : 1802538Sesaxe tmp_od1 = tmpf1 + ".od" 1812538Sesaxe tmp_od2 = tmpf2 + ".od" 1822538Sesaxe 1832538Sesaxe cmd = od_cmd + " -c -t x4" + " " + tmpf1 + " > " + tmp_od1 1842538Sesaxe os.system(cmd) 1852538Sesaxe cmd = od_cmd + " -c -t x4" + " " + tmpf2 + " > " + tmp_od2 1862538Sesaxe os.system(cmd) 1872538Sesaxe 1882538Sesaxe tmpf1 = tmp_od1 1892538Sesaxe tmpf2 = tmp_od2 1902538Sesaxe 1912538Sesaxe data = commands.getoutput(diff_cmd + " " + tmpf1 + " " + tmpf2) 1922538Sesaxe 1932538Sesaxe return data 1942538Sesaxe 1952538Sesaxe# 1962538Sesaxe# Return human readable diffs betweeen two datasets 1972538Sesaxe# 1982538Sesaxedef diffData(d1, d2) : 1992538Sesaxe 2002538Sesaxe global tmpFile1 2012538Sesaxe global tmpFile2 2022538Sesaxe 2032538Sesaxe try: 2042538Sesaxe fd1 = open(tmpFile1, "w") 2052538Sesaxe except: 2062538Sesaxe error("failed to open: " + tmpFile1) 2072538Sesaxe cleanup(1) 2082538Sesaxe try: 2092538Sesaxe fd2 = open(tmpFile2, "w") 2102538Sesaxe except: 2112538Sesaxe error("failed to open: " + tmpFile2) 2122538Sesaxe cleanup(1) 2132538Sesaxe 2142538Sesaxe fd1.write(d1) 2152538Sesaxe fd2.write(d2) 2162538Sesaxe fd1.close() 2172538Sesaxe fd2.close() 2182538Sesaxe 2192538Sesaxe return diffFileData(tmpFile1, tmpFile2) 2202538Sesaxe 2212538Sesaxe##### 2222538Sesaxe# Misc utility functions 2232538Sesaxe# 2242538Sesaxe 2252538Sesaxe# Prune off the leading prefix from string s 2262538Sesaxedef str_prefix_trunc(s, prefix) : 2272538Sesaxe snipLen = len(prefix) 2282538Sesaxe return s[snipLen:] 2292538Sesaxe 2302538Sesaxe# 2312538Sesaxe# Prune off leading proto path goo (if there is one) to yield 2322538Sesaxe# the deliverable's eventual path relative to root 2332538Sesaxe# e.g. proto.base/root_sparc/usr/src/cmd/prstat => usr/src/cmd/prstat 2342538Sesaxe# 2352538Sesaxedef fnFormat(fn) : 2362538Sesaxe root_arch_str = "root_" + arch 2372538Sesaxe 2382538Sesaxe pos = fn.find(root_arch_str) 2392538Sesaxe if pos == -1 : 2402538Sesaxe return fn 2412538Sesaxe 2422538Sesaxe pos = fn.find("/", pos) 2432538Sesaxe if pos == -1 : 2442538Sesaxe return fn 2452538Sesaxe 2462538Sesaxe return fn[pos + 1:] 2472538Sesaxe 2482538Sesaxe##### 2492538Sesaxe# Usage / argument processing 2502538Sesaxe# 2512538Sesaxe 2522538Sesaxe# 2532538Sesaxe# Display usage message 2542538Sesaxe# 2552538Sesaxedef usage() : 2562538Sesaxe sys.stdout.flush() 2572538Sesaxe print >> sys.stderr, """Usage: wsdiff [-vVt] [-r results ] [-i filelist ] old new 2582538Sesaxe -v Do not truncate observed diffs in results 2592538Sesaxe -V Log *all* ELF sect diffs vs. logging the first diff found 2602538Sesaxe -t Use onbld tools in $SRC/tools 2612538Sesaxe -r Log results and observed differences 2622538Sesaxe -i Tell wsdiff which objects to compare via an input file list""" 2632538Sesaxe sys.exit(1) 2642538Sesaxe 2652538Sesaxe# 2662538Sesaxe# Process command line options 2672538Sesaxe# 2682538Sesaxedef args() : 2692538Sesaxe 2702538Sesaxe global logging 2712538Sesaxe global vdiffs 2722538Sesaxe global reportAllSects 2732538Sesaxe 2742538Sesaxe validOpts = 'i:r:vVt?' 2752538Sesaxe 2762538Sesaxe baseRoot = "" 2772538Sesaxe ptchRoot = "" 2782538Sesaxe fileNamesFile = "" 2792538Sesaxe results = "" 2802538Sesaxe localTools = False 2812538Sesaxe 2822538Sesaxe # getopt.getopt() returns: 2832538Sesaxe # an option/value tuple 2842538Sesaxe # a list of remaining non-option arguments 2852538Sesaxe # 2862538Sesaxe # A correct wsdiff invocation will have exactly two non option 2872538Sesaxe # arguments, the paths to the base (old), ptch (new) proto areas 2882538Sesaxe try: 2892538Sesaxe optlist, args = getopt.getopt(sys.argv[1:], validOpts) 2902538Sesaxe except getopt.error, val: 2912538Sesaxe usage() 2922538Sesaxe 2932538Sesaxe if len(args) != 2 : 2942538Sesaxe usage(); 2952538Sesaxe 2962538Sesaxe for opt,val in optlist : 2972538Sesaxe if opt == '-i' : 2982538Sesaxe fileNamesFile = val 2992538Sesaxe elif opt == '-r' : 3002538Sesaxe results = val 3012538Sesaxe logging = True 3022538Sesaxe elif opt == '-v' : 3032538Sesaxe vdiffs = True 3042538Sesaxe elif opt == '-V' : 3052538Sesaxe reportAllSects = True 3062538Sesaxe elif opt == '-t': 3072538Sesaxe localTools = True 3082538Sesaxe else: 3092538Sesaxe usage() 3102538Sesaxe 3112538Sesaxe baseRoot = args[0] 3122538Sesaxe ptchRoot = args[1] 3132538Sesaxe 3142538Sesaxe if len(baseRoot) == 0 or len(ptchRoot) == 0 : 3152538Sesaxe usage() 3162538Sesaxe 3172538Sesaxe if logging and len(results) == 0 : 3182538Sesaxe usage() 3192538Sesaxe 3202538Sesaxe if vdiffs and not logging : 3212538Sesaxe error("The -v option requires a results file (-r)") 3222538Sesaxe sys.exit(1) 3232538Sesaxe 3242538Sesaxe if reportAllSects and not logging : 3252538Sesaxe error("The -V option requires a results file (-r)") 3262538Sesaxe sys.exit(1) 3272538Sesaxe 3282538Sesaxe # alphabetical order 3292538Sesaxe return baseRoot, fileNamesFile, localTools, ptchRoot, results 3302538Sesaxe 3312538Sesaxe##### 3322538Sesaxe# File identification 3332538Sesaxe# 3342538Sesaxe 3352538Sesaxe# 3362538Sesaxe# Identify the file type. 3372538Sesaxe# If it's not ELF, use the file extension to identify 3382538Sesaxe# certain file types that require special handling to 3392538Sesaxe# compare. Otherwise just return a basic "ASCII" type. 3402538Sesaxe# 3412538Sesaxedef getTheFileType(f) : 3422538Sesaxe 3432538Sesaxe extensions = { 'a' : 'ELF Object Archive', 3442538Sesaxe 'jar' : 'Java Archive', 3452538Sesaxe 'html' : 'HTML', 3462538Sesaxe 'ln' : 'Lint Library', 3472538Sesaxe 'db' : 'Sqlite Database' } 3482538Sesaxe 3492538Sesaxe if os.stat(f)[ST_SIZE] == 0 : 3502538Sesaxe return 'ASCII' 3512538Sesaxe 3522538Sesaxe if isELF(f) == 1 : 3532538Sesaxe return 'ELF' 3542538Sesaxe 3552538Sesaxe fnamelist = f.split('.') 3562538Sesaxe if len(fnamelist) > 1 : # Test the file extension 3572538Sesaxe extension = fnamelist[-1] 3582538Sesaxe if extension in extensions.keys(): 3592538Sesaxe return extensions[extension] 3602538Sesaxe 3612538Sesaxe return 'ASCII' 3622538Sesaxe 3632538Sesaxe# 3642538Sesaxe# Return non-zero if "f" is an ELF file 3652538Sesaxe# 3662538Sesaxeelfmagic = '\177ELF' 3672538Sesaxedef isELF(f) : 3682538Sesaxe try: 3692538Sesaxe fd = open(f) 3702538Sesaxe except: 3712538Sesaxe error("failed to open: " + f) 3722538Sesaxe return 0 3732538Sesaxe magic = fd.read(len(elfmagic)) 3742538Sesaxe fd.close() 3752538Sesaxe 3762538Sesaxe if magic == elfmagic : 3772538Sesaxe return 1 3782538Sesaxe return 0 3792538Sesaxe 3802538Sesaxe# 3812538Sesaxe# Return non-zero is "f" is binary. 3822538Sesaxe# Consider the file to be binary if it contains any null characters 3832538Sesaxe# 3842538Sesaxedef isBinary(f) : 3852538Sesaxe try: 3862538Sesaxe fd = open(f) 3872538Sesaxe except: 3882538Sesaxe error("failed to open: " + f) 3892538Sesaxe return 0 3902538Sesaxe s = fd.read() 3912538Sesaxe fd.close() 3922538Sesaxe 3932538Sesaxe if s.find('\0') == -1 : 3942538Sesaxe return 0 3952538Sesaxe else : 3962538Sesaxe return 1 3972538Sesaxe 3982538Sesaxe##### 3992538Sesaxe# Directory traversal and file finding 4002538Sesaxe# 4012538Sesaxe 4022538Sesaxe# 4032538Sesaxe# Return a sorted list of files found under the specified directory 4042538Sesaxe# 4052538Sesaxedef findFiles(d) : 4062538Sesaxe for path, subdirs, files in os.walk(d) : 4072538Sesaxe files.sort() 4082538Sesaxe for name in files : 4092538Sesaxe yield os.path.join(path, name) 4102538Sesaxe 4112538Sesaxe# 4122538Sesaxe# Examine all files in base, ptch 4132538Sesaxe# 4142538Sesaxe# Return a list of files appearing in both proto areas, 4152538Sesaxe# a list of new files (files found only in ptch) and 4162538Sesaxe# a list of deleted files (files found only in base) 4172538Sesaxe# 4182538Sesaxedef protoCatalog(base, ptch) : 4192538Sesaxe compFiles = [] # List of files in both proto areas 4202538Sesaxe ptchList = [] # List of file in patch proto area 4212538Sesaxe 4222538Sesaxe newFiles = [] # New files detected 4232538Sesaxe deletedFiles = [] # Deleted files 4242538Sesaxe 4252538Sesaxe baseFilesList = list(findFiles(base)) 4262538Sesaxe baseStringLength = len(base) 4272538Sesaxe 4282538Sesaxe ptchFilesList = list(findFiles(ptch)) 4292538Sesaxe ptchStringLength = len(ptch) 4302538Sesaxe 4312538Sesaxe # Inventory files in the base proto area 4322538Sesaxe for fn in baseFilesList : 4332538Sesaxe if os.path.islink(fn) : 4342538Sesaxe continue 4352538Sesaxe 4362538Sesaxe fileName = fn[baseStringLength:] 4372538Sesaxe compFiles.append(fileName) 4382538Sesaxe 4392538Sesaxe # Inventory files in the patch proto area 4402538Sesaxe for fn in ptchFilesList : 4412538Sesaxe if os.path.islink(fn) : 4422538Sesaxe continue 4432538Sesaxe 4442538Sesaxe fileName = fn[ptchStringLength:] 4452538Sesaxe ptchList.append(fileName) 4462538Sesaxe 4472538Sesaxe # Deleted files appear in the base area, but not the patch area 4482538Sesaxe for fileName in compFiles : 4492538Sesaxe if not fileName in ptchList : 4502538Sesaxe deletedFiles.append(fileName) 4512538Sesaxe 4522538Sesaxe # Eliminate "deleted" files from the list of objects appearing 4532538Sesaxe # in both the base and patch proto areas 4542538Sesaxe for fileName in deletedFiles : 4552538Sesaxe try: 4562538Sesaxe compFiles.remove(fileName) 4572538Sesaxe except: 4582538Sesaxe error("filelist.remove() failed") 4592538Sesaxe 4602538Sesaxe # New files appear in the patch area, but not the base 4612538Sesaxe for fileName in ptchList : 4622538Sesaxe if not fileName in compFiles : 4632538Sesaxe newFiles.append(fileName) 4642538Sesaxe 4652538Sesaxe return compFiles, newFiles, deletedFiles 4662538Sesaxe 4672538Sesaxe# 4682538Sesaxe# Examine the files listed in the input file list 4692538Sesaxe# 4702538Sesaxe# Return a list of files appearing in both proto areas, 4712538Sesaxe# a list of new files (files found only in ptch) and 4722538Sesaxe# a list of deleted files (files found only in base) 4732538Sesaxe# 4742538Sesaxedef flistCatalog(base, ptch, flist) : 4752538Sesaxe compFiles = [] # List of files in both proto areas 4762538Sesaxe newFiles = [] # New files detected 4772538Sesaxe deletedFiles = [] # Deleted files 4782538Sesaxe 4792538Sesaxe try: 4802538Sesaxe fd = open(flist, "r") 4812538Sesaxe except: 4822538Sesaxe error("could not open: " + flist) 4832538Sesaxe cleanup(1) 4842538Sesaxe 4852538Sesaxe files = [] 4862538Sesaxe files = fd.readlines() 4872538Sesaxe 4882538Sesaxe for f in files : 4892538Sesaxe ptch_present = True 4902538Sesaxe base_present = True 4912538Sesaxe 4922538Sesaxe if f == '\n' : 4932538Sesaxe continue 4942538Sesaxe 4952538Sesaxe # the fileNames have a trailing '\n' 4962538Sesaxe f = f.rstrip() 4972538Sesaxe 4982538Sesaxe # The objects in the file list have paths relative 4992538Sesaxe # to $ROOT or to the base/ptch directory specified on 5002538Sesaxe # the command line. 5012538Sesaxe # If it's relative to $ROOT, we'll need to add back the 5022538Sesaxe # root_`uname -p` goo we stripped off in fnFormat() 5032538Sesaxe if os.path.exists(base + f) : 5042538Sesaxe fn = f; 5052538Sesaxe elif os.path.exists(base + "root_" + arch + "/" + f) : 5062538Sesaxe fn = "root_" + arch + "/" + f 5072538Sesaxe else : 5082538Sesaxe base_present = False 5092538Sesaxe 5102538Sesaxe if base_present : 5112538Sesaxe if not os.path.exists(ptch + fn) : 5122538Sesaxe ptch_present = False 5132538Sesaxe else : 5142538Sesaxe if os.path.exists(ptch + f) : 5152538Sesaxe fn = f 5162538Sesaxe elif os.path.exists(ptch + "root_" + arch + "/" + f) : 5172538Sesaxe fn = "root_" + arch + "/" + f 5182538Sesaxe else : 5192538Sesaxe ptch_present = False 5202538Sesaxe 5212538Sesaxe if os.path.islink(base + fn) : # ignore links 5222538Sesaxe base_present = False 5232538Sesaxe if os.path.islink(ptch + fn) : 5242538Sesaxe ptch_present = False 5252538Sesaxe 5262538Sesaxe if base_present and ptch_present : 5272538Sesaxe compFiles.append(fn) 5282538Sesaxe elif base_present : 5292538Sesaxe deletedFiles.append(fn) 5302538Sesaxe elif ptch_present : 5312538Sesaxe newFiles.append(fn) 5322538Sesaxe else : 5332538Sesaxe if os.path.islink(base + fn) and os.path.islink(ptch + fn) : 5342538Sesaxe continue 5352538Sesaxe error(f + " in file list, but not in either tree. Skipping...") 5362538Sesaxe 5372538Sesaxe return compFiles, newFiles, deletedFiles 5382538Sesaxe 5392538Sesaxe 5402538Sesaxe# 5412538Sesaxe# Build a fully qualified path to an external tool/utility. 5422538Sesaxe# Consider the default system locations. For onbld tools, if 5432538Sesaxe# the -t option was specified, we'll try to use built tools in $SRC tools, 5442538Sesaxe# and otherwise, we'll fall back on /opt/onbld/ 5452538Sesaxe# 5462538Sesaxedef find_tool(tool) : 5472538Sesaxe 5482538Sesaxe # First, check what was passed 5492538Sesaxe if os.path.exists(tool) : 5502538Sesaxe return tool 5512538Sesaxe 5522538Sesaxe # Next try in wsdiff path 5532538Sesaxe for pdir in wsdiff_path : 5542538Sesaxe location = pdir + "/" + tool 5552538Sesaxe if os.path.exists(location) : 5562538Sesaxe return location + " " 5572538Sesaxe 5582538Sesaxe location = pdir + "/" + arch + "/" + tool 5592538Sesaxe if os.path.exists(location) : 5602538Sesaxe return location + " " 5612538Sesaxe 5622538Sesaxe error("Could not find path to: " + tool); 5632538Sesaxe sys.exit(1); 5642538Sesaxe 5652538Sesaxe 5662538Sesaxe##### 5672538Sesaxe# ELF file comparison helper routines 5682538Sesaxe# 5692538Sesaxe 5702538Sesaxe# 5712538Sesaxe# Return a dictionary of ELF section types keyed by section name 5722538Sesaxe# 5732538Sesaxedef get_elfheader(f) : 5742538Sesaxe 5752538Sesaxe header = {} 5762538Sesaxe 5772538Sesaxe hstring = commands.getoutput(elfdump_cmd + " -c " + f) 5782538Sesaxe 5792538Sesaxe if len(hstring) == 0 : 5802538Sesaxe error("Failed to dump ELF header for " + f) 5812538Sesaxe return 5822538Sesaxe 5832538Sesaxe # elfdump(1) dumps the section headers with the section name 5842538Sesaxe # following "sh_name:", and the section type following "sh_type:" 5852538Sesaxe sections = hstring.split("Section Header") 5862538Sesaxe for sect in sections : 5872538Sesaxe datap = sect.find("sh_name:"); 5882538Sesaxe if datap == -1 : 5892538Sesaxe continue 5902538Sesaxe section = sect[datap:].split()[1] 5912538Sesaxe datap = sect.find("sh_type:"); 5922538Sesaxe if datap == -1 : 5932538Sesaxe error("Could not get type for sect: " + section + \ 5942538Sesaxe " in " + f) 5952538Sesaxe sh_type = sect[datap:].split()[2] 5962538Sesaxe header[section] = sh_type 5972538Sesaxe 5982538Sesaxe return header 5992538Sesaxe 6002538Sesaxe# 6012538Sesaxe# Extract data in the specified ELF section from the given file 6022538Sesaxe# 6032538Sesaxedef extract_elf_section(f, section) : 6042538Sesaxe 6052538Sesaxe data = commands.getoutput(dump_cmd + " -sn " + section + " " + f) 6062538Sesaxe 6072538Sesaxe if len(data) == 0 : 6082538Sesaxe error(cmd + " yielded no data") 6092538Sesaxe return 6102538Sesaxe 6112538Sesaxe # dump(1) displays the file name to start... 6122538Sesaxe # get past it to the data itself 6132538Sesaxe dbegin = data.find(":") + 1 6142538Sesaxe data = data[dbegin:]; 6152538Sesaxe 6162538Sesaxe return (data) 6172538Sesaxe 6182538Sesaxe# 6192538Sesaxe# Return a (hopefully meaningful) human readable set of diffs 6202538Sesaxe# for the specified ELF section between f1 and f2 6212538Sesaxe# 6222538Sesaxe# Depending on the section, various means for dumping and diffing 6232538Sesaxe# the data may be employed. 6242538Sesaxe# 6252538Sesaxetext_sections = [ '.text', '.init', '.fini' ] 6262538Sesaxedef diff_elf_section(f1, f2, section, sh_type) : 6272538Sesaxe 6282538Sesaxe if (sh_type == "SHT_RELA") : # sh_type == SHT_RELA 6292538Sesaxe cmd1 = elfdump_cmd + " -r " + f1 + " > " + tmpFile1 6302538Sesaxe cmd2 = elfdump_cmd + " -r " + f2 + " > " + tmpFile2 6312538Sesaxe elif (section == ".group") : 6322538Sesaxe cmd1 = elfdump_cmd + " -g " + f1 + " > " + tmpFile1 6332538Sesaxe cmd2 = elfdump_cmd + " -g " + f2 + " > " + tmpFile2 6342538Sesaxe elif (section == ".hash") : 6352538Sesaxe cmd1 = elfdump_cmd + " -h " + f1 + " > " + tmpFile1 6362538Sesaxe cmd2 = elfdump_cmd + " -h " + f2 + " > " + tmpFile2 6372538Sesaxe elif (section == ".dynamic") : 6382538Sesaxe cmd1 = elfdump_cmd + " -d " + f1 + " > " + tmpFile1 6392538Sesaxe cmd2 = elfdump_cmd + " -d " + f2 + " > " + tmpFile2 6402538Sesaxe elif (section == ".got") : 6412538Sesaxe cmd1 = elfdump_cmd + " -G " + f1 + " > " + tmpFile1 6422538Sesaxe cmd2 = elfdump_cmd + " -G " + f2 + " > " + tmpFile2 6432538Sesaxe elif (section == ".SUNW_cap") : 6442538Sesaxe cmd1 = elfdump_cmd + " -H " + f1 + " > " + tmpFile1 6452538Sesaxe cmd2 = elfdump_cmd + " -H " + f2 + " > " + tmpFile2 6462538Sesaxe elif (section == ".interp") : 6472538Sesaxe cmd1 = elfdump_cmd + " -i " + f1 + " > " + tmpFile1 6482538Sesaxe cmd2 = elfdump_cmd + " -i " + f2 + " > " + tmpFile2 6492538Sesaxe elif (section == ".symtab" or section == ".dynsym") : 6502538Sesaxe cmd1 = elfdump_cmd + " -s -N " + section + " " + f1 + " > " + tmpFile1 6512538Sesaxe cmd2 = elfdump_cmd + " -s -N " + section + " " + f2 + " > " + tmpFile2 6522538Sesaxe elif (section in text_sections) : 6532538Sesaxe # dis sometimes complains when it hits something it doesn't 6542538Sesaxe # know how to disassemble. Just ignore it, as the output 6552538Sesaxe # being generated here is human readable, and we've already 6562538Sesaxe # correctly flagged the difference. 6572538Sesaxe cmd1 = dis_cmd + " -t " + section + " " + f1 + \ 6582538Sesaxe " 2>/dev/null | grep -v disassembly > " + tmpFile1 6592538Sesaxe cmd2 = dis_cmd + " -t " + section + " " + f2 + \ 6602538Sesaxe " 2>/dev/null | grep -v disassembly > " + tmpFile2 6612538Sesaxe else : 6622538Sesaxe cmd1 = elfdump_cmd + " -w " + tmpFile1 + " -N " + \ 6632538Sesaxe section + " " + f1 6642538Sesaxe cmd2 = elfdump_cmd + " -w " + tmpFile2 + " -N " + \ 6652538Sesaxe section + " " + f2 6662538Sesaxe 6672538Sesaxe os.system(cmd1) 6682538Sesaxe os.system(cmd2) 6692538Sesaxe 6702538Sesaxe data = diffFileData(tmpFile1, tmpFile2) 6712538Sesaxe 6722538Sesaxe return (data) 6732538Sesaxe 6742538Sesaxe# 6752538Sesaxe# compare the relevant sections of two ELF binaries 6762538Sesaxe# and report any differences 6772538Sesaxe# 6782538Sesaxe# Returns: 1 if any differenes found 6792538Sesaxe# 0 if no differences found 6802538Sesaxe# -1 on error 6812538Sesaxe# 6822538Sesaxe 6832538Sesaxe# Sections deliberately not considered when comparing two ELF 6842538Sesaxe# binaries. Differences observed in these sections are not considered 6852538Sesaxe# significant where patch deliverable identification is concerned. 6862538Sesaxesections_to_skip = [ ".SUNW_signature", 6872538Sesaxe ".comment", 6882538Sesaxe ".SUNW_ctf", 6892538Sesaxe ".debug", 6902538Sesaxe ".plt", 6912538Sesaxe ".rela.bss", 6922538Sesaxe ".rela.plt", 6932538Sesaxe ".line", 6942538Sesaxe ".note", 695*3002Sesaxe ".compcom", 6962538Sesaxe ] 6972538Sesaxe 6982538Sesaxesections_preferred = [ ".rodata.str1.8", 6992538Sesaxe ".rodata.str1.1", 7002538Sesaxe ".rodata", 7012538Sesaxe ".data1", 7022538Sesaxe ".data", 7032538Sesaxe ".text", 7042538Sesaxe ] 7052538Sesaxe 7062538Sesaxedef compareElfs(base, ptch, quiet) : 7072538Sesaxe 7082538Sesaxe global logging 7092538Sesaxe 7102538Sesaxe base_header = get_elfheader(base) 7112538Sesaxe sections = base_header.keys() 7122538Sesaxe 7132538Sesaxe ptch_header = get_elfheader(ptch) 7142538Sesaxe e2_only_sections = ptch_header.keys() 7152538Sesaxe 7162538Sesaxe e1_only_sections = [] 7172538Sesaxe 7182538Sesaxe fileName = fnFormat(base) 7192538Sesaxe 7202538Sesaxe # Derive the list of ELF sections found only in 7212538Sesaxe # either e1 or e2. 7222538Sesaxe for sect in sections : 7232538Sesaxe if not sect in e2_only_sections : 7242538Sesaxe e1_only_sections.append(sect) 7252538Sesaxe else : 7262538Sesaxe e2_only_sections.remove(sect) 7272538Sesaxe 7282538Sesaxe if len(e1_only_sections) > 0 : 7292538Sesaxe if quiet : 7302538Sesaxe return 1 7312538Sesaxe info(fileName); 7322538Sesaxe if not logging : 7332538Sesaxe return 1 7342538Sesaxe 7352538Sesaxe slist = "" 7362538Sesaxe for sect in e1_only_sections : 7372538Sesaxe slist = slist + sect + "\t" 7382538Sesaxe v_info("\nELF sections found in " + \ 7392538Sesaxe base + " but not in " + ptch) 7402538Sesaxe v_info("\n" + slist) 7412538Sesaxe return 1 7422538Sesaxe 7432538Sesaxe if len(e2_only_sections) > 0 : 7442538Sesaxe if quiet : 7452538Sesaxe return 1 7462538Sesaxe 7472538Sesaxe info(fileName); 7482538Sesaxe if not logging : 7492538Sesaxe return 1 7502538Sesaxe 7512538Sesaxe slist = "" 7522538Sesaxe for sect in e2_only_sections : 7532538Sesaxe slist = slist + sect + "\t" 7542538Sesaxe v_info("\nELF sections found in " + \ 7552538Sesaxe ptch + " but not in " + base) 7562538Sesaxe v_info("\n" + slist) 7572538Sesaxe return 1 7582538Sesaxe 7592538Sesaxe # Look for preferred sections, and put those at the 7602538Sesaxe # top of the list of sections to compare 7612538Sesaxe for psect in sections_preferred : 7622538Sesaxe if psect in sections : 7632538Sesaxe sections.remove(psect) 7642538Sesaxe sections.insert(0, psect) 7652538Sesaxe 7662538Sesaxe # Compare ELF sections 7672538Sesaxe first_section = True 7682538Sesaxe for sect in sections : 7692538Sesaxe 7702538Sesaxe if sect in sections_to_skip : 7712538Sesaxe continue 7722538Sesaxe 7732538Sesaxe s1 = extract_elf_section(base, sect); 7742538Sesaxe s2 = extract_elf_section(ptch, sect); 7752538Sesaxe 7762538Sesaxe if len(s1) != len (s2) or s1 != s2: 7772538Sesaxe if not quiet: 7782538Sesaxe sh_type = base_header[sect] 7792538Sesaxe data = diff_elf_section(base, ptch, sect, \ 7802538Sesaxe sh_type) 7812538Sesaxe 7822538Sesaxe # If all ELF sections are being reported, then 7832538Sesaxe # invoke difference() to flag the file name to 7842538Sesaxe # stdout only once. Any other section differences 7852538Sesaxe # should be logged to the results file directly 7862538Sesaxe if not first_section : 7872538Sesaxe log_difference(fileName, "ELF " + sect, data) 7882538Sesaxe else : 7892538Sesaxe difference(fileName, "ELF " + sect, data) 7902538Sesaxe 7912538Sesaxe if not reportAllSects : 7922538Sesaxe return 1 7932538Sesaxe first_section = False 7942538Sesaxe return 0 7952538Sesaxe 7962538Sesaxe##### 7972538Sesaxe# Archive object comparison 7982538Sesaxe# 7992538Sesaxe# Returns 1 if difference detected 8002538Sesaxe# 0 if no difference detected 8012538Sesaxe# -1 on error 8022538Sesaxe# 8032538Sesaxedef compareArchives(base, ptch, fileType) : 8042538Sesaxe 8052538Sesaxe fileName = fnFormat(base) 8062538Sesaxe 8072538Sesaxe # clear the temp directories 8082538Sesaxe baseCmd = "rm -rf " + tmpDir1 + "*" 8092538Sesaxe status, output = commands.getstatusoutput(baseCmd) 8102538Sesaxe if status != 0 : 8112538Sesaxe error(baseCmd + " failed: " + output) 8122538Sesaxe return -1 8132538Sesaxe 8142538Sesaxe ptchCmd = "rm -rf " + tmpDir2 + "*" 8152538Sesaxe status, output = commands.getstatusoutput(ptchCmd) 8162538Sesaxe if status != 0 : 8172538Sesaxe error(ptchCmd + " failed: " + output) 8182538Sesaxe return -1 8192538Sesaxe 8202538Sesaxe # 8212538Sesaxe # Be optimistic and first try a straight file compare 8222538Sesaxe # as it will allow us to finish up quickly. 8232538Sesaxe if compareBasic(base, ptch, True, fileType) == 0 : 8242538Sesaxe return 0 8252538Sesaxe 8262538Sesaxe # copy over the objects to the temp areas, and 8272538Sesaxe # unpack them 8282538Sesaxe baseCmd = "cp -fp " + base + " " + tmpDir1 8292538Sesaxe status, output = commands.getstatusoutput(baseCmd) 8302538Sesaxe if status != 0 : 8312538Sesaxe error(baseCmd + " failed: " + output) 8322538Sesaxe return -1 8332538Sesaxe 8342538Sesaxe ptchCmd = "cp -fp " + ptch + " " + tmpDir2 8352538Sesaxe status, output = commands.getstatusoutput(ptchCmd) 8362538Sesaxe if status != 0 : 8372538Sesaxe error(ptchCmd + " failed: " + output) 8382538Sesaxe return -1 8392538Sesaxe 8402538Sesaxe bname = string.split(fileName, '/')[-1] 8412538Sesaxe if fileType == "Java Archive" : 8422538Sesaxe baseCmd = "cd " + tmpDir1 + "; " + "jar xf " + bname + \ 8432538Sesaxe "; rm -f " + bname + " META-INF/MANIFEST.MF" 8442538Sesaxe ptchCmd = "cd " + tmpDir2 + "; " + "jar xf " + bname + \ 8452538Sesaxe "; rm -f " + bname + " META-INF/MANIFEST.MF" 8462538Sesaxe elif fileType == "ELF Object Archive" : 8472538Sesaxe baseCmd = "cd " + tmpDir1 + "; " + "/usr/ccs/bin/ar x " + \ 8482538Sesaxe bname + "; rm -f " + bname 8492538Sesaxe ptchCmd = "cd " + tmpDir2 + "; " + "/usr/ccs/bin/ar x " + \ 8502538Sesaxe bname + "; rm -f " + bname 8512538Sesaxe else : 8522538Sesaxe error("unexpected file type: " + fileType) 8532538Sesaxe return -1 8542538Sesaxe 8552538Sesaxe os.system(baseCmd) 8562538Sesaxe os.system(ptchCmd) 8572538Sesaxe 8582538Sesaxe baseFlist = list(findFiles(tmpDir1)) 8592538Sesaxe ptchFlist = list(findFiles(tmpDir2)) 8602538Sesaxe 8612538Sesaxe # Trim leading path off base/ptch file lists 8622538Sesaxe flist = [] 8632538Sesaxe for fn in baseFlist : 8642538Sesaxe flist.append(str_prefix_trunc(fn, tmpDir1)) 8652538Sesaxe baseFlist = flist 8662538Sesaxe 8672538Sesaxe flist = [] 8682538Sesaxe for fn in ptchFlist : 8692538Sesaxe flist.append(str_prefix_trunc(fn, tmpDir2)) 8702538Sesaxe ptchFlist = flist 8712538Sesaxe 8722538Sesaxe for fn in ptchFlist : 8732538Sesaxe if not fn in baseFlist : 8742538Sesaxe difference(fileName, fileType, \ 8752538Sesaxe fn + " added to " + fileName) 8762538Sesaxe return 1 8772538Sesaxe 8782538Sesaxe for fn in baseFlist : 8792538Sesaxe if not fn in ptchFlist : 8802538Sesaxe difference(fileName, fileType, \ 8812538Sesaxe fn + " removed from " + fileName) 8822538Sesaxe return 1 8832538Sesaxe 8842538Sesaxe differs = compareOneFile((tmpDir1 + fn), (tmpDir2 + fn), True) 8852538Sesaxe if differs : 8862538Sesaxe difference(fileName, fileType, \ 8872538Sesaxe fn + " in " + fileName + " differs") 8882538Sesaxe return 1 8892538Sesaxe return 0 8902538Sesaxe 8912538Sesaxe##### 8922538Sesaxe# (Basic) file comparison 8932538Sesaxe# 8942538Sesaxe# There's some special case code here for Javadoc HTML files 8952538Sesaxe# 8962538Sesaxe# Returns 1 if difference detected 8972538Sesaxe# 0 if no difference detected 8982538Sesaxe# -1 on error 8992538Sesaxe# 9002538Sesaxedef compareBasic(base, ptch, quiet, fileType) : 9012538Sesaxe 9022538Sesaxe fileName = fnFormat(base); 9032538Sesaxe 9042538Sesaxe if quiet and os.stat(base)[ST_SIZE] != os.stat(ptch)[ST_SIZE] : 9052538Sesaxe return 1 9062538Sesaxe 9072538Sesaxe try: 9082538Sesaxe baseFile = open(base) 9092538Sesaxe except: 9102538Sesaxe error("could not open " + base) 9112538Sesaxe return -1 9122538Sesaxe try: 9132538Sesaxe ptchFile = open(ptch) 9142538Sesaxe except: 9152538Sesaxe error("could not open " + ptch) 9162538Sesaxe return -1 9172538Sesaxe 9182538Sesaxe baseData = baseFile.read() 9192538Sesaxe ptchData = ptchFile.read() 9202538Sesaxe 9212538Sesaxe baseFile.close() 9222538Sesaxe ptchFile.close() 9232538Sesaxe 9242538Sesaxe needToSnip = False 9252538Sesaxe if fileType == "HTML" : 9262538Sesaxe needToSnip = True 9272538Sesaxe toSnipBeginStr = "<!-- Generated by javadoc" 9282538Sesaxe toSnipEndStr = "-->\n" 9292538Sesaxe 9302538Sesaxe if needToSnip : 9312538Sesaxe toSnipBegin = string.find(baseData, toSnipBeginStr) 9322538Sesaxe if toSnipBegin != -1 : 9332538Sesaxe toSnipEnd = string.find(baseData[toSnipBegin:], \ 9342538Sesaxe toSnipEndStr) + \ 9352538Sesaxe len(toSnipEndStr) 9362538Sesaxe baseData = baseData[:toSnipBegin] + \ 9372538Sesaxe baseData[toSnipBegin + toSnipEnd:] 9382538Sesaxe ptchData = ptchData[:toSnipBegin] + \ 9392538Sesaxe ptchData[toSnipBegin + toSnipEnd:] 9402538Sesaxe 9412538Sesaxe if quiet : 9422538Sesaxe if baseData != ptchData : 9432538Sesaxe return 1 9442538Sesaxe else : 9452538Sesaxe if len(baseData) != len(ptchData) or baseData != ptchData : 9462538Sesaxe diffs = diffData(baseData, ptchData) 9472538Sesaxe difference(fileName, fileType, diffs) 9482538Sesaxe return 1 9492538Sesaxe return 0 9502538Sesaxe 9512538Sesaxe 9522538Sesaxe##### 9532538Sesaxe# Compare two objects by producing a data dump from 9542538Sesaxe# each object, and then comparing the dump data 9552538Sesaxe# 9562538Sesaxe# Returns: 1 if a difference is detected 9572538Sesaxe# 0 if no difference detected 9582538Sesaxe# -1 upon error 9592538Sesaxe# 9602538Sesaxedef compareByDumping(base, ptch, quiet, fileType) : 9612538Sesaxe 9622538Sesaxe fileName = fnFormat(base); 9632538Sesaxe 9642538Sesaxe if fileType == "Lint Library" : 9652538Sesaxe baseCmd = lintdump_cmd + " -ir " + base + \ 9662538Sesaxe " | grep -v LINTLIB:" + " > " + tmpFile1 9672538Sesaxe ptchCmd = lintdump_cmd + " -ir " + ptch + \ 9682538Sesaxe " | grep -v LINTLIB:" + " > " + tmpFile2 9692538Sesaxe elif fileType == "Sqlite Database" : 9702538Sesaxe baseCmd = "echo .dump | " + sqlite_cmd + base + " > " + \ 9712538Sesaxe tmpFile1 9722538Sesaxe ptchCmd = "echo .dump | " + sqlite_cmd + ptch + " > " + \ 9732538Sesaxe tmpFile2 9742538Sesaxe 9752538Sesaxe os.system(baseCmd) 9762538Sesaxe os.system(ptchCmd) 9772538Sesaxe 9782538Sesaxe try: 9792538Sesaxe baseFile = open(tmpFile1) 9802538Sesaxe except: 9812538Sesaxe error("could not open: " + tmpFile1) 9822538Sesaxe try: 9832538Sesaxe ptchFile = open(tmpFile2) 9842538Sesaxe except: 9852538Sesaxe error("could not open: " + tmpFile2) 9862538Sesaxe 9872538Sesaxe baseData = baseFile.read() 9882538Sesaxe ptchData = ptchFile.read() 9892538Sesaxe 9902538Sesaxe baseFile.close() 9912538Sesaxe ptchFile.close() 9922538Sesaxe 9932538Sesaxe if len(baseData) != len(ptchData) or baseData != ptchData : 9942538Sesaxe if not quiet : 9952538Sesaxe data = diffFileData(tmpFile1, tmpFile2); 9962538Sesaxe difference(fileName, fileType, data) 9972538Sesaxe return 1 9982538Sesaxe return 0 9992538Sesaxe 10002538Sesaxe##### 10012538Sesaxe# Compare two objects. Detect type changes. 10022538Sesaxe# Vector off to the appropriate type specific 10032538Sesaxe# compare routine based on the type. 10042538Sesaxe# 10052538Sesaxedef compareOneFile(base, ptch, quiet) : 10062538Sesaxe 10072538Sesaxe # Verify the file types. 10082538Sesaxe # If they are different, indicate this and move on 10092538Sesaxe btype = getTheFileType(base) 10102538Sesaxe ptype = getTheFileType(ptch) 10112538Sesaxe 10122538Sesaxe fileName = fnFormat(base) 10132538Sesaxe 10142538Sesaxe if (btype != ptype) : 10152538Sesaxe difference(fileName, "file type", btype + " to " + ptype) 10162538Sesaxe return 1 10172538Sesaxe else : 10182538Sesaxe fileType = btype 10192538Sesaxe 10202538Sesaxe if (fileType == 'ELF') : 10212538Sesaxe return compareElfs(base, ptch, quiet) 10222538Sesaxe 10232538Sesaxe elif (fileType == 'Java Archive' or fileType == 'ELF Object Archive') : 10242538Sesaxe return compareArchives(base, ptch, fileType) 10252538Sesaxe 10262538Sesaxe elif (fileType == 'HTML') : 10272538Sesaxe return compareBasic(base, ptch, quiet, fileType) 10282538Sesaxe 10292538Sesaxe elif ( fileType == 'Lint Library' ) : 10302538Sesaxe return compareByDumping(base, ptch, quiet, fileType) 10312538Sesaxe 10322538Sesaxe elif ( fileType == 'Sqlite Database' ) : 10332538Sesaxe return compareByDumping(base, ptch, quiet, fileType) 10342538Sesaxe else : 10352538Sesaxe # it has to be some variety of text file 10362538Sesaxe return compareBasic(base, ptch, quiet, fileType) 10372538Sesaxe 10382538Sesaxe# Cleanup and self-terminate 10392538Sesaxedef cleanup(ret) : 10402538Sesaxe 10412538Sesaxe if len(tmpDir1) > 0 and len(tmpDir2) > 0 : 10422538Sesaxe 10432538Sesaxe baseCmd = "rm -rf " + tmpDir1 10442538Sesaxe ptchCmd = "rm -rf " + tmpDir2 10452538Sesaxe 10462538Sesaxe os.system(baseCmd) 10472538Sesaxe os.system(ptchCmd) 10482538Sesaxe 10492538Sesaxe if logging : 10502538Sesaxe log.close() 10512538Sesaxe 10522538Sesaxe sys.exit(ret) 10532538Sesaxe 10542538Sesaxedef main() : 10552538Sesaxe 10562538Sesaxe # Log file handle 10572538Sesaxe global log 10582538Sesaxe 10592538Sesaxe # Globals relating to command line options 10602538Sesaxe global logging, vdiffs, reportAllSects 10612538Sesaxe 10622538Sesaxe # Named temporary files / directories 10632538Sesaxe global tmpDir1, tmpDir2, tmpFile1, tmpFile2 10642538Sesaxe 10652538Sesaxe # Command paths 10662538Sesaxe global lintdump_cmd, elfdump_cmd, dump_cmd, dis_cmd, od_cmd, diff_cmd, sqlite_cmd 10672538Sesaxe 10682538Sesaxe # Default search path 10692538Sesaxe global wsdiff_path 10702538Sesaxe 10712538Sesaxe # Essentially "uname -p" 10722538Sesaxe global arch 10732538Sesaxe 10742538Sesaxe # Some globals need to be initialized 10752538Sesaxe logging = vdiffs = reportAllSects = False 10762538Sesaxe 10772538Sesaxe 10782538Sesaxe # Process command line arguments 10792538Sesaxe # Return values are returned from args() in alpha order 10802538Sesaxe # (Yes, python functions can return multiple values (ewww)) 10812538Sesaxe # Note that args() also set the globals: 10822538Sesaxe # logging to True if verbose logging (to a file) was enabled 10832538Sesaxe # vdiffs to True if logged differences aren't to be truncated 10842538Sesaxe # reportAllSects to True if all ELF section differences are to be reported 10852538Sesaxe # 10862538Sesaxe baseRoot, fileNamesFile, localTools, ptchRoot, results = args() 10872538Sesaxe 10882538Sesaxe # 10892538Sesaxe # Set up the results/log file 10902538Sesaxe # 10912538Sesaxe if logging : 10922538Sesaxe try: 10932538Sesaxe log = open(results, "w") 10942538Sesaxe except: 10952538Sesaxe logging = False 10962538Sesaxe error("failed to open log file: " + log) 10972538Sesaxe sys.exit(1) 10982538Sesaxe 10992538Sesaxe dateTimeStr= "# %d/%d/%d at %d:%d:%d" % time.localtime()[:6] 11002538Sesaxe v_info("# This file was produced by wsdiff") 11012538Sesaxe v_info(dateTimeStr) 11022538Sesaxe 11032538Sesaxe # 11042538Sesaxe # Build paths to the tools required tools 11052538Sesaxe # 11062538Sesaxe # Try to look for tools in $SRC/tools if the "-t" option 11072538Sesaxe # was specified 11082538Sesaxe # 11092538Sesaxe arch = commands.getoutput("uname -p") 11102538Sesaxe if localTools : 11112538Sesaxe try: 11122538Sesaxe src = os.environ['SRC'] 11132538Sesaxe except: 11142538Sesaxe error("-t specified, but $SRC not set. Cannot find $SRC/tools") 11152538Sesaxe src = "" 11162538Sesaxe if len(src) > 0 : 11172538Sesaxe wsdiff_path.insert(0, src + "/tools/proto/opt/onbld/bin") 11182538Sesaxe 11192538Sesaxe lintdump_cmd = find_tool("lintdump") 11202538Sesaxe elfdump_cmd = find_tool("elfdump") 11212538Sesaxe dump_cmd = find_tool("dump") 11222538Sesaxe od_cmd = find_tool("od") 11232538Sesaxe dis_cmd = find_tool("dis") 11242538Sesaxe diff_cmd = find_tool("diff") 11252538Sesaxe sqlite_cmd = find_tool("sqlite") 11262538Sesaxe 11272538Sesaxe # 11282538Sesaxe # validate the base and patch paths 11292538Sesaxe # 11302538Sesaxe if baseRoot[-1] != '/' : 11312538Sesaxe baseRoot += '/' 11322538Sesaxe 11332538Sesaxe if ptchRoot[-1] != '/' : 11342538Sesaxe ptchRoot += '/' 11352538Sesaxe 11362538Sesaxe if not os.path.exists(baseRoot) : 11372538Sesaxe error("old proto area: " + baseRoot + " does not exist") 11382538Sesaxe sys.exit(1) 11392538Sesaxe 11402538Sesaxe if not os.path.exists(ptchRoot) : 11412538Sesaxe error("new proto area: " + ptchRoot + \ 11422538Sesaxe " does not exist") 11432538Sesaxe sys.exit(1) 11442538Sesaxe 11452538Sesaxe # 11462538Sesaxe # log some information identifying the run 11472538Sesaxe # 11482538Sesaxe v_info("Old proto area: " + baseRoot) 11492538Sesaxe v_info("New proto area: " + ptchRoot) 11502538Sesaxe v_info("Results file: " + results + "\n") 11512538Sesaxe 11522538Sesaxe # 11532538Sesaxe # Set up the temporary directories / files 11542538Sesaxe # Could use python's tmpdir routines, but these should 11552538Sesaxe # be easier to identify / keep around for debugging 11562538Sesaxe pid = os.getpid() 11572538Sesaxe tmpDir1 = "/tmp/wsdiff_tmp1_" + str(pid) + "/" 11582538Sesaxe tmpDir2 = "/tmp/wsdiff_tmp2_" + str(pid) + "/" 11592538Sesaxe if not os.path.exists(tmpDir1) : 11602538Sesaxe os.makedirs(tmpDir1) 11612538Sesaxe if not os.path.exists(tmpDir2) : 11622538Sesaxe os.makedirs(tmpDir2) 11632538Sesaxe 11642538Sesaxe tmpFile1 = tmpDir1 + "f1" 11652538Sesaxe tmpFile2 = tmpDir2 + "f2" 11662538Sesaxe 11672538Sesaxe # Derive a catalog of new, deleted, and to-be-compared objects 11682538Sesaxe # either from the specified base and patch proto areas, or from 11692538Sesaxe # from an input file list 11702538Sesaxe newOrDeleted = False 11712538Sesaxe 11722538Sesaxe if fileNamesFile != "" : 11732538Sesaxe changedFiles, newFiles, deletedFiles = \ 11742538Sesaxe flistCatalog(baseRoot, ptchRoot, fileNamesFile) 11752538Sesaxe else : 11762538Sesaxe changedFiles, newFiles, deletedFiles = protoCatalog(baseRoot, ptchRoot) 11772538Sesaxe 11782538Sesaxe if len(newFiles) > 0 : 11792538Sesaxe newOrDeleted = True 11802538Sesaxe info("\nNew objects found: ") 11812538Sesaxe 11822538Sesaxe for fn in newFiles : 11832538Sesaxe info(fnFormat(fn)) 11842538Sesaxe 11852538Sesaxe if len(deletedFiles) > 0 : 11862538Sesaxe newOrDeleted = True 11872538Sesaxe info("\nObjects removed: ") 11882538Sesaxe 11892538Sesaxe for fn in deletedFiles : 11902538Sesaxe info(fnFormat(fn)) 11912538Sesaxe 11922538Sesaxe if newOrDeleted : 11932538Sesaxe info("\nChanged objects: "); 11942538Sesaxe 11952538Sesaxe 11962538Sesaxe # Here's where all the heavy lifting happens 11972538Sesaxe # Perform a comparison on each object appearing in 11982538Sesaxe # both proto areas. compareOneFile will examine the 11992538Sesaxe # file types of each object, and will vector off to 12002538Sesaxe # the appropriate comparison routine, where the compare 12012538Sesaxe # will happen, and any differences will be reported / logged 12022538Sesaxe for fn in changedFiles : 12032538Sesaxe base = baseRoot + fn 12042538Sesaxe ptch = ptchRoot + fn 12052538Sesaxe 12062538Sesaxe compareOneFile(base, ptch, False) 12072538Sesaxe 12082538Sesaxe # We're done, cleanup. 12092538Sesaxe cleanup(0) 12102538Sesaxe 12112538Sesaxeif __name__ == '__main__' : 12122538Sesaxe try: 12132538Sesaxe main() 12142538Sesaxe except KeyboardInterrupt : 12152538Sesaxe cleanup(1); 12162538Sesaxe 12172538Sesaxe 1218