Bläddra i källkod

dpkg-shlibdeps: Improve logic to identify packages owning a library

With things like merged-/usr, a system might have libraries that are
stored for example in /usr/lib but that dpkg knows under /lib. This
breaks some of the initial assumptions made in dpkg-shlibdeps.

We now scan all possible paths for a given library (instead of trying
to guess which one is the canonical one) and whenever we find a match
in the dpkg database, we also associate the package for the associated
realpath(). That way when a library is not properly identified, we can
fallback on looking if its realpath is known and be confident that if
the library was packaged, we did identify it correctly.

[guillem@debian.org:
 - Fold find_library_locations() into find_library().
 - Minor coding style fixes.
 - Squash the two separate commits and cleanup the commit message. ]

Closes: #843073
Signed-off-by: Guillem Jover <guillem@debian.org>
Raphaël Hertzog 9 år sedan
förälder
incheckning
a927295c93
3 ändrade filer med 24 tillägg och 29 borttagningar
  1. 3 0
      debian/changelog
  2. 5 14
      scripts/Dpkg/Shlibs.pm
  3. 16 15
      scripts/dpkg-shlibdeps.pl

+ 3 - 0
debian/changelog

@@ -5,6 +5,9 @@ dpkg (1.18.17) UNRELEASED; urgency=medium
     are optional. Regression introduced in dpkg 1.18.16. Closes: #848422
   * Validate versions too in dpkg-maintscript-helper symlink_to_dir and
     dir_to_symlink commands.
+  * Improve logic to identify packages owning a library in dpkg-shlibdeps,
+    by handling the same library appearing more than once on the filesystem
+    Thanks to Raphaël Hertzog <hertzog@debian.org>. Closes: #843073
   * Documentation:
     - Clarify that dpkg-buildpackage does not run «dpkg-source --before-build»
       when using the -T option. Closes: #649531

+ 5 - 14
scripts/Dpkg/Shlibs.pm

@@ -1,4 +1,4 @@
-# Copyright © 2007 Raphaël Hertzog <hertzog@debian.org>
+# Copyright © 2007, 2016 Raphaël Hertzog <hertzog@debian.org>
 # Copyright © 2007-2008, 2012-2015 Guillem Jover <guillem@debian.org>
 #
 # This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,7 @@ use strict;
 use warnings;
 use feature qw(state);
 
-our $VERSION = '0.02';
+our $VERSION = '0.03';
 our @EXPORT_OK = qw(
     blank_library_paths
     setup_library_paths
@@ -149,29 +149,20 @@ sub find_library {
     setup_library_paths() if not $librarypaths_init;
 
     my @librarypaths = (@{$rpath}, @custom_librarypaths, @system_librarypaths);
+    my @libs;
 
     $root //= '';
     $root =~ s{/+$}{};
     foreach my $dir (@librarypaths) {
 	my $checkdir = "$root$dir";
-	# If the directory checked is a symlink, check if it doesn't
-	# resolve to another public directory (which is then the canonical
-	# directory to use instead of this one). Typical example
-	# is /usr/lib64 -> /usr/lib on amd64.
-	if (-l $checkdir) {
-	    my $newdir = resolve_symlink($checkdir);
-	    if (any { "$root$_" eq "$newdir" } @librarypaths) {
-		$checkdir = $newdir;
-	    }
-	}
 	if (-e "$checkdir/$lib") {
 	    my $libformat = Dpkg::Shlibs::Objdump::get_format("$checkdir/$lib");
 	    if ($format eq $libformat) {
-		return canonpath("$checkdir/$lib");
+		push @libs, canonpath("$checkdir/$lib");
 	    }
 	}
     }
-    return;
+    return @libs;
 }
 
 1;

+ 16 - 15
scripts/dpkg-shlibdeps.pl

@@ -6,7 +6,7 @@
 # Copyright © 2000 Wichert Akkerman
 # Copyright © 2006 Frank Lichtenheld
 # Copyright © 2006-2010,2012-2015 Guillem Jover <guillem@debian.org>
-# Copyright © 2007 Raphaël Hertzog
+# Copyright © 2007, 2016 Raphaël Hertzog <hertzog@debian.org>
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -192,8 +192,8 @@ foreach my $file (keys %exec) {
     my %soname_notfound;
     my %alt_soname;
     foreach my $soname (@sonames) {
-	my $lib = my_find_library($soname, $obj->{RPATH}, $obj->{format}, $file);
-	unless (defined $lib) {
+	my @libs = my_find_library($soname, $obj->{RPATH}, $obj->{format}, $file);
+	unless (scalar @libs) {
 	    $soname_notfound{$soname} = 1;
 	    $global_soname_notfound{$soname} = 1;
 	    my $msg = g_("couldn't find library %s needed by %s (ELF " .
@@ -206,12 +206,14 @@ foreach my $file (keys %exec) {
 	    }
 	    next;
 	}
-	$libfiles{$lib} = $soname;
-	my $reallib = realpath($lib);
-	if ($reallib ne $lib) {
-	    $altlibfiles{$reallib} = $soname;
-	}
-	print "Library $soname found in $lib\n" if $debug;
+	foreach my $lib (@libs) {
+	    $libfiles{$lib} = $soname;
+	    my $reallib = realpath($lib);
+	    if ($reallib ne $lib) {
+		$altlibfiles{$reallib} = $soname;
+	    }
+	    print "Library $soname found in $lib\n" if $debug;
+        }
     }
     my $file2pkg = find_packages(keys %libfiles, keys %altlibfiles);
     my $symfile = Dpkg::Shlibs::SymbolFile->new();
@@ -830,17 +832,14 @@ sub my_find_library {
     foreach my $builddir (@builddirs) {
 	next if defined($dir_checked{$builddir});
 	next if ignore_pkgdir($builddir);
-	$file = find_library($lib, \@RPATH, $format, $builddir);
-	return $file if defined($file);
+	my @libs = find_library($lib, \@RPATH, $format, $builddir);
+	return @libs if scalar @libs;
 	$dir_checked{$builddir} = 1;
     }
 
     # Fallback in the root directory if we have not found what we were
     # looking for in the packages
-    $file = find_library($lib, \@RPATH, $format, '');
-    return $file if defined($file);
-
-    return;
+    return find_library($lib, \@RPATH, $format, '');
 }
 
 my %cached_pkgmatch = ();
@@ -879,7 +878,9 @@ sub find_packages {
 		or syserr(g_('write diversion info to stderr'));
 	} elsif (m/^([-a-z0-9+.:, ]+): (\/.*)$/) {
 	    my ($pkgs, $path) = ($1, $2);
+	    my $realpath = realpath($path);
 	    $cached_pkgmatch{$path} = $pkgmatch->{$path} = [ split /, /, $pkgs ];
+	    $cached_pkgmatch{$realpath} = $pkgmatch->{$realpath} = [ split /, /, $pkgs ];
 	} else {
 	    warning(g_("unknown output from dpkg --search: '%s'"), $_);
 	}