#!/usr/bin/perl use File::Basename; use Getopt::Long; # this dependency analysis program is the only one which need to know # the RPM buildroot to do its work. # Figuring out what files are really executables via magic numbers is # hard. Not only is every '#!' an executable of some type (with a # potentially infinite supply of interpreters) but there are thousands # of valid binary magic numbers for old OS's and old CPU types. # Permissions do not always help discriminate binaries from the rest # of the files, on Solaris the shared libraries are marked as # 'executable'. # -rwxr-xr-x 1 bin bin 1013248 Jul 1 1998 /lib/libc.so.1 # I would like to let the 'file' command take care of the magic # numbers for us. Alas! under linux file prints different kind of # messages for each interpreter, there is no common word 'script' to # look for. # ' perl commands text' # ' Bourne shell script text' # ' a /usr/bin/wish -f script text' # WORSE on solaris there are entries which say: # ' current ar archive, not a dynamic executable or shared object' # how do I grep for 'executable' when people put a 'not executable' in # there? I trim off everything after the first comma (if there is # one) and if the result has the string 'executable' in it then it may # be one. # so we must also do some magic number processing ourselves, and be # satisfied with 'good enough'. # I look for files which have atleast one of the executable bits set # and are either labled 'executable' by the file command (see above # restriction) OR have a '#!' as their first two characters. $is_mode_executable=oct(111); # set a known path $ENV{'PATH'}= ( ':/usr/bin'. ':/bin'. ''); # taint perl requires we clean up these bad environmental variables. delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; $BUILDROOT = ''; %option_linkage = ( "buildroot" => \$BUILDROOT, ); if( !GetOptions (\%option_linkage, "buildroot=s") ) { die("Illegal options in \@ARGV: '@ARGV'\n"); } if ($BUILDROOT == '/') { $BUILDROOT = ''; } if ("@ARGV") { foreach (@ARGV) { process_file($_); } } else { # notice we are passed a list of filenames NOT as common in unix the # contents of the file. foreach (<>) { process_file($_); } } foreach $module (sort keys %provides) { print "executable($module)\n"; } exit 0; sub is_file_script { my ($file) = @_; chomp $file; my $out = 0; open(FILE, "<$file")|| die("$0: Could not open file: '$file' : $!\n"); my $rc = sysread(FILE,$line,2); if ( ($rc > 1) && ($line =~ m/^\#\!/) ) { $out = 1; } close(FILE) || die("$0: Could not close file: '$file' : $!\n"); return $out; } sub is_file_binary_executable { my ($file) = @_; $file_out=`file $file`; # trim off any extra descriptions. $file_out =~ s/\,.*$//; my $out = 0; if ($file_out =~ m/executable/ ) { $out = 1; } return $out; } sub process_file { my ($file) = @_; chomp $file; my $prov_name = $file; $prov_name =~ s!^$BUILDROOT!!; # If its a link find the file it points to. Dead links do not # provide anything. while (-l $file) { my $newfile = readlink($file); if ($newfile !~ m!^/!) { $newfile = dirname($file).'/'.$newfile; } else { $newfile = $BUILDROOT.$newfile; } $file = $newfile; } (-f $file) || return ; ( (stat($file))[2] & $is_mode_executable ) || return ; is_file_script($file) || is_file_binary_executable($file) || return ; $provides{$prov_name}=1; $provides{basename($prov_name)}=1; return ; }