adequate-0.15.1ubuntu5/0000755000000000000000000000000013256653076011622 5ustar adequate-0.15.1ubuntu5/.perlcriticrc0000644000000000000000000000316412370511531014275 0ustar severity = 1 verbose = 1 [-InputOutput::ProhibitInteractiveTest] # we don't want to depend on IO::Interactive, and -t is good enough for our purposes [-InputOutput::ProhibitExplicitStdin] # we never want to iterate over @ARGV implicitly # see also https://github.com/Perl-Critic/Perl-Critic/issues/72 [InputOutput::RequireBriefOpen] lines = 20 [-InputOutput::RequireCheckedOpen] [-InputOutput::RequireCheckedClose] # already covered by RequireCheckedSyscalls [-RegularExpressions::RequireExtendedFormatting] # no, thanks [-RegularExpressions::RequireDotMatchAnything] [-RegularExpressions::RequireLineBoundaryMatching] # we work mostly with single-line strings # reconsider when https://github.com/Perl-Critic/Perl-Critic/issues/551 is fixed [-RegularExpressions::ProhibitEnumeratedClasses] # we work mostly with ASCII [-ErrorHandling::RequireCarping] # die is good enough for our purposes [-Variables::ProhibitPackageVars] # no, thanks [-ValuesAndExpressions::ProhibitVersionStrings] # we don't care about Perl << 5.6, which doesn't support version strings [-ValuesAndExpressions::ProhibitMagicNumbers] # no, thanks [-ValuesAndExpressions::ProhibitNoisyQuotes] [-ValuesAndExpressions::ProhibitEmptyQuotes] # no, thanks [-CodeLayout::ProhibitParensWithBuiltins] # no, thanks [-CodeLayout::RequireTrailingCommas] # no, thanks [-BuiltinFunctions::ProhibitBooleanGrep] # we don't want to depend on List::MoreUtils [NamingConventions::Capitalization] labels = :all_lower file_lexical_variable_exemptions = ARGV_[[:lower:]]+ subroutine_exemptions = Tags [ControlStructures::ProhibitPostfixControls] flowcontrol = die error # vim:ft=dosini adequate-0.15.1ubuntu5/adequate0000755000000000000000000012350013256653076013342 0ustar #!/usr/bin/perl # Copyright © 2012-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. use strict; use warnings; use v5.14; no feature 'unicode_strings'; no if $] >= 5.018, warnings => 'experimental::smartmatch'; use Attribute::Handlers; use Cwd; use English qw(-no_match_vars); use Getopt::Long qw(:config); use Errno; use Fcntl qw(:flock); use IO::Handle qw(); use POSIX qw(setsid); our $VERSION = '0'; BEGIN { $ENV{'DEBCONF_NOWARNINGS'} = 'yes'; ## no critic (LocalizedPunctuationVars) local %::known_tags = (); local %::visible_tags = (); } my $pending_path = '/var/lib/adequate/pending'; my %pending = (); my $pending_fh; sub flush_std_fh { IO::Handle::flush(*STDOUT) or die $ERRNO; IO::Handle::flush(*STDERR) or die $ERRNO; return; } sub read_pending { die if defined $pending_fh; if (open($pending_fh, '+>>', $pending_path)) { ## no critic (BriefOpen) flock $pending_fh, LOCK_EX or die "$pending_path: $ERRNO"; seek($pending_fh, 0, 0) or die "$pending_path: $ERRNO"; while (<$pending_fh>) { chomp; $pending{$_} = 1; } } elsif ($ERRNO{ENOENT}) { return; } else { die "$pending_path: $ERRNO"; } return; } sub write_pending { defined $pending_fh or die; truncate($pending_fh, 0) or die "$pending_path: $ERRNO"; seek($pending_fh, 0, 0) or die "$pending_path: $ERRNO"; for (sort keys %pending) { print {$pending_fh} "$_\n" or die "$pending_path: $ERRNO"; } close $pending_fh or die "$pending_path: $ERRNO"; $pending_fh = undef; return; } sub do_apt_preinst { my $enabled = undef; while () { given ($_) { when ("Adequate::Enabled=true\n") { $enabled = 1; } when ("Adequate::Enabled=false\n") { $enabled = 0; } when ("\n") { last; } } } if (not defined $enabled) { warning('apt hook is not enabled'); } if (not $enabled) { return; } while () { my ($package, $architecture) = m{^(\S+) \s+ \S+ \s+ \S+ \s+ \S+ \s+ /.+_([a-z0-9]+)[.]deb$}x or next; if ($architecture ne 'all') { $package = "$package:$architecture"; } $pending{$package} = 1; } write_pending(); return; } sub do_pending { if (%pending) { process(1, keys %pending); %pending = (); } write_pending(); return; } my $use_debconf = 0; my @debconf_buffer = (); my $ldd_uid = undef; my $ldd_gid = undef; sub process { my ($ignore_missing, @packages) = @_; my %package_map = get_package_map($ignore_missing, @packages); @packages = keys %package_map; if (not @packages) { if ($ignore_missing) { return; } else { error('no packages to check'); } } my %file_map = get_file_map(@packages); check_broken_symlinks(%file_map); check_copyright(@packages); check_obsolete_conffiles(@packages); check_python_bytecompilation(%file_map); check_elfs(%file_map); check_paths(%file_map); check_alternatives(\%package_map, \%file_map); check_binfmts(@packages); check_pkgconfig(%file_map); flush_debconf(); return; } sub debconf { my ($subname, @args) = @_; no strict qw(refs); ## no critic (NoStrict) my $sub = \&{"Debconf::Client::ConfModule::$subname"}; my ($rc, $msg) = $sub->(@args); if ($rc != 0) { die "interaction with debconf failed: $msg"; } } sub flush_debconf { @debconf_buffer or return; my $debconf_buffer = join("\n", @debconf_buffer); $debconf_buffer =~ s/\\/\\\\/g; $debconf_buffer =~ s/\n/\\n/g; my $t = 'adequate/error'; debconf('version', '2.0'); debconf('capb', 'escape'); debconf('fset', $t, 'seen', 0); debconf('subst', $t, 'tags', $debconf_buffer); debconf('input', 'critical', $t); debconf('title', 'adequate found packaging bugs'); debconf('go'); return; } sub tag { my ($pkg, $tag, @extra) = @_; die "attempted to emit unknown tag $tag" if not defined $::known_tags{$tag}; $::visible_tags{$tag} or return; if ($use_debconf) { push @debconf_buffer, "$pkg: $tag @extra"; } elsif (-t STDOUT) { print "$pkg: \e[31m$tag\e[0m @extra\n" or die $ERRNO; } else { print "$pkg: $tag @extra\n" or die $ERRNO; } return; } sub get_package_map { my ($ignore_dpkg_query_errors, @packages) = @_; my %map; flush_std_fh(); open(my $fh, '-|', 'dpkg-query', '-Wf', '${binary:Package} ${Package};${Status};${Provides}\n', ## no critic (Interpolation) # try both ${binary:Package} and ${Package}; the former gives us # architecture information, but the later works with pre-multiarch dpkg '--', @packages ) or die "dpkg-query -W: $ERRNO"; while (<$fh>) { my ($package, $status, $provides) = m/^\s*(\S+).*;.*\s(\S+);(.*)$/; if ($status eq 'installed') { my %provides = map { $_ => 1 } split(m/,\s*/, $provides); $map{$package} = \%provides; } elsif (@packages) { info("skipping $package because it's not installed"); } } close($fh) or $ignore_dpkg_query_errors or die 'dpkg-query -W: ' . ($ERRNO or 'failed'); return %map; } sub get_file_map ## no critic (ArgUnpacking) { my %map = (); flush_std_fh(); open(my $fh, '-|', 'dpkg', '-L', @_) or die "dpkg -L: $ERRNO"; my $pkg = shift; $map{$pkg} = []; while (<$fh>) { if (/^$/) { ## no critic (FixedStringMatches) $pkg = shift; $map{$pkg} = []; next; } if (m{^(?:locally diverted|diverted by \S+) to: (/.+)$}) { $map{$pkg}->[-1] = $1; next; } m{^(/.+)$} or next; push @{$map{$pkg}}, $1; } close($fh) or die 'dpkg -L: ' . ($ERRNO or 'failed'); return %map; } sub get_alternatives { my ($alt) = @_; my @paths = (); local $ENV{LC_ALL} = 'C'; flush_std_fh(); open(my $fh, '-|', 'update-alternatives', '--list', $alt) or die "update-alternatives --list: $ERRNO"; while (<$fh>) { chomp; push(@paths, $_); } close($fh) or die 'update-alternatives --list: ' . ($ERRNO or 'failed'); return @paths; } sub get_alternative_map { my @interesting_alts = @_; my %seen_alts = (); local $ENV{LC_ALL} = 'C'; flush_std_fh(); open(my $fh, '-|', 'update-alternatives', '--get-selections') or die "update-alternatives --get-selections: $ERRNO"; while (<$fh>) { my ($alt) = m/^(\S+)\s+\S+\s+\S+$/ or die 'unexpected output from update-alternatives --get-selections'; $seen_alts{$alt} = 1; } close($fh) or die 'update-alternatives --get-selections: ' . ($ERRNO or 'failed'); my %map = (); for my $alt (@interesting_alts) { next if not $seen_alts{$alt}; for my $path (get_alternatives($alt)) { $map{$alt}{$path} = 1; } } return %map; } sub UNIVERSAL::Tags : ATTR(CODE) { my (undef, $symbol, $code, undef, $tags) = @_; for my $tag (@{$tags}) { $::known_tags{$tag} = 1; } no warnings qw(redefine); ## no critic (NoWarnings) *{$symbol} = sub { local %::visible_tags = map { $_ => 1 } grep { exists $::visible_tags{$_} } @{$tags}; return $code->(@_) if %::visible_tags; return; }; return; } sub check_broken_symlinks : Tags(qw(broken-symlink)) { my %map = @_; while (my ($pkg, $files) = each %map) { for my $file (@{$files}) { if (-l $file and not stat($file)) { my $target = readlink $file; if (defined $target) { tag $pkg, 'broken-symlink', $file, '->', $target; } else { tag $pkg, 'broken-symlink', $file, "($ERRNO)"; } } } } return; } sub check_copyright : Tags(qw(missing-copyright-file)) { my @packages = @_; for my $pkg (@packages) { s/:.*// for my $noarch_pkg = $pkg; ## no critic (PostfixControls) my $file = "/usr/share/doc/${noarch_pkg}/copyright"; if (! -f $file) { tag $pkg, 'missing-copyright-file', $file; } } return; } sub check_obsolete_conffiles : Tags(qw(obsolete-conffile)) { my @packages = @_; my $pkg; flush_std_fh(); open(my $fh, '-|', 'dpkg-query', '-Wf', '${binary:Package},${Package}\n${Conffiles}\n', ## no critic (Interpolation) # try both ${binary:Package} and ${Package}; the former gives us # architecture information, but the later works with pre-multiarch dpkg ) or die "dpkg-query -W: $ERRNO"; my %file2obs = (); my %pkg2files = (); while (<$fh>) { if (m/^,?([^,\s]+)/) { $pkg = $1; } elsif (m{^ (.*) [0-9a-f]+( obsolete)?$}) { my $file = $1; my $obsolete = defined $2; defined $pkg or die 'unexpected output from dpkg-query -W'; if ($obsolete) { $file2obs{$file} //= 1; my $files = $pkg2files{$pkg} //= []; push @{$files}, $file; } else { # Work-around for dpkg bug #645849: don't consider a conffile # obsolete if it's listed as non-obsolete in a different # package. $file2obs{$file} = 0; } } } close($fh) or die 'dpkg-query -W: ' . ($ERRNO or 'failed'); for my $pkg (@packages) { my $files = $pkg2files{$pkg} // []; defined $files or die; for my $file (@{$files}) { if ($file2obs{$file}) { tag $pkg, 'obsolete-conffile', $file; } } } return; } sub get_python_versions { my @group = (undef, undef); for my $version (2..3) { my @result = (); my $path = "/usr/share/python$version/debian_defaults"; $path =~ s{/python\K2/}{/}; if (open(my $fh, '<', $path)) { while (<$fh>) { if (/^supported-versions\s*=\s*(\S.+\S)\s*$/) { my $versions = $1; push @result, grep { -f "/usr/lib/$_/os.py" } split(/\s*,\s*/, $versions); last; } } close($fh) or die "$path: $ERRNO"; } elsif (not $ERRNO{ENOENT}) { die "$path: $ERRNO"; } push @group, \@result; } return @group; } my $bytecompilation_not_needed_re = qr{ etc/ | bin/ | sbin/ | usr/bin/ | usr/games/ | usr/lib/debug/bin/ | usr/lib/debug/sbin/ | usr/lib/debug/usr/bin/ | usr/lib/debug/usr/games/ | usr/lib/debug/usr/sbin/ | usr/lib/pypy/lib-python/\d[.]\d+/test/bad | usr/lib/pypy/lib-python/\d[.]\d+/lib2to3/tests/data/ | usr/sbin/ | usr/share/apport/package-hooks/ | usr/share/doc/ | usr/share/jython/ | usr/share/paster_templates/ | usr/lib/python\d[.]\d+/__phello__[.]foo[.]py$ | usr/lib/python\d[.]\d+/lib2to3/tests/data/ | usr/lib/python\d[.]\d+/test/bad }x; # Please keep it in sync with lintian4python! sub check_python_bytecompilation : Tags(qw(pyshared-file-not-bytecompiled py-file-not-bytecompiled)) { my %map = @_; my @pythons = get_python_versions(); my @python2s = @{$pythons[2]}; my @python3s = @{$pythons[3]}; my $pypy_installed = -f '/usr/bin/pypy'; my $pysupport_old = -d '/usr/lib/python-support/private/'; # python-support < 0.90 my $pysupport_new = -d '/usr/share/python-support/private/'; # python-support >= 0.90 while (my ($pkg, $files) = each %map) { file: for (@{$files}) { my ($path, $dir, $base) = m{^((/.+/)([^/]+)[.]py)$} or next; next file if m{^/$bytecompilation_not_needed_re}; if (m{^/usr/share/pyshared/(.+)} or m{^/usr/share/python-support/[^/]+/(? 0x04, 'GPLv3' => 0x08, 'AGPLv3' => 0x08, 'GPLv2+' => 0x0c, 'GPLv3+' => 0x08, 'AGPLv3+' => 0x08, 'LGPLv2.1' => 0x14c, 'LGPLv3' => 0x188, 'LGPLv2.1+' => 0x1cc, 'LGPLv3+' => 0x188, 'LGPLv3+ | GPLv2+' => 0x18c, 'OpenSSL' => 0x100, ); my %soname2license = ( 'libcrypto.so.0.9.8' => 'OpenSSL', 'libcrypto.so.1.0.0' => 'OpenSSL', 'libgmp.so.10' => 'LGPLv3+ | GPLv2+', # FIXME: libgmp10 in wheezy is LGPLv3+-only 'libgnutls-extra.so.26' => 'GPLv3+', 'libgnutls-openssl.so.27' => 'GPLv3+', # FIXME: libgs9 and libjbig2dec in jessie are GPLv2+ 'libgs.so.9' => 'AGPLv3+', 'libjbig2dec.so.0' => 'AGPLv3+', 'libltdl.so.7' => 'GPLv2+', 'libpoppler.so.19' => 'GPLv2', 'libpoppler.so.28' => 'GPLv2', 'libpoppler.so.37' => 'GPLv2', 'libpoppler.so.43' => 'GPLv2', 'libpoppler.so.44' => 'GPLv2', 'libpoppler.so.46' => 'GPLv2', 'libpoppler.so.47' => 'GPLv2', 'libpoppler.so.5' => 'GPLv2', 'libpoppler.so.57' => 'GPLv2', 'libreadline.so.5' => 'GPLv2+', 'libreadline.so.6' => 'GPLv3+', 'libreadline.so.7' => 'GPLv3+', 'libssl.so.0.9.8' => 'OpenSSL', 'libssl.so.1.0.0' => 'OpenSSL', ); sub parse_copyright_files { my @packages = @_; my %licenses = (); for my $pkg (@packages) { s/:.*// for my $noarch_pkg = $pkg; ## no critic (PostfixControls) my %pkg_licenses = (); my $path = "/usr/share/doc/${noarch_pkg}/copyright"; if (open(my $fh, '<', $path)) { my $firstpara = 1; my $machine_readable = 0; line: while (<$fh>) { if (m/^\s*$/) { $firstpara = 0; $machine_readable or last; next line; } if ($firstpara && m{^Format:\s+(\S+)\s*$}i) { my $url = $1; if ($url eq 'http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/') { $machine_readable = 1; next line; } else { $machine_readable = 0; last line; } } if (not $firstpara and m/^License:\s+(.+\S)\s*$/i) { my $license = $1; $pkg_licenses{$license} = 1; $machine_readable or die; } } close($fh) or die "$path: $ERRNO"; if (scalar keys %pkg_licenses == 1) { my ($license) = keys %pkg_licenses; # “AGPL” is not one the of standard short names, so in theory # one could use it for something else than FSF's GPL. # Hopefully nobody will ever do that… if ($license =~ /^([AL]?GPL)-([2-3])([.][0-9]+)?([+]?)$/) { my ($lname, $lmajor, $lminor, $lsuffix) = ($1, $2, $3, $4); $lminor //= ''; if ($lminor eq '.0') { $lminor = ''; } $license = "${lname}v${lmajor}${lminor}${lsuffix}"; } if (defined $license2id{$license}) { $licenses{$pkg} = $license; } } } elsif (not $ERRNO{ENOENT}) { die "$path: $ERRNO"; } } return %licenses; } sub is_inside_directories { my ($path, $dirs) = @_; my $realpath = Cwd::realpath($path) // die "resolving $path failed: $ERRNO"; my ($realdir) = $realpath =~ m{(.*)/[^/]+$}; if (defined $dirs->{$realdir}) { return $realpath; } else { return; } } sub augmented_path { my ($orig_path, $path, $interesting_dirs) = @_; if ($orig_path eq $path) { return $path; } my $realpath = Cwd::realpath($path) // die "resolving $path failed: $ERRNO"; my ($realdir) = $realpath =~ m{(.*)/[^/]+$}; # If the symlink target is still in an “interesting” directory, # then any issue hopefully will be reported against another # package. return if defined $interesting_dirs->{$realdir}; return "$orig_path => $realpath"; } sub check_elfs : Tags(qw(bin-or-sbin-binary-requires-usr-lib-library undefined-symbol symbol-size-mismatch missing-symbol-version-information library-not-found incompatible-licenses ldd-failure)) { my %map = @_; my @ld_vars = grep { /^LD_/ } keys %ENV; delete local @ENV{@ld_vars}; local $ENV{LC_ALL} = 'C'; my %interesting_dirs = ( '/bin' => 1, '/sbin' => 1, ); if ([keys %::visible_tags] ~~ ['bin-or-sbin-binary-requires-usr-lib-library']) { # /usr/* and ldconfig paths are not interesting in this case. } else { %interesting_dirs = (%interesting_dirs, '/usr/bin' => 1, '/usr/games' => 1, '/usr/sbin' => 1, ); flush_std_fh(); open(my $ldconfig, '-|', '/sbin/ldconfig', '-p') or die "ldconfig -p: $ERRNO"; while (<$ldconfig>) { if (m{\s[(]libc[^)]+[)]\s+=>\s+(\S+)[/][^/]+$}) { $interesting_dirs{$1} = 1; } } close($ldconfig) or die 'ldconfig -p: ' . ($ERRNO or 'failed'); } my %path2pkg = (); my %path_on_rootfs = (); while (my ($pkg, $files) = each %map) { file: for my $path (@{$files}) { my ($dir) = $path =~ m{(.*)/[^/]+$}; next file if $path =~ /\s/; next file if $path =~ m{^/lib\d*/.*(?<=/)ld(?:-.+)[.]so(?:$|[.])}; # dynamic linker defined $interesting_dirs{$dir} or next file; my $on_rootfs = $path =~ m{^/s?bin/\S+$}; -f -r $path or next file; if (-l $path) { my $realpath = Cwd::realpath($path) // die "resolving $path failed: $ERRNO"; my ($realdir) = $realpath =~ m{(.*)/[^/]+$}; # If the symlink target is still in an “interesting” directory, # then any issue hopefully will be reported against another # package. next file if defined $interesting_dirs{$realdir}; $on_rootfs &&= $realpath =~ m{^/s?bin/\S+$} } $path2pkg{$path} = $pkg; $path_on_rootfs{$path} = $on_rootfs; } } my %dep5_licenses = parse_copyright_files(keys %map); my @licenses; my %license_conflicts = (); for my $path (sort keys %path2pkg) { my $pkg = $path2pkg{$path}; my $on_rootfs = $path_on_rootfs{$path}; my $depends = {}; my $license = $dep5_licenses{$pkg}; my $license_id_product; if (defined $license) { $license_id_product = $license2id{$license}; @licenses = ([undef, $license]); } else { $license_id_product = -1; @licenses = (); } flush_std_fh(); my $ldd_pid = open(my $ldd, '-|') // die "can't fork: $ERRNO"; if ($ldd_pid) { # parent my $dynamic = 1; my $suspected_error = 0; foreach (<$ldd>) { when (m/^\s+not a dynamic executable$/) { $dynamic = 0; } when (m/^\s+statically linked$/) { # skip } when (m/^undefined symbol:\s+(\S+)(?:,\s+version\s+(\S+))?\s+[(](\S+)[)]$/) { my $symbol = $1; if (defined $2) { $symbol = "$symbol\@$2"; } my $triggering_path = $3; next if $path =~ m/python|py[23]/ and $symbol =~ /^_?Py/; next if $path =~ m/perl/ and $symbol =~ /^(?:Perl|PL)_/; next if $path =~ m{/liblua} and $symbol =~ /^luaL?_/; next if $path =~ m{/libthread_db-[0-9.]+[.]so$} and $symbol =~ /^ps_/; my $augmented_path = augmented_path($path, $triggering_path, \%interesting_dirs); defined $augmented_path or next; tag $pkg, 'undefined-symbol', $augmented_path, '=>', $symbol; } when (m/^symbol (\S+),? version (\S+) not defined in file (\S+) with link time reference\s+[(](\S+)[)]/) { my $symbol = "$1\@$2"; my $lib = $3; my $triggering_path = $4; my $augmented_path = augmented_path($path, $triggering_path, \%interesting_dirs); defined $augmented_path or next; tag $pkg, 'undefined-symbol', $augmented_path, '=>', $symbol, "($lib)"; } when (m/^(\S+): Symbol `(\S+)' has different size in shared object, consider re-linking$/) { next if $path ne $1; my $symbol = $2; tag $pkg, 'symbol-size-mismatch', $path, '=>', $symbol; } when (m/^(\S+): (\S+): no version information available [(]required by (\S+)[)]$/) { my $path = $1; ## no critic (ReusedNames) my $lib = $2; my $triggering_path = $3; my $augmented_path = augmented_path($path, $triggering_path, \%interesting_dirs); defined $augmented_path or next; tag $pkg, 'missing-symbol-version-information', $augmented_path, '=>', $lib; } when (m/^\t(\S+) => not found$/) { tag $pkg, 'library-not-found', $path, '=>', $1; } when (m{^\t(\S+) => (\S+) [(]0x[0-9a-f]+[)]$}) { my ($soname, $sopath) = ($1, $2); if ($on_rootfs and $sopath =~ m{^/usr/lib/}) { tag $pkg, 'bin-or-sbin-binary-requires-usr-lib-library', $path, '=>', $sopath; } my $realsopath = is_inside_directories($sopath, \%interesting_dirs); if (defined $realsopath) { $depends->{$realsopath} = 1; } my $license = $soname2license{$soname}; if (defined $license) { my $license_id = $license2id{$license} or die "unknown license $license"; my $new_license_id_product = $license_id_product & $license_id; if ($license_id_product != $new_license_id_product) { push @licenses, [$soname, $license]; $license_id_product = $new_license_id_product; if ($license_id_product == 0) { # Don't emit incompatible-licenses tag yet, because # the conflict might have been caused by one of the # dependencies. my @tagdata = ($pkg, $path, join(' + ', map { defined $_->[0] ? "$_->[1] ($_->[0])" : $_->[1] } @licenses) ); $license_conflicts{$path} = [$depends, @tagdata]; } } } } when (m/^\t(?:\S+)\s.*(?<=\s)[(]0x[0-9a-f]+[)]$/) { # skip } when (m/^ldd: /) { $suspected_error = 1; s/^ldd:\s+//; chomp; warning("ldd -r $path: $_"); } default { s/^\s+//; s/^\Q$path\E:\s+//; chomp; warning("ldd -r $path: $_"); } } wait or die "ldd -r: $ERRNO"; if ($CHILD_ERROR == 0) { # okay! } elsif (not $dynamic and not $suspected_error and $CHILD_ERROR == (1 << 8)) { # also okay! } else { tag $pkg, 'ldd-failure', $path; } close $ldd; ## no critic (CheckedSyscalls) } else { # child open(STDIN, '<', '/dev/null') or die "can't redirect stdin to /dev/null: $ERRNO"; open(STDERR, '>&STDOUT') or die "can't redirect stderr: $ERRNO"; switch_uid_gid($ldd_uid, $ldd_gid); exec('ldd', '-r', $path); die "can't exec ldd -r $path: $ERRNO"; } } my %dependency_licenses = (); for my $path (keys %license_conflicts) { for my $sopaths ($license_conflicts{$path}->[0]) { for my $sopath (keys %{$sopaths}) { $dependency_licenses{$sopath} = -1; } } } for my $path (sort keys %dependency_licenses) { my $license_id_product = -1; flush_std_fh(); my $ldd_pid = open(my $ldd, '-|') // die "can't fork: $ERRNO"; if ($ldd_pid) { # parent my $suspected_error = 0; foreach (<$ldd>) { when (m{^\t(\S+) => (\S+) [(]0x[0-9a-f]+[)]$}) { my ($soname, $sopath) = ($1, $2); my $license = $soname2license{$soname}; if (defined $license) { my $license_id = $license2id{$license} or die "unknown license $license"; $dependency_licenses{$path} &= $license_id; } } } wait or die "ldd: $ERRNO"; if ($CHILD_ERROR != 0) { die "ldd $path: failed"; } close $ldd; ## no critic (CheckedSyscalls) } else { # child open(STDIN, '<', '/dev/null') or die "can't redirect stdin: $ERRNO"; open(STDERR, '>&STDOUT') or die "can't redirect stderr: $ERRNO"; switch_uid_gid($ldd_uid, $ldd_gid); exec('ldd', $path); die "can't exec ldd $path: $ERRNO"; } } file: while (my ($path, $license_conflict) = each %license_conflicts) { my ($sopaths, $pkg, @tagdata) = @{$license_conflicts{$path}}; for my $sopath (keys %{$sopaths}) { next file if $dependency_licenses{$sopath} == 0; } tag $pkg, 'incompatible-licenses', @tagdata; } return; } sub check_paths : Tags(qw(program-name-collision)) { my %map = @_; my @dirs = qw(/usr/sbin /usr/bin /sbin /bin /usr/games); my %whitelist = ( # molly-guard: bugs #733213, #660064 '/usr/sbin/halt' => 'molly-guard', '/usr/sbin/poweroff' => 'molly-guard', '/usr/sbin/reboot' => 'molly-guard', '/usr/sbin/shutdown' => 'molly-guard', # safe-rm '/usr/bin/rm' => 'safe-rm', ); my @bash_builtins = qw< . [ alias bg bind break builtin caller case cd command compgen complete compopt continue coproc declare dirs disown echo enable eval exec exit export false fc fg for function getopts hash help history if jobs kill let local logout mapfile popd printf pushd pwd read readarray readonly return select set shift shopt source suspend test time times trap true type typeset ulimit umask unalias unset until variables wait while >; my %bash_builtins = map { $_ => 1 } @bash_builtins; my %bash_whitelist = map { $_ => 1 } qw( coreutils time procps ); while (my ($pkg, $files) = each %map) { my %files = map { $_ => 1 } @{$files}; for my $sfile (@{$files}) { for my $sdir (@dirs) { $sfile =~ qr{^$sdir/(.*)} or next; -f $sfile or next; my $suffix = $1; if (not exists $bash_whitelist{$pkg} and exists $bash_builtins{$suffix}) { tag $pkg, 'program-name-collision', $sfile, '(bash builtin command)'; } for my $ddir (@dirs) { my $dfile = "$ddir/$suffix"; -f $dfile or next; next if exists $files{$dfile}; next if exists $whitelist{$dfile}; next if ($whitelist{$sfile} // '') eq $pkg; my $real_sfile = Cwd::realpath($sfile) // die "resolving $sfile failed: $ERRNO"; my $real_dfile = Cwd::realpath($dfile) // die "resolving $dfile failed: $ERRNO"; next if $real_dfile eq $real_sfile; tag $pkg, 'program-name-collision', $sfile, $dfile; } last; } } } return; } sub check_alternatives : Tags(qw(missing-alternative)) { my ($package_map, $file_map) = @_; my %providers; my @vpkgs = qw(x-window-manager x-terminal-emulator); while (my ($pkg, $provides) = each %{$package_map}) { for my $vpkg (@vpkgs) { if ($provides->{$vpkg}) { push @{$providers{$vpkg}}, $pkg; } } } %providers or return; my %alternative_map = get_alternative_map(@vpkgs); while (my ($vpkg, $pkgs) = each %providers) { my @registered_paths = keys %{$alternative_map{$vpkg} // {}}; for my $pkg (@{$pkgs}) { my $files = $file_map->{$pkg}; my $found = 0; if (@registered_paths) { for my $file (@{$files}) { if ($file ~~ @registered_paths) { $found = 1; last; } } } if (not $found) { tag $pkg, 'missing-alternative', $vpkg; } } } return; } sub get_binfmt_map { local $ENV{LC_ALL} = 'C'; flush_std_fh(); my $update_binfmts = '/usr/sbin/update-binfmts'; -x $update_binfmts or return (); open(my $fh, '-|', $update_binfmts, '--display') or die "update-binfmts --display: $ERRNO"; my %map = (); my $name = undef; my $format = {}; while (<$fh>) { if (/^(\S+) .*:$/) { $name = $1; if (exists $map{$name}) { die 'unexpected output from update-binfmts --display'; } $map{$name}{NAME} = $name; next; } if (/^ +([a-z]+) = (.*)$/) { my ($key, $value) = ($1, $2); if (not defined $name or exists $map{$name}{$key}) { die 'unexpected output from update-binfmts --display'; } if ($value ne '') { $map{$name}{$key} = $value; } next; } die 'unexpected output from update-binfmts --display'; } close($fh) or die 'update-binfmts --display: ' . ($ERRNO or 'failed'); return %map; } sub check_binfmts : Tags(qw(broken-binfmt-detector broken-binfmt-interpreter)) { my @packages = @_; my %packages = map ## no critic (ComplexMappings, MutatingList) { s/:.*// for my $pkg = $_; $pkg => 1 } ## no critic (PostfixControls) @packages; my %formats = get_binfmt_map(); for my $fmt (sort { $a->{NAME} cmp $b->{NAME} } values %formats) { my $name = $fmt->{NAME}; my $interpreter = $fmt->{interpreter}; my $pkg = $fmt->{package}; defined $name or next; defined $interpreter or next; exists $packages{$pkg} or next; local $ERRNO = 0; if (stat($interpreter) and -x _) { # okay } else { my @errno = (); if ($ERRNO) { push @errno, "($ERRNO)"; } tag $pkg, 'broken-binfmt-interpreter', $name, '=>', $interpreter, @errno; } my $detector = $fmt->{detector}; defined $detector or next; local $ERRNO = 0; if (stat($detector) and -x _) { # okay } else { my @errno = (); if ($ERRNO) { push @errno, "($ERRNO)"; } tag $pkg, 'broken-binfmt-detector', $name, '=>', $detector, @errno; } } return; } sub check_pkgconfig : Tags(qw(missing-pkgconfig-dependency)) { my %file_map = @_; my %pkg_map = (); -x '/usr/bin/pkg-config' or return; while (my ($debpkg, $files) = each %file_map) { for my $file (@{$files}) { $file =~ m{^/usr/(?:share|lib(?:/[^/]+)?)/pkgconfig/([^/]+)[.]pc$} or next; my $pkg = $1; $pkg_map{$pkg} = $debpkg; } } while (my ($pkg, $debpkg) = each %pkg_map) { local $ENV{LC_ALL} = 'C'; flush_std_fh(); my $pkgconfig_pid = open(my $pkgconfig, '-|') // die "can't fork: $ERRNO"; if ($pkgconfig_pid) { # parent while (<$pkgconfig>) { if (m/^Package '(.+)', required by '\Q$pkg\E', not found$/) { my $deppkg = $1; tag $debpkg, 'missing-pkgconfig-dependency', $pkg, '=>', $deppkg; } } wait or die "pkg-config --exists: $ERRNO"; close $pkgconfig; ## no critic (CheckedSyscalls) } else { # child open(STDERR, '>&STDOUT') or die "can't redirect stderr: $ERRNO"; exec('pkg-config', '--exists', '--print-errors', $pkg); die "can't exec pkg-config: $ERRNO"; } } return; } sub switch_uid_gid { my ($uid, $gid) = @_; defined $uid or return; defined $gid or return; # If the child process had a controlling terminal, the user we switch to # could take over the process with ptrace(2), and then hijack the terminal # using TIOCSTI. setsid() or die; # Similarly, if the child process inherited an fd of an open terminal, the # user could do nefarious things with the terminal. die if -t STDIN; die if -t STDOUT; die if -t STDERR; # (There might be other fds open at this point, but Perl conveniently # closes them for us on exec.) ## no critic (LocalizedPunctuationVars) $ERRNO = 0; $GID = $gid; die "setting real gid to $gid: $ERRNO" if $ERRNO; $EGID = "$gid $gid"; die "setting effective gid to $gid: $ERRNO" if $ERRNO; $UID = $uid; die "setting real uid to $uid: $ERRNO" if $ERRNO; $EUID = $uid; die "setting effective uid to $uid: $ERRNO" if $ERRNO; ## use critic die if $UID != $uid; die if $EUID != $uid; die if $GID ne "$gid $gid"; die if $EGID ne "$gid $gid"; delete $ENV{HOME}; return; } sub display_help { print <<'EOF' usage: adequate [options] ... adequate [options] --all adequate [options] --apt-preinst adequate [options] --pending adequate --help options: --all check all installed packages --tags [,...] emit only these tags --tags -[,...] don't emit these tags --debconf report issues via debconf --root switch root directory --user [:] switch user and group --apt-preinst (used internally by the APT hook) --pending (used internally by the APT hook) --help display this help and exit EOF or die $ERRNO; exit(0); } sub display_version { my $version; if (not $VERSION) { s{[^/]*$}{} for my $dir = $PROGRAM_NAME; ## no critic (PostfixControls) open (my $fp, '<', "$dir/debian/changelog") or die $ERRNO; $_ = <$fp>; ($version) = m/^\w+ [(]([^)]+)[)]/; close($fp) or die $ERRNO; } else { $version = $VERSION; } say "adequate $version" or die $ERRNO; exit(0) } sub error { say {*STDERR} "adequate: error: @_" or die $ERRNO; exit(1); } sub warning { say {*STDERR} "adequate: @_" or die $ERRNO; return; } sub info { if (0) { # disabled for the moment say {*STDERR} "adequate: @_" or die $ERRNO; } return; } my @ARGV_copy = @ARGV; sub enable_debconf { $use_debconf = 1; if (not exists $ENV{DEBIAN_HAS_FRONTEND}) { @ARGV = @ARGV_copy; ## no critic (LocalizedPunctuationVars) # import will re-exec this program } require Debconf::Client::ConfModule; Debconf::Client::ConfModule::import(); return; } umask 022; my $opt_all = 0; my $opt_tags = undef; my $opt_debconf = 0; my $opt_root = undef; my $opt_user = undef; my $opt_apt_preinst = 0; my $opt_pending = 0; my $rc = GetOptions( 'all' => \$opt_all, 'tags=s' => \$opt_tags, 'debconf' => \$opt_debconf, 'root=s' => \$opt_root, 'user=s' => \$opt_user, 'apt-preinst' => \$opt_apt_preinst, 'pending' => \$opt_pending, 'help' => \&display_help, 'version' => \&display_version, ); if (not $rc) { exit(1); } %::visible_tags = %::known_tags; if (defined $opt_tags) { my $negative; if ($opt_tags =~ s/^-//) { $negative = 1; } else { $negative = 0; %::visible_tags = (); } my @tags = split(m/,/, $opt_tags); for my $tag (@tags) { if (not $::known_tags{$tag}) { error("unknown tag $tag"); } if ($negative) { delete $::visible_tags{$tag}; } else { $::visible_tags{$tag} = 1; } } } if ($opt_debconf) { enable_debconf(); } if (defined $opt_user) { my ($user, $group) = $opt_user =~ m/^([^\s:]++)(?::(\S+))?$/ or error('invalid user/group specification'); if ($user =~ m/^\d+$/) { (undef, undef, $ldd_uid, $ldd_gid) = getpwuid($user) or error("$user: no such user"); } else { (undef, undef, $ldd_uid, $ldd_gid) = getpwnam($user) or error("$user: no such user"); } if (defined $group) { if ($group =~ m/^\d+$/) { (undef, undef, $ldd_gid) = getgrgid($group) or error("$group: no such group"); } else { (undef, undef, $ldd_gid) = getgrnam($group) or error("$group: no such group"); } } } if ($opt_apt_preinst) { error('--apt-preinst and --pending cannot be used together') if $opt_pending; error('--apt-preinst and --all cannot be used together') if $opt_all; error('--apt-preinst and --root cannot be used together') if defined $opt_root; error('too many arguments') if @ARGV; read_pending(); do_apt_preinst(); } elsif ($opt_pending) { error('--pending and --all cannot be used together') if $opt_all; error('--pending and --root cannot be used together') if defined $opt_root; error('too many arguments') if (@ARGV); read_pending(); do_pending(); } else { error('too many arguments') if ($opt_all and @ARGV); error('no packages to check') if (not $opt_all and not @ARGV); if (defined $opt_root) { chroot($opt_root) or die "chroot $opt_root: $ERRNO"; chdir('/') or die "chdir /: $ERRNO"; } process(0, @ARGV); } exit(0); END { # Catch late write errors: local $ERRNO = 0; close(STDOUT) or die $ERRNO; close(STDERR) or die $ERRNO; } # vim:ts=4 sts=4 sw=4 et adequate-0.15.1ubuntu5/apt.conf.d/0000755000000000000000000000000012322316340013533 5ustar adequate-0.15.1ubuntu5/apt.conf.d/20adequate0000644000000000000000000000064412266266100015422 0ustar // If you set this to "true", adequate will run on every install, reporting the // results via debconf. Adequate::Enabled "false"; DPkg::Pre-Install-Pkgs { "adequate --help >/dev/null 2>&1 || exit 0; exec adequate --user nobody --apt-preinst"; }; DPkg::Post-Invoke { "adequate --help >/dev/null 2>&1 || exit 0; exec adequate --debconf --user nobody --pending"; }; DPkg::Tools::Options::adequate::Version "2"; adequate-0.15.1ubuntu5/debian/0000755000000000000000000000000013256653441013040 5ustar adequate-0.15.1ubuntu5/debian/NEWS0000644000000000000000000000034312266266100013527 0ustar adequate (0.3.1) experimental; urgency=low The APT hook is now disabled by default. To re-enable it, please edit the /etc/apt/apt.conf.d/20adequate file. -- Jakub Wilk Tue, 22 Jan 2013 23:30:21 +0100 adequate-0.15.1ubuntu5/debian/README.source0000644000000000000000000000034112266266100015205 0ustar If you fork adequate (NMU, backport, derivative-specific change, etc.), please consider changing the source format to “3.0 (quilt)”. Thanks in advance! -- Jakub Wilk Sun, 03 Feb 2013 23:00:48 +0100 adequate-0.15.1ubuntu5/debian/changelog0000644000000000000000000004725013256653441014722 0ustar adequate (0.15.1ubuntu5) bionic; urgency=medium * Fix regular expression for undefined symbol output from ldd (lost a comma). -- Julian Andres Klode Wed, 28 Mar 2018 10:49:37 +0200 adequate (0.15.1ubuntu4) artful; urgency=medium * Don't run the test for an undefined symbol in an executable. Always failed on ppc64el, and now fails on amd64 and i386 as well with updated binutils. See PR ld/22126. -- Matthias Klose Tue, 12 Sep 2017 18:50:31 +0200 adequate (0.15.1ubuntu3) artful; urgency=medium * debian/tests/run-test: Skip over non-deb members in changes files. -- Adam Conrad Sat, 22 Apr 2017 00:51:26 -0600 adequate (0.15.1ubuntu2) zesty; urgency=medium * Add libreadline7 -- Iain Lane Mon, 31 Oct 2016 17:45:07 +0000 adequate (0.15.1ubuntu1) yakkety; urgency=medium * Compile symbol-size-mismatch test package with -fno-PIE to trigger symbol size missmatch warning. LP: #1619377 -- Dimitri John Ledkov Thu, 01 Sep 2016 17:41:27 +0100 adequate (0.15.1) unstable; urgency=low * Fix false positive program-name-collision in less. * Use date of last modification in the manual page footer. This should help to make the package builds reproducible. * Fix typo in a tag description. * Add license information for libpoppler.so.57. -- Jakub Wilk Tue, 12 Jan 2016 15:34:17 +0100 adequate (0.15) unstable; urgency=low * Add license information for the Ghostscript library (closes: #795566). Thanks to Didier Raboud for the bug report. * Add license information for the jbig2dec library. * Recognize AGPL-3 in machine-readable copyright files. * Add license information for libpoppler.so.46 and libpoppler.so.47. -- Jakub Wilk Wed, 26 Aug 2015 11:07:21 +0200 adequate (0.14) unstable; urgency=low * Summary of tag changes: + Added: - ldd-failure * Run ldd on each file separately. * Don't abort when “ldd -r” fails, but emit ldd-failure instead (closes: #762615). -- Jakub Wilk Wed, 15 Jul 2015 15:59:36 +0200 adequate (0.13.3) unstable; urgency=low * Require pkg-config 0.27 or later in the test suite. In older versions, --exists didn't check dependencies. * Add pkg-config to Recommends (closes: #787169). Thanks to Micah Gersten for the bug report. * Exclude VCS-specific files from the source package in debian/source/options. -- Jakub Wilk Sun, 31 May 2015 18:37:54 +0200 adequate (0.13.2) unstable; urgency=low * Drop “XS-Testsuite: autopkgtest”. * Add pkg-config to the DEP-8 test Depends (closes: #787043). Thanks to Micah Gersten for the bug report. -- Jakub Wilk Thu, 28 May 2015 10:42:14 +0200 adequate (0.13.1) unstable; urgency=low * Update the package description. * Don't emit program-name-collision when one programs symlinks to the other. * Bump standards version to 3.9.6 (no changes needed). -- Jakub Wilk Sun, 10 May 2015 20:15:51 +0200 adequate (0.13) unstable; urgency=low * Summary of tag changes: + Added: - missing-pkgconfig-dependency * Check for missing pkg-config dependencies (closes: #781037). Thanks to Niels Thykier for the bug report. * Fix false positive program-name-collision in debianutils (closes: #784068). * Improve error handling. -- Jakub Wilk Mon, 27 Apr 2015 19:17:57 +0200 adequate (0.12.1) unstable; urgency=medium * Fix “keys/push on reference is experimental” warnings (closes: #758306). Thanks to Axel Beckert for the bug report. -- Jakub Wilk Sat, 16 Aug 2014 19:07:55 +0200 adequate (0.12) unstable; urgency=low * Exclude /usr/lib/pythonX.Y/lib2to3/tests/data/ and /usr/lib/pythonX.Y/test/bad* from byte-compilation checks. * Check for collisions between executables and bash builtin commands. * Use HTTPS URLs when they are available, in documentation and code. * Simplify error handling. * Test suite: fix compatibility with dpkg (>= 1.17.7). -- Jakub Wilk Mon, 07 Jul 2014 22:41:34 +0200 adequate (0.11.6) unstable; urgency=medium * Fix a typo in the --help message. * Improve the test suite: + Don't use APT for package installation, but manually call dpkg. This greatly reduces memory usage and improves speed. + If a package installation failed, don't try to upgrade newer versions of the same package. + Improve error handling. * Fix license information for libgmp. -- Jakub Wilk Sun, 20 Apr 2014 20:06:53 +0200 adequate (0.11.5) unstable; urgency=low * DEP-8 tests: add a smoke test, which can be run without any restrictions. * Use the smoke test also at build time. * Add license information for libpoppler.so.44. * Update year range in the copyright file. -- Jakub Wilk Mon, 03 Mar 2014 13:44:14 +0100 adequate (0.11.4) unstable; urgency=low * Use dh-buildinfo. * Add the --version option. Thanks to Holger Levsen for the bug report. -- Jakub Wilk Sat, 25 Jan 2014 23:19:34 +0100 adequate (0.11.3) unstable; urgency=medium * Brown paper bag release. * Fix false positive missing-alternative when there is more than one provider of the tested virtual package. Thanks to James McCoy for the bug report and the initial patch. * Add license information for libpoppler.so.43 (seen in Ubuntu). * Force gzip for tarball compression. * Bump minimum required version of Perl to 5.14. Perl 5.14 features have been used since adequate 0.10. -- Jakub Wilk Fri, 17 Jan 2014 19:15:40 +0100 adequate (0.11.2) unstable; urgency=low * Fix license information for GnuTLS. -- Jakub Wilk Sun, 12 Jan 2014 18:51:27 +0100 adequate (0.11.1) unstable; urgency=low * Brown paper bag release. * Fix false positive broken-binfmt-interpreter. * Tidy up the code. Thanks, perlcritic. -- Jakub Wilk Fri, 10 Jan 2014 15:31:08 +0100 adequate (0.11) unstable; urgency=low * Summary of tag changes: + Added: - broken-binfmt-detector - broken-binfmt-interpreter * Check for broken binfmt interpreters and detectors. * Update the package description. * Fix a typo in the manual page (closes: #734692). Thanks to Shirish Agarwal for the bug report. -- Jakub Wilk Thu, 09 Jan 2014 23:41:45 +0100 adequate (0.10) unstable; urgency=low * Don't strip architecture qualifiers when reporting missing copyright files in “Multi-Arch: same” packages. * Extract license information from machine-readable copyright files. * Don't complain about scripts in /usr/lib/pythonX.Y/config-*/ not being byte-compiled. * Don't complain about program name collisions between molly-guard and sysvinit(-core). Thanks to Thorsten Glaser for the bug report. * Don't complain about program name collision between safe-rm and coreutils. * Tidy up the code. Thanks, perlcritic. -- Jakub Wilk Fri, 27 Dec 2013 17:48:30 +0100 adequate (0.9.1) unstable; urgency=low * Update the package description. * Improve the test suite: + Fix Architecture fields of test packages. + Don't hardcode the i386 architecture (closes: #732448). Thanks to Martin Pitt for the bug report and the initial patch. + Fix DEP-8 test dependencies. + Fix test failures with ld that defaults to --as-needed. Thanks to Martin Pitt for the bug report and the patch. -- Jakub Wilk Wed, 18 Dec 2013 09:25:29 +0100 adequate (0.9) unstable; urgency=low * Summary of tag changes: + Added: - program-name-collision - missing-alternative * Add license information for libgmp.so.10 and libltdl.so.7. * Check for program name collisions. * Check if providers of x-terminal-emulator and x-window-manager register required alternatives. * Test runner: don't expect deterministic order of emitted tags. * Improve error handling. * Tidy up the code. Thanks, perlcritic. -- Jakub Wilk Mon, 16 Dec 2013 14:16:11 +0100 adequate (0.8.2) unstable; urgency=low * Improve the manual page: + Fix hyphens used as minus signs. + Add examples (closes: #726152) Thanks to Shirish Agarwal for the bug report. * Don't complain about files in /usr/share/paster_templates/ not being byte-compiled. * Fix reporting incompatible-licenses, and other ELF-related tags, against wrong package (closes: #729031). * Fix incorrect implementation of --tags for ELF-related tags. -- Jakub Wilk Thu, 05 Dec 2013 10:04:22 +0100 adequate (0.8.1) unstable; urgency=medium * Fix possible privilege escalation via tty hijacking (CVE-2013-6409, closes: #730691). + Switch users only when running ldd. + Run ldd with stdin redirected to /dev/null, and without controlling terminal when run with reduced privileges. * Bump standards version to 3.9.5 (no changes needed). -- Jakub Wilk Thu, 28 Nov 2013 11:27:21 +0100 adequate (0.8) unstable; urgency=low * Summary of tag changes: + Added: - missing-symbol-version-information - symbol-size-mismatch * When printing warnings from ldd, avoid outputting binary name twice. * Check for symbol size mismatches. * Check for missing version information. * Report symbol issues with libraries in private directories (when they can be triggered by running ldd against binaries or libraries in public directories). * Add license information for libpoppler.so.37. * Don't complain about missing lua_* and luaL_* symbols in liblua* libraries. * Add “Summary of tag changes” sections to old changelog entries. -- Jakub Wilk Mon, 16 Sep 2013 13:27:06 +0200 adequate (0.7.1) unstable; urgency=low * When checking ELFs, skip unresolvable symlinks (closes: #709484, #716988). Thanks to Laurent Bonnaud and Peter Karbaliotis for the bug reports. -- Jakub Wilk Tue, 16 Jul 2013 15:37:13 +0200 adequate (0.7) unstable; urgency=low * Summary of tag changes: + Added: - incompatible-licenses * Check if Python modules in /usr/lib/pypy/ are byte-compiled (closes: #710021). * Check for binaries linked to libraries with incompatible licenses. Currently only licenses of the following libraries are recognized: OpenSSL, GnuTLS, Poppler, and GNU Readline. * Remove a duplicate label. Thanks to Niels Thykier for the bug report. * Silence “skipping because it's not installed” warnings (closes: #712446). Thanks to Paul Wise for the bug report. * Add a section about reporting bugs to the manual page. * Update the package description. * Add “XS-Testsuite: autopkgtest”. -- Jakub Wilk Tue, 25 Jun 2013 00:25:26 +0200 adequate (0.6) unstable; urgency=low * Improve error handling when resolving symlinks (see bug #709484). * Improve error handling when accessing /var/lib/adequate/pending. * Add the --tags option (closes: #709372). * Assume that executable .py files in private directories that start with shebangs are scripts, rather than Python modules, and therefore don't require bytecompilation (closes: #709192). * Disable warnings about use of smartmatch (closes: #710063). * Add a minimal build-time test that verifies that adequate runs successfully and without warnings on a simple package (coreutils). + Add “perl (>= 5.12)” to Build-Depends. * Unset all LD_* environment variables when running ldd. -- Jakub Wilk Wed, 29 May 2013 22:25:59 +0200 adequate (0.5.3) unstable; urgency=low * Make the obsolete conffile check work with pre-multi-arch dpkg. * Don't consider a conffile obsolete if dpkg-query lists it as non-obsolete and belonging to a different package (closes: #708588). This is a work-around for dpkg bug #645849. * Don't complain about /usr/lib/pythonX.Y/__phello__.foo.py not being byte-compiled. * Don't complain about .py files in /usr/share/apport/package-hooks/ not being byte-compiled (closes: #709187). -- Jakub Wilk Tue, 21 May 2013 21:10:41 +0200 adequate (0.5.2) unstable; urgency=low * Don't use dh_testdir; instead, use makefile rules to ensure that debian/rules can be only run in the correct directory. * Whitelist ps_* symbols in libthread_db-*.so libraries when checking for undefined symbols. * Improve diagnostics when ldd fails (closes: #706915). Thanks to Paul Wise for the bug report. * Find more undefined versioned symbols. * Make --pending ignore dpkg-query exit code (closes: #707080). This is needed because packages listed in /var/lib/adequate/pending might have been removed in the mean time. Thanks to Paul Wise for the bug report. * Don't complain about missing .pyc in /usr/lib/python2.X/dist-packages/ if 2.X is not a supported Python version (closes: #707614). * Don't complain about missing .pyc in /usr/lib/python3/dist-packages/ if no supported Python 3 version is installed. * Clean tests/ subdirectory in the clean target. -- Jakub Wilk Fri, 10 May 2013 12:39:39 +0200 adequate (0.5.1) unstable; urgency=low * Update the package description. * Disable the unicode_strings Perl feature. * Improve the manual page: + Call “Debian Python Policy” simply “Python Policy”. + Add links to Debian Policy and Python Policy. Thanks to Shirish Agarwal for the bug report. * Handle diversions correctly (closes: #706107). Thanks to Ben Hutchings for the bug report. * Fix Restrictions field in debian/tests/control. (The items should be space-separated, rather than comma-separated.) -- Jakub Wilk Wed, 24 Apr 2013 21:57:35 +0200 adequate (0.5) unstable; urgency=low * Summary of tag changes: + Added: - library-not-found * When looking for /(s)bin binaries, don't skip symlinks that point outside /(s)bin. * When looking for public executables and shared libraries, don't skip symlinks that point to directories that wouldn't normally be checked. * Check for binaries linked to libraries that cannot be found. * Change Debconf prompt priority to critical. -- Jakub Wilk Thu, 04 Apr 2013 22:09:12 +0200 adequate (0.4.4) unstable; urgency=low * Make sure that the APT hook won't fail when the package is removed but not purged (closes: #702904). Thanks to Andreas Beckmann for the bug report. -- Jakub Wilk Thu, 14 Mar 2013 17:50:28 +0100 adequate (0.4.3) unstable; urgency=low * Upload to unstable. -- Jakub Wilk Mon, 11 Mar 2013 22:30:21 +0100 adequate (0.4.2) experimental; urgency=low * Skip packages that are not fully installed (closes: #701995). Thanks to Axel Beckert for the bug report. * Refactor code responsible for printing errors and warnings. -- Jakub Wilk Sat, 02 Mar 2013 10:59:42 +0100 adequate (0.4.1) experimental; urgency=low * Update the package description. * Add description to the manual page. * Document --apt-preinst and --pending in more details. * Add a test suite. + Add DEP-8 test script. * Add README.source asking to change source format when forking. * Improve the pyshared-file-not-bytecompiled tag description. * Fix Python byte-compilation checks for Python < 2.6. * Fix Python byte-compilation checks for python-support < 0.90. * Improve error handling. -- Jakub Wilk Thu, 21 Feb 2013 13:41:14 +0100 adequate (0.4) experimental; urgency=low * Detect missing versioned symbols, too. * Avoid running ldd against the following files: - files that are known not to be readable; - dynamic linkers; - files with whitespace in their names. * Filter package names through dpkg-query. This adds or removes architecture suffixes, as needed. * Reduce number of ldd(1) calls to at most two. * Add option for chroot(2)ing into another directory: --root. * Add option for switching user and group: --user. * Make the APT hook run as user ‘nobody’. * Make the package more portable: + Stop requiring multi-arch-aware dpkg. Drop versioned runtime dependency on dpkg. + Stop using IPC::Run. Drop libipc-run-perl recommendation. + Load debconf modules lazily. * Improve options parsing. Exit with error for incompatible combinations of options (e.g. both --pending and --all). * Make --help more verbose. * Improve the documentation: + Work around bug #280148 in pod2man: manual page references should be rendered in bold, not in italics. + Add a to-do list. + Rewrite the undefined-symbol tag description. + Don't repeat “Debian Policy” if a tag refers multiple policy sections. + Document the --help option. * Replace “underlinked libraries” with “undefined symbols” in the package description. The latter is what adequate actually detects, while the former might or might not be the root cause of the observed problem. * Make generating the POD file atomic. -- Jakub Wilk Wed, 30 Jan 2013 23:46:24 +0100 adequate (0.3.1) experimental; urgency=low * Initial upload to Debian (closes: #698656). * Update years in debian/copyright. * Disable the APT hook. (It can be re-enabled by editing /etc/apt/apt.conf.d/20adequate). * Improve error handling. * Improve the documentation. * Rebuild the documentation from source. * Add Vcs-* and Homepage fields. -- Jakub Wilk Tue, 22 Jan 2013 23:30:21 +0100 adequate (0.3) unstable; urgency=low * Summary of tag changes: + Added: - undefined-symbol * Improve the documentation. * Remove some no-op code. * Check for undefined symbols. * Add libipc-run-perl to Recommends (needed for the new check). * Update the package description. * Bump standards version to 3.9.4 (no changes needed). -- Jakub Wilk Mon, 21 Jan 2013 20:25:37 +0100 adequate (0.2.1) unstable; urgency=low * Don't expect third-party Python 2.X modules to be byte-compiled if the corresponding Python version is not installed. * Print symlink target when reporting broken symlink. * Provide a manual page. -- Jakub Wilk Fri, 14 Sep 2012 17:32:13 +0200 adequate (0.2) unstable; urgency=low * Summary of tag changes: + Added: - bin-or-sbin-binary-requires-usr-lib-library * Don't complain about .py files in /usr/lib/debug/usr/bin/ etc. * Don't complain about .py files in /usr/games/. * Check for /bin and /sbin binaries requiring /usr/lib libraries. * Reduce number of dpkg -L calls to one. -- Jakub Wilk Mon, 03 Sep 2012 20:27:04 +0200 adequate (0.1.1) unstable; urgency=low * Summary of tag changes: + Added: - pyshared-file-not-bytecompiled * Don't store ambiguous package names (for Multi-Arch: same packages) in /var/lib/adequate/pending. * Don't complain about .py files in /etc that are not byte-compiled. * Don't complain about .py files within standard libraries of alternative Python interpreters (jython, pypy) that are not byte-compiled. * Check byte-compilation of files in /usr/share/pyshared/ and /usr/share/python-support/. * Fix emitting messages longer than 2 lines via debconf. * Don't put colon between tag name and extra information. -- Jakub Wilk Sat, 11 Aug 2012 18:51:40 +0200 adequate (0.1) unstable; urgency=low * Initial release. * Summary of tag changes: + Added: - broken-symlink - missing-copyright-file - obsolete-conffile - py-file-not-bytecompiled -- Jakub Wilk Thu, 02 Aug 2012 21:19:14 +0200 adequate-0.15.1ubuntu5/debian/compat0000644000000000000000000000000212006551124014221 0ustar 7 adequate-0.15.1ubuntu5/debian/control0000644000000000000000000000221312762055166014442 0ustar Source: adequate Section: utils Priority: optional Maintainer: Ubuntu Developers XSBC-Original-Maintainer: Jakub Wilk Build-Depends: debhelper (>= 7), dh-buildinfo, perl (>= 5.14), python3 (>= 3.2), python3-apt Standards-Version: 3.9.6 Vcs-Hg: https://bitbucket.org/jwilk/adequate Vcs-Browser: https://bitbucket.org/jwilk/adequate Homepage: http://jwilk.net/software/adequate Package: adequate Architecture: all Depends: ${misc:Depends}, ${perl:Depends}, perl (>= 5.14), debconf Recommends: pkg-config (>= 0.27) Description: Debian package quality testing tool adequate checks packages installed on the system and reports bugs and policy violations. . The following checks are currently implemented: * broken symlinks; * missing copyright file; * obsolete conffiles; * Python modules not byte-compiled; * /bin and /sbin binaries requiring /usr/lib libraries; * missing libraries, undefined symbols, symbol size mismatches; * license conflicts; * program name collisions; * missing alternatives; * missing binfmt interpreters and detectors; * missing pkg-config dependencies. adequate-0.15.1ubuntu5/debian/copyright0000644000000000000000000000226112610025352014757 0ustar Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Files: * Copyright: 2012-2015 Jakub Wilk License: Expat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: . The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. . THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. adequate-0.15.1ubuntu5/debian/dirs0000644000000000000000000000002312006551124013702 0ustar /var/lib/adequate/ adequate-0.15.1ubuntu5/debian/install0000644000000000000000000000010612006551124014411 0ustar adequate /usr/bin/ apt.conf.d /etc/apt/ templates /usr/share/debconf/ adequate-0.15.1ubuntu5/debian/prerm0000644000000000000000000000015512610025352014074 0ustar #!/bin/sh set -e #DEBHELPER# [ $1 = upgrade ] || rm -f /var/lib/adequate/pending # vim:ts=4 sts=4 sw=4 et adequate-0.15.1ubuntu5/debian/rules0000755000000000000000000000163212627105764014123 0ustar #!/usr/bin/make -f version = $(word 2,$(shell dpkg-parsechangelog | grep ^Version:)) .PHONY: clean clean: doc/Makefile tests/Makefile $(MAKE) -C doc/ clean $(MAKE) -C tests/ clean dh_clean debian/build-stamp .PHONY: build build-arch build-indep build: build-indep build-indep: debian/build-stamp debian/build-stamp: doc/Makefile adequate $(MAKE) -B -C doc/ ifeq "$(filter nocheck,$(DEB_BUILD_OPTIONS))" "" adt_adequate=./adequate adt_testpkg=coreutils debian/tests/smoke-test endif touch $(@) .PHONY: binary binary-arch binary-indep binary: binary-indep binary-indep: build-indep dh_testroot dh_prep dh_installdirs dh_install sed -i \ -r -e 's/^(our \$$VERSION) =.*/\1 = "$(version)";/' \ debian/*/usr/bin/* dh_installman doc/*.1 dh_perl dh_installdocs dh_installchangelogs dh_buildinfo dh_compress dh_fixperms dh_installdeb dh_gencontrol dh_md5sums dh_builddeb # vim:ts=4 sts=4 sw=4 noet adequate-0.15.1ubuntu5/debian/source/0000755000000000000000000000000012610025352014323 5ustar adequate-0.15.1ubuntu5/debian/source/format0000644000000000000000000000001512564170337015546 0ustar 3.0 (native) adequate-0.15.1ubuntu5/debian/source/options0000644000000000000000000000012112610025352015733 0ustar compression = gzip tar-ignore = .git* tar-ignore = .hg* tar-ignore = .travis.yml adequate-0.15.1ubuntu5/debian/tests/0000755000000000000000000000000012626613526014202 5ustar adequate-0.15.1ubuntu5/debian/tests/control0000644000000000000000000000034712610025352015574 0ustar Tests: smoke-test Depends: adequate Tests: full-test Depends: adequate, build-essential, debhelper, python3 (>= 3.2), python3-apt, python (>= 2.7), python (<< 2.8), pkg-config (>= 0.27) Restrictions: breaks-testbed needs-root adequate-0.15.1ubuntu5/debian/tests/full-test0000755000000000000000000000030712610025352016032 0ustar #!/bin/sh set -e -u if [ "$(id -u)" != 0 ] then printf '%s: you must run this as root.\n' "$0" >&2 exit 1 fi cp -a tests/* "$ADTTMP" cd "$ADTTMP" make 2>&1 make run # vim:ts=4 sts=4 sw=4 et adequate-0.15.1ubuntu5/debian/tests/smoke-test0000755000000000000000000000104612334145771016222 0ustar #!/bin/sh set -e -u : ${adt_adequate:=adequate} : ${adt_testpkg:=adequate} # ---------------------------------------------------------------------- echo TESTING: $adt_adequate --help $adt_adequate --help # ---------------------------------------------------------------------- echo TESTING: $adt_adequate --version $adt_adequate --version 2>&1 | ( ! grep -vE '^adequate [0-9a-z.+-:~]+$' ) # ---------------------------------------------------------------------- echo TESTING: $adt_adequate $adt_testpkg $adt_adequate $adt_testpkg 2>&1 | ( ! grep . ) adequate-0.15.1ubuntu5/doc/0000755000000000000000000000000013156010117012345 5ustar adequate-0.15.1ubuntu5/doc/Makefile0000644000000000000000000000073712621437336014030 0ustar version = $(word 2,$(shell cd .. && dpkg-parsechangelog | grep ^Version:)) .PHONY: all all: adequate.1 tags.desc: ../adequate ../private/update-tags adequate.pod: adequate.podt tags.desc ../adequate ../private/generate-manpage > $(@).tmp mv $(@).tmp $(@) %.1: %.pod date=$(shell sed -n -e "/^pod-date:/s///p" $(<)) && \ pod2man --utf8 -c '' -d $$date -q none -r "$(*) $(version)" $(<) $(@) .PHONY: clean clean: rm -f adequate.pod *.1 *.tmp # vim:ts=4 sts=4 sw=4 noet adequate-0.15.1ubuntu5/doc/adequate.podt0000644000000000000000000000503212621427675015047 0ustar =encoding UTF-8 =head1 NAME adequate - Debian package quality testing tool =head1 SYNOPSIS =over 1 =item B [I] I... =item B [I] --all =item B [I] --apt-preinst =item B [I] --pending =item B --help =back =head1 DESCRIPTION B checks packages installed on the system and reports bugs and policy violations. =head1 OPTIONS =over 4 =item B<--all> Run checks against all the installed packages. =item B<--tags> I[,I...] Emit only these tags. =item B<--tags> -I[,I...] Don't emit these tags. =item B<--debconf> Report issues via L. =item B<--root> I Change the root directory (using L). =item B<--user> I[:I] Switch user and group before running any checks. This is most useful together with B<--root> or B<--pending>, which require superuser privileges. =item B<--apt-preinst> Read APT configuration and F<.deb> filenames from stdin, and append packages names to F for later processing (see B<--pending>). This option is used internally by the APT hook. The hook is disabled by default; please edit F to enable it. =item B<--pending> Run checks against packages listed in F, then empty the file. =item B<--help> Display help and exit. =back =head1 TAGS =head1 EXAMPLES =over 4 =item B> Check the B package. =item B> Check all the packages for obsolete conffiles. =item B> Check all the packages, ignoring Python bytecompilation issues. =back =head1 REPORTING BUGS If you report a bug that was found by adequate, please use the following usertags: =over 4 =item Z<> =over =item User: debian-qa@lists.debian.org =item Usertags: adequate I =back =back Please keep in mind that adequate is not perfect; therefore false positives are possible. Don't report the bug unless you understand the underlying problem. When in doubt, please ask at I first. =head1 SEE ALSO Debian Policy: F or L Python Policy: F or L L, L =for comment pod-date:2015-07-15 vim:ft=pod adequate-0.15.1ubuntu5/doc/tags.desc0000644000000000000000000000635513155760145014170 0ustar Tag: bin-or-sbin-binary-requires-usr-lib-library Description: This package ships a binary in /bin or /sbin that requires a library in /usr/lib. This will make impossible to use this binary before /usr is mounted. Tag: broken-binfmt-detector Description: The detector registered with update-binfmts(8) does not exist. Tag: broken-binfmt-interpreter Description: The interpreter registered with update-binfmts(8) does not exist. Tag: broken-symlink Description: This package ships a symlink which points to a non-existent file. Tag: incompatible-licenses Description: Licenses of the libraries the binary is linked to are incompatible. Tag: ldd-failure Description: Running "`ldd -r`" on the file failed unexpectedly. This is most like a bug in libc or adequate itself. References: https://bugs.debian.org/710521 Tag: library-not-found Description: The binary is linked with a library, which cannot be found. References: Debian Policy §8.6 Tag: missing-alternative Description: This package is a provider of the virtual package `x-terminal-emulator`, but it doesn't register itself as an alternative for `/usr/bin/x-terminal-emulator`; or it is a provider of the virtual package `x-window-manager`, but it doesn't register itself as an alternative for `/usr/bin/x-window-manager`. References: Debian Policy §11.8.3 Debian Policy §11.8.4 Tag: missing-copyright-file Description: The copyright file for this package is missing. This often happens if /usr/share/doc// was a real directory in a previous version of the package, but it's now a symlink; dpkg never replaces directory with a symlink to a directory. References: Debian Policy §12.5, §6.6 Tag: missing-pkgconfig-dependency Description: Dependency of a pkg-config (.pc) file shipped by this package couldn't be satisfied. References: Debian Policy §8.4 Tag: missing-symbol-version-information Description: The binary uses versioned symbols, but the library provides only unversioned ones. Tag: obsolete-conffile Description: The current version of this package no longer ships a conffile (that used to be included in the past). However, the conffile hasn't been removed on upgrade. References: https://wiki.debian.org/DpkgConffileHandling dpkg-maintscript-helper(1) Tag: program-name-collision Description: This package ships a program with the same name as another program. References: Debian Policy §10.1 Tag: py-file-not-bytecompiled Description: This package ships Python modules that are not byte-compiled. References: Python Policy §2.6 Tag: pyshared-file-not-bytecompiled Description: This package ships Python modules in /usr/share/pyshared that are not byte-compiled. References: Python Policy §2.6, §1.5 Tag: symbol-size-mismatch Description: The symbol has changed size since the package was built. It might be an indication that the library broke ABI. If ABI wasn't broken, and the library bumped shlibs (or symbols), the package should be binNMUed. Tag: undefined-symbol Description: The symbol has not been found in the libraries linked with the binary. Either the binary either needs to be linked with an additional shared library, or the dependency on the shared library package that provides this symbol is too weak. References: Debian Policy §3.5, §8.6, §10.2 adequate-0.15.1ubuntu5/doc/todo.perlcritic0000644000000000000000000000061112610025352015373 0ustar 1 CodeLayout::RequireTidyCode 1 ControlStructures::ProhibitDeepNests 2 InputOutput::ProhibitReadlineInForLoop 4 InputOutput::RequireBriefOpen 1 Miscellanea::ProhibitUselessNoCritic 1 Modules::ProhibitExcessMainComplexity 5 RegularExpressions::ProhibitComplexRegexes 2 Subroutines::ProhibitExcessComplexity 1 Variables::ProhibitReusedNames adequate-0.15.1ubuntu5/private/0000755000000000000000000000000012610025352013253 5ustar adequate-0.15.1ubuntu5/private/generate-manpage0000755000000000000000000000704512610025352016407 0ustar #!/usr/bin/python3 # Copyright © 2012, 2013 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import io import os import re import subprocess as ipc import sys import apt_pkg def podify_reference(s): s = s.strip() s = re.sub(r'^([a-z]+://\S+)$', r'>', s) s = re.sub(r'^([\w-]+)[(](\d)[)]$', r'B>(\2)', s) return s def podify_synopsis(s): if s.startswith(' '): s = s.lstrip() s = re.sub(r'<(.+?)>', r'I<\1>', s) s = re.sub(r'^(\S+)', r'B<\1>', s) s += '\n' return s def podify_description(s): s = re.sub(r'^\s+', '', s, flags=re.MULTILINE) s = re.sub(r'<(.+?)>', r'I<\1>', s) s = re.sub(r'`(.+?)`', r'C<\1>', s) s = re.sub(r'([\w-]+)[(](\d)[)]', r'B>(\2)', s) return s def fix_markup(s): # : # manpage references should be rendered in bold, not in italics s = re.sub('L<([\w-]+)[(](\d)[)]>', r'B>(\2)', s) s = re.sub('L<([a-z]+://\S+)>', r'>', s) return s def main(): sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='UTF-8') base = os.path.join(os.path.dirname(__file__), os.pardir) desc_fn = os.path.join(base, 'doc', 'tags.desc') tmpl_fn = os.path.join(base, 'doc', 'adequate.podt') code_fn = os.path.join(base, 'adequate') with open(tmpl_fn, 'rt', encoding='UTF-8') as file: for line in file: line = line.rstrip() if line == '=head1 TAGS': output_tags(desc_fn) else: line = fix_markup(line) print(line) def output_tags(desc_fn): print('=head1 TAGS') print() print('=over 4') print() with open(desc_fn, 'rt', encoding='UTF-8') as file: for section in apt_pkg.TagFile(file): tag = section['tag'] print('=item B>'.format(tag=tag)) print() try: description = section['description'] except LookupError: pass else: description = podify_description(description) print(description) print() try: references = section['references'] except LookupError: pass else: references = ', '.join(podify_reference(s) for s in references.splitlines()) print('References: {refs}.'.format(refs=references)) print() print('=back') if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et adequate-0.15.1ubuntu5/private/update-bash-builtin-commands0000755000000000000000000000030212370511531020636 0ustar #!/bin/sh set -e export LC_ALL=C commands=$(bash -c "help '*'" 2>&1 \ | grep -o -E '^[^%: ]+:' \ | tr -d : \ | xargs ) sed -r -e "s/(my @bash_builtins) = .*;/\1 = qw< $commands >;/" -i adequate adequate-0.15.1ubuntu5/private/update-coverage0000755000000000000000000000463212610025352016261 0ustar #!/usr/bin/python3 # Copyright © 2013 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import collections import apt_pkg def main(): base = os.path.join(os.path.dirname(__file__), os.pardir) tags = {} filename = '{base}/doc/tags.desc'.format(base=base) with open(filename, 'rt', encoding='UTF-8') as file: for section in apt_pkg.TagFile(file): tag = section['tag'] tags[tag] = 0 filename = '{base}/tests/testpkg/debian/control'.format(base=base) with open(filename, 'rt', encoding='UTF-8') as file: for n, section in enumerate(apt_pkg.TagFile(file)): if n == 0: continue description = section['description'] emitted_tags = frozenset( line.split()[0] for line in description.splitlines()[1:] ) for tag in emitted_tags: tags[tag] += 1 filename = '{base}/tests/coverage.txt'.format(base=base) with open(filename, 'wt', encoding='UTF-8') as file: for tag, n in sorted(tags.items()): if n == 0: checkbox = '[ ]' elif n == 1: checkbox = '[x]' else: checkbox = '[{n}]'.format(n=n) print('{c} {tag}'.format(c=checkbox, tag=tag), file=file) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et adequate-0.15.1ubuntu5/private/update-perlcritic0000755000000000000000000000065212610025352016624 0ustar #!/bin/sh set -e -u here=$(basename "$0") cd "$here/.." target=doc/todo.perlcritic if perlcritic --verbose '%p\n' adequate > "${target}.tmp" then : else rc=$? if [ $rc -ne 2 ] then rm -f "${target}.tmp" exit $rc fi fi sort "${target}.tmp" | uniq -c > "${target}.new" rm -f "${target}.tmp" diff -u "${target}" "${target}.new" || true mv "${target}.new" "${target}" # vim:ts=4 sts=4 sw=4 et adequate-0.15.1ubuntu5/private/update-tags0000755000000000000000000000554512610025352015430 0ustar #!/usr/bin/python3 # Copyright © 2012, 2013 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import re import sys import apt_pkg tag_re = re.compile(r"^:\s+Tags[(]qw[(](.+?)[)][)]") required_fields = {'Tag', 'Description'} known_fields = required_fields | {'References'} def main(): base = os.path.join(os.path.dirname(__file__), os.pardir) desc_fn = os.path.join(base, 'doc', 'tags.desc') code_fn = os.path.join(base, 'adequate') tags = {} with open(desc_fn, 'rt', encoding='UTF-8') as file: for section in apt_pkg.TagFile(file): tag = section['tag'] tags[tag] = section for field in required_fields: if field not in section: print('W: {tag}: required field {field} is missing'.format(tag=tag, field=field), file=sys.stderr) for field in section.keys(): if field not in known_fields: print('W: {tag}: unknown field {field}'.format(tag=tag, field=field), file=sys.stderr) obsolete_tags = set(tags) with open(code_fn, 'rt', encoding='UTF-8') as file: for line in file: match = tag_re.match(line) if match is None: continue for tag in match.group(1).split(): if tag in obsolete_tags: obsolete_tags.remove(tag) if tag in tags: continue tags[tag] = 'Tag: {tag}\n\n'.format(tag=tag) with open(desc_fn + '+', 'wt', encoding='UTF-8') as file: for tag, section in sorted(tags.items()): print(section, file=file, end='') os.rename(desc_fn + '+', desc_fn) for tag in sorted(obsolete_tags): print('W: {tag}: obsolete tag'.format(tag=tag), file=sys.stderr) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et adequate-0.15.1ubuntu5/templates/0000755000000000000000000000000012322316331013577 5ustar adequate-0.15.1ubuntu5/templates/adequate.templates0000644000000000000000000000007112006551124017306 0ustar Template: adequate/error Type: note Description: ${tags} adequate-0.15.1ubuntu5/tests/0000755000000000000000000000000013256652736012766 5ustar adequate-0.15.1ubuntu5/tests/Makefile0000644000000000000000000000144712610025352014411 0ustar arch = $(shell dpkg-architecture -qDEB_HOST_ARCH) changes = adequate-testpkg_1_$(arch).changes .PHONY: all all: $(changes) $(info Run "make run" as root.) $(info Alternatively, if you have user-mode-linux installed, you can try "make run-uml" as normal user.) $(info )@: $(changes): cd testpkg && dpkg-buildpackage -b -us -uc .PHONY: run run: $(changes) ./run-tests $(<) .PHONY: run-uml run-uml: $(changes) fallocate -l 1G uml-guest-swap linux init=$(CURDIR)/uml-guest-init \ $(shell printf '%s' '$(CURDIR)' | base64 -w0 | tr = _) \ $(shell printf '%s' '$(<)' | base64 -w0 | tr = _) \ rootfstype=hostfs ubd0=uml-guest-swap mem=128M quiet con=null,fd:1 \ | cat .PHONY: clean clean: cd testpkg && debian/rules clean rm -f *.changes *.deb rm -f uml-guest-swap # vim:ts=4 sts=4 sw=4 noet adequate-0.15.1ubuntu5/tests/coverage.txt0000644000000000000000000000072612610025352015304 0ustar [x] bin-or-sbin-binary-requires-usr-lib-library [ ] broken-binfmt-detector [ ] broken-binfmt-interpreter [x] broken-symlink [2] incompatible-licenses [ ] ldd-failure [x] library-not-found [x] missing-alternative [x] missing-copyright-file [x] missing-pkgconfig-dependency [x] missing-symbol-version-information [x] obsolete-conffile [x] program-name-collision [x] py-file-not-bytecompiled [x] pyshared-file-not-bytecompiled [x] symbol-size-mismatch [x] undefined-symbol adequate-0.15.1ubuntu5/tests/run-tests0000755000000000000000000002033713256652736014665 0ustar #!/usr/bin/python3 # Copyright © 2013, 2014 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import argparse import collections import difflib import errno import functools import os import re import subprocess as ipc import sys import apt_pkg @functools.total_ordering class debversion(str): def __lt__(self, other): return apt_pkg.version_compare(self, other) < 0 def __eq__(self, other): return apt_pkg.version_compare(self, other) == 0 def log_start(s): print(s, end=' ... ') sys.stdout.flush() def log_end(s): print(s) def log_stderr(s): for line in s.splitlines(): print('!', line) class DpkgError(Exception): pass class Uninstallable(DpkgError): pass class DebPkg(object): def __init__(self, path): self.depends = self.pre_depends = '' self.conflicts = self.breaks = '' cmdline = [ 'dpkg-deb', '-f', path, ] output = ipc.check_output(cmdline) output = output.decode('ASCII').splitlines() attr = None def a_get(): return getattr(self, attr, '') def a_set(value): return setattr(self, attr, value) def a_append(value): return setattr(self, attr, a_get() + '\n' + line) for line in output: if line[0] == ' ': a_append(line) else: key, value = line.split(': ', 1) attr = key.lower().replace('-', '_') a_set(value) self.path = path self.name = os.path.basename(path).split('_', 1)[0] def check_installability(self): depends = '{0.pre_depends}, {0.depends}'.format(self) conflicts = '{0.conflicts}, {0.breaks}'.format(self) cmdline = [ 'dpkg-checkbuilddeps', '-d', depends, '-c', conflicts, os.devnull ] child = ipc.Popen(cmdline, stdout=ipc.PIPE, stderr=ipc.PIPE) stdout, stderr = child.communicate() if child.wait() != 0: error = stderr.decode('ASCII', 'replace').strip() error = re.sub('^dpkg-checkbuilddeps: ', '', error) error = re.sub('^Unmet build dependencies', 'unmet dependencies', error) error = re.sub('^Build conflicts', 'conflicts', error) raise Uninstallable(error) def install(self): cmdline = ['dpkg', '-i', self.path] child = ipc.Popen(cmdline, stdout=ipc.PIPE, stderr=ipc.PIPE) stdout, stderr = child.communicate() if child.wait() != 0: stderr = stderr.decode('ASCII', 'replace') raise DpkgError(stderr) def purge(self): cmdline = ['dpkg', '-P', self.name] child = ipc.Popen(cmdline, stdout=ipc.PIPE, stderr=ipc.PIPE) stdout, stderr = child.communicate() if child.wait() != 0: stderr = stderr.decode('ASCII', 'replace') raise DpkgError(stderr) def get_version(self): return self.version def format_os_error(exc): try: prefix = errno.errorcode[exc.args[0]] except KeyError: prefix = 'errno={}'.format(exc.args[0]) return '{}: {}'.format(prefix, exc.args[1]) def main(): apt_pkg.init() ap = argparse.ArgumentParser() ap.add_argument('paths', metavar='DEB-OR-CHANGES', nargs='+') ap.add_argument('--no-skip', action='store_true') ap.add_argument('--adequate', default='adequate') options = ap.parse_args() if os.getuid() != 0: print('{}: error: administrator privileges are required'.format(ap.prog), file=sys.stderr) sys.exit(1) packages = collections.defaultdict(list) for path in options.paths: if path.endswith('.changes'): with open(path, 'rt', encoding='UTF-8') as file: for para in apt_pkg.TagFile(file): for line in para['Files'].splitlines(): md5, size, section, priority, path = line.split() if path.endswith('deb'): debpkg = DebPkg(path) packages[debpkg.name] += [debpkg] elif path.endswith('.deb'): debpkg = DebPkg(path) packages[debpkg.name] += [debpkg] rc = 0 for name, debpkg_group in sorted(packages.items()): debpkg_group.sort(key=DebPkg.get_version) prev_version = None for debpkg in debpkg_group: if prev_version is None: if len(debpkg_group) == 1: log_start('install {}'.format(name)) else: log_start('install {} ({})'.format(name, debpkg.version)) else: log_start('upgrade {} ({} => {})'.format(name, prev_version, debpkg.version)) try: debpkg.check_installability() except Uninstallable as exc: if options.no_skip: action = 'ERROR' rc = 1 else: action = 'SKIP' log_end('{} ({})'.format(action, exc)) break try: debpkg.install() except DpkgError as exc: log_end('ERROR (dpkg failed)') log_stderr(str(exc)) rc = 1 break else: log_end('ok') log_start('check {}'.format(name)) error = None try: child = ipc.Popen( [options.adequate, name], stdout=ipc.PIPE, stderr=ipc.PIPE, ) except OSError as exc: error = format_os_error(exc) stderr = b'' else: stdout, stderr = child.communicate() if child.wait() != 0: error = 'non-zero exit code' elif stderr: error = 'non-empty stderr' if error is not None: log_end('ERROR ({})'.format(error)) stderr = stderr.decode('ASCII', 'replace') log_stderr(stderr) rc = 1 break output = stdout.decode('ASCII').splitlines() output = sorted(output) # tag order is not deterministic if debpkg is debpkg_group[-1]: expected = [ '{}: {}'.format(name, line.strip()) for line in debpkg.description.splitlines(False)[1:] if line ] else: expected = [] if output == expected: log_end('ok') else: log_end('FAIL') diff = list( difflib.unified_diff(expected, output, n=9999) ) for line in diff[3:]: print(line) rc = 1 prev_version = debpkg.version log_start('remove {}'.format(name)) try: debpkg.purge() except DpkgError as exc: log_end('ERROR (dpkg failed)') log_stderr(str(exc)) rc = 1 else: log_end('ok') sys.exit(rc) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et adequate-0.15.1ubuntu5/tests/testpkg/0000755000000000000000000000000012762055164014440 5ustar adequate-0.15.1ubuntu5/tests/testpkg/adequate-test-pnc0000755000000000000000000000002112610025352017667 0ustar #!/bin/sh exit 0 adequate-0.15.1ubuntu5/tests/testpkg/debian/0000755000000000000000000000000013156010044015644 5ustar ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootadequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-bin-or-sbin-binary-requires-usr-lib-library.installadequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-bin-or-sbin-binary-requires-usr-lib-lib0000644000000000000000000000045012266266100030420 0ustar libadequate-lib.so.0 lib/ libadequate-usrlib.so.0 usr/lib/ adequate-lib1 bin/ adequate-lib2 sbin/ adequate-lib3 usr/bin/ adequate-lib4 usr/sbin/ adequate-lib5 usr/games/ adequate-usrlib1 bin/ adequate-usrlib2 sbin/ adequate-usrlib3 usr/bin/ adequate-usrlib4 usr/sbin/ adequate-usrlib5 usr/games/ adequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-broken-symlink.links0000644000000000000000000000010112266266100025117 0ustar /this/file/does/not/exist usr/share/adequate/test-broken-symlink adequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-incompatible-licenses-dep5.copyright0000644000000000000000000000014512266266222030164 0ustar Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Files: * License: GPL-2.0 adequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-incompatible-licenses-dep5.install0000644000000000000000000000005012266266222027615 0ustar adequate-license-conflict-dep5 /usr/bin adequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-incompatible-licenses.install0000644000000000000000000000004312266266100026757 0ustar adequate-license-conflict /usr/bin adequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-library-not-found.install0000644000000000000000000000002312266266100026057 0ustar adequate-lib1 bin/ adequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-missing-pkgconfig-dependency.install0000644000000000000000000000004512610025352030235 0ustar libadequate.pc /usr/share/pkgconfig/ ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootadequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-missing-symbol-version-information.installadequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-missing-symbol-version-information.inst0000644000000000000000000000010712266266100031000 0ustar adequate-test-msvi usr/bin/ libadequate-test-versionless.so.0 usr/lib/ adequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-obsolete-conffile.install0000644000000000000000000000012012266266100026101 0ustar test-non-obsolete-conffile /etc/adequate/ test-obsolete-conffile /etc/adequate/ adequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-program-name-collision.install0000644000000000000000000000007512610025352027064 0ustar true /usr/games adequate-test-pnc /usr/bin/adequate-test-pnc adequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-program-name-collision.links0000644000000000000000000000006712610025352026537 0ustar /usr/bin/adequate-test-pnc /usr/sbin/adequate-test-pnc adequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-py-file-not-bytecompiled.install0000644000000000000000000000043512266266100027334 0ustar test_no_pyc.py /usr/lib/python2.1/site-packages/adequate/ test_no_pyc.py /usr/lib/python2.7/dist-packages/adequate/ test_no_pyc.py /usr/lib/python2.9/dist-packages/adequate/ test_pyc.py /usr/lib/python2.7/dist-packages/adequate/ test_pyc.pyc /usr/lib/python2.7/dist-packages/adequate/ adequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-pyshared-file-not-bytecompiled.install0000644000000000000000000000006612266266100030523 0ustar test_pyshared_no_pyc.py /usr/share/pyshared/adequate/ adequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-symbol-size-mismatch.install0000644000000000000000000000010612266266100026566 0ustar adequate-test-symsize usr/bin/ libadequate-test-symsize.so.0 usr/lib/ adequate-0.15.1ubuntu5/tests/testpkg/debian/adequate-testpkg-undefined-symbol.install0000644000000000000000000000010513156007375025757 0ustar adequate-test-us2 usr/bin/ libadequate-test-versioning.so.0 usr/lib/ adequate-0.15.1ubuntu5/tests/testpkg/debian/changelog0000644000000000000000000000020512266266100017522 0ustar adequate-testpkg (1) unstable; urgency=low * Initial release. -- Jakub Wilk Sat, 02 Feb 2013 13:08:18 +0100 adequate-0.15.1ubuntu5/tests/testpkg/debian/compat0000644000000000000000000000000212266266100017051 0ustar 7 adequate-0.15.1ubuntu5/tests/testpkg/debian/control0000644000000000000000000000676513156010044017265 0ustar Source: adequate-testpkg Section: misc Priority: extra Maintainer: Jakub Wilk Build-Depends: debhelper (>= 7), python2.7 Standards-Version: 3.9.4 Package: adequate-testpkg-bin-or-sbin-binary-requires-usr-lib-library Architecture: any Description: adequate test package; do not install bin-or-sbin-binary-requires-usr-lib-library /bin/adequate-usrlib1 => /usr/lib/libadequate-usrlib.so.0 bin-or-sbin-binary-requires-usr-lib-library /sbin/adequate-usrlib2 => /usr/lib/libadequate-usrlib.so.0 Package: adequate-testpkg-broken-symlink Architecture: all Description: adequate test package; do not install broken-symlink /usr/share/adequate/test-broken-symlink -> /this/file/does/not/exist Package: adequate-testpkg-library-not-found Architecture: any Description: adequate test package; do not install library-not-found /bin/adequate-lib1 => libadequate-lib.so.0 Package: adequate-testpkg-incompatible-licenses Architecture: any Description: adequate test package; do not install incompatible-licenses /usr/bin/adequate-license-conflict OpenSSL (libssl.so.1.0.0) + GPLv3+ (libreadline.so.7) Package: adequate-testpkg-incompatible-licenses-dep5 Architecture: any Description: adequate test package; do not install incompatible-licenses /usr/bin/adequate-license-conflict-dep5 GPLv2 + GPLv3+ (libreadline.so.7) Package: adequate-testpkg-missing-alternative Architecture: all Provides: x-terminal-emulator, x-window-manager Description: adequate test package; do not install missing-alternative x-terminal-emulator missing-alternative x-window-manager Package: adequate-testpkg-missing-copyright-file Architecture: all Description: adequate test package; do not install missing-copyright-file /usr/share/doc/adequate-testpkg-missing-copyright-file/copyright Package: adequate-testpkg-missing-pkgconfig-dependency Architecture: all Depends: pkg-config (>= 0.27) Description: adequate test package; do not install missing-pkgconfig-dependency libadequate => libnonexistent Package: adequate-testpkg-missing-symbol-version-information Architecture: any Description: adequate test package; do not install missing-symbol-version-information /usr/bin/adequate-test-msvi => /usr/lib/libadequate-test-versionless.so.0 Package: adequate-testpkg-obsolete-conffile Architecture: all Description: adequate test package; do not install obsolete-conffile /etc/adequate/test-obsolete-conffile Package: adequate-testpkg-program-name-collision Architecture: all Description: adequate test package; do not install program-name-collision /usr/games/true (bash builtin command) program-name-collision /usr/games/true /bin/true Package: adequate-testpkg-py-file-not-bytecompiled Architecture: all Depends: python (>= 2.7), python (<< 2.8) Description: adequate test package; do not install py-file-not-bytecompiled /usr/lib/python2.7/dist-packages/adequate/test_no_pyc.py Package: adequate-testpkg-pyshared-file-not-bytecompiled Architecture: all Depends: python Description: adequate test package; do not install pyshared-file-not-bytecompiled /usr/share/pyshared/adequate/test_pyshared_no_pyc.py Package: adequate-testpkg-symbol-size-mismatch Architecture: any Description: adequate test package; do not install symbol-size-mismatch /usr/bin/adequate-test-symsize => this_symbol_size_varies Package: adequate-testpkg-undefined-symbol Architecture: any Description: adequate test package; do not install undefined-symbol /usr/bin/adequate-test-us2 => this_symbol_might_be_undefined@ADEQUATE_TEST (libadequate-test-versioning.so.0) adequate-0.15.1ubuntu5/tests/testpkg/debian/copyright0000644000000000000000000000004012266266100017600 0ustar This is a dummy copyright file. adequate-0.15.1ubuntu5/tests/testpkg/debian/rules0000755000000000000000000000712213156007216016735 0ustar #!/usr/bin/make -f tmp = debian/tmp at = adequate-test .PHONY: clean clean: dh_clean .PHONY: build build: build-stamp build-stamp: mkdir -p $(tmp) # bin-or-sbin-binary-requires-usr-lib-library; library-not-found $(CC) lib.c -fPIC -shared -Wl,-soname,libadequate-lib.so.0 -o $(tmp)/libadequate-lib.so.0 ln -sf libadequate-lib.so.0 $(tmp)/libadequate-lib.so $(CC) lib.c -fPIC -shared -Wl,-soname,libadequate-usrlib.so.0 -o $(tmp)/libadequate-usrlib.so.0 ln -sf libadequate-usrlib.so.0 $(tmp)/libadequate-usrlib.so $(CC) prog.c -L$(tmp) -Wl,--no-as-needed -ladequate-lib -o $(tmp)/adequate-lib1 cd $(tmp) && seq 2 5 | xargs -t -I {} ln -f adequate-lib1 adequate-lib{} $(CC) prog.c -L$(tmp) -Wl,--no-as-needed -ladequate-usrlib -o $(tmp)/adequate-usrlib1 cd $(tmp) && seq 2 5 | xargs -t -I {} ln -f adequate-usrlib1 adequate-usrlib{} # incompatible-licenses $(CC) lib.c -fPIC -shared -Wl,-soname,libssl.so.1.0.0 -o $(tmp)/libssl.so $(CC) lib.c -fPIC -shared -Wl,-soname,libreadline.so.7 -o $(tmp)/libreadline.so $(CC) prog.c -L$(tmp) -Wl,--no-as-needed -lssl -lreadline -o $(tmp)/adequate-license-conflict $(CC) prog.c -L$(tmp) -Wl,--no-as-needed -lreadline -o $(tmp)/adequate-license-conflict-dep5 # missing-version-information $(CC) -shared -Wl,--soname=lib$(at)-versionless.so.0 -Wl,--version-script=verscript-global lib.c -o $(tmp)/lib$(at)-versionless.so.0 ln -sf lib$(at)-versionless.so.0 $(tmp)/lib$(at)-versionless.so $(CC) undef.c -L$(tmp) -o $(tmp)/$(at)-msvi -l$(at)-versionless $(CC) -shared -Wl,--soname=lib$(at)-versionless.so.0 lib.c -o $(tmp)/lib$(at)-versionless.so.0 # symbol-size-mismatch $(CC) -shared -Wl,--soname=lib$(at)-symsize.so.0 lib.c -o $(tmp)/lib$(at)-symsize.so.0 ln -sf lib$(at)-symsize.so.0 $(tmp)/lib$(at)-symsize.so $(CC) -fno-PIE -no-pie symsize.c -L$(tmp) -o $(tmp)/$(at)-symsize -l$(at)-symsize $(CC) -shared -Wl,--soname=lib$(at)-symsize.so.0 -DADEQUATE_SYMBOL_SIZE=42 lib.c -o $(tmp)/lib$(at)-symsize.so.0 # undefined-symbol $(CC) -shared -Wl,--soname=lib$(at)-versioning.so.0 -Wl,--version-script=verscript-global lib.c -o $(tmp)/lib$(at)-versioning.so.0 ln -sf lib$(at)-versioning.so.0 $(tmp)/lib$(at)-versioning.so # what is the purpose of this test? always failed on ppc64el, starts # failing on x86 architectures with binutils-2.29 ifeq (,$(filter $(DEB_HOST_ARCH),amd64 i386 x32 ppc64el)) $(CC) undef.c -fPIE -Wl,--unresolved-symbols,ignore-all -L$(tmp) -o $(tmp)/$(at)-us1 endif $(CC) undef.c -L$(tmp) -o $(tmp)/$(at)-us2 -l$(at)-versioning $(CC) -shared -Wl,--soname=lib$(at)-versioning.so.0 -Wl,--version-script=verscript-local lib.c -o $(tmp)/lib$(at)-versioning.so.0 # py-file-not-bytecompiled; pyshared-file-not-bytecompiled cp *.py debian/tmp/ python2.7 -m compileall debian/tmp/ touch $(@) .PHONY: build-arch build-indep build-arch build-indep: $(error $(@) is not implemented) .PHONY: binary binary: dh_install dh_installdocs -N adequate-testpkg-missing-copyright-file dh_installchangelogs dh_link dh_compress dh_fixperms dh_strip dh_makeshlibs dh_installdeb dh_gencontrol dh_md5sums dh_builddeb rm debian/adequate-testpkg-obsolete-conffile/etc/adequate/test-obsolete-conffile sed -i -e '/test-obsolete/d' debian/adequate-testpkg-obsolete-conffile/DEBIAN/conffiles cp -f debian/files debian/files.orig dh_gencontrol -p adequate-testpkg-obsolete-conffile -- -v2 -fdebian/files2 cat debian/files2 >> debian/files rm -f debian/files2 dh_md5sums -p adequate-testpkg-obsolete-conffile dh_builddeb -p adequate-testpkg-obsolete-conffile .PHONY: binary-arch binary-indep binary-arch binary-indep: $(error $(@) is not implemented) # vim:ts=4 sts=4 sw=4 noet adequate-0.15.1ubuntu5/tests/testpkg/debian/source/0000755000000000000000000000000012266266100017153 5ustar adequate-0.15.1ubuntu5/tests/testpkg/debian/source/format0000644000000000000000000000001412266266100020361 0ustar 3.0 (quilt) adequate-0.15.1ubuntu5/tests/testpkg/lib.c0000644000000000000000000000025512266266100015345 0ustar void this_symbol_might_be_undefined(void) { } #if !defined(ADEQUATE_SYMBOL_SIZE) #define ADEQUATE_SYMBOL_SIZE 37 #endif char this_symbol_size_varies[ADEQUATE_SYMBOL_SIZE]; adequate-0.15.1ubuntu5/tests/testpkg/libadequate.pc0000644000000000000000000000027212610025352017231 0ustar prefix=/usr exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include Name: adequate Description: adequate test library Version: 1.0 Requires: libnonexistent >= 3.14 adequate-0.15.1ubuntu5/tests/testpkg/prog.c0000644000000000000000000000005712266266100015546 0ustar int main(int argc, char **argv) { return 0; } adequate-0.15.1ubuntu5/tests/testpkg/symsize.c0000644000000000000000000000016212266266100016277 0ustar extern char this_symbol_size_varies[37]; int main(int argc, char **argv) { return this_symbol_size_varies[0]; } adequate-0.15.1ubuntu5/tests/testpkg/test-non-obsolete-conffile0000644000000000000000000000004612266266100021520 0ustar # This is a dummy configuration file. adequate-0.15.1ubuntu5/tests/testpkg/test-obsolete-conffile0000644000000000000000000000004612266266100020730 0ustar # This is a dummy configuration file. adequate-0.15.1ubuntu5/tests/testpkg/test_no_pyc.py0000644000000000000000000000004612266266100017331 0ustar # This is a dummy Python source file. adequate-0.15.1ubuntu5/tests/testpkg/test_pyc.py0000644000000000000000000000004612266266100016635 0ustar # This is a dummy Python source file. adequate-0.15.1ubuntu5/tests/testpkg/test_pyshared_no_pyc.py0000644000000000000000000000004612266266100021230 0ustar # This is a dummy Python source file. adequate-0.15.1ubuntu5/tests/testpkg/true0000755000000000000000000000002112266266222015334 0ustar #!/bin/sh exit 0 adequate-0.15.1ubuntu5/tests/testpkg/undef.c0000644000000000000000000000020512266266100015673 0ustar extern void this_symbol_might_be_undefined(void); int main(int argc, char **argv) { this_symbol_might_be_undefined(); return 0; } adequate-0.15.1ubuntu5/tests/testpkg/verscript-global0000644000000000000000000000004012266266100017625 0ustar ADEQUATE_TEST { global: *; }; adequate-0.15.1ubuntu5/tests/testpkg/verscript-local0000644000000000000000000000003712266266100017465 0ustar ADEQUATE_TEST { local: *; }; adequate-0.15.1ubuntu5/tests/uml-guest-init0000755000000000000000000000230312610025352015552 0ustar #!/bin/sh set -e -u -x export PATH=/usr/sbin:/usr/bin:/sbin:/bin mount_stuff() { mount -n -t proc proc /proc mount -n -t sysfs sysfs /sys mkdir -p /dev/pts mount -n -t devpts devpts /dev/pts mount -n -o bind /usr/lib/uml/modules /lib/modules mount -n -t tmpfs tmpfs /tmp -o size=1G } if [ "$1" != '--cow' ] then export testdir="$(printf '%s' "$1" | tr _ = | base64 -d)" export testfile="$(printf '%s' "$2" | tr _ = | base64 -d)" mount_stuff mkdir -m 0700 /tmp/dev mknod /tmp/dev/ubda b 98 0 mkswap -f /tmp/dev/ubda swapon /tmp/dev/ubda mkdir -m 0700 /tmp/ro /tmp/rw /tmp/aufs mount -n -t hostfs hostfs /tmp/ro -o /,ro mount -n -t aufs aufs /tmp/aufs -o noatime,noxino,dirs=/tmp/rw:/tmp/ro=ro exec chroot /tmp/aufs "$0" --cow else mount_stuff rm -vf \ /var/lib/adequate/* \ /var/lib/dpkg/lock \ /var/lib/dpkg/triggers/Lock \ /var/lib/apt/listchanges.db \ /var/log/apt/term.log \ /var/log/apt/history.log \ /var/log/dpkg.log \ /var/cache/apt/archives/lock \ /var/cache/debconf/*.dat cd "$testdir" ./run-tests "$testfile" halt -f fi # vim:ts=4 sts=4 sw=4 et