Vincent Danen <[EMAIL PROTECTED]> writes:

> Something like StackGuard+FormatGuard (from Immunix although I think
> they're quite out-dated) would be good (cover buffer overflows and
> format string vulns all at the same time).

the later should be covered if one check compiler output with modern
gcc.

i once again promote pixel "install deps, build it, check it and offer
to upload it" script that filter output and only output stderr thus
highlighting gcc warnings:
#!/usr/bin/perl

use MDK::Common;
use POSIX;

my $rpm = "rpm --nosignature";
my $rpmdir  = chomp_(`rpm --eval '%_topdir'`);
my $tmppath = chomp_(`rpm --eval '%_tmppath'`);

s|/$|| foreach $rpmdir, $tmppath;


if ($0 =~ /isrpms/i) {
    @ARGV == 1 or die "isrpms <package name>\n";
    my $srpm = previous_pkg('SRPMS', $ARGV[0]);
    print "installing $srpm\n";
    system("rpm -i $srpm");
    my $name = pkg_info($srpm)->{name};
    chdir "$rpmdir/SPECS";
    -e "$name.spec" or die "bad spec file name, missing $name.spec\n";
    system("emacsclient --no-wait $name.spec 2>/dev/null");
} elsif ($0 =~ /compare/i) {
    @ARGV or die "Compare_package_files <rpm file>\n";
    foreach (@ARGV) {
        my $info = pkg_info($_);
        my $previous = previous_pkg('RPMS', $info->{name});
        compare_package_files($info, $previous);
    }
} else {
    goto upload;
}
exit 0;

