#!/usr/bin/perl ################################################# # Updater script for a local, uninstalled copy # of a Slackware 7.1 distribution. # Author: Mike Pastore # File: slackupd.pl # Version: 0.8.0 # Modified: 01/11/2001 ################################################# # To Do: # 1) More robust installer # 2) Integration with /var/adm/packages (ie, # update an INSTALLED copy of Slack) # 3) Use GetOpts or similar package, add options # for auto-install, auto-commit, etc. # 4) user root check ################################################# use strict; #use warnings 'all'; use LWP::Simple qw(get getstore); use Digest::MD5; # global user variables our $tmp = '/tmp'; our $mirror = 'ftp://ftp.freesoftware.com' . '/pub/slackware/slackware-current/slakware'; local $| = 1; # enable auto-flush my $all_pkg = int($ARGV[0] eq "-a"); # get bool val my($target, $source) = # set target (local) and source (remote) map { s/\/+$//; $_ } @ARGV[$all_pkg .. $all_pkg + 1]; $source ||= $mirror; # default to mirror # usage rules my @rules = ( [ -d $target, "No such file or directory: $target" ], [ !$source || (defined $source && $source =~ /^ftp:\/\// && $source =~ /slakware$/), "Invalid mirror path: $source" ] ); # build error message my $err; for(@rules) { $err .= $_->[1]."\n" unless $_->[0]; } # usage error die < 0, local => 0, updated => 0); my @tarballs = (); # build list of current packages opendir(PRUNE, $target) or die "Unable to read target directory: $!\n"; my %packages = map { $_ => 1 } grep { !/^\./ && -d "$target/$_" } readdir(PRUNE); closedir(PRUNE); print "Reading remote CHECKSUMs from $source:\n"; my $md5_list = get($source . "/CHECKSUMS.md5"); die "The location you specified \"$source\" does not have a checksum file. Please choose another mirror, or check your path.\n" unless defined $md5_list; # parse slurped file/checksum list and build LoH for(split /\n/, $md5_list) { next unless /^([a-z0-9]+?)\s+\.\/(\S+?)\/(\S+?)$/; next unless($all_pkg || $packages{$2}); push @tarballs, { update => (! -e "$target/$2/$3"), # update if DNE package => $2, filename => $3, checksum => $1, hexdigest => undef }; $counts{remote}++ && print '.'; } print " ($counts{remote} remote packages)\n\n"; print "Generating local CHECKSUMs for $target:\n"; # verify checksums for files not already marked for updating for(grep !($_->{update}), @tarballs) { my $digest = $_->{hexdigest} = &hexdigest(join '/', $target, $_->{package}, $_->{filename}); $_->{update} = ($digest ne $_->{checksum}); $counts{local}++ && print '.'; } print " ($counts{local} local packages)\n\n"; print "Download packages [". do { local $" = ','; "@{[ keys %packages ]}" } ."]:\n"; # download tarballs to our temp target mkdir("$tmp/slakware", 0777); &retrieve($_) && $counts{updated}++ for(grep $_->{update}, @tarballs); unless($counts{updated} > 0) { print "No tarballs to update, none fetched.\n"; exit; } print "Updating FILE_LIST, CHECKSUMS, README, etc...\n"; getstore("$source/$_", "/tmp/slakware/$_") for('CHECKSUMS', 'CHECKSUMS.md5', 'FILE_LIST', 'makeflop', 'MANIFEST.gz', 'README'); print "\nCommit? (Overwrite tree with new packages) [y/N] "; my $prompt = ; unless($prompt =~ /^y/i) { print "\nPackages can be found in $tmp/slakware\n"; } else { print "\nUpdating directory tree...\n"; system("cp -R $tmp/slakware/* $target"); } print "\nInstall packages? (installpkg) [Y/n] "; $prompt = ; if($prompt =~ /^n/i) { print "Alrighty then!\n"; exit; } for(grep $_->{update}, @tarballs) { my($package, $filename) = @$_{'package', 'filename'}; print "Install $package/$filename? [y/N] "; my $prompt = ; if($prompt =~ /^y/i) { system('installpkg', "$tmp/slakware/$package/$filename"); } } sub hexdigest { my $file = shift; local *TARBALL; open(TARBALL, $file) or die "Unable to open file for checksum: $!\n"; binmode(TARBALL); Digest::MD5->new->addfile(*TARBALL)->hexdigest; } sub retrieve { my $tarball = shift; my($package, $filename) = @$tarball{'package', 'filename'}; my $local = "$tmp/slakware/$package"; my $remote = "$source/$package"; # create target directory if needed mkdir($local, 0777) if(! -d $local); print "retrieving $package/$filename..."; # check to see if the file already exists if(-e "$local/$filename") { print " already exists!"; my $checksum = &hexdigest(join '/', $local, $filename); if($checksum eq $tarball->{checksum}) { print " checksum verified, skipping file"; $tarball->{update} = 0; } else { print " invalid checksum, overwriting"; } } my $count = 0; FETCH: while($tarball->{update} && ++$count < 3) { my $filepath = join('/', $local, $filename); getstore("$remote/$filename", $filepath) or next FETCH; my $checksum = &hexdigest($filepath); if($checksum eq $tarball->{checksum}) { print " (@{[ -s $filepath ]} bytes OK)"; last FETCH; } else { unlink $filepath; } } continue { warn "\nUnable to download package, continuing...\n"; } print "\n"; }