#!/usr/bin/perl
#
# revdep: check library and executable linking for issues after package upgrades
#         output of revdep can be fed directly to prt-get, eg: revdep | xargs prt-get update
#
# Written by Alan Mizrahi, alan at mizrahi dot com dot ve
#
use strict;
use warnings;
use Getopt::Long;

my %port; # (portname => [elf1, ...], ...)

my ($verbose, $help);
if (!GetOptions('verbose' => \$verbose, 'help' => \$help) || $help) {
	print "revdep: Check library and executable linking for issues after package upgrades\n\nSyntax: revdep [--verbose] [--help] [port1] ...\n\n";
        exit 0;
}

open FD, '/var/lib/pkg/db' or die "Error opening /var/lib/pkg/db: $!\n";
my ($name, $version);
while (<FD>) {
	chomp;
	if ($_ eq '') {
		$name = $version = undef;
	} elsif (!defined($name)) {
		$name = $_;
	} elsif (!defined($version)) {
		$version = $_;
	} elsif ((/^.*lib.+\.so[^\/]*$/ || (/^.*bin\/[^\/]+$/ && -x "/$_")) && (-f "/$_" && ! -l "/$_")) {
		push(@{$port{$name}}, "/$_");
        }
}
close FD;

PORT: foreach my $name (sort($#ARGV == -1 ? keys %port : @ARGV)) {
	my %missing; # (prog1 => (missinglib1 => 1, ...), ...)
	print "Checking $name\n" if $verbose;
	foreach my $elf (@{$port{$name}}) {
		open LDD, "ldd \"$elf\" 2>/dev/null |" or warn "Error running ldd on $elf: $!";
		while (<LDD>) {
			if (/^\s*(.+) => not found/) {
				if ($verbose) {
					$missing{$elf}{$1} = 1;
				} else {
					print "$name\n";
					close LDD;
					next PORT;
				}
			}
		}
		close LDD;
	}
	if ($verbose) {
		foreach (sort keys %missing) {
			print "$name: $_ linked against missing ", join(' ', (sort keys $missing{$_})), "\n";
		}
	}
}

exit 0;