diff --git a/debian/tests/control b/debian/tests/control index 2eab46db25d57750971311ca65976c935ef86cb3..38a94afc99c8dee0f000ec53bfd59be3d2c34da6 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 c83e142f20c5f04aa8ae83ccc6c01b53a87f2ec3..f047731cc2da611ae01556a77469115b6d679b23 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 d5009f91e8eb51a9ea7faa9498a0d67c46f5c7d0..e84926ea03f6000b40f437e1d4a85260ae5be14d 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;