#!/usr/bin/perl
# binaries -- lintian check script

# Copyright (C) 1998 by Christian Schwarz
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, you can find it on the World Wide
# Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free
# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
# MA 02111-1307, USA.

($#ARGV == 1) or fail("syntax: binaries <pkg> <type>");
$pkg = shift;
$type = shift;

# read architecture file
if (open(IN,"fields/architecture")) {
  chop($arch = <IN>);
  close(IN);
} else {
  # Don't display this tag, since `fields' check already checks for this!
  # -> no-architecture-field
  #print "E: $pkg $type: package-does-not-specify-architecture\n";
}

# read data from objdump-info file
open(IN,"objdump-info")
    or fail("cannot find objdump-info for $type package $pkg");
while (<IN>) {
  chop;

  next if /^\s*$/o;

  if (/^-- (\S+)\s*$/o) {
    $file = $1;
  } elsif (/^\s*NEEDED\s*(\S+)/o) {
    push(@{$NEEDED{$file}},$1);
  } elsif (/^\s*RPATH\s*(\S+)/o) {
    $RPATH{$file} = $1;
  } elsif (/^\s*\d+\s+\.comment\s+/o) {
    $COMMENT{$file} = 1;
  } elsif (/^\s*\d+\s+\.note\s+/o) {
    $NOTE{$file} = 1;
  }
}
close(IN);

my $needs_depends_line = 0;
  
# process all files in package
open(IN,"file-info") or fail("cannot find file-info for $type package $pkg");
while (<IN>) {
  chop;
  
  /^(.*?):\s+(.*)$/o or fail("syntax error in file-info file: $_");
  my ($file,$info) = ($1,$2);

  # binary or object file?
  next unless ($info =~ /ELF/o) or ($info =~ /current ar archive/o);

  if ($arch eq 'all') {
    # package is `Architecture: all' but contains libs!?
    print "E: $pkg $type: arch-independent-package-contains-binary-or-object $file\n";
  }

  # ELF?
  next unless $info =~ m,^ELF,o;

  # stripped?
  if ($info =~ m,not stripped\s*$,o) {
    # Is it an object file (which generally can not be stripped),
    # or perhaps a debugging package? 
    unless ($file =~ m,\.o$, or $pkg =~ /-dbg$/ or $pkg =~ /debug/) {
      print "E: $pkg $type: unstripped-binary-or-object $file\n";
    }
  } else {
    # stripped but a debug or profiling library?
    if (($file =~ m,lib/debug/,o) or ($file =~ m,lib/profile/,o)) {
      print "E: $pkg $type: library-in-debug-or-profile-should-not-be-stripped $file\n";
    } else {
      # appropriately stripped, but is it stripped enough?
      if (exists $NOTE{$file}) {
	print "I: $pkg $type: binary-has-unneeded-section $file .note\n";
      }
      if (exists $COMMENT{$file}) {
	print "I: $pkg $type: binary-has-unneeded-section $file .comment\n";
      }
    }
  }

  # rpath?
  if (exists $RPATH{$file}) {
    print "W: $pkg $type: binary-or-shlib-defines-rpath $file $RPATH{$file}\n";
  }

  # binary or shared object?
  next unless ($info =~ /executable/o) or ($info =~ /shared object/o);

  # statically linked?
  my @needed = @{$NEEDED{$file}};
  if ($#needed == -1) {
    if ($info =~ /shared object/o) {
      print "W: $pkg $type: shared-lib-without-dependency-information $file\n";
    } else {
      print "E: $pkg $type: statically-linked-binary $file\n";
    }
  } else {
    my $lib;
    my $no_libc = 1;
    $needs_depends_line = 1;
    for $lib (@needed) {
      # linked against libc5?
      if ($lib =~ /^libc\.so\.5/o) {
	# yes.
	# libc5-compat ?
	if (($file =~ /libc5-compat/) or (/i486-linuxlibc1/)) {
	  # ok, ignore it
	} else {
	  print "W: $pkg $type: libc5-binary $file\n" unless $libc5_binary{$file}++;
	}
      }

      if ($lib =~ /^libc/o) {
	$no_libc = 0;
      }
    }

    if ($no_libc and not $file =~ m,/libc\b,) {
      if ($info =~ /shared object/) {
	print "W: $pkg $type: library-not-linked-against-libc $file\n";
      } else {
        print "W: $pkg $type: program-not-linked-against-libc $file\n";
      }
    }
  }
}
close(IN);

if ($needs_depends_line) {
    if (not -e "fields/depends" and not -e "fields/pre-depends") {
	print "W: $pkg $type: missing-depends-line\n"
	    unless $pkg eq 'ldso';
    }
}

    

exit 0;

# -----------------------------------

sub fail {
  if ($_[0]) {
    print STDERR "error: $_[0]\n";
  } elsif ($!) {
    print STDERR "error: $!\n";
  } else {
    print STDERR "error.\n";
  }
  exit 1;
}
