diff options
author | jbj <devnull@localhost> | 1999-10-20 16:46:54 +0000 |
---|---|---|
committer | jbj <devnull@localhost> | 1999-10-20 16:46:54 +0000 |
commit | b38f7bc532b038cfc0aac13ba8a7ff15c6c6b923 (patch) | |
tree | 786b9f67dbbb76548c40c8f311b1014b78d85853 | |
parent | 925c8130d5e4b8399e45e79b6253df5f8a8de760 (diff) | |
download | librpm-tizen-b38f7bc532b038cfc0aac13ba8a7ff15c6c6b923.tar.gz librpm-tizen-b38f7bc532b038cfc0aac13ba8a7ff15c6c6b923.tar.bz2 librpm-tizen-b38f7bc532b038cfc0aac13ba8a7ff15c6c6b923.zip |
Dependency code from Ken Estes.
CVS patchset: 3384
CVS date: 1999/10/20 16:46:54
-rw-r--r-- | scripts/rpmdiff | 873 | ||||
-rwxr-xr-x | scripts/vpkg-provides.sh | 275 | ||||
-rw-r--r-- | tools/javadeps.c | 478 |
3 files changed, 1460 insertions, 166 deletions
diff --git a/scripts/rpmdiff b/scripts/rpmdiff new file mode 100644 index 000000000..65efd433a --- /dev/null +++ b/scripts/rpmdiff @@ -0,0 +1,873 @@ + +#!/usr/local/bin/perl + +# rpmdiff - a program for comparing two rpm files for differences. +# Written by Ken Estes, Mail.com. + +use Getopt::Long; + +# much of this code comes from reading the book +# "Maximum RPM" by Edward C. Bailey + + +sub usage { + + my $args = "[--".join("] [--", @ARGS)."]"; + my @default_args = map $RPMTAG->{$_}->{'arg'}, @DEFAULT_CMP; + my $default_args = "--".join(" --", @default_args).""; + + my $usage =<<EOF; + +$0 [--version] [--help] [--cmpmode] [--all] + $args + old_rpm_file new_rpm_file + + +Arguments + + +--version Print version information for this program + +--help Show this usage page + +--cmpmode Do not send any information to stdout, instead + exit with zero if the rpm files are identical and + exit with 1 if there are differences. + +--all Ensure that all possible comparisons will be performed. + This argument should not be used with any CMP arguments. + + +CMP Arguments + + +Many of the options are designed to select which comparisons the user +is interested in so that spurious differences can be ignored. If no +CMP arguments are chosen then the default arguments are picked. + +The CMP arguments are: + $args + +The default arguments are: + $default_args + +There are two methods of picking which comparisions will be performed. +Any differences between the two files which are not in the list of +performed comparisons will be ignored. + +First arguments may be specified on the command line preceeded with a +'--' as in '--md5' these arguments specify which comparisons will be +performed. If a comparison is not mentioned on the command line it will +not be performed. + +Second arguments may be specified on the command line preceeded with a +'--no' as in '--nomd5' these arguments specify which comparisons will +not be performed. If a comparison is not mentioned on the command line +it will be prefomed. + +You can not mix the two types of arguments. + + +Synopsis + + +This script will compare old_rpm_file and new_rpm_file and print to +standard out the differences between the two files. The output is +designed to help isolate the changes which will occur when upgrading +an installed package. The output looks like the output of 'rpm -V'. +It is assumed that you have installed oldpackage and are thinking of +upgrading to newpackage. The output is as if you ran 'rpm -Va' after +installing the new package with cpio so that the rpm database was not +up todate. Thus 'rpm -Va' will pick up the differences between the +two pacakges. + + +Additionally the RPM scripts (prein, postin, triggers, verify, etc) +are compared and their results are displayed as if the scripts ended +up as files in the filesystem. + +Exit Code + + +The if not run in cmpmode the program exists with the number of files +which are different between the two packages, the exitcode will get no +bigger than $MAX_EXIT. + +If run in cmpmode then the program will exit with zero if the rpm +files are identical and exit with 1 if there are differences. + + +BUGS + + +This program only parses the RPM file headers not the cpio payload +inside the RPM file. In the rare case where an tag is defined in one +RPM and not in another we charitably assume that the RPMs match on +this tag. An example of this may be file uid/gid\'s. Currently rpm +does not store this information in the header, it appears only in the +cpio payload. If you were to compare two rpm files and one of them +does not have the uid/gid\'s in the header then no difference in +uid/gid will ever appear in the output regardless of what the RPMs +actually contain. + +The program only checks differences between files and scripts, any +changes to dependencies, prefixes, or spec file header information are +not checked. + +There is no method provided to check changes in a files flags, this +includes changes to the files documentation, MISSINGOK, NOREPLACE, or +configuration status. + + +Output Format + + +The differences are sent to stdout. There is one line for each file +which is different. The differences are encoded in a string using the +following letters to represent the differerences and the following +order to encode the information: + + S is the file size + + M is the files mode + + 5 is the MD5 checksum of the file + + D is the files major and monor numbers + + L is the files symbolic link contents. + + U is the owner of the file + + T is the modification time of the file + +Any attributes which match are denoted with a '.'. + + +Output Example + + +S.5..... PREIN +.....U.. /dev/vcsa1 +..5....T /dev/printer +S.5....T /etc/info-dir +missing /usr/doc/dhcpcd-0.70/README +.M...... /usr/lib/libpanel.so.4 +added /usr/lib/libmenu.so.4 +SM5....T /usr/info/dir + + +Usage Example + + +$0 --help +$0 --version + +$0 java-jdk-1.1.7-2.rpm java-jdk-1.1.7-3.rpm +$0 --md5 java-jdk-1.1.7-2.rpm java-jdk-1.1.7-3.rpm +$0 --nomd5 java-jdk-1.1.7-2.rpm java-jdk-1.1.7-3.rpm +$0 --md5 --link --mtime java-jdk-1.1.7-2.rpm java-jdk-1.1.7-3.rpm +$0 --all java-jdk-1.1.7-2.rpm java-jdk-1.1.7-3.rpm +$0 --cmpmode java-jdk-1.1.7-2.rpm java-jdk-1.1.7-3.rpm +$0 --cmpmode --md5 java-jdk-1.1.7-2.rpm java-jdk-1.1.7-3.rpm + + +EOF + + print $usage; + exit 0; + +} + + + +sub set_static_vars { + +# This functions sets all the static variables which are often +# configuration parameters. Since it only sets variables to static +# quantites it can not fail at run time. Some of these variables are +# adjusted by parse_args() but asside from that none of these +# variables are ever written to. All global variables are defined here +# so we have a list of them and a comment of what they are for. + + +# The numerical indicies to the hash comes from ~rpm/lib/rpmlib.h +# the index is the number of the tag as it appears in the rpmfile. + +# tag_name: the name of the tag as it appears in rpmlib.h. + +# all entries have a tag_name if an entry has one of the next three +# fields it must have the rest. If a tag does not have the next three +# fields we we will still gather data for it. This is for future +# functionality as these fields look important, and for debugging. + + +# diff_order: if the tag is used in the different output then this is +# the order of the character differences. + +# diff_char: if the tag is used in the different output then this is +# the character which will appear when there is a +# difference. + +# arg: the name of the command line option to specify whether this tag +# is used in the difference or not + +# The scripts contained in the rpm (preinstall, postinstall) do not +# have the comparison information that files have. Some of the +# comparisons (md5, size) can be performed on scripts, using regular +# perl functions, others (uid, modes, link) can not. We use +# script_cmp to link the perl comparison function to the comparison +# arguments and to the diff_char. + +# script_cmp: the perl comparion function to perform if this +# difference can be performed on the rpm scripts + +# is_script: if defined this indicates that the datatype is a script +# and we can use script_cmp on it. The data is stored as an array +# containing a single string. + + +# note: that although we may need to denote differences in the flags +# this table may not be appropriate for that task. + + +# The data from the RPM files is stored in $RPM0, $RPM1 they are HoL. +# The hash is indexed with the same index as appears in $RPMTAG, the +# other data is what ever comes out of the file. Most of the data we +# want is stored as arrays of values. We keep a hash to allow us to +# find the index number to use in all arrays given the filename. Some +# information like the package name and the posinstall script are +# stored, in the hash table as an array which contains a single +# string. + + + + + $RPMTAG = { + 1000 => { + 'tag_name' => 'NAME', + }, + 1001 => { + 'tag_name' => 'VERSION', + }, + 1002 => { + 'tag_name' => 'RELEASE', + }, + 1006 => { + 'tag_name' => 'BUILDTIME', + }, + 1027 => { + 'tag_name' => 'FILENAMES', + }, + 1028 => { + 'tag_name' => 'FILESIZES', + 'diff_order' => 0, + 'diff_char' => 'S', + 'arg' => 'size', + 'script_cmp' => sub { return (length($_[0]) ne + length($_[1])); }, + }, + 1029 => { + 'tag_name' => 'FILESTATES', + }, + 1030 => { + 'tag_name' => 'FILEMODES', + 'diff_order' => 1, + 'diff_char' => 'M', + 'arg' => 'mode', + }, + 1031 => { + # /* internal */ + 'tag_name' => 'FILEUIDS', + 'diff_order' => 5, + 'diff_char' => 'U', + 'arg' => 'user', + }, + 1032 => { + # /* internal */ + 'tag_name' => 'FILEGIDS', + 'diff_order' => 6, + 'diff_char' => 'G', + 'arg' => 'group', + }, + 1033 => { + 'tag_name' => 'FILERDEVS', + 'diff_order' => 3, + 'diff_char' => 'D', + 'arg' => 'dev', + }, + 1034 => { + 'tag_name' => 'FILEMTIMES', + 'diff_order' => 7, + 'diff_char' => 'T', + 'arg' => 'mtime', + }, + 1035 => { + 'tag_name' => 'FILEMD5S', + 'diff_order' => 2, + 'diff_char' => '5', + 'arg' => 'md5', + 'script_cmp' => sub{ return ($_[0] ne + $_[1]); }, + }, + 1036 => { + 'tag_name' => 'FILELINKTOS', + 'diff_order' => 4, + 'diff_char' => 'L', + 'arg' => 'link', + }, + 1037 => { + 'tag_name' => 'FILEFLAGS', + }, + + # support for differences of scripts + + 1023 => { + 'tag_name' => 'PREIN', + 'is_script' => 1, + }, + 1024 => { + 'tag_name' => 'POSTIN', + 'is_script' => 1, + }, + 1025 => { + 'tag_name' => 'PREUN', + 'is_script' => 1, + }, + 1026 => { + 'tag_name' => 'POSTUN', + 'is_script' => 1, + }, + 1079 => { + 'tag_name' => 'VERIFYSCRIPT', + 'is_script' => 1, + }, + 1065 => { + 'tag_name' => 'TRIGGERSCRIPTS', + 'is_script' => 1, + }, + 1091 => { + 'tag_name' => 'VERIFYSCRIPTPROG', + 'is_script' => 1, + }, + 1092 => { + 'tag_name' => 'TRIGGERSCRIPTPROG', + 'is_script' => 1, + }, + + }; + + # by default check these options, which are the "contents" of the + # files. + + @DEFAULT_CMP = ( 1028, 1035, 1036, ); + + + $RPM_FILE_MAGIC = chr(0xed).chr(0xab).chr(0xee).chr(0xdb); + $RPM_HEADER_MAGIC = chr(0x8e).chr(0xad).chr(0xe8); + + # we want the second header block, as the first header is the + # signature block. + + $HEADER_BLOCK_NUM = 2; + + # number of bytes in the file to skip when looking for the first + # header. Actually I think the lead is bigger then this like 96, but + # I am sure this minimum value is correct. + + $LEAD_LENGTH = 66; + + $HEADER_RECORD_SIZE = 16; + + # largest exit code we allow. + + $MAX_EXIT = 250; + + $NUM_DIFFERENCES = 0; + + $RCS_REVISION = ' $Revision: 1.1 $ '; + + # set a known path. + + $ENV{'PATH'}= ( + '/opt/gnu/bin'. + ':/usr/local/bin'. + ':/usr/bin'. + ':/bin'. + ''); + + # taint perl requires we clean up these bad environmental variables. + + delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; + + + $VERSION = 'NONE'; + if ( $RCS_REVISION =~ m/([.0-9]+)/ ) { + $VERSION = $1; + } + + return ; +} + + +sub parse_args{ + + my $arg_include = ''; + my $arg_exclude = ''; + my %arg_tags= (); + + my @args_with_bang = (); + my %arg2tag = (); + + # find out what arguments are availible and build some + # data structures to work with them. + + foreach $tag (keys %$RPMTAG ) { + my $arg = $RPMTAG->{$tag}->{'arg'}; + ($arg) || next; + push @ARGS, $arg; + push @ALL_CMP_TAGS, $tag; + push @args_with_bang, "$arg!"; + $arg2tag{$arg}=$tag; + } + + # sort the tags to determine the proper comparison order. + # use the order stored in the RPMTAG table. + # If this code is too confusing, look up + # 'Schwartzian Transform' in perlfaq4 or an advanced perl book. + + @ALL_CMP_TAGS = map { $_->[0] } + sort{ $a->[1] <=> $b->[1] } + map { [ $_, $RPMTAG->{$_}->{'diff_order'} ] } + @ALL_CMP_TAGS; + + $FILES_EQ_STRING = '.' x scalar(@ALL_CMP_TAGS); + + if( !GetOptions("version", "help", "all", "cmpmode!", @args_with_bang) ) { + print("Illegal options in \@ARGV: '@ARGV'\n"); + usage() ; + exit 1 ; + } + + if($opt_version) { + print "Version: $VERSION\n"; + exit 0; + } + + if ($opt_help) { + usage(); + } + + if ($opt_all) { + # all is just an exclude with nothing to exclude + $arg_exclude = 1; + } + + # process each of the arguments derived from the $RPMTAG hash + + foreach $arg (@ARGS) { + my $arg_var = "opt_$arg"; + if (defined($$arg_var)) { + $arg_tags{$arg2tag{$arg}} = 1; + if ($$arg_var) { + $arg_include = 1; + } else { + $arg_exclude = 1; + } + } + } + + ($arg_include) && ($arg_exclude) && + die("$0: Can not mix both include and exclude arguements ". + "on the command line.\n"); + + if ($arg_include) { + # check only the options listed + foreach $tag (keys %arg_tags) { + $CMP_TAGS{$tag} = 1; + } + } elsif ($arg_exclude) { + # check everything but the options listed + foreach $tag (@ALL_CMP_TAGS) { + $CMP_TAGS{$tag} = 1; + } + foreach $tag (keys %arg_tags) { + delete $CMP_TAGS{$tag}; + } + } else { + # check the default options + foreach $tag (@DEFAULT_CMP) { + $CMP_TAGS{$tag} = 1; + } + } + + ($#ARGV == 1) || + die("$0: Argument list must include two file names\n"); + + $RPMFILE0 = $ARGV[0]; + $RPMFILE1 = $ARGV[1]; + + ( !(-f $RPMFILE0) || !(-r $RPMFILE0) ) && + die("$0: '$RPMFILE0' is not a readable file\n"); + + ( !(-f $RPMFILE1) || !(-r $RPMFILE1) ) && + die("$0: '$RPMFILE1' is not a readable file\n"); + + $CMP_MODE = ($opt_cmpmode == 1); + + return ; +} + +# read the rpmfile and extract the header information. + +sub parse_rpm_headers { + my ($filename) = @_; + + my $file = ''; + my $out = {}; + + # read whole file into memory + { + open (RPMFILE, "<$filename")|| + die("$0: Could not open: $filename for reading. $!\n"); + + # not needed on unix but lets be very clear + binmode (RPMFILE); + + # slurp whole file + my $old_irs = $/; + undef $/; + + $file = <RPMFILE>; + + $/ = $old_irs; + + close(RPMFILE)|| + die("$0: Could not close: $filename. $!\n"); + + $file =~ m/^$RPM_FILE_MAGIC/ || + die("$0: file: $filename is not an RPM file. ". + "No magic number found.\n"); + } + + # we want the second header block, as the first header is the + # signature block. + + my ($header_start, $store_start) = ($LEAD_LENGTH,0); + my ($_version, $_reserved, $num_header_entries, $num_store_bytes) = (); + + foreach $i (1 .. $HEADER_BLOCK_NUM) { + + # find beginning of header, + $header_start = index($file, $RPM_HEADER_MAGIC, $header_start); + ($header_start < 0) && + die("$0: file: $filename is not an RPM file. ". + "No: $i, header found.\n"); + + $header_start += length($RPM_HEADER_MAGIC); + + ($_version, $_reserved, $num_header_entries, $num_store_bytes) = + unpack("CNNN", substr($file, $header_start, 1+(4*3))); + $header_start += 1+(4*3); + + # find beginning of store + $store_start = $header_start + + ($num_header_entries * $HEADER_RECORD_SIZE); + + ( ($store_start + $num_store_bytes) < length($file) ) || + die("$0: File Parse Error, file: $filename, ". + "is not long enough to hold store.\n"); + } + + # the header is just a list of information about data. + # the data is stored in the store futher down the file. + my $header_position = $header_start; + foreach $i (0 .. $num_header_entries-1) { + + my ($tag, $data_type, $offset, $data_count) = + unpack("N4", substr($file, $header_position, $HEADER_RECORD_SIZE)); + $header_position += $HEADER_RECORD_SIZE; + + ( + ( ($tag < 100) || ($tag > 1200) ) || + ( ($data_type < 0) || ($data_type > 10) ) || + ($offset < 0) + ) && die("$0: Error parsing header in rpm file: $filename, ". + "record number: $i.\n"); + + # we are only interested in the tags which are defined + $RPMTAG->{$tag} || next; + + foreach $j (0 .. $data_count-1) { + my $value =''; + if (0) { + # dummy for aliging the code like a case statement + } elsif ($data_type == 0) { + # null + $value = ''; + } elsif ($data_type == 1) { + # char + $value = substr($file, $store_start+$offset, 1); + $offset += 1; + } elsif ($data_type == 2) { + # int8 + $value = ord(substr($file, $store_start+$offset, 1)); + $offset += 1; + } elsif ($data_type == 3) { + # int16 + $value = unpack("n", substr($file, $store_start+$offset, 2)); + $offset += 2; + } elsif ($data_type == 4) { + # int32 + $value = unpack("N", substr($file, $store_start+$offset, 4)); + $offset += 4; + } elsif ($data_type == 5) { + # int64 + # ---- These aren't supported by RPM (yet) */ + die("$0: int64 type found in rpm file: $filename, ". + "record number: $i.\n"); + } elsif ($data_type == 6) { + # string + my $null_position = index ($file, "\0", $store_start+$offset); + my $length = $null_position - ($store_start+$offset); + $value = substr($file, $store_start+$offset, $length); + $offset += $length; + } elsif ($data_type == 7) { + # bin + # to properly support this I need to move it outside the $j + # loop. However I do not need it. + die("$0: Bin type found in rpm file: $filename, ". + "record number: $i.\n"); + } elsif ($data_type == 8) { + # string_array + my $null_position = index ($file, "\0", $store_start+$offset); + my $length = $null_position - ($store_start+$offset); + $value = substr($file, $store_start+$offset, $length); + $offset += $length+1 + } elsif ($data_type == 9) { + # this is listed as both RPM_I18NSTRING_TYPE and RPM_MAX_TYPE + # in file ~rpm/lib/header.h but I ignore it + die("$0: I18NSTRING type found in rpm file: $filename, ". + "record number: $i.\n"); + } + + push @{$out->{$tag}}, $value; + if ($RPMTAG->{$tag}->{"tag_name"} eq 'FILENAMES') { + $out->{'name2index'}->{$value} = $j; + } + } # foreach $j + + } # foreach $i + + return $out; +} + + +# traverse the datastructures to create a text representation of the +# critical differences between rpmscripts. If we are running in +# cmpmode and a difference is found exit early. + + +sub format_script_differences { + my ($rpm0, $rpm1) = @_; + + my $out = '';; + my %seen = (); + + foreach $script ( sort (keys %$RPMTAG) ) { + + ($RPMTAG->{$script}->{'is_script'}) || next; + + ($rpm0->{$script} || $rpm1->{$script}) || next; + + my $prefix=''; + + if ( ($rpm0->{$script}) && (!($rpm1->{$script})) ) { + $prefix = 'missing '; + } elsif ( (!($rpm0->{$script})) && ($rpm1->{$script}) ) { + $prefix = 'added '; + } else { + my $diff_str = ''; + foreach $cmp_tag (@ALL_CMP_TAGS) { + if ( !($CMP_TAGS{$cmp_tag}) || + !($RPMTAG->{$cmp_tag}->{'script_cmp'}) ){ + $diff_str .= '.'; + next; + } + + # In the rare case where an tag is defined in one RPM and not + # in another we charitably assume that the RPMs match on this + # tag. There is a warning in the stderr anyway. + + if ( + ($rpm0->{$cmp_tag}) && + ($rpm1->{$cmp_tag}) && + + # use the anonymous comparison function (stored in the + # table) to compare the two scripts + + (&{$RPMTAG->{$cmp_tag}->{'script_cmp'}} + ($rpm0->{$script}->[0], $rpm1->{$script}->[0])) + ) { + $diff_str .= $RPMTAG->{$cmp_tag}->{'diff_char'}; + } else { + $diff_str .= '.'; + } + + } # foreach $tag + if ($diff_str ne $FILES_EQ_STRING) { + $prefix = $diff_str; + } + } + + ($prefix) || next; + + if ($CMP_MODE) { + exit 1; + } + + ($NUM_DIFFERENCES < $MAX_EXIT) && + $NUM_DIFFERENCES++; + + $out .= "$prefix $RPMTAG->{$script}->{'tag_name'}\n"; + + } # foreach $filename + + return $out; +} + + + +# traverse the datastructures to create a text representation of the +# critical differences between file stored in the pacakge. If we are +# running in cmpmode and a difference is found exit early. + + + +sub format_file_differences { + my ($rpm0, $rpm1) = @_; + + my $out = '';; + my %seen = (); + + foreach $filename ( sort ( + (keys %{$rpm0->{'name2index'}}), + (keys %{$rpm1->{'name2index'}}) + ) ) { + + $seen{$filename} && next; + $seen{$filename} = 1; + $index0 = $rpm0->{'name2index'}->{$filename}; + $index1 = $rpm1->{'name2index'}->{$filename}; + + my $prefix=''; + + if ( ($index0) && (!($index1)) ) { + $prefix = 'missing '; + } elsif ( (!($index0)) && ($index1) ) { + $prefix = 'added '; + } else { + my $diff_str = ''; + foreach $cmp_tag (@ALL_CMP_TAGS) { + if (!($CMP_TAGS{$cmp_tag})){ + $diff_str .= '.'; + next; + } + + # In the rare case where an tag is defined in one RPM and not + # in another we charitably assume that the RPMs match on this + # tag. There is a warning in the stderr anyway. + + if ( + ($rpm0->{$cmp_tag}->[$index0]) && + ($rpm1->{$cmp_tag}->[$index1]) && + ($rpm0->{$cmp_tag}->[$index0] ne + $rpm1->{$cmp_tag}->[$index1]) + ) { + $diff_str .= $RPMTAG->{$cmp_tag}->{'diff_char'}; + } else { + $diff_str .= '.'; + } + + } # foreach $tag + if ($diff_str ne $FILES_EQ_STRING) { + $prefix = $diff_str; + } + } + + ($prefix) || next; + + if ($CMP_MODE) { + die 1; + } + + ($NUM_DIFFERENCES < $MAX_EXIT) && + $NUM_DIFFERENCES++; + + # this set of blanks would contain information from the flags, if + # only I was not so lazy + + $out .= "$prefix $filename\n"; + + } # foreach $filename + + return $out; +} + +# warn user of a cmp that was requested can not be carried out due to +# lack of data in the header of atleast one file. + +sub data_missing_warnings { + my ($rpm0, $rpm1) = @_; + + my $out = '';; + + foreach $cmp_tag (@ALL_CMP_TAGS) { + if (!($CMP_TAGS{$cmp_tag})) { + next; + } + + if ( ($CMP_TAGS{$cmp_tag}) && + (!$rpm0->{$cmp_tag}) + ){ + $out .= ("Comparison: '$RPMTAG->{$cmp_tag}->{'arg'}' ". + "specified, but data is not availible in ". + "rpm: $RPMFILE0.\n"); + } + if ( ($CMP_TAGS{$cmp_tag}) && + (!$rpm1->{$cmp_tag}) + ){ + $out .= ("Comparison: '$RPMTAG->{$cmp_tag}->{'arg'}' ". + "specified, but data is not availible in ". + "rpm: $RPMFILE1.\n"); + } + } + return $out; +} + + + + +# -------------- main -------------- +{ + set_static_vars(); + parse_args(); + $RPM0 = parse_rpm_headers($RPMFILE0); + $RPM1 = parse_rpm_headers($RPMFILE1); + + my $warnings = data_missing_warnings($RPM0, $RPM1); + + # we must print warnings before running diff as we may exit early. + + ($warnings) && + warn($warnings); + + my $header = "oldpkg $RPMFILE0\n"."newpkg $RPMFILE1\n"."\n\n"; + my $script_diffs = format_script_differences($RPM0, $RPM1); + my $file_diffs = format_file_differences($RPM0, $RPM1); + + ($script_diffs || $file_diffs) && + print $header, $script_diffs, $file_diffs; + + exit $NUM_DIFFERENCES; +} diff --git a/scripts/vpkg-provides.sh b/scripts/vpkg-provides.sh index df4746791..88130420c 100755 --- a/scripts/vpkg-provides.sh +++ b/scripts/vpkg-provides.sh @@ -1,12 +1,15 @@ + + #!/bin/sh # # Original Author: Tim Mooney (mooney@plains.NoDak.edu) +# Improvements by: Ken Estes <kestes@staff.mail.com> # # This file is distributed under the terms of the GNU General Public License # -# non-linux-provides is part of RPM, the Red Hat Package Manager. -# non-linux-provides searches a list of directories (based on what OS it's +# vpkg-provides.sh is part of RPM, the Red Hat Package Manager. +# vpkg-provides.sh searches a list of directories (based on what OS it's # being executed on) for shared libraries and interpreters that have been # installed by some packaging system other than RPM. It then generates a # spec file that can be used to build a "virtual package" that provides all @@ -20,15 +23,55 @@ # first effort was great, so I didn't want to wait until the better solution # was done. +# you will need to create a spec_header for the virtual package. This +# header will provide such specfile information as: +# +# Summary: +# Name: +# Version: +# Release: +# Copyright: +# Group: +# Source: + + +usage= "usage: $0 [--spec_header '/path/to/os-base-header.spec'] \n" +usage= "$usage\t[--find_provides '/path/to/find-provides']\n" +usage= "$usage\t[--shlib_dirs 'dirs:which:contain:shared:libs']\n" +usage= "$usage\t[--ignore_dirs 'egrep|pattern|of|paths|to|ignore']\n" + +# these two should be unnessary as the regular dependency analysis +# should take care of interpreters as well as shared libraries. + +usage= "$usage\t[--interp_dirs 'dirs:which:contain:interpreters']\n" +usage= "$usage\t[--interps 'files:to:assume:are:installed']\n" + + +# this command may not be portable to all OS's, does something else +# work? can this be set in the case $osname statement? + +sum_cmd="xargs cksum" + +date=`date` +hostname=`uname -n` + +# if some subdirectories of the system directories needs to be ignored +# (eg /usr/local is a subdirectory of /usr but should not be part of +# the virtual package) then call this script with IGNORE_DIRS set to a +# vaild egrep pattern which discribes the directories to ignored. + PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/ucb:/usr/bsd export PATH + # -# The default directories to use if they're not specified as -# arguments 1 and 2, respectively. +# The (OS independent) default values. # -default_spec_header='/usr/local/lib/rpm/os-base-header.spec'; -default_find_provides='/usr/local/lib/rpm/find-provides'; +spec_header='/usr/local/lib/rpm/os-base-header.spec'; +interps="sh:csh:ksh:dtksh:wish:tclsh:perl:awk:gawk:nawk:oawk" +find_provides='/usr/local/lib/rpm/find-provides'; +ignore_dirs="." + osname=`uname -s` if test $? -ne 0 || test X$osname = X ; then @@ -36,73 +79,29 @@ if test $? -ne 0 || test X$osname = X ; then exit 1 fi -if test X$1 = X ; then - if test -f $default_spec_header ; then - spec_header=$default_spec_header - else - echo "You must pass me the full path to the partial spec file" - echo "as my first argument, since this file does not appear in the" - echo "default location of $default_spec_header" - echo - echo "usage: $0 [ /path/to/spec-header ] [ /path/to/find-provides ]" - echo - exit 9 - fi -else - spec_header=$1 - if test ! -f $spec_header ; then - echo "$spec_header does not exist or is not what I was expecting." - exit 10 - fi -fi - -if test X$2 = X ; then - if test -f $default_find_provides ; then - find_provides=$default_find_provides - else - echo "You must pass me the full path to the find-provides script as my" - echo "second argument, since find-provides does not appear in the" - echo "default location of $default_find_provides" - echo - echo "usage: $0 [ /path/to/spec-header ] [ /path/to/find-provides ]" - echo - exit 9 - fi -else - find_provides=$2 - if test ! -f $find_provides ; then - echo "$find_provides does not exist or is not what I was expecting." - exit 10 - fi -fi # -# Set what directories we search for shared libraries and what interpreters -# we look for, based on what OS we're on. +# Set OS dependent defaults # case $osname in OSF1) shlib_dirs='/shlib:/usr/shlib:/usr/dt/lib:/usr/opt' interp_dirs='/bin:/usr/bin:/sbin:/usr/dt/bin:/usr/bin/posix' - interps="sh:csh:ksh:dtksh:wish:tclsh:perl:awk:gawk:nawk:oawk" ;; HP-UX) shlib_dirs='/usr/shlib:/usr/dt/lib:/opt' shlib_dirs="$shlib_dirs:/usr/bms:/usr/obam:/usr/sam" interp_dirs='/bin:/usr/bin:/sbin:/usr/dt/bin:/usr/bin/posix' - interps="sh:csh:ksh:dtksh:wish:tclsh:perl:awk:gawk:nawk:oawk" ;; AIX) shlib_dirs='/usr/lib:/usr/ccs/lib:/usr/dt/lib:/usr/lpp:/usr/opt' interp_dirs='/bin:/usr/bin:/sbin:/usr/dt/bin' - interps="bsh:sh:csh:ksh:dtksh:wish:tclsh:perl:awk:gawk:nawk:oawk" ;; SunOS) shlib_dirs='/etc/lib:/etc/vx:/opt:/usr/lib:/usr/ccs/lib:/usr/dt/lib' shlib_dirs="$shlib_dirs:/usr/4lib:/usr/openwin/lib:/usr/snadm/lib" shlib_dirs="$shlib_dirs:/usr/ucblib:/usr/xpg4/lib" interp_dirs='/bin:/usr/bin:/sbin:/usr/dt/bin:/usr/xpg4/bin' - interps="bsh:sh:csh:ksh:dtksh:wish:tclsh:perl:awk:gawk:nawk:oawk" ;; IRIX|IRIX64) shlib_dirs='/lib:/usr/lib:/usr/lib32:/usr/lib64' @@ -111,7 +110,6 @@ case $osname in shlib_dirs="$shlib_dirs:/usr/sgitcl:/usr/SGImeeting:/usr/pcp/lib" shlib_dirs="$shlib_dirs:/usr/Motif-2.1" interp_dirs='/bin:/usr/bin:/sbin:/usr/sbin:/usr/dt/bin' - interps="sh:csh:tcsh:ksh:dtksh:wish:tclsh:perl:perl5:awk:gawk:nawk:oawk" ;; *) echo "I'm sorry. I haven't been configured yet to work on $osname." @@ -126,9 +124,96 @@ case $osname in ;; esac -tmp_file=/tmp/shlibs.$$ -if test -f $tmp_file ; then - echo "$tmp_file already exists. Exiting." + +# allow the user to change defaults with the command line arguments. + +# Loop over all args + +while : +do + +# Break out if there are no more args + case $# in + 0) + break + ;; + esac + +# Get the first arg, and shuffle + option=$1 + shift + +# Make all options have two hyphens + orig_option=$option # Save original for error messages + case $option in + --*) ;; + -*) option=-$option ;; + esac + + + case $option in + --spec_header) + spec_header=$1 + shift + ;; + --ignore_dirs) + ignore_dirs=$1 + shift + ;; + --find_provides) + find_provides=$1 + shift + ;; + --shlib_dirs) + shlib_dirs=$1 + shift + ;; + --interp_dirs) + interp_dirs=$1 + shift + ;; + --interps) + interps=$1 + shift + ;; + --help) + echo $usage + exit 0 + ;; + *) + echo "$0: Unrecognized option: \"$orig_option\"; use --help for usage." >&2 + exit 1 + ;; + + +# consistancy checks on the arguments + +if [ ! -f $spec_header ]; then + echo "You must pass me the full path to the partial spec file" + echo "as my first argument, since this file does not appear in the" + echo "default location of $default_spec_header" + echo + echo $usage + echo + exit 9 +fi + + +if [ ! -f $find_provides ]; then + echo "You must pass me the full path to the find-provides script as my" + echo "second argument, since find-provides does not appear in the" + echo "default location of $default_find_provides" + echo + echo $usage + echo + exit 9 +fi + + + +provides_tmp=/tmp/provides.$$ +if test -f $provides_tmp ; then + echo "$provides_tmp already exists. Exiting." exit 11 fi @@ -138,16 +223,25 @@ fi # for d in `echo $shlib_dirs | sed -e 's/:/ /g'` do - find $d -type f -print 2>/dev/null | $find_provides >> $tmp_file + find $d -type f -print 2>/dev/null | egrep -v \'$IGNORE_DIRS\' | $find_provides >> $provides_tmp done -provides=/tmp/provides.$$ -if test -f $provides ; then - echo "$provides already exists. Exiting." +sum_tmp=/tmp/sum.$$ +if test -f $sum_tmp ; then + echo "$sum_tmp already exists. Exiting." exit 11 fi # +# iterate through all the directories in shlib_dirs, record the sum +# +for d in `echo $shlib_dirs | sed -e 's/:/ /g'` +do + find $d -type f -print 2>/dev/null | egrep -v \'$IGNORE_DIRS\' | $sum_cmd >> $sum_tmp +done + + +# # output the initial part of the spec file # cat $spec_header @@ -155,7 +249,7 @@ cat $spec_header # # Output the shared libraries # -for f in `cat $tmp_file | sort -u` +for f in `cat $provides_tmp | sort -u` do echo "Provides: $f" done @@ -174,10 +268,8 @@ do done # -# Finish off the spec file we're spitting out. +# Output the discription of the spec file # -date=`date` -hostname=`uname -n` cat <<_EIEIO_ @@ -194,6 +286,9 @@ $date. _EIEIO_ +# +# Output the build sections of the spec file +# echo '%prep' echo '# nothing to do' echo '%build' @@ -202,4 +297,58 @@ echo '%install' echo '# nothing to do' echo '%clean' echo '# nothing to do' + +# +# Output the verify section of the spec file +# + +cat <<_EIEIO_ + +%verifyscript + +PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/ucb:/usr/bsd +export PATH + +sum_current_tmp=/tmp/rpm.sum.current.\$\$ +if test -f \$sum_current_tmp ; then + echo "\$sum_current_tmp already exists. Exiting." + exit 11 +fi + +sum_package_tmp=/tmp/rpm.sum.package.\$\$ +if test -f \$sum_package_tmp ; then + echo "\$sum_package_tmp already exists. Exiting." + exit 11 +fi + +for d in `echo $shlib_dirs | sed -e 's/:/ /g'` +do + find \$d -type f -print 2>/dev/null | egrep -v \'$IGNORE_DIRS\' | $sum_cmd >> \$sum_current_tmp +done + +cat >\$sum_package_tmp <<_EOF_ +_EIEIO_ + +# the contents of the temporary file are hardcoded into the verify +# script so that the file can be reproduced at verification time. + +cat $sum_tmp + +cat <<_EIEIO_ +_EOF_ + + +cmp \$sum_package_tmp \$sum_current_tmp + +if [ $? -ne 0 ]; then + echo"Differences found by: cmp \$sum_package_tmp \$sum_current_tmp" + exit \$? +fi + +_EIEIO_ + +# +# Output the files section of the spec file +# + echo '%files' diff --git a/tools/javadeps.c b/tools/javadeps.c index 40389d42e..8ce36d477 100644 --- a/tools/javadeps.c +++ b/tools/javadeps.c @@ -1,3 +1,5 @@ + + /* Simple progam for pullng all the referenced java classes out of a class file. Java files are supposed to be platform independent, so @@ -32,6 +34,7 @@ */ #include "system.h" + #include <stdarg.h> /*---------typedefs---------*/ @@ -51,13 +54,13 @@ typedef struct { /*---------Global Variables, in all caps---------*/ /*name of this program*/ -char *PROGRAMNAME=0; +char *PROGRAM_NAME=0; /*name of the current class file*/ -char *FILENAME=0; +char *FILE_NAME=0; /*the name of the last class file seen*/ -char *CLASSNAME=0; +char *CLASS_NAME=0; /*arguments chosen*/ int ARG_PROVIDES=0; @@ -68,8 +71,34 @@ int ARG_STARPROV=0; /*keywords found in class file*/ char *KEYWORD_VERSION=0; +char *KEYWORD_REVISION=0; +char *KEYWORD_EPOCH=0; + +/* + + Quantify says over 80 percent of the time of the program is spent + in printf (and the functions it calls) AND I verified that only + about a quarter of the classes found in the dependency analysis are + unique. After the change no function used more then 26% of the over + all time. + + I implement a simple mechanism to remove most duplicate dependencies. + The print_table is a table of string which are to be printed. Just + before the program exists it is sorted and all unique entries are + printed. If it fills up during then it is flushed using the same + technique as above. + + The functions which manipulate the table are: + void print_table_flush(void) + void print_table_add(char *str) + +*/ +#define MAX_PRINT_TABLE 10000 +char *PRINT_TABLE[MAX_PRINT_TABLE]; +int SIZE_PRINT_TABLE; + /*--------- declare all functions ---------*/ void usage (void); @@ -79,7 +108,9 @@ size_t my_fread(void *ptr, size_t size, size_t nitems, FILE *stream); void check_range(short value, short poolSize); char *is_lower_equal (char *string, char *pattern); int findJavaMagic (FILE *fileHandle); -int dumpClassName(char *pSomeString, char terminator, char print_star); +void print_table_flush(void); +void print_table_add(char *str); +char *formatClassName(char *pSomeString, char terminator, char print_star); void dumpRefType(char *pSomeString); void dumpRequires(symbolTable_t *symbolTable); void genSymbolTable (FILE *fileHandle, symbolTable_t *symbolTable); @@ -93,7 +124,7 @@ void usage (void) { printf("NAME:\n\tjavadeps - Examine Java class files and\n" - "\t\treturn information about their dependencies.\n\n"); + "\t\t\treturn information about their dependencies.\n\n"); printf("USAGE:\n"); printf("\t javadeps { --provides | --requires } \n" "\t\t [--rpmformat] [--keywords] \n" @@ -135,27 +166,61 @@ usage (void) printf("\n\n"); printf("If --keywords is specified then the following strings are \n" "searched for (case insensitive) in the class file string table\n" - "and, if found, are used to change the dependencies accordingly.\n" - "RPM_Provides and RPM_Requires may appear multiple times in the \n" - "string table indicating that the dependency is the union of all\n" - "entries.\n\n" + "and, if a string is found with a prefix matching the keyword then \n" + "the dependencies are changed accordingly. There may be multiple \n" + "string tables entries prefixed with RPM_Provides and RPM_Requires. \n" + "This would indicate that the dependency is the union\n" + "of all entries.\n" + "\n\n" "Keyword List:\n\n" "'$Revision: ' This RCS/CVS compatible keyword is assumed to \n" " contain the version number of the class file \n" " it is found in. Care should be taken with this\n" " option as RPM's notion of which version is later\n" " may not corrispond with your own, especially\n" - " if you use branches. This keyword only effects\n" - " the output of --provides. \n" - " (rpm needs modifications to support version \n" - " numbers in find-provides)\n\n" - "'RPM_Provides: ' This string lists additinal capabilites provided\n" - " by the java class. This keyword only effects \n" - " the output of --provides.\n\n" + " if you use branches. This keyword\n" + " only effects the output of --provides and only\n" + " when RPM_Version is not defined.\n\n" + "'RPM_Version: ' This is an alternative method of specifing the\n" + " version number of the class. It will override\n" + " $Revision if set. This keyword only effects\n" + " the output of --provides \n\n" + "'RPM_Epoch: ' This string contains the epoch to use with the \n" + " version number stored in Revision. If not \n" + " specified, the epoch is assumed to be zero.\n" + " This keyword only effects the output of\n " + " --provides and only when $Revision number is\n" + " used.\n\n" + "'RPM_Provides: ' This string lists additional capabilites\n" + " provided by the java class. The string should\n" + " be a white space ([\\t\\v\\n\\r\\f\\ ])\n" + " separated list of dependency strings. Each\n" + " dependency string must be of the same format as\n" + " would be valid in the Requires or Provides line\n" + " of the specfile. This keyword only effects the\n" + " output of --provides.\n\n" "'RPM_Requires: ' This string lists additional requirements of\n" - " the java class. This keyword only effects the \n" - " output of --requires.\n\n"); - printf("EXAMPLES: \n\n" + " the java class. The string should be a white \n" + " space ([\\t\v\\n\\r\\f\\ ]) separated list of \n" + " dependency strings. Each dependency string must\n" + " be of the same format as would be valid in the \n" + " Requires or Provides line of the specfile. This\n" + " keyword only effects the output of --requires.\n " + " \n\n" + "Note that there is no means of setting the release number. This\n" + "is necessary because release numbers are incremented when the\n" + "source does not change but the package needs to be rebuilt. So\n" + "relase numbers can not be stored in the source. The release is\n" + "assumed to be zero. \n\n" + ""); + printf("EXAMPLES (Java Keywords): \n\n" + "\t public static final String REVISION = \"$Revision: 2.3 $\";\n" + "\t public static final String EPOCH = \"4\";\n" + "\t public static final String REQUIRES = \"RPM_Requires: " + "java(gnu.regexp.RE) java(com.ibm.site.util.Options)>=1.5\";\n" + ""); + printf("\n\n"); + printf("EXAMPLES (Arguments): \n\n" "\tjavadeps --requires -- filename.class\n\n" "\tjavadeps --provides -- filename.class\n\n" "\tjavadeps --help\n\n" @@ -163,7 +228,8 @@ usage (void) "\tjavadeps --requires --rpmformat --keywords -- filename.class\n\n" "\tjavadeps --requires -- filename1.class filename2.class\n\n" "\tcat filename2.class | javadeps --requires -- filename1.class -\n\n" - "\tunzip -p filename.jar | javadeps --requires -- - \n\n"); + "\tunzip -p filename.jar | javadeps --requires -- - \n\n" + ""); printf("\n\n"); exit(-1); } @@ -184,7 +250,7 @@ void die(char *format, ...) { This function throws a fatal error and accepts arguments like printf does*/ - char *newformat, *newmsg = NULL; + char *newformat = NULL, *newmsg = NULL; va_list ap; if ( !(newformat = malloc(1024)) || !(newmsg = malloc(1024)) ) @@ -195,26 +261,26 @@ void die(char *format, ...) { at the time of the error. Display the maximum ammount of information. */ - /* notice the FILENAME is useless for jar files. We would want to + /* notice the FILE_NAME is useless for jar files. We would want to print the name of the classfile which caused the error. That is hard since we only know that name when we are done parsing the file, and most errors will occur before that.*/ va_start(ap, format); - if ( (!FILENAME) ) { + if ( (!FILE_NAME) ) { sprintf (newformat, "\n%s: %s", - PROGRAMNAME, format); + PROGRAM_NAME, format); - } else if ( (FILENAME) && (!CLASSNAME) ) { + } else if ( (FILE_NAME) && (!CLASS_NAME) ) { sprintf (newformat, "\n%s: Java classfile: %s, %s", - PROGRAMNAME, FILENAME, format); + PROGRAM_NAME, FILE_NAME, format); - } else if (CLASSNAME) { + } else if (CLASS_NAME) { sprintf (newformat, "\n%s: Java classfile: %s, classname: %s, %s", - PROGRAMNAME, FILENAME, CLASSNAME, format); + PROGRAM_NAME, FILE_NAME, CLASS_NAME, format); } vsprintf (newmsg, newformat, ap); @@ -292,7 +358,9 @@ char /* Read fileHandle until we find the next instance of the Java Classfile magic number indicating a java file or find EOF or - fileread error. + fileread error. Since we are reading from stdin which may contain + the concatination of many class files we can not be sure that the + magic number will be the first few bytes. Return 1 on success 0 on failure. */ @@ -352,6 +420,118 @@ int findJavaMagic (FILE *fileHandle) #undef mod4 +my_strcmp (const void *a, const void *b) { +char **a1; char **b1; +int ret; + +a1 = (char **)a; +b1 = (char **)b; +ret = strcmp(*a1,*b1); + return ret; +} + +/* print the unique strings found in PRINT_TABLE and clear it out */ + +void +print_table_flush(void) { + int i; + char *last_string; + + if (!SIZE_PRINT_TABLE) { + return ; + } + + /* The qsort line gives a warning on some unicies who insist that + strcmp takes arguments of type pointers to void not the + traditional pointers to char. */ + + qsort( (void *) PRINT_TABLE, (size_t) SIZE_PRINT_TABLE, + sizeof(char *), &my_strcmp); + + printf("%s",PRINT_TABLE[0]); + last_string = PRINT_TABLE[0]; + PRINT_TABLE[0] = NULL; + + for (i = 1; i < SIZE_PRINT_TABLE; i++) { + if ( strcmp(last_string, PRINT_TABLE[i]) ){ + printf("%s",PRINT_TABLE[i]); + free(last_string); + last_string = PRINT_TABLE[i]; + } else { + free(PRINT_TABLE[i]); + } + PRINT_TABLE[i] = NULL; + } + + free(last_string); + SIZE_PRINT_TABLE = 0; + return ; +} + + +/* add an element to PRINT_TABLE for later printing to stdout. We do + not make a copy of the string so each string must be unique, + (different calls must pass pointers to different areas of memory) + and the string must not be freed anywhere else in the code and the + string must be from memory which can be freed.*/ + +void +print_table_add(char *str) { + + if (SIZE_PRINT_TABLE == MAX_PRINT_TABLE) { + print_table_flush(); + } + + PRINT_TABLE[SIZE_PRINT_TABLE] = str; + SIZE_PRINT_TABLE++; + return ; +} + + +/* Given a list separated by whitespace, put each element in the print + table with an added "\n" */ + +void +print_list(char *in_string) { + char *WhiteSpace_Set = "\t\v\n\r\f "; + char *newEnd, *out_string; + int copy_len; + + in_string += strspn(in_string, WhiteSpace_Set); + + while (*in_string) { + newEnd = strpbrk(in_string, WhiteSpace_Set); + + if (newEnd) { + copy_len = newEnd-in_string; + } else { + if (*in_string) { + copy_len = strlen(in_string); + } else { + copy_len = 0; + } + } + + out_string = malloc(copy_len+10); + if ( !out_string ) { + outofmemory(); + } + out_string[0]= '\0'; + + if (copy_len) { + strncat(out_string, in_string, copy_len); + in_string+=copy_len; + strcat(out_string, "\n"); + print_table_add(out_string); + } + + in_string += strspn(in_string+copy_len, WhiteSpace_Set); + } + + return ; +} + + /* Print a properly formatted java class name, and returns the length of the class string . Do not print \n here as we may wish to append the version number IFF we are printing the name of this classfile @@ -366,58 +546,93 @@ int findJavaMagic (FILE *fileHandle) (though this would be less accurate then explicit dependencies since any leaf class will satify a star dependency). */ -int -dumpClassName(char *pSomeString, char terminator, - char print_star) +char +*formatClassName(char *in_string, char terminator, + char print_star) { - char *leaf_class=0; - int chars =0; - /* - For each char in the class name format it and print it to stdout. - No class terminator is written in this function. - */ + char *leaf_class=0, *out_string=0; + char *ClassName_Break_Set=0; + + out_string = malloc(strlen(in_string) + 10); + if ( !out_string ) { + outofmemory(); + } + out_string[0]= '\0'; + + /*these characters end the current parse of the string in function + formatClassName.*/ + + ClassName_Break_Set = malloc(3); + if ( !ClassName_Break_Set ) { + outofmemory(); + } + ClassName_Break_Set[0] = '/'; + /*terminator can be '\0' this must go after '/'*/ + ClassName_Break_Set[1] = terminator; + ClassName_Break_Set[2] = '\0'; + if(ARG_RPMFORMAT) { - printf("java("); + strcat(out_string, "java("); } - if (print_star) { - /*do not print the leaf class*/ - leaf_class = strrchr(pSomeString, '/'); + /* print the path to the leaf class but do not print the leaf + class, stop at the last '/' we fix this back below*/ + leaf_class = strrchr(in_string, '/'); if (leaf_class) { leaf_class[0] = terminator; } } - while (1) { - if (*pSomeString == terminator) { - /* normal exit from loop when end of class reached */ - if (leaf_class) { - /* print the star and fix the leaf class*/ - printf(".*"); - leaf_class[0] = '.'; - } - if(ARG_RPMFORMAT) { - printf(")"); - } - return chars; - } else if (*pSomeString == '\0' ) { - /* fatal error, exit from loop when end of string reached and - terminator is not \0 */ - die("Classname does not terminate with: '%c'\n", - terminator); - } else if (*pSomeString == '/' ) { - /* convert '/' to '.' */ - printf("."); - } else { - /* print this char and keep going, */ - printf("%c",*pSomeString); - } /*end switch*/ - pSomeString++; - chars++; - } /*end while*/ - /*not reached*/ - return chars; + while (*in_string != terminator) { + char *newEnd=0; + int copy_len; + + /* handle the break_set */ + + if (in_string[0] == '\0' ) { + die("Classname does not terminate with: '%c', '%s'\n", + terminator, in_string); + } else { + if (in_string[0] == '/' ) { + /* convert '/' to '.' */ + strcat(out_string, "."); + in_string++; + } + } + + newEnd = strpbrk(in_string, ClassName_Break_Set); + + if (newEnd) { + copy_len = newEnd-in_string; + } else { + if (terminator == '\0') { + copy_len = strlen(in_string); + } else { + copy_len = 0; + } + } + + /* handle upto but not including the break_set*/ + if (copy_len) { + strncat(out_string, in_string, copy_len); + in_string+=copy_len; + } + + } /*end while*/ + + if (leaf_class) { + /* print the star and fix the leaf class*/ + strcat(out_string, ".*"); + leaf_class[0] = '/'; + } + if(ARG_RPMFORMAT) { + strcat(out_string, ")"); + } + strcat(out_string, "\n"); + + free(ClassName_Break_Set); + return out_string; } @@ -434,8 +649,8 @@ dumpRefType(char *string) string = strchr(string, 'L'); while (string) { string++; - string = (string) + dumpClassName(string, ';', 0); - printf("\n"); + print_table_add(formatClassName(string, ';', 0)); + string = strchr(string, ';'); string = strchr(string, 'L'); } @@ -478,8 +693,7 @@ dumpRequires(symbolTable_t *symbolTable) { dumpRefType(string); } } else { - dumpClassName(string, '\0', 0); - printf("\n"); + print_table_add(formatClassName(string, '\0', 0)); } } @@ -492,7 +706,7 @@ dumpRequires(symbolTable_t *symbolTable) { "which is null.\n", tem, ref); } - /* this is a java type... parr out the class names */ + /* this is a java type... parse out the class names */ dumpRefType(string); } @@ -512,7 +726,7 @@ dumpRequires(symbolTable_t *symbolTable) { void genSymbolTable (FILE *fileHandle, symbolTable_t *symbolTable) { char ignore[10]; - int i; + int i=0; /* We are called just after fileHandle saw the magic number, seek a @@ -588,16 +802,20 @@ void genSymbolTable (FILE *fileHandle, symbolTable_t *symbolTable) bother with datastructures to store these strings, if we need to print it print it now. */ + /* it would be better if instead of printing the + strings "raw" I turn the space separated list + into a "\n" separated list*/ + if (ARG_REQUIRES) { ptr = is_lower_equal(someString, "rpm_requires: "); if(ptr){ - printf(ptr); + print_list(ptr); } } if (ARG_PROVIDES) { ptr = is_lower_equal(someString, "rpm_provides: "); if(ptr){ - printf(ptr); + print_list(ptr); } } /* I wish there was a good way to handle this @@ -605,13 +823,31 @@ void genSymbolTable (FILE *fileHandle, symbolTable_t *symbolTable) */ ptr = is_lower_equal(someString, "$revision: "); if(ptr){ - KEYWORD_VERSION=ptr; + KEYWORD_REVISION=ptr; /* terminate the string before " $" */ + ptr = strchr(KEYWORD_REVISION, ' '); + if (ptr) { + *ptr = 0; + } + } + ptr = is_lower_equal(someString, "rpm_version: "); + if(ptr){ + KEYWORD_VERSION=ptr; + /* terminate the string at first whitespace */ ptr = strchr(KEYWORD_VERSION, ' '); if (ptr) { *ptr = 0; } } + ptr = is_lower_equal(someString, "rpm_epoch: "); + if(ptr){ + KEYWORD_EPOCH=ptr; + /* terminate the string at first whitespace */ + ptr = strchr(KEYWORD_EPOCH, ' '); + if (ptr) { + *ptr = 0; + } + } } break; } @@ -679,7 +915,9 @@ findClassName (FILE *fileHandle, symbolTable_t *symbolTable) { char ignore[10]; unsigned short type = 0; unsigned short class = 0; - + char *out_string; + char *newline; + /* seek a little past the end of the table */ my_fread(&ignore, 2, 1, fileHandle); @@ -692,30 +930,63 @@ findClassName (FILE *fileHandle, symbolTable_t *symbolTable) { !symbolTable->stringList[class] ) { die("Couln't find class: %d, provided by file.\n", class); } - CLASSNAME=symbolTable->stringList[class]; - dumpClassName(symbolTable->stringList[class], '\0', 0); + CLASS_NAME=symbolTable->stringList[class]; - if(KEYWORD_VERSION){ - /* - rpm does not currenly allow version numbers via find-provides - so as a hack dump the name twice, once with the version and - once without. Eventually we will not need this extra dump. - */ - printf("\n"); dumpClassName(symbolTable->stringList[class], '\0', 0); + out_string = formatClassName(symbolTable->stringList[class], '\0', 0); - printf("=%s", KEYWORD_VERSION); + newline = strchr(out_string, '\n'); + if (newline) { + *newline ='\0'; } - printf("\n"); + { + int len = 10; + + if (out_string) { + len += strlen(out_string); + } + if (KEYWORD_EPOCH) { + len += strlen(KEYWORD_EPOCH); + } + if (KEYWORD_VERSION) { + len += strlen(KEYWORD_VERSION); + } + if (KEYWORD_REVISION) { + len += strlen(KEYWORD_REVISION); + } + + out_string = realloc(out_string, len ); + } + + if (! out_string ){ + outofmemory(); + } + + if( KEYWORD_VERSION || KEYWORD_REVISION ){ + strcat(out_string, "="); + if(KEYWORD_EPOCH){ + strcat(out_string, KEYWORD_EPOCH); + strcat(out_string, ":"); + } + if( KEYWORD_VERSION ){ + strcat(out_string, KEYWORD_VERSION); + } else { + strcat(out_string, KEYWORD_REVISION); + } + strcat(out_string, "\n"); + print_table_add(out_string); + out_string=NULL; + } + /* Provide the star version of this class for jhtml dependencies. This option is deprecated since jhtml is deprecated. */ - + if (ARG_STARPROV) { - dumpClassName(symbolTable->stringList[class], '\0', 1); + out_string = formatClassName(symbolTable->stringList[class], '\0', 1); + print_table_add(out_string); } - printf("\n"); - + return ; } @@ -725,7 +996,7 @@ findClassName (FILE *fileHandle, symbolTable_t *symbolTable) { void freeSymbolTable (symbolTable_t *symbolTable) { - int i; + int i=0; for(i=1; i < symbolTable->poolSize; i++) { if( symbolTable->stringList[i] ) { @@ -780,7 +1051,7 @@ main(int argc, char **argv) int rc = 0; int foundMagic=0; - PROGRAMNAME=argv[0]; + PROGRAM_NAME=argv[0]; if(argv[1] == NULL) { usage(); @@ -839,14 +1110,14 @@ main(int argc, char **argv) /* parse arguments which are filenames. */ - for (i = 0; argv[i] != NULL; i++) { + for ( /*null initializer*/; argv[i] != NULL; i++) { /*open the correct file and process it*/ if ( !strcmp("-", argv[i]) ) { /* use stdin, might be a jar file */ fileHandle = stdin; - FILENAME = "<stdin>"; + FILE_NAME = "<stdin>"; foundMagic = findJavaMagic(fileHandle); while (foundMagic) { @@ -860,7 +1131,7 @@ main(int argc, char **argv) die ("Could not open file: %s.\n", argv[i]); } fileHandle = fileHandle; - FILENAME = argv[i]; + FILE_NAME = argv[i]; foundMagic = findJavaMagic(fileHandle); if (foundMagic) { @@ -870,10 +1141,11 @@ main(int argc, char **argv) rc = fclose(fileHandle); if( rc ) { - die ("Could not close file: %s.\n", FILENAME); + die ("Could not close file: %s.\n", FILE_NAME); } - CLASSNAME=0; + CLASS_NAME=0; } /*end parsing arguments which are filenames*/ + print_table_flush(); return 0; } |