#!/usr/bin/perl use strict; use IO::Socket; # this is the master data structure for our runtime DB, which is: # {(PACKAGE, VERSION, RELEASE, OS, ARCH, SIZE, FILE, SRC, PKGSIZE, SRCSIZE, (DEPS), ACTION)} my %package_db; # Global Defines my %gconfig; $gconfig{RPMS_LOC}="cdrom"; # currently can be 'cdrom' or 'http' $gconfig{REMOTEHOST}="www.tru64unix.compaq.com"; $gconfig{REMOTEPORT}="80"; $gconfig{REMOTEPATH}="/demos/ossc"; $gconfig{PROXYHOST}=""; $gconfig{PROXYPORT}=""; $gconfig{CDROMPATH}="/mnt"; $gconfig{TACHDIR}="/var/tachometer"; $gconfig{PKGDIR}="packages"; $gconfig{PKGLIST}="packages.idx.gz"; $gconfig{QUIET} = 0; $gconfig{ASSUME_YES} = 0; # necessary application paths my $RPM="/usr/local/bin/rpm"; my $GZCAT="/usr/bin/gzcat"; my $PERL="/usr/bin/perl"; # Database column numbers my $PACKAGE_COL=0; my $VERSION_COL=1; my $RELEASE_COL=2; my $OS_COL=3; my $ARCH_COL=4; my $SIZE_COL=5; my $FILE_COL=6; my $SRC_COL=7; my $PKGSIZE_COL=8; my $SRCSIZE_COL=9; my $DEPS_COL=10; my $ACTION_COL=11; sub read_package_db { my ($path, $package_file) = @_; # a few packages requires different perl versions. # our in-memory DB is built to work with either one my $perl_version = check_perl_version(); open(PKGFILE, "$GZCAT $path/$package_file | sort |") || die "Could not open package database."; while() { chomp($_); my @db_record = split(/:/, $_); my @deps; if(defined($db_record[$DEPS_COL])) { @deps = split(/,/, $db_record[$DEPS_COL]); } $db_record[$DEPS_COL] = \@deps; $db_record[$ACTION_COL] = "-"; if(!($db_record[$VERSION_COL] =~ /perl/)) { # since it appears perl is not a factor with this package, # it is added to the DB $package_db{$db_record[$PACKAGE_COL]} = \@db_record; } elsif($db_record[$VERSION_COL] =~ /$perl_version/) { # if, and only if, the perl versions match do we add # this package to our in-memory database $package_db{$db_record[$PACKAGE_COL]} = \@db_record; } } close(PKGFILE); } sub check_perl_version { my $version=`$PERL -V:version`; # It would be nice to simply use the Perl special variable $] # but it does not return the version of perl consistent with # how some of the OSSC packages are named (i.e. perl5.6.0 has # '5.006' as the $] variable. $version =~ s/version=\'//; $version =~ s/\'\;\n//; $version = substr($version, 0, 5); return $version; } sub comp_versions { my ($first_version, $second_version) = @_; if($first_version eq $second_version) { return 0; } my @first_version = split(/\./, $first_version); my @second_version = split(/\./, $second_version); my $first = shift(@first_version); my $second = shift(@second_version); while(defined($first) && defined($second)) { # the following line takes care of lines which dependency version strings # as in xchat-1.2.1.perl5.6.0-4 (it ignores from alpha chars onward). # This is, at best, a hack to get around 2 different versions of Perl # (which is the only reason a package should be listed twice in our simple DB). $first =~ s/[a-zA-Z]+.*//g; $second =~ s/[a-zA-Z]+.*//g; if($first eq "" || $second eq "") { last; } if($first > $second) { return -1; } elsif($first < $second) { return 1; } $first = shift(@first_version); $second = shift(@second_version); } if($first ne "") { return -1; } elsif($second ne "") { return 1; } return 0; } sub comp_releases { my ($first_release, $second_release) = @_; if($first_release > $second_release) { return -1; } elsif($first_release < $second_release) { return 1; } else { return 0; } } sub determine_action { my ($package_name) = @_; my $do_install = 0; # these 5 lines account for situations where 2 packages provide the same # functionality our database (like imlib and imlib-16bit) and one is already # installed. my $installed_package=`$RPM -q --whatprovides $package_name 2>/dev/null`; if($installed_package ne "") { chomp($installed_package); } else { $installed_package = $package_name; } my $installed_version=`$RPM -q $installed_package --queryformat "%{VERSION}" 2>/dev/null`; my $db_version = $package_db{$package_name}->[$VERSION_COL]; if($installed_version ne "") { $do_install = comp_versions($installed_version, $db_version); if($do_install <= 0) { my $installed_release=`$RPM -q $installed_package --queryformat "%{RELEASE}" 2>/dev/null`; my $db_release = $package_db{$package_name}->[$RELEASE_COL]; $do_install = comp_releases($installed_release, $db_release); } } else { # this is the special case where the queried record is not yet installed $do_install = 2; } return $do_install; } sub download_file { my ($rpmhost, $rpmport, $filepath, $downloadpath, $filename, $blocksize) = @_; my $localfile = $filename; my $bytes_read = 0; my $prepend = ""; my $readbuf = ""; my $sock; $localfile =~ s/^.*\///g; if( ! -d $downloadpath ) { system("mkdir -p $downloadpath"); } open(OUTFILE, ">$downloadpath/$localfile.tmp") || die "Could not open: $!"; if($gconfig{PROXYHOST} && $gconfig{PROXYPORT}) { $sock = IO::Socket::INET->new( PeerAddr => $gconfig{PROXYHOST}, PeerPort => $gconfig{PROXYPORT}, Proto => 'tcp', ) || print "Error: $!\n"; $prepend = "http://$rpmhost:$rpmport"; } else { $sock = IO::Socket::INET->new( PeerAddr => $rpmhost, PeerPort => $rpmport, Proto => 'tcp', ) || print "Error: $!\n"; } if($sock == 1) { close($sock); close(OUTFILE); unlink("$downloadpath/$localfile.tmp"); return -1; } $sock->autoflush(1); print $sock "GET $prepend$filepath/$filename HTTP/1.0\n\n"; my $statusbuf = ""; my $lastbuf = ""; my $ret_val = recv($sock, $readbuf, 1, 0); while(1) { # we explicitely break out of this loop if(!defined($ret_val)) { print "Error receiving file: $!" && return -1; } $statusbuf .= $readbuf; if($readbuf eq "\n" && $lastbuf eq "\r") { last; } $lastbuf = $readbuf; $ret_val = recv($sock, $readbuf, 1, 0); } # now we check status! if(!($statusbuf =~ / 200 /)) { chomp($statusbuf); print "\n\tError with $filepath/$filename:\n\t$statusbuf\n"; close($sock); close(OUTFILE); unlink("$downloadpath/$localfile.tmp"); return -1; } while(1) { # we explicitely break out of this loop if(!defined($ret_val)) { print "Error receiving file: $!" && return -1; } if($readbuf eq "\r" && $lastbuf eq "\n") { $ret_val = recv($sock, $readbuf, 1, 0); # pull the remain \r off the recv buffer last; } $lastbuf = $readbuf; $ret_val = recv($sock, $readbuf, 1, 0); } my $ofh = select STDOUT; $| = 1; select $ofh; $ret_val = recv($sock, $readbuf, 512, 0); while($readbuf) { if(!defined($ret_val)) { print "Error receiving file: $!" && return -1; } $bytes_read += length($readbuf); while($bytes_read > $blocksize) { print "#" unless($gconfig{QUIET}); $bytes_read -= $blocksize; } print OUTFILE $readbuf; $ret_val = recv($sock, $readbuf, 512, 0); } close($sock); close(OUTFILE); if(!(rename("$downloadpath/$localfile.tmp", "$downloadpath/$localfile"))) { return -1; } else { return 0; } } sub build_action_table { my ($is_upgrade) = shift(); my $package_name = ""; my $dependencies = ""; my $dependency = ""; my $db_record = ""; my $do_install = 0; my $ret_val = 0; foreach $package_name (@_) { if(defined($package_db{$package_name})) { # if we have already seen this DB entry, skip it if($package_db{$package_name}->[$ACTION_COL] ne "-") { next; } $do_install = determine_action($package_name); if($is_upgrade == 1 && $do_install == 2) { #package is not installed yet $do_install = 0; # since this is an upgrade, we don't add new packages } if($do_install == 0) { $package_db{$package_name}->[$ACTION_COL] = "n"; } elsif($do_install == 1) { $package_db{$package_name}->[$ACTION_COL] = "u"; } elsif($do_install == 2) { $package_db{$package_name}->[$ACTION_COL] = "i"; } } else { print "There is no package '$package_name' in the database.\n"; return -1; } # we only step down the dependency tree of this package if it is # going to be installed if($do_install > 0) { $dependencies = $package_db{$package_name}->[$DEPS_COL]; if(defined($dependencies) && scalar(@{$dependencies}) > 0) { foreach $dependency (@{$dependencies}) { $ret_val = build_action_table(0, $dependency); if($ret_val < 0) { return $ret_val; } } } } # reset the install flag $do_install = 0; } return $ret_val; } sub build_removal_table { my $package_name = ""; my $dependant = ""; my $dependency = ""; my @dependants; foreach $package_name (@_) { if(defined($package_db{$package_name})) { # if we have already seen this DB entry, skip it if($package_db{$package_name}->[$ACTION_COL] ne "-") { next; } $package_db{$package_name}->[$ACTION_COL] = "r"; foreach $dependant (keys(%package_db)) { if(defined($package_db{$dependant}->[$DEPS_COL])) { foreach $dependency (@{$package_db{$dependant}->[$DEPS_COL]}) { if($dependency eq $package_name) { push(@dependants, $dependant); last; } } } } } else { print "There is no package '$package_name' in the database.\n"; return -1; } } if(scalar(@dependants) > 0) { return build_removal_table(@dependants); } else { return 0; } } sub print_status { my ($install_listp, $upgrade_listp, $remove_listp, $total_download_kb, $total_install_kb, $total_remove_kb) = @_; my $flag = 0; if($gconfig{QUIET}) { if(scalar(@{$install_listp}) > 0 || scalar(@{$upgrade_listp}) > 0 || scalar(@{$remove_listp}) > 0) { return 0; } else { return -1; } } if(scalar(@{$install_listp}) > 0) { print "The following packages will be installed:\n"; print " " . join(" ", @{$install_listp}) . "\n"; $flag = 1; } if(scalar(@{$upgrade_listp}) > 0) { print "The following packages will be upgraded:\n"; print " " . join(" ", @{$upgrade_listp}) . "\n"; $flag = 1; } if(scalar(@{$remove_listp}) > 0) { print "The following packages will be removed:\n"; print " " . join(" ", @{$remove_listp}) . "\n"; $flag = 1; } if($flag > 0) { print scalar(@{$upgrade_listp}) . " packages upgraded, "; print scalar(@{$install_listp}) . " newly installed, "; print scalar(@{$remove_listp}) . " removed.\n"; if($total_download_kb > 0) { if($total_download_kb < 1024) { printf "Need to get %dkB of files. ", $total_download_kb; } else { printf "Need to get %.1fMB of files. ", $total_download_kb / 1024; } } if($total_install_kb > 0) { if($total_install_kb < 1024) { printf "After installation %dkB will be used.\n", $total_install_kb; } else { printf "After installation %.1fMB will be used.\n", $total_install_kb / 1024; } } if($total_remove_kb > 0) { if($total_remove_kb < 1024) { printf "After removal %dkB will be freed.\n", $total_remove_kb; } else { printf "After removal %.1fMB will be freed.\n", $total_remove_kb / 1024; } } unless($gconfig{ASSUME_YES}) { print "Do you want to continue? [y/N] "; my $user_input = ; unless($user_input =~ /[Yy].*/) { return -1; } } } else { print "\nNothing to do. Exiting...\n"; return -1; } } sub do_source { my $package_name = ""; my $tmpfilename = ""; my $ret_val = 0; print "Downloading...\n" unless($gconfig{QUIET}); foreach $package_name (@_) { if(!defined($package_db{$package_name})) { print "There is no package '$package_name' in the database.\n"; return -1; } print "$package_name" unless($gconfig{QUIET}); $tmpfilename = $package_db{$package_name}->[$SRC_COL]; $tmpfilename =~ s/^.*\///g; for(my $i=0; $i<30 - length($package_name); $i++) { print " " unless($gconfig{QUIET}); } if( !-f "$tmpfilename") { if(!defined($package_db{$package_name}->[$SRCSIZE_COL])) { $package_db{$package_name}->[$SRCSIZE_COL] = 0; } $ret_val = download_file($gconfig{REMOTEHOST}, $gconfig{REMOTEPORT}, $gconfig{REMOTEPATH}, ".", $package_db{$package_name}->[$SRC_COL], $package_db{$package_name}->[$SRCSIZE_COL]/48); if($ret_val < 0) { return -1; } } else { print "File already downloaded." unless($gconfig{QUIET}); } print "\n" unless($gconfig{QUIET}); } return 0; } sub do_install { my $package_name = ""; my $is_complete_install = shift(); my @install_list; my $install_list_download_bytes = 0; my $install_list_install_bytes = 0; my @upgrade_list; my $upgrade_list_download_bytes = 0; my $upgrade_list_install_bytes = 0; my @remove_list; my $rpm_args = ""; my $tmpfilename = ""; my $ret_val = build_action_table(0, @_); if($ret_val < 0) { return -1; } foreach $package_name (@_) { if(defined($package_db{$package_name}) && ($package_db{$package_name}->[$ACTION_COL] eq "n") && ($is_complete_install == 0)) { print "Package $package_name is already installed.\n"; return -1; } } foreach $package_name (keys(%package_db)) { if($package_db{$package_name}->[$ACTION_COL] eq "i") { $tmpfilename = $package_db{$package_name}->[$FILE_COL]; $tmpfilename =~ s/^.*\///g; push(@install_list, $package_name); if( !-f "$gconfig{TACHDIR}/$gconfig{PKGDIR}/$tmpfilename" ) { $install_list_download_bytes += $package_db{$package_name}->[$PKGSIZE_COL]; } $install_list_install_bytes += $package_db{$package_name}->[$SIZE_COL]; } if($package_db{$package_name}->[$ACTION_COL] eq "u") { $tmpfilename = $package_db{$package_name}->[$FILE_COL]; $tmpfilename =~ s/^.*\///g; push(@upgrade_list, $package_name); if( !-f "$gconfig{TACHDIR}/$gconfig{PKGDIR}/$tmpfilename" ) { $upgrade_list_download_bytes += $package_db{$package_name}->[$PKGSIZE_COL]; } $upgrade_list_install_bytes += $package_db{$package_name}->[$SIZE_COL]; } } $ret_val = print_status(\@install_list, \@upgrade_list, \@remove_list, ($install_list_download_bytes + $upgrade_list_download_bytes)/1024, ($install_list_install_bytes + $upgrade_list_install_bytes)/1024, 0); if($ret_val < 0) { return $ret_val; } if($gconfig{RPMS_LOC} eq "http") { print "\nDownloading...\n" unless($gconfig{QUIET}); foreach $package_name (@install_list, @upgrade_list) { print "$package_name" unless($gconfig{QUIET}); $tmpfilename = $package_db{$package_name}->[$FILE_COL]; $tmpfilename =~ s/^.*\///g; $rpm_args .= " $gconfig{TACHDIR}/$gconfig{PKGDIR}/$tmpfilename"; for(my $i=0; $i<30 - length($package_name); $i++) { print " " unless($gconfig{QUIET}); } if( !-f "$gconfig{TACHDIR}/$gconfig{PKGDIR}/$tmpfilename") { $ret_val = download_file($gconfig{REMOTEHOST}, $gconfig{REMOTEPORT}, $gconfig{REMOTEPATH}, "$gconfig{TACHDIR}/$gconfig{PKGDIR}", $package_db{$package_name}->[$FILE_COL], $package_db{$package_name}->[$PKGSIZE_COL]/48); if($ret_val < 0) { return -1; } } else { print "File already downloaded." unless($gconfig{QUIET}); } print "\n" unless($gconfig{QUIET}); } } elsif($gconfig{RPMS_LOC} eq "cdrom") { foreach $package_name (@install_list, @upgrade_list) { $rpm_args .= " $gconfig{CDROMPATH}/$package_db{$package_name}->[$FILE_COL]"; } } if($gconfig{QUIET}) { system("$RPM -U --quiet $rpm_args"); } else { print "\nInstalling packages...\n"; system("$RPM -Uhv $rpm_args"); } } sub do_upgrade { my $package_name = ""; my @install_list; my $install_list_download_bytes = 0; my $install_list_install_bytes = 0; my @upgrade_list; my $upgrade_list_download_bytes = 0; my $upgrade_list_install_bytes = 0; my @remove_list; my $rpm_args = ""; my $tmpfilename = ""; my $ret_val = 0; foreach $package_name (keys(%package_db)) { $ret_val = build_action_table(1, $package_name); if($ret_val < 0) { return -1; } } foreach $package_name (keys(%package_db)) { if($package_db{$package_name}->[$ACTION_COL] eq "i") { $tmpfilename = $package_db{$package_name}->[$FILE_COL]; $tmpfilename =~ s/^.*\///g; push(@install_list, $package_name); if( !-f "$gconfig{TACHDIR}/$gconfig{PKGDIR}/$tmpfilename" ) { $install_list_download_bytes += $package_db{$package_name}->[$PKGSIZE_COL]; } $install_list_install_bytes += $package_db{$package_name}->[$SIZE_COL]; } if($package_db{$package_name}->[$ACTION_COL] eq "u") { $tmpfilename = $package_db{$package_name}->[$FILE_COL]; $tmpfilename =~ s/^.*\///g; push(@upgrade_list, $package_name); if( !-f "$gconfig{TACHDIR}/$gconfig{PKGDIR}/$tmpfilename" ) { $upgrade_list_download_bytes += $package_db{$package_name}->[$PKGSIZE_COL]; } $upgrade_list_install_bytes += $package_db{$package_name}->[$SIZE_COL]; } } $ret_val = print_status(\@install_list, \@upgrade_list, \@remove_list, ($install_list_download_bytes + $upgrade_list_download_bytes)/1024, ($install_list_install_bytes + $upgrade_list_install_bytes)/1024, 0); if($ret_val < 0) { return $ret_val; } if($gconfig{RPMS_LOC} eq "http") { print "\nDownloading...\n" unless($gconfig{QUIET}); foreach $package_name (@install_list, @upgrade_list) { print "$package_name" unless($gconfig{QUIET}); $tmpfilename = $package_db{$package_name}->[$FILE_COL]; $tmpfilename =~ s/^.*\///g; $rpm_args .= " $gconfig{TACHDIR}/$gconfig{PKGDIR}/$tmpfilename"; for(my $i=0; $i<30 - length($package_name); $i++) { print " " unless($gconfig{QUIET}); } if( !-f "$gconfig{TACHDIR}/$gconfig{PKGDIR}/$tmpfilename") { $ret_val = download_file($gconfig{REMOTEHOST}, $gconfig{REMOTEPORT}, $gconfig{REMOTEPATH}, "$gconfig{TACHDIR}/$gconfig{PKGDIR}", $package_db{$package_name}->[$FILE_COL], $package_db{$package_name}->[$PKGSIZE_COL]/48); if($ret_val < 0) { return -1; } } else { print "File already downloaded." unless($gconfig{QUIET}); } print "\n" unless($gconfig{QUIET}); } } elsif($gconfig{RPMS_LOC} eq "cdrom") { foreach $package_name (@install_list, @upgrade_list) { $rpm_args .= " $gconfig{CDROMPATH}/$package_db{$package_name}->[$FILE_COL]"; } } if($gconfig{QUIET}) { system("$RPM -U --quiet $rpm_args"); } else { print "\nInstalling packages...\n"; system("$RPM -Uhv $rpm_args"); } } sub do_remove { my @package_names = @_; my $package_name = ""; my @install_list; my @upgrade_list; my @remove_list; my $remove_list_remove_bytes = 0; my $remove_list_remove_kb = 0; my $rpm_args = ""; my $installed_package = ""; my $db_package = ""; my $flag = 0; my $ret_val = build_removal_table(@_); if($ret_val < 0) { return -1; } foreach $package_name (keys(%package_db)) { if($package_db{$package_name}->[$ACTION_COL] eq "r") { $installed_package = `$RPM -q --queryformat \"%{VERSION}-%{RELEASE}\" $package_name 2>&1`; $db_package = $package_db{$package_name}->[$VERSION_COL] . "-" . $package_db{$package_name}->[$RELEASE_COL]; if($installed_package eq $db_package) { push(@remove_list, $package_name); $remove_list_remove_bytes += $package_db{$package_name}->[$SIZE_COL]; } } } $ret_val = print_status(\@install_list, \@upgrade_list, \@remove_list, 0, 0, $remove_list_remove_bytes / 1024); if($ret_val < 0) { return $ret_val; } print "\nRemoving packages..." unless $gconfig{QUIET}; $rpm_args = join(" ", @remove_list); if($gconfig{QUIET}) { system("$RPM -e $rpm_args"); } else { system("$RPM -ev $rpm_args"); print " Done.\n"; } return 0; } sub do_clean { print "Deleting package files..." unless $gconfig{QUIET}; system("rm -f $gconfig{TACHDIR}/$gconfig{PKGDIR}/*"); print " Done.\n" unless $gconfig{QUIET}; } sub do_update { if($gconfig{RPMS_LOC} eq "cdrom") { print "No update will occur until tachometer is set to use \"http\"\n" . "as the RPM location (to change this, edit the top of this script file).\n\n"; return -1; } print "Getting package list...\t" unless($gconfig{QUIET}); my $ret_val = download_file($gconfig{REMOTEHOST}, $gconfig{REMOTEPORT}, $gconfig{REMOTEPATH}, $gconfig{TACHDIR}, $gconfig{PKGLIST}, 128); print "\n" unless($gconfig{QUIET}); if($ret_val < 0) { return -1; } return 0; } sub do_list { my $package_name = ""; my $action = ""; my $ret_val = 0; foreach $package_name (keys(%package_db)) { $ret_val = build_action_table(0, $package_name); if($ret_val < 0) { return -1; } } print "------------------------------------------------------------------------\n"; printf " %-30s%-20s%-20s\n", "Package Name", "Version", "Action"; print "------------------------------------------------------------------------\n"; foreach $package_name (sort(keys(%package_db))) { if($package_db{$package_name}->[$ACTION_COL] eq "n") { $action = "Up To Date"; } elsif($package_db{$package_name}->[$ACTION_COL] eq "i") { $action = "Not Installed"; } elsif($package_db{$package_name}->[$ACTION_COL] eq "u") { $action = "New Version"; } printf " %-30s%-20s%-20s\n", $package_name, $package_db{$package_name}->[$VERSION_COL]."-".$package_db{$package_name}->[$RELEASE_COL], $action; } return 0; } sub print_usage { print << "END_OF_USAGE"; Usage: tachometer command tachometer install|remove pkg1 [pkg2 ...] tachometer source pkg1 [pkg2 ...] Commands: update - Download the most recent package list upgrade - Upgrade installed packages to the newest available versions install-all - Install all packages (excluding any already installed) remove-all - Remove all packages currently installed list - Show state of all packages in the package list clean - Delete any downloaded RPM files Options: -q - Perform operation with no output -y - Assume "yes" as the answer to all question (use with caution) END_OF_USAGE } # At some point in the future, tachometer will read in a config file... for # now the config is defined at the top of the file sub read_config { # if( -f ".tachometerrc" ) { # open(TACHRC, "<.tachometerrc") || die "Could not open config file: $!"; # while() { # if($_ =~ /^\w*\#/ || $_ =~ /^\w*$/) { # skip config file comments # next; # } # # @key_val = split(/=/, $_); # # } # close(TACHRC); # } # elsif( -f "/usr/local/etc/tachometerrc" ) { # print "Yahoo!\n"; # } # else { # print "No configuration file found!\n"; # return -1; # } return 0; } sub main { my (@opts) = @ARGV; my $opt; my $ret_val = 0; my $cmd; my @pkgs; while($opt = shift(@opts)) { if($opt =~ /^-.*/) { if($opt =~ /q/) { $gconfig{QUIET} = 1; } if($opt =~ /y/) { $gconfig{ASSUME_YES} = 1; } } else { $cmd = $opt; last; } } # now we get the remaining args @pkgs = @opts; # throughout this script we want to always flush STDOUT and STDERR # as soon as possible my $ofh = select STDOUT; $| = 1; select STDERR; $| = 1; select $ofh; if(!defined($cmd)) { print_usage(); return -1; } $ret_val = read_config(); if($ret_val < 0) { return $ret_val; } if($cmd eq "update") { $ret_val = do_update(); return 0; } if($gconfig{RPMS_LOC} eq "http") { read_package_db($gconfig{TACHDIR}, $gconfig{PKGLIST}); } elsif($gconfig{RPMS_LOC} eq "cdrom") { read_package_db($gconfig{CDROMPATH}."/SETUP", $gconfig{PKGLIST}); } if($cmd eq "upgrade") { $ret_val = do_upgrade(); } elsif($cmd eq "install-all") { $ret_val = do_install(1, keys(%package_db)); } elsif($cmd eq "remove-all") { $ret_val = do_remove(keys(%package_db)); } elsif($cmd eq "clean") { $ret_val = do_clean(); } elsif($cmd eq "list") { $ret_val = do_list(); } elsif($cmd eq "install") { $ret_val = do_install(0, @pkgs); } elsif($cmd eq "remove") { $ret_val = do_remove(@pkgs); } elsif($cmd eq "source") { $ret_val = do_source(@pkgs); } else { print_usage(); } return $ret_val; } exit main($_);