home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/perl
-
- # @ARGV contains list of RPMs to upgrade
- $|=1;
- $dryrun = 1;
- $verbose = 0;
- $philine = 'phi-gen-upgrade ';
- $RPM = 'rpm';
- $logfile = '/var/log/update';
-
- $usrpath = '/usr/lib/PHI';
-
- $outofspace = 0;
-
- sub usage {
- print STDERR "This program upgrades your OpenLinux system from one version to the\n";
- print STDERR "RPMs as given on the commandline and as specified by additional options below.\n";
- print STDERR "\n";
- print STDERR "Usage: phi-upgrade [<options>] <path to RPMS>\n";
- print STDERR "\n";
- print STDERR " --help Print this helptext and exit.\n";
- print STDERR " --root /root/dir/ Use this as root directory for all RPM \n";
- print STDERR " operations (db and install) and scripts.\n";
- print STDERR " --suggest /path/to/list Points to a list of suggested additional RPMS of\n";
- print STDERR " the form:\n";
- print STDERR "\n";
- print STDERR " <pkg>:<suggestpkg1>,<suggestpkg2>,...\n";
- print STDERR " --list /path/to/list Points to a list of unconditional additional\n";
- print STDERR " RPMs to be installed.\n";
- print STDERR " --verbose / -v Increase verbosity.\n";
- print STDERR "\n";
- print STDERR " --indeed Do the real update (instead of just printing\n";
- print STDERR " the number of RPMs to update).\n";
- print STDERR "\n\n";
- print STDERR "Make sure you are in single user mode before running this on a live system!\n";
- exit 1;
- }
-
- open(LOGFILE,">>$logfile");
-
- $numberofrpms = 0;
-
- @NARGV=();
- while (@ARGV) {
- $_ = shift @ARGV;
- if (/--help/) { &usage(); }
- if (/--root/) {
- $rootdir = shift @ARGV;
- $RPM .= " --root $rootdir";
- $philine .= " --root $rootdir";
- next;
- }
- if (/--indeed/) {
- $dryrun = 0;
- next;
- }
- if (/--suggest/) {
- $suggest = shift @ARGV;
- $philine .= " --suggest $suggest";
- next;
- }
- if (/--list/) {
- $suggest = shift @ARGV;
- $philine .= " --list $suggest";
- next;
- }
- if (/--verbose/ || /-v/) {
- $verbose = 1;
- next;
- }
- push @NARGV,$_;
- }
- @ARGV=@NARGV;
-
- if ($dryrun) {
- $philine .= " --pretty";
- }
-
- $debug = 0;
- sub xdeb { print STDERR @_ if ($debug); }
-
- if (@ARGV==0) { &usage(); }
-
- #############################################################################
-
- system("mount -t proc none $rootdir/proc/");
- system("mkdir -p $rootdir/var/lib/PHI/");
-
- check_for_rebuild_rpmdb();
-
- if (@ARGV==1) {
- $d1 = shift @ARGV;
- $philine.=" --to $d1";
- open(TOUPGRADE,"$philine 2>&1|")||die "could not start $philine:$!";
- @toupgrade = <TOUPGRADE>;
- close(TOUPGRADE);
- print LOGFILE @toupgrade;
- slurp_installed_rpms();
- slurp_new_rpms($d1);
- } else {
- $d1 = shift @ARGV;
- $d2 = shift @ARGV;
- $philine.=" --from $d1 --to $d2 ";
- open(TOUPGRADE,"$philine 2>&1|")||die "could not start $philine:$!";
- @toupgrade = <TOUPGRADE>;
- close(TOUPGRADE);
- print LOGFILE @toupgrade;
- slurp_old_rpms($d1);
- slurp_new_rpms($d2);
- }
-
- foreach (@toupgrade) {
- xdeb($_);
- chomp;
- if (/^install: (\S*)/) {
- $rpm = $1;
- $toupgrade{$rpm}=1;
- $numberofrpms++;
- next;
- }
- if (/^interlocked: (\S*)/) {
- %{$interlocked{$rpm}} = map { $_ => 1 } split(/,/,$1);
- # the following is for catching 'broken' dependency RPMs.
- foreach (keys %{$interlocked{$rpm}}) {
- next if (/^!/);
- if (!$toupgrade{$_}) {
- $toupgrade{$_}=1;
- %{$interlocked{$_}} = %{$interlocked{$rpm}};
- }
- }
- next;
- }
- if (/^remove: (\S*)/) {
- $toremove{$1}=1;
- $numberofrpms++;
- next;
- }
- }
-
- sub do_exec_fixupscript {
- my($cmd) = @_;
-
- return 0 if (! -x "$usrpath/$cmd");
- return system("$usrpath/$cmd") if (!$rootdir);
- system("mkdir -p $rootdir/$usrpath");
- system("cp -a $usrpath/$cmd $rootdir/$usrpath");
- chdir($rootdir) || print LOGFILE "chdir $rootdir did not work:$!\n";
- open(EXECOUT,"chroot . /$usrpath/$cmd 2>&1|");
- while (<EXECOUT>) { print LOGFILE; }
- close(EXECOUT);
- return 1;
- }
-
- sub do_execute {
- my($cmd) = @_;
- my($res);
-
- open(CMD,"$cmd 2>&1|")||return 0;
- while (<CMD>) {
- if (/installing.*needs.*on the.*filesystem/) {
- $outofspace = 1;
- }
- print LOGFILE;
- }
- if (!close(CMD)) {
- return 0;
- }
- if ($outofspace) {
- return 0;
- }
- return 1;
- }
-
- sub do_rpm {
- my($rpmline,@rpms) = @_;
- my($res,$rpm);
-
- if ($dryrun) {
- $verbose && print "$rpmline\n";
- } else {
- foreach $rpm (@rpms) {
- &do_exec_fixupscript("$rpm.prefixup");
- }
- if (!do_execute("$rpmline")) {
- if ($outofspace) {
- print STDERR "Failure: Out of memory.\n";
- return 0;
- }
- print STDERR "Failure: trying with --force\n";
- if (!do_execute("$rpmline --force")) {
- print STDERR "Failure: trying with --force --nodeps\n";
- if ($outofspace) {
- print STDERR "Failure: Out of memory.\n";
- return 0;
- }
- if (!do_execute("$rpmline --force --nodeps")){
- if ($outofspace) {
- print STDERR "Failure: Out of memory.\n";
- return 0;
- }
- print STDERR "--force --nodeps failed too ... Umm.\n";
- }
- }
- }
- foreach $rpm (@rpms) {
- &do_exec_fixupscript("$rpm.postfixup");
- }
- print join("\n",@rpms) . "\n";
- }
- if ($outofspace) {
- exit(42);
- }
- return 1;
- }
-
- sub delete_all_ilockrefs {
- my($rpm) = @_;
-
- foreach $blub (keys %interlocked) {
- %ilocks = %{$interlocked{$blub}};
- foreach $xrpm (keys %ilocks) {
- next if (defined($toupgrade{$xrpm}) || defined($topremove{$xrpm}));
- delete $ilocks{$xrpm};
- }
- %{$interlocked{$blub}} = %ilocks;
- }
- }
-
- sub output_rpmline {
- my($rpm) = @_;
- if ($newrealname{$rpm} ne $oldrealname{$rpm}) {
- do_rpm("$RPM -Uvh $newrpmfn{$rpm}");
- } else {
- do_rpm("$RPM -Uvh --force $newrpmfn{$rpm}");
- }
- }
-
- sub slurp_new_rpms($) {
- my($path) = @_;
- my(@rpms,$rpm,$rpmname,$rpmversion);
-
- # regular glob doesn't work in Live FS.
- $foo = `echo $path/*.rpm`;chomp($foo);@rpms=split(/ /,$foo);
- foreach $rpm (@rpms) {
- $rpm =~ s/.*\///;
- $rpmname = $rpm;
- $rpmversion = $rpmname;
- $rpmversion =~ s/\.[^.]*\.rpm$//; # strip .i386/src.rpm;
- $rpmname =~ s/-[^-]*-[^-]*\.[^.]*\.rpm$//; # strip version-release-i386/src.rpm;
- $newrealname{$rpmname} = $rpm;
- $newrpmfn{$rpmname} = "$path/$rpm";
-
- }
- }
-
- sub slurp_old_rpms($) {
- my($path) = @_;
- my(@rpms,$rpm,$rpmname,$rpmversion);
-
- # regular glob doesn't work in Live FS.
- $foo = `echo $path/*.rpm`;chomp($foo);@rpms=split(/ /,$foo);
- foreach $rpm (@rpms) {
- $rpm =~ s/.*\///;
- $rpmname = $rpm;
- $rpmversion = $rpmname;
- $rpmversion =~ s/\.[^.]*\.rpm$//; # strip .i386/src.rpm;
- $rpmname =~ s/-[^-]*-[^-]*\.[^.]*\.rpm$//; # strip version-release-i386/src.rpm;
- $oldrealname{$rpmname} = $rpm;
- $oldrpmfn{$rpmname} = "$path/$rpm";
-
- }
- }
-
- sub slurp_installed_rpms() {
- my(@rpms,$rpm,$rpmname,$rpmversion);
- open(RPMQA,"$RPM -qa|");
- @rpms=<RPMQA>;chomp(@rpms);
- close(RPMQA);
-
- foreach $rpm (@rpms) {
- $rpmname = $rpm;
- $rpmversion = $rpmname; # no .i386.rpm here
- $rpmname =~ s/-[^-]*-[^-]*$//; # strip version-release
- $oldrealname{$rpmname} = "$rpm.i386.rpm";
- }
- }
-
- sub check_for_rebuild_rpmdb {
- my (@rpms);
- open(RPMQA,"$RPM -qi bash 2>&1|");
- @rpms=<RPMQA>;chomp(@rpms);
- if (!close(RPMQA)) {
- do_rpm("$RPM --rebuilddb",'rpmupdatedb');
- }
- }
-
- ##############################################################################
- # main() :)
-
- if (!$dryrun) {
- &do_exec_fixupscript("phi-upgrade-start.fixup");
- }
-
- # check versions of RPM.
- $orpmver = $oldrealname{'rpm'};
- $nrpmver = $newrealname{'rpm'};
- # If they are not the same release, upgrade by all means necessary.
- if (defined($newrealname{'rpm'})) {
- $xorpmver = $ormpver;
- $xnrpmver = $nrmpver;
-
- $xorpmver =~ s/-[^-]*$//g; # strip release
- $xnrpmver =~ s/-[^-]*$//g; # strip release
-
- if ($orpmver ne $nrpmver) {
- do_rpm("$RPM -Uvh --nodeps --force " . $newrpmfn{'rpm'},'rpm');
- }
- $orpmver =~ s/-[^-]*$//g; # strip release
- $nrpmver =~ s/-[^-]*$//g; # strip release
- }
-
- while (scalar %toupgrade) {
- # 1. Find smallest interlocked set.
-
- $smallestsetsize = 10000;
- $smallestrpm = '';
- foreach $rpm (keys %toupgrade) {
- @xkeys = keys %{$interlocked{$rpm}};
- $xkeys = @xkeys;
- if ($xkeys<$smallestsetsize) {
- next if (!$xkeys);
- $smallestrpm = $rpm;
- $smallestsetsize = $xkeys;
- }
- }
- last if ($smallestsetsize == 10000);
-
- # 2. First remove the RPMS from this interlocked set.
-
- %ilocks = %{$interlocked{$smallestrpm}};
- foreach $rpm (keys %ilocks) {
- if ($rpm =~ /^!(.*)/) {
- next if (!defined($toremove{$1}));
- do_rpm("$RPM -e $1",$1);
- delete $toremove{$1};
- # &delete_all_ilockrefs($1);
- }
- }
- $rpmline="";$useforce=0;$usedrpms=0;@rpms = ();
- foreach $rpm (keys %ilocks) {
- next if (!defined($toupgrade{$rpm}));
- if ($newrealname{$rpm} eq $oldrealname{$rpm}) {
- $useforce=1;
- }
- $rpmline .= " $newrpmfn{$rpm}";
- push @rpms,$rpm;
- # &delete_all_ilockrefs($rpm);
- delete $toupgrade{$rpm};
- $usedrpms++;
- }
- if ($useforce) {
- # needs --force --nodeps. RPM does not get it otherwise.
- if ($usedrpms > 1) {
- do_rpm("$RPM -Uvh --force --nodeps $rpmline",@rpms);
- } else {
- do_rpm("$RPM -Uvh --force $rpmline",@rpms);
- }
- } else {
- do_rpm("$RPM -Uvh $rpmline",@rpms);
- }
- delete $interlocked{$smallestrpm};
- }
- if (!$dryrun) {
- &do_exec_fixupscript("phi-upgrade-end.fixup");
- }
-
- $dryrun && print "Number of RPMS to upgrade: $numberofrpms\n";
-
- close(LOGFILE);
- system("umount $rootdir/proc/");
-