#!/usr/bin/perl use warnings; use strict; use IO::Handle; use IO::File; my $version= '1.2.6'; # This line modified by Makefile my %kmap= (optional => 'suggests', recommended => 'recommends', class => 'priority', package_revision => 'revision', ); my @fieldpri= ('Package', 'Source', 'Version', 'Priority', 'Section', 'Essential', 'Maintainer', 'Pre-Depends', 'Depends', 'Recommends', 'Suggests', 'Conflicts', 'Provides', 'Replaces', 'Enhances', 'Architecture', 'Filename', 'Size', 'Installed-Size', 'MD5sum', 'Description', 'Origin', 'Bugs' ); # This maps the fields into the proper case my %field_case; @field_case{map{lc($_)} @fieldpri} = @fieldpri; use Getopt::Long qw(:config bundling); my %options = (help => 0, udeb => 0, arch => undef, multiversion => 0, ); my $result = GetOptions(\%options,'help|h|?','udeb|u!','arch|a=s','multiversion|m!'); print <] [-m] binarypath overridefile [pathprefix] > Packages Options: --udeb, -u scan for udebs --arch, -a architecture to scan for --multiversion, -m allow multiple versions of a single package --help, -h show this help END my $udeb = $options{udeb}; my $arch = $options{arch}; my $ext = $options{udeb} ? 'udeb' : 'deb'; my @find_args; if ($options{arch}) { @find_args = ('(','-name',"*_all.$ext",'-o','-name',"*_${arch}.$ext",')',); } else { @find_args = ('-name',"*.$ext"); } push @find_args, '-follow'; my ($binarydir, $override, $pathprefix) = @ARGV; -d $binarydir or die "Binary dir $binarydir not found\n"; -e $override or die "Override file $override not found\n"; $pathprefix = '' if not defined $pathprefix; our %vercache; sub vercmp { my ($a,$b)=@_; return $vercache{$a}{$b} if exists $vercache{$a}{$b}; system('dpkg','--compare-versions',$a,'le',$b); $vercache{$a}{$b}=$?; return $?; } my %packages; my $find_h = new IO::Handle; open($find_h,'-|','find',"$binarydir/",@find_args,'-print') or die "Couldn't open $binarydir for reading: $!\n"; FILE: while (<$find_h>) { chomp; my $fn = $_; my $control = `dpkg-deb -I $fn control`; if ($control eq "") { warn "Couldn't call dpkg-deb on $fn: $!, skipping package\n"; next; } if ($?) { warn "\`dpkg-deb -I $fn control' exited with $?, skipping package\n"; next; } my %tv = (); my $temp = $control; while ($temp =~ s/^\n*(\S+):[ \t]*(.*(\n[ \t].*)*)\n//) { my ($key,$value)= (lc $1,$2); if (defined($kmap{$key})) { $key= $kmap{$key}; } if (defined($field_case{$key})) { $key= $field_case{$key}; } $value =~ s/\s+$//; $tv{$key}= $value; } $temp =~ /^\n*$/ or die "Unprocessed text from $fn control file; info:\n$control / $temp\n"; defined($tv{'Package'}) or die "No Package field in control file of $fn\n"; my $p= $tv{'Package'}; delete $tv{'Package'}; if (defined($packages{$p}) and not $options{multiversion}) { foreach (@{$packages{$p}}) { if (&vercmp($tv{'Version'}, $_->{'Version'})) { print(STDERR " ! Package $p (filename $fn) is repeat but newer version;\n". " used that one and ignored data from $_->{Filename} !\n") || die $!; $packages{$p} = []; } else { print(STDERR " ! Package $p (filename $fn) is repeat;\n". " ignored that one and using data from $_->{Filename} !\n") or die $!; next FILE; } } } print(STDERR " ! Package $p (filename $fn) has Filename field!\n") || die $! if defined($tv{'Filename'}); $tv{'Filename'}= "$pathprefix$fn"; open(C,"md5sum <$fn |") || die "$fn $!"; chop($_=); close(C); $? and die "\`md5sum < $fn' exited with $?\n"; /^([0-9a-f]{32})\s*-?\s*$/ or die "Strange text from \`md5sum < $fn': \`$_'\n"; $tv{'MD5sum'}= $1; my @stat= stat($fn) or die "Couldn't stat $fn: $!\n"; $stat[7] or die "$fn is empty\n"; $tv{'Size'}= $stat[7]; if (defined $tv{Revision} and length($tv{Revision})) { $tv{Version}.= '-'.$tv{Revision}; delete $tv{Revision}; } push @{$packages{$p}}, {%tv}; } close($find_h); select(STDERR); $= = 1000; select(STDOUT); sub writelist { my $title= shift(@_); return unless @_; print(STDERR " $title\n") || die $!; my $packages= join(' ',sort @_); format STDERR = ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $packages . while (length($packages)) { write(STDERR) || die $!; } print(STDERR "\n") || die $!; } my (@samemaint,@changedmaint); my %overridden; my $override_fh = new IO::File $override,'r' or die "Couldn't open override file $override: $!\n"; while (<$override_fh>) { s/\#.*//; s/\s+$//; next unless $_; my ($p,$priority,$section,$maintainer)= split(/\s+/,$_,4); next unless defined($packages{$p}); for my $package (@{$packages{$p}}) { if ($maintainer) { if ($maintainer =~ m/(.+?)\s*=\>\s*(.+)/) { my $oldmaint= $1; my $newmaint= $2; my $debmaint= $$package{Maintainer}; if (!grep($debmaint eq $_, split(m:\s*//\s*:, $oldmaint))) { push(@changedmaint, " $p (package says $$package{Maintainer}, not $oldmaint)\n"); } else { $$package{Maintainer}= $newmaint; } } elsif ($$package{Maintainer} eq $maintainer) { push(@samemaint," $p ($maintainer)\n"); } else { print(STDERR " * Unconditional maintainer override for $p *\n") || die $!; $$package{Maintainer}= $maintainer; } } $$package{Priority}= $priority; $$package{Section}= $section; } $overridden{$p} = 1; } close($override_fh); my @missingover=(); my $records_written = 0; for my $p (sort keys %packages) { if (not defined($overridden{$p})) { push(@missingover,$p); } for my $package (@{$packages{$p}}) { my $record= "Package: $p\n"; for my $key (@fieldpri) { next unless defined $$package{$key}; $record .= "$key: $$package{$key}\n"; } $record .= "\n"; $records_written++; print(STDOUT $record) or die "Failed when writing stdout: $!\n"; } } close(STDOUT) or die "Couldn't close stdout: $!\n"; my @spuriousover= grep(!defined($packages{$_}),sort keys %overridden); &writelist("** Packages in archive but missing from override file: **", @missingover); if (@changedmaint) { print(STDERR " ++ Packages in override file with incorrect old maintainer value: ++\n", @changedmaint, "\n") || die $!; } if (@samemaint) { print(STDERR " -- Packages specifying same maintainer as override file: --\n", @samemaint, "\n") || die $!; } if (@spuriousover) { print(STDERR " -- Packages in override file but not in archive: --\n", @spuriousover, "\n") || die $!; } print(STDERR " Wrote $records_written entries to output Packages file.\n") || die $!;