Mon, 28 Jan 2013 17:37:18 +0100
Correct socket error reporting improvement with IPv6 portable code,
after helpful recommendation by Saúl Ibarra Corretgé on OSips devlist.
michael@428 | 1 | ## |
michael@428 | 2 | ## lint-rpm.pl -- OpenPKG *.rpm File Checker |
michael@428 | 3 | ## Copyright (c) 2000-2012 OpenPKG GmbH <http://openpkg.com/> |
michael@428 | 4 | ## |
michael@428 | 5 | ## This software is property of the OpenPKG GmbH, DE MUC HRB 160208. |
michael@428 | 6 | ## All rights reserved. Licenses which grant limited permission to use, |
michael@428 | 7 | ## copy, modify and distribute this software are available from the |
michael@428 | 8 | ## OpenPKG GmbH. |
michael@428 | 9 | ## |
michael@428 | 10 | ## THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED |
michael@428 | 11 | ## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
michael@428 | 12 | ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
michael@428 | 13 | ## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR |
michael@428 | 14 | ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
michael@428 | 15 | ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
michael@428 | 16 | ## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
michael@428 | 17 | ## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
michael@428 | 18 | ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
michael@428 | 19 | ## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
michael@428 | 20 | ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
michael@428 | 21 | ## SUCH DAMAGE. |
michael@428 | 22 | ## |
michael@428 | 23 | |
michael@428 | 24 | # Perl run-time requirement |
michael@428 | 25 | require 5; |
michael@428 | 26 | BEGIN { |
michael@428 | 27 | eval "use Getopt::Long; use IO;"; |
michael@428 | 28 | if ($@) { |
michael@428 | 29 | print STDERR |
michael@428 | 30 | "lint-rpm: ERROR: This command requires a full-size Perl installation!\n" . |
michael@428 | 31 | "lint-rpm: HINT: Install OpenPKG \"perl\" package to use this command.\n"; |
michael@428 | 32 | exit(1); |
michael@428 | 33 | } |
michael@428 | 34 | } |
michael@428 | 35 | |
michael@428 | 36 | # OpenPKG instance prefix |
michael@428 | 37 | my $my_prefix = $ENV{'OPENPKG_PREFIX'}; |
michael@428 | 38 | delete $ENV{'OPENPKG_PREFIX'}; |
michael@428 | 39 | |
michael@428 | 40 | # program information |
michael@428 | 41 | my $progname = "lint-rpm"; |
michael@428 | 42 | my $progvers = "1.0.0"; |
michael@428 | 43 | |
michael@428 | 44 | # parameters (defaults) |
michael@428 | 45 | my $version = 0; |
michael@428 | 46 | my $verbose = 0; |
michael@428 | 47 | my $help = 0; |
michael@428 | 48 | my $check = 'all'; |
michael@428 | 49 | my $tmpdir = ($ENV{TMPDIR} || $ENV{TEMPDIR} || "/tmp") . "/$progname"; |
michael@428 | 50 | my $rpm = "$my_prefix/bin/openpkg rpm"; |
michael@428 | 51 | my $rpm2cpio = "$my_prefix/bin/openpkg rpm2cpio"; |
michael@428 | 52 | |
michael@428 | 53 | # exception handling support |
michael@428 | 54 | $SIG{__DIE__} = sub { |
michael@428 | 55 | my ($err) = @_; |
michael@428 | 56 | $err =~ s|\s+at\s+.*||s if (not $verbose); |
michael@428 | 57 | print STDERR "$progname:ERROR: $err ". ($! ? "($!)" : "") . "\n"; |
michael@428 | 58 | exit(1); |
michael@428 | 59 | }; |
michael@428 | 60 | |
michael@428 | 61 | # command line parsing |
michael@428 | 62 | Getopt::Long::Configure("bundling"); |
michael@428 | 63 | my $result = GetOptions( |
michael@428 | 64 | 'V|version' => \$version, |
michael@428 | 65 | 'v|verbose' => \$verbose, |
michael@428 | 66 | 'h|help' => \$help, |
michael@428 | 67 | 'c|check=s' => \$check, |
michael@428 | 68 | 't|tmpdir=s' => \$tmpdir, |
michael@428 | 69 | 'r|rpm=s' => \$rpm, |
michael@428 | 70 | ) || die "option parsing failed"; |
michael@428 | 71 | if ($help) { |
michael@428 | 72 | print "Usage: $progname [options] [RPMFILE ...]\n" . |
michael@428 | 73 | "Available options:\n" . |
michael@428 | 74 | " -v,--verbose enable verbose run-time mode\n" . |
michael@428 | 75 | " -h,--help print out this usage page\n" . |
michael@428 | 76 | " -c,--check=CHECKS select checks to perform (default='all')\n" . |
michael@428 | 77 | " -r,--rpm=FILE filesystem path to RPM program\n" . |
michael@428 | 78 | " -t,--tmpdir=PATH filesystem path to temporary directory\n" . |
michael@428 | 79 | " -V,--version print program version\n"; |
michael@428 | 80 | exit(0); |
michael@428 | 81 | } |
michael@428 | 82 | if ($version) { |
michael@428 | 83 | print "OpenPKG $progname $progvers\n"; |
michael@428 | 84 | exit(0); |
michael@428 | 85 | } |
michael@428 | 86 | |
michael@428 | 87 | # verbose message printing |
michael@428 | 88 | sub msg_verbose { |
michael@428 | 89 | my ($msg) = @_; |
michael@428 | 90 | print STDERR "$msg\n" if ($verbose); |
michael@428 | 91 | } |
michael@428 | 92 | |
michael@428 | 93 | # warning message printing |
michael@428 | 94 | sub msg_warning { |
michael@428 | 95 | my ($msg) = @_; |
michael@428 | 96 | print STDERR "$progname:WARNING: $msg\n"; |
michael@428 | 97 | } |
michael@428 | 98 | |
michael@428 | 99 | # error message printing |
michael@428 | 100 | sub msg_error { |
michael@428 | 101 | my ($msg) = @_; |
michael@428 | 102 | print STDERR "$progname:ERROR: $msg\n"; |
michael@428 | 103 | } |
michael@428 | 104 | |
michael@428 | 105 | # determine check list |
michael@428 | 106 | my @check_list = (qw( |
michael@428 | 107 | layout |
michael@428 | 108 | attrib |
michael@428 | 109 | content |
michael@428 | 110 | )); |
michael@428 | 111 | my @checks = (); |
michael@428 | 112 | if ($check eq 'all') { |
michael@428 | 113 | @checks = @check_list; |
michael@428 | 114 | } |
michael@428 | 115 | else { |
michael@428 | 116 | foreach my $c (split(/,/, $check)) { |
michael@428 | 117 | if (not grep(/^$c$/, @check_list)) { |
michael@428 | 118 | die "invalid check \"$c\""; |
michael@428 | 119 | } |
michael@428 | 120 | push(@checks, $c); |
michael@428 | 121 | } |
michael@428 | 122 | } |
michael@428 | 123 | |
michael@428 | 124 | # global return code |
michael@428 | 125 | $main::GRC = 0; |
michael@428 | 126 | |
michael@428 | 127 | # environment preparation |
michael@428 | 128 | system("rm -rf $tmpdir"); |
michael@428 | 129 | system("mkdir -p $tmpdir"); |
michael@428 | 130 | |
michael@428 | 131 | # iterate over all .rpm files |
michael@428 | 132 | foreach my $filename (@ARGV) { |
michael@428 | 133 | die "unable to open file \"$filename\" for reading" |
michael@428 | 134 | if (not -f $filename); |
michael@428 | 135 | my $info = &rpm_info($filename, \@checks); |
michael@428 | 136 | foreach my $check (@checks) { |
michael@428 | 137 | eval "\&check_$check(\$filename, \$info);"; |
michael@428 | 138 | } |
michael@428 | 139 | &rpm_info_cleanup($filename, \@checks, $info); |
michael@428 | 140 | } |
michael@428 | 141 | |
michael@428 | 142 | # environment cleanup |
michael@428 | 143 | system("rm -rf $tmpdir"); |
michael@428 | 144 | |
michael@428 | 145 | # die gracefully |
michael@428 | 146 | exit($main::GRC); |
michael@428 | 147 | |
michael@428 | 148 | ## _________________________________________________________________ |
michael@428 | 149 | ## |
michael@428 | 150 | ## COMMON SUBROUTINES |
michael@428 | 151 | ## _________________________________________________________________ |
michael@428 | 152 | ## |
michael@428 | 153 | |
michael@428 | 154 | sub lint_message { |
michael@428 | 155 | my ($type, $file, $msg) = @_; |
michael@428 | 156 | $file =~ s|^.+?/([^/]+)$|$1|s; |
michael@428 | 157 | printf(STDERR "%s:%s: %s: %s\n", $progname, $type, $file, $msg); |
michael@428 | 158 | } |
michael@428 | 159 | |
michael@428 | 160 | sub lint_warning { |
michael@428 | 161 | my ($file, $msg) = @_; |
michael@428 | 162 | &lint_message("WARNING", $file, $msg); |
michael@428 | 163 | $main::GRC = 1 if ($main::GRC < 1); |
michael@428 | 164 | } |
michael@428 | 165 | |
michael@428 | 166 | sub lint_error { |
michael@428 | 167 | my ($file, $msg) = @_; |
michael@428 | 168 | &lint_message("ERROR", $file, $msg); |
michael@428 | 169 | $main::GRC = 2 if ($main::GRC < 2); |
michael@428 | 170 | } |
michael@428 | 171 | |
michael@428 | 172 | ## _________________________________________________________________ |
michael@428 | 173 | ## |
michael@428 | 174 | ## RPM INFORMATION GATHERING |
michael@428 | 175 | ## _________________________________________________________________ |
michael@428 | 176 | ## |
michael@428 | 177 | |
michael@428 | 178 | sub rpm_info { |
michael@428 | 179 | my ($filename, $checks) = @_; |
michael@428 | 180 | my $info = {}; |
michael@428 | 181 | |
michael@428 | 182 | # query package name |
michael@428 | 183 | &msg_verbose("++ querying RPM package name"); |
michael@428 | 184 | $info->{name} = `$rpm -qp --qf '%{NAME}' $filename`; |
michael@428 | 185 | |
michael@428 | 186 | # query prefix |
michael@428 | 187 | &msg_verbose("++ querying RPM package installation prefix"); |
michael@428 | 188 | $info->{prefix} = `$rpm -qp --qf '%{PREFIXES}' $filename`; |
michael@428 | 189 | |
michael@428 | 190 | # query file listing |
michael@428 | 191 | &msg_verbose("++ querying RPM package file listing"); |
michael@428 | 192 | my @list = `$rpm -qplv $filename`; |
michael@428 | 193 | my @config = `$rpm -qplc $filename`; |
michael@428 | 194 | |
michael@428 | 195 | # process file listing |
michael@428 | 196 | $info->{ls} = {}; |
michael@428 | 197 | foreach my $entry (@list) { |
michael@428 | 198 | if ($entry =~ m|^\(contains no files\)\s*$|s) { |
michael@428 | 199 | next; |
michael@428 | 200 | } |
michael@428 | 201 | elsif ($entry =~ m|^(\S+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(.{12})\s+(.+)\s*$|s) { |
michael@428 | 202 | my ($perm, $links, $owner, $group, $size, $mtime, $path) = ($1, $2, $3, $4, $5, $6, $7); |
michael@428 | 203 | my $symlink = ""; |
michael@428 | 204 | if ($path =~ m|^(\S+)\s+->\s+(\S+)$|) { |
michael@428 | 205 | ($path, $symlink) = ($1, $2); |
michael@428 | 206 | } |
michael@428 | 207 | $path =~ s|\s+$||s; |
michael@428 | 208 | my $config = 0; |
michael@428 | 209 | if (grep(m|^$path$|, @config)) { |
michael@428 | 210 | $config = 1; |
michael@428 | 211 | } |
michael@428 | 212 | $info->{ls}->{$path} = { |
michael@428 | 213 | 'perm' => $perm, |
michael@428 | 214 | 'links' => $links, |
michael@428 | 215 | 'owner' => $owner, |
michael@428 | 216 | 'group' => $group, |
michael@428 | 217 | 'size' => $size, |
michael@428 | 218 | 'time' => $mtime, |
michael@428 | 219 | 'path' => $path, |
michael@428 | 220 | 'symlink' => $symlink, |
michael@428 | 221 | 'config' => $config, |
michael@428 | 222 | }; |
michael@428 | 223 | } |
michael@428 | 224 | else { |
michael@428 | 225 | &lint_error($filename, "invalid file listing entry: \"$entry\""); |
michael@428 | 226 | } |
michael@428 | 227 | } |
michael@428 | 228 | |
michael@428 | 229 | # unpacking files |
michael@428 | 230 | if (grep(/^content$/, @{$checks})) { |
michael@428 | 231 | &msg_verbose("++ unpacking RPM package files"); |
michael@428 | 232 | $info->{root} = "$tmpdir/root"; |
michael@428 | 233 | system("mkdir -p ".$info->{root}); |
michael@428 | 234 | system("$rpm2cpio $filename | (cd ".$info->{root}." && cpio -idmu 2>/dev/null)"); |
michael@428 | 235 | } |
michael@428 | 236 | |
michael@428 | 237 | return $info; |
michael@428 | 238 | } |
michael@428 | 239 | |
michael@428 | 240 | sub rpm_info_cleanup { |
michael@428 | 241 | my ($filename, $checks, $info) = @_; |
michael@428 | 242 | |
michael@428 | 243 | if (grep(/^content$/, @{$checks})) { |
michael@428 | 244 | system("rm -rf ".$info->{root}) if ($info->{root} =~ m/^\/.+/ and -d $info->{root}); |
michael@428 | 245 | } |
michael@428 | 246 | } |
michael@428 | 247 | |
michael@428 | 248 | ## _________________________________________________________________ |
michael@428 | 249 | ## |
michael@428 | 250 | ## CHECK "layout": file path layout |
michael@428 | 251 | ## _________________________________________________________________ |
michael@428 | 252 | ## |
michael@428 | 253 | |
michael@428 | 254 | sub check_layout { |
michael@428 | 255 | my ($rpm, $info) = @_; |
michael@428 | 256 | |
michael@428 | 257 | # no need to check 'openpkg' package because it |
michael@428 | 258 | # has a hard-coded file list! |
michael@428 | 259 | return if ($rpm =~ m|^(.+?/)?openpkg-\d[^/]+$|); |
michael@428 | 260 | |
michael@428 | 261 | # check prefix |
michael@428 | 262 | if ($info->{prefix} !~ m|^/.+$|) { |
michael@428 | 263 | &lint_error($rpm, "invalid installation prefix ".$info->{prefix}. |
michael@428 | 264 | " (expected to match \"^/.+\$\")"); |
michael@428 | 265 | return; |
michael@428 | 266 | } |
michael@428 | 267 | |
michael@428 | 268 | # check top-level path (all-in-one) |
michael@428 | 269 | my @topdirs = (qw( |
michael@428 | 270 | bin cgi etc include info lib libexec |
michael@428 | 271 | local man pub sbin share usr var |
michael@428 | 272 | )); |
michael@428 | 273 | my $topdirs = "{".join(",", @topdirs)."}"; |
michael@428 | 274 | if (not keys(%{$info->{ls}})) { |
michael@428 | 275 | &lint_error($rpm, "invalid empty package (expected at least one file)"); |
michael@428 | 276 | return; |
michael@428 | 277 | } |
michael@428 | 278 | foreach my $path (keys(%{$info->{ls}})) { |
michael@428 | 279 | my $ok = 0; |
michael@428 | 280 | foreach my $topdir (@topdirs) { |
michael@428 | 281 | my $prefix = quotemeta($info->{prefix} . "/" . $topdir); |
michael@428 | 282 | if ($path =~ m/^$prefix$/ && $rpm !~ m|^openpkg-\d+|) { |
michael@428 | 283 | &lint_error($rpm, "top-level directory \"$topdir\" provided" . |
michael@428 | 284 | " (expected none except for 'openpkg' package)"); |
michael@428 | 285 | } |
michael@428 | 286 | if ($path =~ m/^$prefix/) { |
michael@428 | 287 | $ok = 1; |
michael@428 | 288 | last; |
michael@428 | 289 | } |
michael@428 | 290 | } |
michael@428 | 291 | if (not $ok) { |
michael@428 | 292 | &lint_error($rpm, "invalid top-level directory in path \"$path\"". |
michael@428 | 293 | " (expected one of $topdirs)"); |
michael@428 | 294 | } |
michael@428 | 295 | } |
michael@428 | 296 | |
michael@428 | 297 | # check for second-level path (all-in-one) |
michael@428 | 298 | my @topdirs_subdir_no = (qw(bin cgi info sbin)); |
michael@428 | 299 | my @topdirs_subdir_yes = (qw(etc libexec share var)); |
michael@428 | 300 | foreach my $path (keys(%{$info->{ls}})) { |
michael@428 | 301 | foreach my $topdir (@topdirs_subdir_yes) { |
michael@428 | 302 | my $prefix = quotemeta($info->{prefix} . "/" . $topdir); |
michael@428 | 303 | if ($path =~ m/^$prefix\/[^\/]+$/) { |
michael@428 | 304 | if ($info->{ls}->{$path}->{perm} !~ m|^d|) { |
michael@428 | 305 | &lint_error($rpm, "invalid positioned file \"$path\" under topdir \"$topdir\" (expected directory)"); |
michael@428 | 306 | } |
michael@428 | 307 | } |
michael@428 | 308 | } |
michael@428 | 309 | foreach my $topdir (@topdirs_subdir_no) { |
michael@428 | 310 | my $prefix = quotemeta($info->{prefix} . "/" . $topdir); |
michael@428 | 311 | if ($path =~ m/^$prefix\/[^\/]+$/) { |
michael@428 | 312 | if ($info->{ls}->{$path}->{perm} =~ m|^d|) { |
michael@428 | 313 | &lint_error($rpm, "invalid positioned directory \"$path\" under topdir \"$topdir\" (expected file)"); |
michael@428 | 314 | } |
michael@428 | 315 | } |
michael@428 | 316 | } |
michael@428 | 317 | } |
michael@428 | 318 | |
michael@428 | 319 | # check "bin" and "sbin" directories |
michael@428 | 320 | foreach my $path (keys(%{$info->{ls}})) { |
michael@428 | 321 | foreach my $topdir (qw(bin sbin)) { |
michael@428 | 322 | my $prefix = quotemeta($info->{prefix} . "/" . $topdir); |
michael@428 | 323 | if ($path =~ m/^$prefix\/(.+)$/) { |
michael@428 | 324 | my $file = $1; |
michael@428 | 325 | if ($file =~ m|^[^/]+\.[^/.]+$|) { |
michael@428 | 326 | &lint_warning($rpm, "strange executable filename \"$path\" containing an extension (expected no extension)"); |
michael@428 | 327 | } |
michael@428 | 328 | my $perm = $info->{ls}->{$path}->{'perm'}; |
michael@428 | 329 | if ($perm =~ m|^-| && $perm !~ m|^-[-r][-w][sx][-r][-w][-sx][-r][-w][-tx]$|) { |
michael@428 | 330 | &lint_error($rpm, "non-executable file \"$path\" (with permissions \"$perm\" under topdir \"$topdir\" (expected to be executable)"); |
michael@428 | 331 | } |
michael@428 | 332 | } |
michael@428 | 333 | } |
michael@428 | 334 | } |
michael@428 | 335 | |
michael@428 | 336 | # check for symbolic link targets (outside absolute, dangling) |
michael@428 | 337 | foreach my $path (keys(%{$info->{ls}})) { |
michael@428 | 338 | my $symlink = $info->{ls}->{$path}->{'symlink'}; |
michael@428 | 339 | if ($symlink ne '') { |
michael@428 | 340 | # check for outside absolute target |
michael@428 | 341 | my $prefix = quotemeta($info->{prefix}); |
michael@428 | 342 | if ($symlink =~ m|^/.*| and $symlink !~ m|^$prefix|s) { |
michael@428 | 343 | &lint_warning($rpm, "symbolic link \"$path\" points to absolute path \"$symlink\" outside prefix \"$info->{prefix}\" (expected it to be under prefix only)"); |
michael@428 | 344 | } |
michael@428 | 345 | # check for dangling target |
michael@428 | 346 | my $resolved = &resolve($info, $path); |
michael@428 | 347 | sub resolve { |
michael@428 | 348 | my ($info, $path) = @_; |
michael@428 | 349 | if (not defined($info->{ls}->{$path})) { |
michael@428 | 350 | return $path; |
michael@428 | 351 | } |
michael@428 | 352 | my $symlink = $info->{ls}->{$path}->{'symlink'}; |
michael@428 | 353 | if ($symlink eq '') { |
michael@428 | 354 | return $path; |
michael@428 | 355 | } |
michael@428 | 356 | else { |
michael@428 | 357 | my $resolved; |
michael@428 | 358 | if ($symlink =~ m|^/|) { |
michael@428 | 359 | $resolved = $symlink; |
michael@428 | 360 | } |
michael@428 | 361 | else { |
michael@428 | 362 | $resolved = $path; |
michael@428 | 363 | $resolved =~ s|/[^/]+$||s; |
michael@428 | 364 | $resolved .= "/" . $symlink; |
michael@428 | 365 | $resolved =~ s|/{2,}|/|sg; |
michael@428 | 366 | $resolved =~ s|/\.(?=/)||sg; |
michael@428 | 367 | $resolved =~ s|/\.$||sg; |
michael@428 | 368 | 1 while ($resolved =~ s|/[^/]+/\.\./|/|s); |
michael@428 | 369 | $resolved =~ s|/[^/]+/\.\.$||s; |
michael@428 | 370 | $resolved =~ s|(.)/$|$1|s; |
michael@428 | 371 | } |
michael@428 | 372 | return &resolve($info, $resolved); |
michael@428 | 373 | } |
michael@428 | 374 | } |
michael@428 | 375 | if (not defined($info->{ls}->{$resolved})) { |
michael@428 | 376 | &lint_error($rpm, "symbolic link \"$path\" points to not existing target path \"$resolved\" (expected existing target path)"); |
michael@428 | 377 | } |
michael@428 | 378 | } |
michael@428 | 379 | } |
michael@428 | 380 | } |
michael@428 | 381 | |
michael@428 | 382 | ## _________________________________________________________________ |
michael@428 | 383 | ## |
michael@428 | 384 | ## CHECK "attrib": file attributes |
michael@428 | 385 | ## _________________________________________________________________ |
michael@428 | 386 | ## |
michael@428 | 387 | |
michael@428 | 388 | sub check_attrib { |
michael@428 | 389 | my ($rpm, $info) = @_; |
michael@428 | 390 | |
michael@428 | 391 | # check for empty files |
michael@428 | 392 | foreach my $path (keys(%{$info->{ls}})) { |
michael@428 | 393 | if ( $info->{ls}->{$path}->{'size'} == 0 |
michael@428 | 394 | and $info->{ls}->{$path}->{'perm'} !~ m|^d| |
michael@428 | 395 | and $path !~ m/^.*\/lib\/perl\/.+\.bs$/ |
michael@428 | 396 | and $rpm !~ m/\bopenpkg-[0-9]+/) { |
michael@428 | 397 | &lint_warning($rpm, "empty file \"$path\" found (expected no empty files)"); |
michael@428 | 398 | } |
michael@428 | 399 | } |
michael@428 | 400 | |
michael@428 | 401 | # check for %config flagged files |
michael@428 | 402 | my $prefix = quotemeta($info->{'prefix'}); |
michael@428 | 403 | my $name = quotemeta($info->{'name'}); |
michael@428 | 404 | foreach my $path (keys(%{$info->{ls}})) { |
michael@428 | 405 | my $config = $info->{ls}->{$path}->{'config'}; |
michael@428 | 406 | my $path = $info->{ls}->{$path}->{'path'}; |
michael@428 | 407 | if ($rpm !~ m/\bopenpkg-[0-9]+/ and $config and $path !~ m/^$prefix\/etc\/($name\d*|fsl)\/.+/) { |
michael@428 | 408 | &lint_warning($rpm, "non-config file \"$path\" flagged as \%config (expected only \"$prefix/etc/$name/*\" files to be \%config files)"); |
michael@428 | 409 | } |
michael@428 | 410 | if ($config and $path =~ m/^$prefix\/s?bin\/[^\/]+$/) { |
michael@428 | 411 | &lint_error($rpm, "executable file \"$path\" flagged as \%config"); |
michael@428 | 412 | } |
michael@428 | 413 | if ($config and $path =~ m/^$prefix\/etc\/rc\.d\/rc\.$name$/) { |
michael@428 | 414 | &lint_error($rpm, "run-command file \"$path\" flagged as \%config"); |
michael@428 | 415 | } |
michael@428 | 416 | } |
michael@428 | 417 | |
michael@428 | 418 | # check for permissions |
michael@428 | 419 | foreach my $path (keys(%{$info->{ls}})) { |
michael@428 | 420 | my $perm = $info->{ls}->{$path}->{'perm'}; |
michael@428 | 421 | if ($path =~ m/^$prefix\/(bin|sbin)\/[^\/]+$/) { |
michael@428 | 422 | if ($perm !~ m|^[^d]..[xs]..[xs]..[xt]$|) { |
michael@428 | 423 | &lint_warning($rpm, "executable file \"$path\" has permissions \"$perm\" only (expected it to be executable by everyone)"); |
michael@428 | 424 | } |
michael@428 | 425 | } |
michael@428 | 426 | } |
michael@428 | 427 | |
michael@428 | 428 | # TODO: user/group? |
michael@428 | 429 | } |
michael@428 | 430 | |
michael@428 | 431 | ## _________________________________________________________________ |
michael@428 | 432 | ## |
michael@428 | 433 | ## CHECK "content": file content |
michael@428 | 434 | ## _________________________________________________________________ |
michael@428 | 435 | ## |
michael@428 | 436 | |
michael@428 | 437 | sub check_content { |
michael@428 | 438 | my ($rpm, $info) = @_; |
michael@428 | 439 | |
michael@428 | 440 | # TODO: stripped (file) |
michael@428 | 441 | # TODO: syslibs (ldd) |
michael@428 | 442 | # TODO: hard-coded paths pointing outside instance |
michael@428 | 443 | # TODO: sanity check for shebang-lines |
michael@428 | 444 | # TODO: contained temporary path |
michael@428 | 445 | # TODO: bad-files: .po |
michael@428 | 446 | } |
michael@428 | 447 |