From f6642d9d5eb86064d558a32f52db19abd862bb02 Mon Sep 17 00:00:00 2001 From: Simon McVittie <smcv@collabora.com> Date: Mon, 23 Apr 2018 14:55:24 +0100 Subject: [PATCH] capture-libs: Decouple capture of dependencies and the library itself For Mesa DRI drivers, we will need to capture the dependencies but not the driver itself, because we load the driver itself by setting LIBGL_DRIVERS_PATH instead. I don't have a concrete use-case for no-dependencies:, which is implemented for symmetry. Signed-off-by: Simon McVittie <smcv@collabora.com> --- debian/tests/control | 1 + tests/capture-libs.pl | 95 +++++++++++++++++++++++++++++++++++++++++++ utils/capture-libs.c | 49 +++++++++++++++++++++- 3 files changed, 144 insertions(+), 1 deletion(-) diff --git a/debian/tests/control b/debian/tests/control index 2eab46db2..38a94afc9 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -10,6 +10,7 @@ Depends: libcapsule-tests, libcapsule-tools, libipc-run-perl, + libglib2.0-0, libjpeg62 (>= 6b1) | libjpeg62-turbo, libtool, perl, diff --git a/tests/capture-libs.pl b/tests/capture-libs.pl index c83e142f2..f047731cc 100644 --- a/tests/capture-libs.pl +++ b/tests/capture-libs.pl @@ -165,6 +165,101 @@ run_ok([qw(bwrap --ro-bind / / --ro-bind /), $host, "--dest=$libdir", "--provider=$host", 'if-exists:soname-match:this*library*does?not?exist']); +# libgobject-2.0.so.0 depends on libglib-2.0.so.0 so normally, +# capturing GObject captures GLib +ok(! system('rm', '-fr', $libdir)); +mkdir($libdir); +run_ok([qw(bwrap --ro-bind / / --ro-bind /), $host, + '--bind', $libdir, $libdir, + qw(--dev-bind /dev /dev), + $CAPSULE_CAPTURE_LIBS_TOOL, '--link-target=/', + "--dest=$libdir", "--provider=$host", + 'soname:libgobject-2.0.so.0']); +{ + opendir(my $dir_iter, $libdir); + foreach my $symlink (readdir $dir_iter) { + next if $symlink eq '.' || $symlink eq '..'; + diag "- $symlink -> ".readlink("$libdir/$symlink"); + } + closedir $dir_iter; +} +like(readlink "$libdir/libgobject-2.0.so.0", + qr{^$LIBDIR/libgobject-2\.0\.so\.0(?:[0-9.]+)$}, + '$libdir/libgobject-2.0.so.0 is captured'); +like(readlink "$libdir/libglib-2.0.so.0", + qr{^$LIBDIR/libglib-2\.0\.so\.0(?:[0-9.]+)$}, + '$libdir/libglib-2.0.so.0 is captured as a dependency'); + +# only-dependencies: captures the dependency, GLib but not the +# dependent library, GObject +ok(! system('rm', '-fr', $libdir)); +mkdir($libdir); +run_ok([qw(bwrap --ro-bind / / --ro-bind /), $host, + '--bind', $libdir, $libdir, + qw(--dev-bind /dev /dev), + $CAPSULE_CAPTURE_LIBS_TOOL, '--link-target=/', + "--dest=$libdir", "--provider=$host", + 'only-dependencies:soname:libgobject-2.0.so.0']); +{ + opendir(my $dir_iter, $libdir); + foreach my $symlink (readdir $dir_iter) { + next if $symlink eq '.' || $symlink eq '..'; + diag "- $symlink -> ".readlink("$libdir/$symlink"); + } + closedir $dir_iter; +} +ok(! -e "$libdir/libgobject-2.0.so.0", + 'only-dependencies: does not capture the library itself'); +like(readlink "$libdir/libglib-2.0.so.0", + qr{^$LIBDIR/libglib-2\.0\.so\.0(?:[0-9.]+)$}, + '$libdir/libglib-2.0.so.0 is captured as a dependency'); + +# no-dependencies: captures the dependent library, GObject but not the +# dependency, GLib (not amazingly useful) +ok(! system('rm', '-fr', $libdir)); +mkdir($libdir); +run_ok([qw(bwrap --ro-bind / / --ro-bind /), $host, + '--bind', $libdir, $libdir, + qw(--dev-bind /dev /dev), + $CAPSULE_CAPTURE_LIBS_TOOL, '--link-target=/', + "--dest=$libdir", "--provider=$host", + 'no-dependencies:soname:libgobject-2.0.so.0']); +{ + opendir(my $dir_iter, $libdir); + foreach my $symlink (readdir $dir_iter) { + next if $symlink eq '.' || $symlink eq '..'; + diag "- $symlink -> ".readlink("$libdir/$symlink"); + } + closedir $dir_iter; +} +like(readlink "$libdir/libgobject-2.0.so.0", + qr{^$LIBDIR/libgobject-2\.0\.so\.0(?:[0-9.]+)$}, + '$libdir/libgobject-2.0.so.0 is captured'); +ok(! -e "$libdir/libglib-2.0.so.0", + 'no-dependencies: does not capture libglib-2.0.so.0'); + +# only-dependencies:no-dependencies: (either way round) is completely useless +ok(! system('rm', '-fr', $libdir)); +mkdir($libdir); +my $result = run_verbose([qw(bwrap --ro-bind / / --ro-bind /), $host, + '--bind', $libdir, $libdir, + qw(--dev-bind /dev /dev), + $CAPSULE_CAPTURE_LIBS_TOOL, '--link-target=/', + "--dest=$libdir", "--provider=$host", + 'only-dependencies:no-dependencies:libglib-2.0.so.0'], + '>&2'); +ok(! $result, 'only-dependencies:no-dependencies: is useless'); +ok(! system('rm', '-fr', $libdir)); +mkdir($libdir); +my $result = run_verbose([qw(bwrap --ro-bind / / --ro-bind /), $host, + '--bind', $libdir, $libdir, + qw(--dev-bind /dev /dev), + $CAPSULE_CAPTURE_LIBS_TOOL, '--link-target=/', + "--dest=$libdir", "--provider=$host", + 'no-dependencies:only-dependencies:libglib-2.0.so.0'], + '>&2'); +ok(! $result, 'no-dependencies:only-dependencies: is useless'); + SKIP: { skip "not on Linux? Good luck!", 1 unless $^O eq 'linux'; my $stdout; diff --git a/utils/capture-libs.c b/utils/capture-libs.c index d5009f91e..e84926ea0 100644 --- a/utils/capture-libs.c +++ b/utils/capture-libs.c @@ -163,6 +163,10 @@ static void usage (int code) "\tCapture every library in ld.so.cache that matches\n" "\ta shell-style glob (which will usually need to be\n" "\tquoted when using a shell)\n" ); + fprintf( fh, "only-dependencies:PATTERN\n" + "\tCapture the dependencies of each library matched by\n" + "\tPATTERN, but not the library matched by PATTERN itself\n" + "\t(unless a match for PATTERN depends on another match)\n" ); fprintf( fh, "if-exists:PATTERN\n" "\tCapture PATTERN, but don't fail if nothing matches\n" ); fprintf( fh, "even-if-older:PATTERN\n" @@ -180,6 +184,8 @@ typedef enum CAPTURE_FLAG_NONE = 0, CAPTURE_FLAG_EVEN_IF_OLDER = (1 << 0), CAPTURE_FLAG_IF_EXISTS = (1 << 1), + CAPTURE_FLAG_LIBRARY_ITSELF = ( 1 << 2 ), + CAPTURE_FLAG_DEPENDENCIES = ( 1 << 3 ), } capture_flags; static bool @@ -254,6 +260,21 @@ capture_one( const char *soname, capture_flags flags, continue; } + if( i == 0 && !( flags & CAPTURE_FLAG_LIBRARY_ITSELF ) ) + { + DEBUG( DEBUG_TOOL, "Not capturing \"%s\" itself as requested", + provider.needed[i].name ); + continue; + } + + if( i > 0 && !( flags & CAPTURE_FLAG_DEPENDENCIES ) ) + { + DEBUG( DEBUG_TOOL, + "Not capturing dependencies of \"%s\" as requested", + provider.needed[0].name ); + break; + } + its_basename = my_basename( provider.needed[i].name ); if( fstatat( dest_fd, its_basename, &statbuf, @@ -529,6 +550,17 @@ capture_pattern( const char *pattern, capture_flags flags, { DEBUG( DEBUG_TOOL, "%s", pattern ); + if ( ( flags & ( CAPTURE_FLAG_LIBRARY_ITSELF | + CAPTURE_FLAG_DEPENDENCIES ) ) == 0 ) + { + _capsule_set_error( code, message, EINVAL, + "combining no-dependencies: with " + "only-dependencies: is meaningless, " + "so \"%s\" is invalid", + pattern ); + return false; + } + if( strstarts( pattern, "soname:" ) ) { return capture_one( pattern + strlen( "soname:" ), @@ -555,6 +587,20 @@ capture_pattern( const char *pattern, capture_flags flags, code, message ); } + if( strstarts( pattern, "only-dependencies:" ) ) + { + return capture_pattern( pattern + strlen( "only-dependencies:" ), + flags & ~CAPTURE_FLAG_LIBRARY_ITSELF, + code, message ); + } + + if( strstarts( pattern, "no-dependencies:" ) ) + { + return capture_pattern( pattern + strlen( "no-dependencies:" ), + flags & ~CAPTURE_FLAG_DEPENDENCIES, + code, message ); + } + if( strcmp( pattern, "gl:" ) == 0 ) { // Useful information: @@ -650,7 +696,8 @@ capture_patterns( const char * const *patterns, capture_flags flags, int main (int argc, char **argv) { - capture_flags flags = CAPTURE_FLAG_NONE; + capture_flags flags = (CAPTURE_FLAG_LIBRARY_ITSELF | + CAPTURE_FLAG_DEPENDENCIES); int code = 0; char *message = NULL; -- GitLab