diff options
Diffstat (limited to 'urpmi.recover')
-rw-r--r-- | urpmi.recover | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/urpmi.recover b/urpmi.recover new file mode 100644 index 00000000..39e417ae --- /dev/null +++ b/urpmi.recover @@ -0,0 +1,217 @@ +#!/usr/bin/perl + +# $Id$ + +#- Copyright (C) 2006, 2007, 2008, 2009, 2010 Mandriva SA + +use strict; + +BEGIN { + #- clean environment + $ENV{PATH} = "/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin"; + delete @ENV{qw(ENV BASH_ENV IFS CDPATH)}; +} + +use urpm::args; +use urpm::msg; +use URPM; +use urpm; + +our $MACROS = '/etc/rpm/macros.d/urpmi.recover.macros'; +our $listdate; +our $do_checkpoint; +our $noclean; +our $rollback; +our $disable; + +sub usage () { + print N("urpmi.recover version %s +Copyright (C) 2006-2010 Mandriva. +This is free software and may be redistributed under the terms of the GNU GPL. + +usage: +", $urpm::VERSION) . N(" --help - print this help message. +") . N(" --checkpoint - set repackaging start now +") . N(" --noclean - don't clean repackage directory on checkpoint +") . N(" --urpmi-root - use another root for urpmi db & rpm installation. +") . N(" --list - list transactions since provided date/duration argument +") . N(" --list-all - list all transactions in rpmdb (long) +") . N(" --list-safe - list transactions since checkpoint +") . N(" --rollback - rollback until specified date, + or rollback the specified number of transactions +") . N(" --disable - turn off repackaging +"); + exit(1); +} + +sub fmt_tid { + my ($tid) = @_; + require POSIX; POSIX->import('strftime'); + strftime("%F %T", localtime($tid)); +} + +sub date_to_tid { + my ($date) = @_; + require Date::Manip; Date::Manip->import; + my $d = ParseDate($date) + or die N("Invalid date or duration [%s]\n", $date); + UnixDate($d, '%s'); +} + +#- clean up repackage directory +sub clean_repackage_dir { + my ($repackage_dir) = @_; + if (!$repackage_dir || $repackage_dir eq '/') { + die N("Repackage directory not defined\n"); + } + -d $repackage_dir + or die N("Can't write to repackage directory [%s]\n", $repackage_dir); + unless ($noclean) { + print N("Cleaning up repackage directory [%s]...\n", $repackage_dir); + my $nb = unlink grep { ! -d $_ } glob("$repackage_dir/*"); + print P("%d file removed\n", "%d files removed\n", $nb, $nb); + } +} + +#- option parsing + +@ARGV or usage(); +my $command_line = "@ARGV"; #- for logging +urpm::args::parse_cmdline() + or exit(1); +@ARGV and die N("Spurious command-line arguments [%s]\n", "@ARGV"); +$do_checkpoint && $rollback + and die N("You can't specify --checkpoint and --rollback at the same time\n"); +$do_checkpoint && $listdate + and die N("You can't specify --checkpoint and --list at the same time\n"); +$rollback && $listdate + and die N("You can't specify --rollback and --list at the same time\n"); +$disable && ($listdate || $rollback || $do_checkpoint) + and die N("You can't specify --disable along with another option"); + +#- --list <date> and --list-all + +if ($listdate) { + my $listtime = -1; + if ($listdate eq 'checkpoint') { + URPM::read_config_files(); + $listtime = URPM::expand("%_unsafe_rollbacks"); + } elsif ($listdate ne -1) { + #- convert to timestamp + $listtime = date_to_tid($listdate); + } + my %tids; + + my $db = URPM::DB::open() or die "Can't open RPM DB\n"; + $db->traverse(sub { + my ($p) = @_; + my $tid = $p->installtid; + return if $tid < $listtime; + exists $tids{$tid} or $tids{$tid} = []; + push @{ $tids{$tid} }, scalar($p->fullname); + }); + + unless (scalar keys %tids) { + die N("No transaction found since %s\n", $listdate); + } + print "Date rpms\n"; + print "------------------- -------------------\n"; + foreach my $tid (sort { $a <=> $b } keys %tids) { + my @p = @{$tids{$tid}}; + print fmt_tid($tid), " ", shift(@p), "\n"; + while (@p) { + print " " x 20, shift(@p), "\n"; + } + } + exit(0); +} + +#- check we're running as root +$< == 0 or die N("You must be superuser to do this"); + +#- --checkpoint + +if ($do_checkpoint) { + + URPM::read_config_files(); + my $repackage_dir = URPM::expand("%_repackage_dir"); + my $unsafe_rollbacks = time(); + + clean_repackage_dir($repackage_dir); + + #- write rpm config file + print N("Writing rpm macros file [%s]...\n", $MACROS); + open my $fh, '>', $MACROS + or die "Can't open $MACROS for writing: $!\n"; + print $fh <<MACROS; +# Generated by urpmi.recover + +# Turn repackaging on +%_repackage_all_erasures 1 + +# Put repackaged rpms here (lots of space necessary) +%_repackage_dir $repackage_dir + +# Don't erase on rollback before this date (seconds since epoch) +%_unsafe_rollbacks $unsafe_rollbacks + +# Automate transaction rollbacks on upgrade failure +%_rollback_transaction_on_failure 0 +MACROS + close $fh; + + sys_log("checkpoint defined"); + exit(0); +} + +#- --rollback + +if ($rollback) { + sys_log("called with: $command_line"); + + my $tid; + if ($rollback !~ /\D/) { + #- $rollback contains a number of transactions to roll back + #- get a date from there + my %tids; + my $db = URPM::DB::open() or die "Can't open RPM DB\n"; + $db->traverse(sub { ++$tids{ $_[0]->installtid } }); + my @tids = sort { $b <=> $a } keys %tids; + $tid = $tids[$rollback - 1]; + } else { + #- $rollback contains a date, convert it to tid + $tid = date_to_tid($rollback); + } + $tid or die N("No rollback date found\n"); + + my $rollbackdate = fmt_tid($tid); + print N("Rollback until %s...\n", $rollbackdate), "\n"; + exec '/bin/rpm', '-Uvh', '--rollback', $rollbackdate; +} + +#- --disable + +if ($disable) { + print N("Disabling repackaging\n"); + + unless ($noclean) { + URPM::read_config_files(); + my $repackage_dir = URPM::expand("%_repackage_dir"); + clean_repackage_dir($repackage_dir); + } + + open my $fh, '<', $MACROS + or die "Can't open $MACROS for reading: $!\n"; + my $macrosfile = join '', <$fh>; + close $fh; + #- turn off repackaging macro + $macrosfile =~ s/_repackage_all_erasures\s+\w+/_repackage_all_erasures 0/g; + print N("Writing rpm macros file [%s]...\n", $MACROS); + open $fh, '>', $MACROS + or die "Can't open $MACROS for writing: $!\n"; + print $fh $macrosfile; + close $fh; + + sys_log("repackaging disabled"); + exit(0); +} |