OpenPKG CVS Repository
  http://cvs.openpkg.org/
  ____________________________________________________________________________

  Server: cvs.openpkg.org                  Name:   Ralf S. Engelschall
  Root:   /e/openpkg/cvs                   Email:  [EMAIL PROTECTED]
  Module: openpkg-re                       Date:   04-Jul-2003 19:04:45
  Branch: HEAD                             Handle: 2003070418044400

  Added files:
    openpkg-re              rpmlint.pl

  Log:
    first cut for a .rpm file lint

  Summary:
    Revision    Changes     Path
    1.1         +345 -0     openpkg-re/rpmlint.pl
  ____________________________________________________________________________

  patch -p0 <<'@@ .'
  Index: openpkg-re/rpmlint.pl
  ============================================================================
  $ cvs diff -u -r0 -r1.1 rpmlint.pl
  --- /dev/null 2003-07-04 19:04:45.000000000 +0200
  +++ rpmlint.pl        2003-07-04 19:04:45.000000000 +0200
  @@ -0,0 +1,345 @@
  +#!/bin/sh -- # -*- perl -*-
  +eval 'exec perl -S $0 ${1+"$@"}'
  +    if $running_under_some_shell;
  +##
  +##  rpmlint -- OpenPKG .rpm File Checker
  +##  Copyright (c) 2003 The OpenPKG Project <http://www.openpkg.org/>
  +##  Copyright (c) 2003 Ralf S. Engelschall <[EMAIL PROTECTED]>
  +##  Copyright (c) 2003 Cable & Wireless <http://www.cw.com/>
  +##
  +##  Permission to use, copy, modify, and distribute this software for
  +##  any purpose with or without fee is hereby granted, provided that
  +##  the above copyright notice and this permission notice appear in all
  +##  copies.
  +##
  +##  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  +##  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  +##  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  +##  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
  +##  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  +##  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  +##  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  +##  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  +##  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  +##  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  +##  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  +##  SUCH DAMAGE.
  +##
  +
  +require 5;
  +use Getopt::Long;
  +use IO;
  +use strict;
  +
  +#   program information
  +my $progname = "rpmlint";
  +my $progvers = "0.0.1";
  +
  +#   parameters (defaults)
  +my $version  = 0;
  +my $verbose  = 0;
  +my $help     = 0;
  +my $check    = 'all';
  +my $tmpdir   = ($ENV{TMPDIR} || $ENV{TEMPDIR} || "/tmp") . "/$progname";
  +my $rpm      = 'rpm';
  +my $rpm2cpio = 'rpm2cpio';
  +
  +#   exception handling support 
  +$SIG{__DIE__} = sub {
  +    my ($err) = @_;
  +    $err =~ s|\s+at\s+.*||s if (not $verbose);
  +    print STDERR "$progname:ERROR: $err ". ($! ? "($!)" : "") . "\n";
  +    exit(1);
  +};
  +
  +#   command line parsing
  +Getopt::Long::Configure("bundling");
  +my $result = GetOptions(
  +    'V|version'     => \$version,
  +    'v|verbose'     => \$verbose,
  +    'h|help'        => \$help,
  +    'c|check=s'     => \$check,
  +    't|tmpdir=s'    => \$tmpdir,
  +    'r|rpm=s'       => \$rpm,
  +) || die "option parsing failed";
  +if ($help) {
  +    print "Usage: $progname [options] [RPMFILE ...]\n" .
  +          "Available options:\n" .
  +          " -v,--verbose       enable verbose run-time mode\n" .
  +          " -h,--help          print out this usage page\n" .
  +          " -c,--check=CHECKS  select checks to perform (default='all')\n" .
  +          " -r,--rpm=FILE      filesystem path to RPM program\n" .
  +          " -t,--tmpdir=PATH   filesystem path to temporary directory\n" .
  +          " -V,--version       print program version\n" .
  +    exit(0);
  +}
  +if ($version) {
  +    print "OpenPKG $progname $progvers\n";
  +    exit(0);
  +}
  +
  +#   verbose message printing
  +sub msg_verbose {
  +    my ($msg) = @_;
  +    print STDERR "$msg\n" if ($verbose);
  +}
  +
  +#   warning message printing
  +sub msg_warning {
  +    my ($msg) = @_;
  +    print STDERR "$progname:WARNING: $msg\n";
  +}
  +
  +#   error message printing
  +sub msg_error {
  +    my ($msg) = @_;
  +    print STDERR "$progname:ERROR: $msg\n";
  +}
  +
  +#   determine check list
  +my @check_list = (qw(
  +    layout
  +    attrib
  +    content
  +));
  +my @checks = ();
  +if ($check eq 'all') {
  +    @checks = @check_list;
  +}
  +else {
  +    foreach my $c (split(/,/, $check)) {
  +        if (not grep(/^$c$/, @check_list)) {
  +            die "invalid check \"$c\"";
  +        }
  +        push(@checks, $c);
  +    }
  +}
  +
  +#   global return code
  +$main::GRC = 0;
  +
  +#   environment preparation
  +system("rm -rf $tmpdir");
  +system("mkdir -p $tmpdir");
  +
  +#   iterate over all .spec files
  +foreach my $filename (@ARGV) {
  +    die "unable to open file \"$filename\" for reading"
  +        if (not -f $filename);
  +    my $info = &rpm_info($filename, [EMAIL PROTECTED]);
  +    foreach my $check (@checks) {
  +        eval "\&check_$check(\$filename, \$info);";
  +    }
  +}
  +
  +#   environment cleanup
  +system("rm -rf $tmpdir");
  +
  +#   die gracefully
  +exit($main::GRC);
  +
  +##  _________________________________________________________________
  +##
  +##  COMMON SUBROUTINES
  +##  _________________________________________________________________
  +##
  +
  +sub lint_message {
  +    my ($type, $file, $msg) = @_;
  +    $file =~ s|^.+?/([^/]+)$|$1|s;
  +    printf(STDERR "%s:%s: %s: %s\n", $progname, $type, $file, $msg);
  +}
  +
  +sub lint_warning {
  +    my ($file, $msg) = @_;
  +    &lint_message("WARNING", $file, $msg);
  +    $main::GRC = 1 if ($main::GRC < 1);
  +}
  +
  +sub lint_error {
  +    my ($file, $msg) = @_;
  +    &lint_message("ERROR", $file, $msg);
  +    $main::GRC = 2 if ($main::GRC < 2);
  +}
  +
  +##  _________________________________________________________________
  +##
  +##  RPM INFORMATION GATHERING
  +##  _________________________________________________________________
  +##
  +
  +sub rpm_info {
  +    my ($filename, $checks) = @_;
  +    my $info = {};
  +
  +    #   query prefix
  +    &msg_verbose("++ querying RPM package installation prefix");
  +    $info->{prefix} = `$rpm -qp --qf '%{PREFIXES}' $filename`;
  +
  +    #   query file listing
  +    &msg_verbose("++ querying RPM package file listing");
  +    my @list = `$rpm -qplv $filename`;
  +    my @config = `$rpm -qplc $filename`;
  +
  +    #   process file listing
  +    $info->{ls} = {};
  +    foreach my $entry (@list) {
  +        if ($entry =~ m|^\(contains no files\)\s*$|s) {
  +            next;
  +        }
  +        elsif ($entry =~ 
m|^(\S+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\d+)\s+(.{12})\s+(.+)\s*$|s) {
  +            my ($perm, $links, $owner, $group, $size, $mtime, $path) = ($1, $2, $3, 
$4, $5, $6, $7);
  +            my $symlink = "";
  +            if ($path =~ m|^(\S+)\s+->\s+(\S+)$|) {
  +                ($path, $symlink) = ($1, $2);
  +            }
  +            $path =~ s|\s+$||s;
  +            my $config = 0;
  +            if (grep(m|^$path$|, @config)) {
  +                $config = 1;
  +            }
  +            $info->{ls}->{$path} = {
  +                'perm'    => $perm,
  +                'links'   => $links,
  +                'owner'   => $owner,
  +                'group'   => $group,
  +                'size'    => $size,
  +                'time'    => $mtime,
  +                'path'    => $path,
  +                'symlink' => $symlink,
  +                'config'  => $config,
  +            };
  +        }
  +        else {
  +            &lint_error($filename, "invalid file listing entry: \"$entry\"");
  +        }
  +    }
  +
  +    #  unpacking files
  +    if (grep(/^content$/, @checks)) {
  +        &msg_verbose("++ unpacking RPM package files");
  +        $info->{root} = "$tmpdir/root"; 
  +        system("mkdir -p ".$info->{root});
  +        system("$rpm2cpio $filename | (cd ".$info->{root}." && cpio -idmu 
2>/dev/null)");
  +    }
  +
  +    return $info;
  +}
  +
  +##  _________________________________________________________________
  +##
  +##  CHECK "layout": file path layout
  +##  _________________________________________________________________
  +##
  +
  +sub check_layout {
  +    my ($rpm, $info) = @_;
  +
  +    #   no need to check 'openpkg' package because it
  +    #   has a hard-coded file list!
  +    return if ($rpm =~ m|^openpkg-\d+|);
  +
  +    #   check prefix
  +    if ($info->{prefix} !~ m|^/.+$|) {
  +        &lint_error($rpm, "invalid installation prefix ".$info->{prefix}.
  +                    " (expected to match \"^/.+\$\")");
  +        return;
  +    }
  +
  +    #   check top-level path (all-in-one)
  +    my @topdirs = (qw(
  +        bin cgi etc include info lib libexec
  +        local man pub sbin share usr var
  +    ));
  +    my $topdirs = "{".join(",", @topdirs)."}";
  +    if (not keys(%{$info->{ls}})) {
  +        &lint_error($rpm, "invalid empty package (expected at least one file)");
  +        return;
  +    }
  +    foreach my $path (keys(%{$info->{ls}})) {
  +        my $ok = 0;
  +        foreach my $topdir (@topdirs) {
  +            my $prefix = quotemeta($info->{prefix} . "/" . $topdir);
  +            if ($path =~ m/^$prefix$/ && $rpm !~ m|^openpkg-\d+|) {
  +                &lint_error($rpm, "top-level directory \"$topdir\" provided" .
  +                            " (expected none except for 'openpkg' package)");
  +            }
  +            if ($path =~ m/^$prefix/) {
  +                $ok = 1;
  +                last;
  +            }
  +        }
  +        if (not $ok) {
  +            &lint_error($rpm, "invalid top-level directory in path \"$path\"".
  +                       " (expected one of $topdirs)");
  +        }
  +    }
  +
  +    #   check for second-level path (all-in-one)
  +    my @topdirs_subdir_no  = (qw(bin cgi info sbin));
  +    my @topdirs_subdir_yes = (qw(etc libexec share var));
  +    foreach my $path (keys(%{$info->{ls}})) {
  +        foreach my $topdir (@topdirs_subdir_yes) {
  +            my $prefix = quotemeta($info->{prefix} . "/" . $topdir);
  +            if ($path =~ m/^$prefix\/[^\/]+$/) {
  +                if ($info->{ls}->{$path}->{perm} !~ m|^d|) {
  +                    &lint_error($rpm, "invalid positioned file \"$path\" under 
topdir \"$topdir\" (expected directory)");
  +                }
  +            }
  +        }
  +        foreach my $topdir (@topdirs_subdir_no) {
  +            my $prefix = quotemeta($info->{prefix} . "/" . $topdir);
  +            if ($path =~ m/^$prefix\/[^\/]+$/) {
  +                if ($info->{ls}->{$path}->{perm} =~ m|^d|) {
  +                    &lint_error($rpm, "invalid positioned directory \"$path\" under 
topdir \"$topdir\" (expected file)");
  +                }
  +            }
  +        }
  +    }
  +
  +    #   check "bin" and "sbin" directories
  +    foreach my $path (keys(%{$info->{ls}})) {
  +        foreach my $topdir (qw(bin sbin)) {
  +            my $prefix = quotemeta($info->{prefix} . "/" . $topdir);
  +            if ($path =~ m/^$prefix\/(.+)$/) {
  +                my $file = $1;
  +                if ($file =~ m|^[^/]+\.[^/.]+$|) {
  +                    &lint_warning($rpm, "strange executable filename \"$path\" 
containing an extension (expected no extension)");
  +                }
  +                my $perm = $info->{ls}->{$path}->{'perm'};
  +                if ($perm =~ m|^-| && $perm !~ m|^-([-r][-w][sx]){3}$|) {
  +                    &lint_error($rpm, "non-executable file \"$path\" under topdir 
\"$topdir\" (expected to be executable)");
  +                }
  +            }
  +        }
  +    }
  +}
  +
  +##  _________________________________________________________________
  +##
  +##  CHECK "attrib": file attributes
  +##  _________________________________________________________________
  +##
  +
  +sub check_attrib {
  +    my ($rpm, $info) = @_;
  +
  +    #   permissions
  +    #   user/group
  +    #   size
  +    #   %config flag
  +}
  +
  +##  _________________________________________________________________
  +##
  +##  CHECK "content": file content
  +##  _________________________________________________________________
  +##
  +
  +sub check_content {
  +    my ($rpm, $info) = @_;
  +
  +    #   stripped (file)
  +    #   syslibs (ldd)
  +}
  +
  @@ .
______________________________________________________________________
The OpenPKG Project                                    www.openpkg.org
CVS Repository Commit List                     [EMAIL PROTECTED]

Reply via email to