upload:
my $short_circuit = $ARGV[0] eq '--short-circuit' && shift(@ARGV);
my ($q_spec) = @ARGV;
if ($q_spec =~ /\.src\.rpm$/) {
    system("rpm", "-i", $q_spec) == 0 or die "bad srpm $q_spec\n";
    ($q_spec) = `$rpm -qpl $q_spec` =~ /(.*)\.spec$/m or internal_error("missing 
spec");
}
-e $q_spec or $q_spec = "$rpmdir/SPECS/$q_spec.spec";
-e $q_spec && @ARGV == 1 or die "Upload <spec file>\n";

my $spec = basename($q_spec);
my $buildlog = "$tmppath/.upload-$spec";

$| = 1;
system("chmod", "644", $q_spec, grep { -f $_ } glob_("$rpmdir/SOURCES/*"));

if (system("rpmbuild -bs $q_spec > $buildlog") != 0) {
    system("rpmbuild -bs $q_spec > /dev/null 2> $buildlog");
    if (my @deps_needed = cat_($buildlog) =~ /^\s+(\S+)\s+.*is needed by/gm) {
        foreach (@deps_needed) {
            system("sudo ue -u $_");
            system("sudo ue -c $_");
        }
        warn "Waiting for @deps_needed to be installed\n";
        sleep 120;
    }
    if (my @deps_conflict = cat_($buildlog) =~ /^\s+(\S+)\s+.*conflicts with/gm) {
        @deps_conflict = map { chomp_(`rpm -q --whatprovides --qf '%{name}\n' $_`) } 
@deps_conflict;
        print STDERR "There are conflicting packages.\nRemove packages @deps_conflict 
(Y/n) ?";
        <STDIN> !~ /n/i or exit 0;

        system("sudo ue -e $_") foreach @deps_conflict;
        warn "Waiting for @deps_conflict to be removed\n";
        sleep 120;
    }
    system("rpmbuild -bs $q_spec > $buildlog") == 0 or die "rpmbuild -bs $spec 
failed\n";
}
my ($srpm) = map { if_(/^Wrote: (.*)/, $1) } cat_($buildlog);

my $info = pkg_info($srpm);
my $previous_srpm = eval { previous_pkg('SRPMS', $info->{name}, 
"$info->{name}-$info->{version}") };
my $previous = $previous_srpm && pkg_info($previous_srpm);

my $cooker_or_contrib;
if ($previous_srpm) {
    $info->{version} eq $previous->{version} && $info->{release} eq 
$previous->{release} 
      and die "ERROR: package $info->{name} already exists in cooker 
($previous_srpm)\ndid you increase the release number?\n";

    if ($previous_srpm =~ m|mandrake/uploads|) {
        print "package $info->{name} is already in the upload queue 
($previous_srpm)\n";
        print "continue anyway (y/N)? ";
        <STDIN> =~ /^y/i or exit 1;
    }
    $cooker_or_contrib = $previous_srpm =~ m|contrib/| ? 'contrib' : 'cooker';
}

while (!$cooker_or_contrib) {
    print($previous_srpm ? "Weird, $info->{name} is both in contrib and main" : 
"$info->{name} is neither in contrib nor main");
    print ", what do you choose (contrib/cooker)? ";
    my $r = <STDIN>;
    $cooker_or_contrib = 'contrib' if $r =~ /con/i;
    $cooker_or_contrib = 'cooker' if $r =~ /coo/i;
    $cooker_or_contrib or print qq(Bad answer, please type "cooker" or "contrib"\n");
};

if ($short_circuit) {
    print "installing...\n";
    system("rpmbuild -bi --short-circuit $q_spec > $buildlog") == 0 or die "rpmbuild 
-bi --short-circuit $spec failed\n";
    system("rpmbuild -bb --short-circuit $q_spec >> $buildlog") == 0 or die "rpmbuild 
-bb --short-circuit $spec failed\n";
} else {
    print "building...\n";
    system("rpmbuild -bb $q_spec > $buildlog") == 0 or die "rpmbuild -bb $spec 
failed\n";
}
my @rpms = map { pkg_info($_) } map { if_(/^Wrote: (.*)/, $1) } cat_($buildlog);

if ($previous_srpm) {
    @rpms = compare_package_files($previous, @rpms);
    compare_package_requires($previous, @rpms);
    compare_package_provides($previous, @rpms);
} else {
    if (any { $_->{name} =~ /-debug$/ } @rpms) {
        print "Do you want to upload $info->{name}-debug (the debug version) (y/N)? ";
        if (<STDIN> !~ /^y/i) {
            @rpms = grep { $_->{name} !~ /-debug$/ } @rpms;
        }
    }
}

{
    my $rpms = join(" ", map { $_->{file} } @rpms);
    if (my $s = `rpmlint $srpm $rpms`) {
        print "rpmlint 
***********************************************************************\n";
        print $s;
    }
}

print 
"*******************************************************************************\n";
print "test package" . (@rpms > 1 ? 's' : '') . ' ' . join(', ', map { 
"$_->{name}-$_->{release}" } @rpms) . "\n";
print "then press <enter> to upload to $cooker_or_contrib (or <ctrl-C> to abort)\n";
<STDIN>;

print "ftp$cooker_or_contrib...\n";
system("sudo", "ftp$cooker_or_contrib", $srpm, map { $_->{file} } @rpms) == 0 or die 
"$cooker_or_contrib failed\n";

system("rpmbuild --clean --rmsource --nodeps $q_spec");
system("rm -f $q_spec $q_spec.old $buildlog");


sub pkg_info {
    my ($srpm) = @_;
    my ($name, $version, $release) = split ' ', `$rpm -qp --qf '%{name} %{version} 
%{release}' $srpm`;
    (my $rpmdir = dirname($srpm)) =~ s/SRPMS/RPMS/;
    { name => $name, version => $version, release => $release, rpmdir => $rpmdir, file 
=> $srpm };
}

sub previous_pkg {
    my ($rpm_or_srpm, $name, $o_q_name) = @_;
    my @dirs = map { "$_$rpm_or_srpm" } qw(/home/mandrake/uploads/cooker/ 
/home/mandrake/uploads/contrib/ / /contrib/);
    foreach (if_($o_q_name, @dirs)) {
        my @l = glob("$_/$o_q_name-*.rpm") or next;
        return keep_the_one($name, @l);
    }
    if (my @l = (map { glob("$_/$name-*.rpm") } @dirs)) {
        return keep_the_one($name, @l);
    }
    die "no existing package named $name\n";
}

sub keep_the_one {
    my ($name, @l) = @_;

    @l = grep { `$rpm -qp --queryformat "%{name}" $_` eq $name } @l if @l > 1;

    if (@l == 1) {
        return $l[0];
    } elsif (@l) {
        die "more than one package is named $name: " . join(" ", @l) . "\n";
    } else {
        die "no existing package named $name\n";
    }
}

my $package_files_banner_displayed;
sub compare_one_package_files {
    my ($rpm_info, $previous_rpm) = @_;

    my @new = `$rpm -qpl $rpm_info->{file}`;
    my @old = `$rpm -qpl $previous_rpm`;
    @old = map { moved_files($_) } @old;
    @old || $rpm_info->{name} !~ /-debug$/ or return;

    compare_lists('files', $rpm_info, [EMAIL PROTECTED], [EMAIL PROTECTED]);

    check_bad_files($_) foreach @new;
    1;
}

sub compare_package_files {
    my ($previous, @rpms) = @_;

    grep {
        my $previous_rpm = 
"$previous->{rpmdir}/$_->{name}-$previous->{version}-$previous->{release}*.rpm";
        if (compare_one_package_files($_, $previous_rpm)) {
            1;
        } else {
            unlink $_->{file};
            0;
        }
    } @rpms;
}

sub compare_package_requires {
    my ($previous, @rpms) = @_;

    foreach my $rpm_info (@rpms) {
        my $previous_rpm = 
"$previous->{rpmdir}/$rpm_info->{name}-$previous->{version}-$previous->{release}*.rpm";

        my $non_interesting_requires = sub {
            /^\Qld-linux.so.2/;
        };
        my @new = grep { !$non_interesting_requires->() } `$rpm -qp --requires 
$rpm_info->{file}`;
        my @old = grep { !$non_interesting_requires->() } `$rpm -qp --requires 
$previous_rpm`;
        compare_lists('requires', $rpm_info, [EMAIL PROTECTED], [EMAIL PROTECTED]);
    }
}

sub compare_package_provides {
    my ($previous, @rpms) = @_;

    foreach my $rpm_info (@rpms) {
        my $previous_rpm = 
"$previous->{rpmdir}/$rpm_info->{name}-$previous->{version}-$previous->{release}*.rpm";

        my $non_interesting_provides = sub {
            /\Q$rpm_info->{name} = /;
        };
        my @new = grep { !$non_interesting_provides->() } `$rpm -qp --provides 
$rpm_info->{file}`;
        my @old = grep { !$non_interesting_provides->() } `$rpm -qp --provides 
$previous_rpm`;
        compare_lists('provides', $rpm_info, [EMAIL PROTECTED], [EMAIL PROTECTED]);
    }
}

my %banner_displayed;
sub compare_lists {
    my ($name, $rpm_info, $new, $old) = @_;

    $new = join('', sort @$new);
    $old = join('', sort @$old);

    $new ne $old or return 1;

    my $olddir = POSIX::getcwd();
    chdir $rpmdir;
    output("$rpm_info->{name}--$name.new", $new);
    output("$rpm_info->{name}--$name.old", $old);
    print "compare package $name 
*********************************************************\n" if 
!$banner_displayed{$name}++;
    system("diff -u $rpm_info->{name}--$name.old $rpm_info->{name}--$name.new");
    unlink "$rpm_info->{name}--$name.old", "$rpm_info->{name}--$name.new";
    chdir $olddir;
    0;
}

sub moved_files {
    local ($_) = @_;
    s|site_perl|vendor_perl|;
    s|5.6.1|5.8.1|;
    s|5.8.0|5.8.1|;
    s|python2.2|python2.3|;
    s|/man3pm/|/man3/|;
    s|/i386-linux/|/i386-linux-thread-multi/|;
    $_;
}

sub check_bad_files {
    local ($_) = @_;
    my $ok = 1;
    chomp;
    m|/site_perl/| and warn("ERROR: bad file $_\n"), $ok = 0;
    $ok;
}

Reply via email to