diff --git a/scripts/prtcheckmissing b/scripts/prtcheckmissing index 3686627..5b404b2 100755 --- a/scripts/prtcheckmissing +++ b/scripts/prtcheckmissing @@ -2,26 +2,28 @@ # # $Id: prtcheckmissing,v 1.1 2003/10/27 15:26:50 opel Exp $ # prtcheckmissing,v 1.2 2022/05/31 18:41:19 jmq Exp $ +# prtcheckmissing,v 1.3 2023/09/07 18:51:46 jmq Exp $ use strict; use warnings; -my @mask = parse_pkgadd_conf(); +sub check_missing { + my @mask = parse_pkgadd_conf(); + open (my $dbh, "/var/lib/pkg/db") or die "Could not read package database!\n"; + local $/ = ""; # read files paragraph-wise; see ``perldoc perlvar'' -open (my $dbh, "/var/lib/pkg/db") or die "Could not read package database!\n"; -local $/ = ""; # read files paragraph-wise; see ``perldoc perlvar'' + while(<$dbh>) { + my ($name, $version, @files) = split /\n/; -while(<$dbh>) { - my ($name, $version, @files) = split /\n/; + # apply the pkgadd rules to eliminate false positives + my @missing = grep { (! -e "/$_") && wanted($_, @mask) } @files; - # apply the pkgadd rules to eliminate false positives - my @missing = grep { (! -e "/$_") && wanted($_, @mask) } @files; - - # final report for this package - next if not @missing; - print map "/$_ $name\n", @missing; + # final report for this package + next if not @missing; + print map "/$_ $name\n", @missing; + } + close($dbh); } -close($dbh); sub parse_pkgadd_conf { my @unwanted; @@ -48,3 +50,57 @@ sub wanted { } return $retval; } + +sub check_perms { + my %wrongmode; # hash from suspicious file to the port(s) that claim to own it + + foreach (split('\n', `prt-get printf "%i:%p:%n\n"`)) { + my ($isinst, $repo, $name) = split(':', $_, 3); + next if ($isinst eq "no"); + open (my $fp,"$repo/$name/.footprint") or die "no footprint for $repo/$name"; + while(<$fp>) { + my ($Emod,$Eown,$file) = split(/\t| -> /, $_, 3); + chomp($file); $file =~ s/\/$//; + next if (! -e "/$file"); # this case is handled by check_missing + + # there's a file on disk, so inspect its owner and perms + my @stat = (-l "/$file") ? lstat("/$file") : stat("/$file"); + my $Fown = getpwuid($stat[4]) . "/" . getgrgid($stat[5]); + my $Fmod = mode_to_string($stat[2]); + $wrongmode{$file} .= " $name" if (($Eown ne $Fown) or ($Emod ne $Fmod)); + } + close($fp); + } + + # final report + next if (not %wrongmode); + print map "/$_ $wrongmode{$_}\n", sort keys %wrongmode; +} + +# inlined from Stat::lsMode in order to avoid an extra dependency +# (https://metacpan.org/pod/Stat::lsMode) +sub mode_to_string { + my ($mode) = @_; + my @perms = qw(--- --x -w- -wx r-- r-x rw- rwx); + my @ftype = qw(. p c ? d ? b ? - ? l ? s D ? ?); + $ftype[0] = ''; + my @str_mode = @perms[($mode&0700)>>6, ($mode&0070)>>3, $mode&0007]; + my $ftype = $ftype[($mode & 0170000)>>12]; + + my $setids = ($mode & 07000)>>9; + if ($setids) { + if ($setids & 01) { # Sticky bit + $str_mode[2] =~ s/([-x])$/$1 eq 'x' ? 't' : 'T'/e; + } + if ($setids & 02) { # Setgid bit + $str_mode[1] =~ s/([-x])$/$1 eq 'x' ? 's' : 'S'/e; + } + if ($setids & 04) { # Setuid bit + $str_mode[0] =~ s/([-x])$/$1 eq 'x' ? 's' : 'S'/e; + } + } + return join '', $ftype, @str_mode; +} + +if ($0 =~ /perms$/) { check_perms; +} else { check_missing; }