#!/usr/bin/perl
# $RedRiver: find_depends,v 1.7 2008/04/22 20:08:41 andrew Exp $
use strict;
use warnings;
my %opts;
my @Files;
foreach (@ARGV) {
if (/^-+(\w+)$/) {
$opts{$1} = 1;
} else {
push @Files, $_;
}
}
Help() if $opts{h} || $opts{help};
Usage() unless @Files;
my %libs;
foreach my $file (@Files) {
my $l = find_libs($file);
foreach (keys %{ $l }) {
$libs{$_} = $l->{$_};
}
}
foreach (keys %libs) {
print $libs{$_}, "\n";
}
exit;
sub Usage
{
print "Usage: $0 [-v] file [file2 [file3 [...]]]\n";
exit;
}
sub Help
{
print <<EOL;
Hopefully finds all libraries that are required by an executable
or shared library.
Usage:
$0 [-v] file [file2 [file3 [...]]]
Example:
find /var/www/ -name *.so* | xargs find_depends | \\
sort -u | xargs -I {} cp {} /var/www{}
EOL
exit;
}
sub find_libs
{
my $file = shift;
my $ld = shift || get_ldconfig();
my $locs = shift || {};
print STDERR "Finding libs for '$file'\n" if $opts{v};
my @libs = search_file($file);
foreach (@libs) {
my ($name, $maj, $min) = $_ =~ /lib([^\/]+)\.so\.(\d+)\.(\d+)$/;
next if ! $name;
my $spec = 'l' . $name . '.' . $maj . '.' . $min;
if (exists $ld->{$spec}) {
next if exists $locs->{$spec};
$locs->{$spec} = $ld->{$spec};
$locs = find_libs($locs->{$spec}, $ld, $locs);
} else {
warn "Couldn't find location for lib '$_' (file '$file')";
}
}
return $locs;
}
sub search_file
{
my $file = shift;
my @libs;
open my $libs, '-|', '/usr/bin/ldd', $file or die "Couldn't open ldd '$file': $!";
while (<$libs>) {
next if length($_) < 56;
chomp;
my $spec = substr $_, 56;
next if $spec !~ m{^/}xms;
push @libs, $spec;
}
close $libs;
return @libs;
}
sub get_ldconfig
{
my $ldconfig = '/sbin/ldconfig';
my (%paths, %libs);
open my $ld, '-|', $ldconfig, '-r'
or die "Couldn't open pipe to ldconfig: $!";
while (<$ld>) {
chomp;
if (/search directories:\s+(.*)/) {
#search directories: /usr/lib:/usr/local/lib
my @p = split /:/, $1;
@paths{@p} = 1;
} elsif (/\d+:-(\S+)\s+=>\s+(\S+)/) {
#0:-ldes.9.0 => /usr/lib/libdes.so.9.0
my $lib = $1;
my $loc = $2;
#my ($name, $maj, $min) = $lib =~ /l([^\.]+)\.(\d+)\.(\d+)/;
#my $spec = 'lib' . $name . '.so.' . $maj . '.' . $min;
$libs{$lib} = $loc;
} else {
#print $_, "\n";
}
}
close $ld;
$libs{_paths} = [ keys %paths ];
return \%libs;
}