#!/usr/bin/perl # # ftp-upgrade - fetch redhat package manager updates from the network # # usage: ftp-upgrade [-n] [-u uname] # # -u - specify a username to use - will be prompted for a password # -n - identify packages that are "new" (e.g. not yet installed) # # ftp-upgrade queries the set of installed packages on the local machine. It # then connects to the redhat repository of your choice via ftp, examines # the list of available updates there, and informs you of any packages that # have had their patch level increased or version number changed. You can # then choose to have all of the indicated packages downloaded, or # individually select which packages to download. The transferred RPMs are # placed in the current working directory. They can then be installed on # your system by using the command rpm -u , where is one of # the downloaded RPMs. # # Note that if there is an update to RPM or GLINT, these should be updated # first! # # $Header: /storage/cvsroot/user/www/homepage/linux/ftp-upgrade,v 1.1 2003/06/02 13:01:37 pere Exp $ # # $Log: ftp-upgrade,v $ # Revision 1.1 2003/06/02 13:01:37 pere # Add all my patches to CVS. # # Revision 1.10-pr 1998/05/28 10:00:00 pere # Lost of changes. Added handling of many directories, etc. # # Revision 1.10 1995/11/27 11:01:33 ahby # Changed default path to be for the 2.1 RPMS directory. # # Revision 1.9 1995/11/22 09:38:21 ahby # Removed some debugging code. # # Revision 1.8 1995/11/20 19:27:58 ahby # Added ability to get packages that are not yet installed. # # Revision 1.7 1995/11/14 21:53:41 ahby # Fixed an erroneously anchored string. # Improved package recognition. # Fixed a stupid array reference (I really am a better programmer # than this!). # # Revision 1.6 1995/11/14 19:09:35 ahby # Added list of mirror sites and username option. # Changed handling on connection error. # # Revision 1.5 1995/11/14 15:59:07 ahby # Changed it so if there are no changes it just terminates. # # Revision 1.4 1995/11/14 15:51:16 ahby # Cleaned up some comments. # # Revision 1.3 1995/11/09 23:15:46 ahby # CHanged revision tracking strategy to be smarter and use associative # array instead of a flat array and a search. # # Revision 1.2 1995/11/09 17:27:01 ahby # Fixed RCS headers. # # sub get_redhat_version { my($tmp) = `rpm -q redhat-release`; my($ver) = $tmp =~ m/^.+-([\d\.]+)-\d+/; if ($ver) { return $ver; } else { print "Unable to determine RedHat version. Exiting.\n"; exit(1); } } sub get_redhat_architecture { my($tmp) = `uname -m`; chomp($tmp); my($arch); if ($tmp =~ m/i?86/) { $arch = 'i386'; } else { $arch = $tmp; } return $arch; } $version = get_redhat_version(); $arch = get_redhat_architecture(); @rpm_dirs = ("redhat-$version/$arch/RedHat/RPMS", "updates/$version/$arch", "powertools-$version/$arch"); # Popular RedHat mirrors sites #$host = "ftp.nvg.unit.no"; #$path = "/pub/linux/redhat"; $host = "sunsite.uio.no"; $path = "/pub/unix/linux/redhat"; #$host = "ftp.caldera.com"; #$path = "/pub/mirrors/redhat"; #$host = "ftp.cc.gatech.edu"; #$path = "/pub/linux/distributions/redhat"; #$host = "ftp.pht.com"; #$path = "/pub/linux/redhat"; #$host = "ftp.cms.uncwil.edu"; #$path = "/linux/redhat"; #$host = "ftp.wilmington.net"; #$path = "/linux/redhat"; #$host = "ftp.caldera.com"; #$path = "/pub/mirrors/redhat"; #$host = "ftp.lasermoon.co.uk"; #$path = "/pub/distributions/RedHat"; #$host = "sunsite.unc.edu"; #$path = "/pub/Linux/distributions/redhat"; #$host = "sunsite.doc.ic.ac.uk"; #$path = "/packages/linux/sunsite.unc-mirror/distributions/redhat"; #$host = "ftp.cc.gatech.edu"; #$path = "/pub/linux/distributions/redhat"; #$host = "uiarchive.cso.uiuc.edu"; #$path = "/pub/systems/linux/distributions/redhat"; #$host = "ftp.ibp.fr"; #$path = "/pub/linux/distributions/redhat"; #$host = "ftp.gwdg.de"; #$path = "/pub/linux/install/redhat"; #$host = "ftp.uoknor.edu"; #$path = "/linux/redhat"; #$host = "ftp.msu.ru"; #$path = "/pub/Linux/RedHat"; #$host = "linux.ucs.indiana.edu"; #$path = "/pub/linux/redhat"; #$host = "ftp.cvut.cz"; #$path = "/pub/linux/redhat"; #$host = "ftp.ton.tut.fi"; #$path = "/pub/Linux/RedHat"; #$host = "ftp.funet.fi"; #$path = "/pub/Linux/images/RedHat"; BEGIN { # Find Net::FTP if it is in an nonstandard place push(@INC, "/store/lib/perl5", "/store/lib/perl5/site_perl" ); # Workaround for a bug in early RedHat 5 perl distributions. eval 'require "ftp.pl"; import ftp;'; return unless ( $@ ); # Make backup include files mkdir "/tmp/perl-fix", 0777; mkdir "/tmp/perl-fix/gnu", 0777; my($tmp) = `echo '1;' > /tmp/perl-fix/gnu/stubs.ph`; $tmp = `echo '1;' > /tmp/perl-fix/stddef.ph`; push(@INC, "/tmp/perl-fix"); } # compare versions - needs more work # 1.9.1 is newer then 1.9 and 3.19 is newer then 3.2 # Return true if v2 is newer then v1 sub version_newer { my ($v1, $v2) = @_; my($r1, $r2); ($v1,$r1) = $v1 =~ m/^(.+)-(\d+).+rpm/; ($v2,$r2) = $v2 =~ m/^(.+)-(\d+).+rpm/; if ($v1 eq $v2) { return ($r1 < $r2); } my @v1 = split(/\./, $v1); my @v2 = split(/\./, $v2); if ($v1[0] < $v2[0] || ($v1[0] == $v2[0] && $v1[1] < $v2[1]) || ($v1[0] == $v2[0] && $v1[1] == $v2[1] && $v1[2] lt $v2[2])) { # print "Comparing $v1 and $v2 - true\n"; return 1; } # print "Comparing $v1 and $v2 - false\n"; return 0; } use Getopt::Std; # XXX use Net::FTP; require "ftp.pl"; import ftp; $uname = "anonymous"; $pword = "upgrade-user@"; &getopts('nu:'); if ($opt_u) { $uname = $opt_u; system "stty -echo"; print "Password: "; chop($pword = ); print "\n"; system "stty echo"; } # subroutine to get y/n answer sub getyn { local($prompt) = @_; local($answer) = ""; local($a) = ""; do { print "$prompt (y/n)? "; $answer = ; $a = substr($answer, 0, 1); } while (($a ne "Y") && ($a ne "y") && ($a ne "N") && ($a ne "n")); return (($a eq "Y") || ($a eq "y")); } # get the local list of installed packages print "Getting list of installed packages\n"; @llist = `rpm -qa`; chop(@llist); sort(@llist); # now connect to the remote host print ("Getting the list of updated packages from $host.\n"); # make the connection and fetch the directory print "Opening connection to $host\n"; # XXX $ftp = Net::FTP->new($host, Timeout => '30'); ftp::set_timeout(30); $ftp = ftp::open($host,21,0,10); if ( ! $ftp ) { die("open of $host failed"); } print "Logging in to $host as $uname\n"; # XXX $ftp->login($uname,$pword) || die("login failed"); ftp::login($uname,$pword) || die("login failed"); for $dir (@rpm_dirs) { fetch_subdir_list($dir); } ## # Exports: @templist, %rlist sub fetch_subdir_list { my($dir) = @_; my($curpath) = $path . "/" . $dir; print "Changing to directory $curpath on $host\n"; # XXX $ftp->cwd($curpath); if ( ! ftp::cwd($curpath) ) { return; } print "Fetching directory list\n"; # XXX my(@longlist) = $ftp->ls(); ftp::dir_open(""); @longlist = ; ftp::dir_close(); push(@templist, grep(/\.rpm/, @longlist)); undef @longlist; chomp(@templist); sort (@templist); my(@temp); for (@templist) { @temp = m/([^ ]*)-([^- ]*-[0-9]*[^ ]*rpm).*/; ($file) = m/(\S+rpm)/; # Only add newer package if ( (! $rlist{$temp[0]} ) || ($rlist{$temp[0]} && version_newer($rlist{$temp[0]},$temp[1])) ) { $rlist{$temp[0]} = $temp[1]; $directory{$file} = $curpath; } } } # XXX $ftp->type("I"); ftp::type("I"); # XXX $ftp->debug(1); #ftp::debug(1); if ($opt_n) { # if we are looking for new packages for (@llist) { @temp = m/([^ ]*)-([^-]*-[0-9]*)/; $ilist{$temp[0]} = $temp[1]; } $uindex = 0; #initialize index for uninstalled package array for (@templist) { $fname = $_; $fname =~ s/.*\s([^ ]*rpm).*/$1/; @pname = ($fname =~ m/^(.*)-([^-]*)-([0-9]*)/); if (! $ilist{$pname[0]}) { # if this not package already installed @ulist[$uindex] = $fname; $uindex++; } } @ulist = sort(@ulist); if (@ulist) { print "Uninstalled packages:\n"; for (@ulist) { print " $_\n"; } $all = getyn("Fetch all?"); for (@ulist) { if (! $all) { if (!getyn("Fetch $_")) { next }; } getfile($ftp, $_); } } else { print ("No new packages are available on $host\n"); } } else { # check for updated packages $nindex = 0; #initialize index for new version array $cindex = 0; #initialize index for changed patch array for (@llist) { @lname = m/^(.*)-([^-]*)-([0-9]*$)/; if ($rlist{$lname[0]}) { # if this package has an update @temp = ($rlist{$lname[0]} =~ m/([^-]*)-([0-9]*).*rpm/); if ($lname[1] eq $temp[0]) { # if versions equal if ($lname[2] < $temp[1]) { # if patch level has increased @clist[$cindex] = $lname[0] . '-' . $rlist{$lname[0]}; $cindex++; }; } else { # if different version if (version_newer($lname[1], $temp[0])) { @nlist[$nindex] = $lname[0] . '-' . $rlist{$lname[0]}; $nindex++; } } } } if (@clist || @nlist) { @clist = sort(@clist); @nlist = sort(@nlist); print "New patches:\n\n"; for (@clist) { print " $_\n" } print "\nDifferent versions:\n\n"; for (@nlist) { print " $_\n" } $all = getyn("Fetch all?"); for (@clist) { if (! $all) { if (!getyn("Fetch $_")) { next }; } getfile($ftp, $_); } for (@nlist) { if (! $all) { if (!getyn("Fetch $_")) { next }; } getfile($ftp, $_); } print "\nTo upgrade, run 'rpm -Uvh *.rpm' as root.\n" } else { print ("No new updates are available on $host\n"); } } #$ftp->debug(0); # XXX $ftp->quit(); ftp::close(); sub getfile { my($ftphandle, $filename) = @_; my($dir) = $directory{$filename}; print "Fetching $dir/$filename\n"; # XXX $ftphandle->cwd($dir); ftp::cwd($dir); # XXX $ftphandle->get($filename); ftp::get($filename); }