summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--urpm/args.pm12
-rw-r--r--urpmi.recover172
2 files changed, 184 insertions, 0 deletions
diff --git a/urpm/args.pm b/urpm/args.pm
index ab0d7863..4bc5b425 100644
--- a/urpm/args.pm
+++ b/urpm/args.pm
@@ -313,6 +313,14 @@ my %options_spec = (
},
},
+ 'urpmi.recover' => {
+ 'list=s' => \$::listdate,
+ 'list-all' => sub { $::listdate = -1 },
+ checkpoint => \$::do_checkpoint,
+ 'rollback=s' => \$::rollback,
+ noclean => \$::noclean,
+ },
+
);
# generate urpmf options callbacks
@@ -370,6 +378,10 @@ foreach my $k ("help|h", "wget", "curl", "proxy=s", "proxy-user=s", "c", "f", "z
$options_spec{'urpmi.addmedia'}{$k} = $options_spec{'urpmi.update'}{$k};
}
+foreach my $k ("help|h", "version") {
+ $options_spec{'urpmi.recover'}{$k} = $options_spec{urpmi}{$k};
+}
+
sub parse_cmdline {
my %args = @_;
$urpm = $args{urpm};
diff --git a/urpmi.recover b/urpmi.recover
new file mode 100644
index 00000000..312cbaf4
--- /dev/null
+++ b/urpmi.recover
@@ -0,0 +1,172 @@
+#!/usr/bin/perl
+
+# $Id$
+
+#- Copyright (C) 2006 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;
+
+our $MACROS = '/etc/rpm/macros.d/urpmi.recover.macros';
+our $listdate;
+our $do_checkpoint;
+our $noclean;
+our $rollback;
+
+sub usage () {
+ print N("urpmi.recover version %s
+Copyright (C) 2006 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(" --list - list transactions since checkpoint
+ or since provided date/duration argument
+") . N(" --list-all - list all transactions in rpmdb (long)
+") . N(" --rollback - rollback until specified date,
+ or rollback the specified number of transactions
+");
+ exit(0);
+}
+
+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');
+}
+
+#- option parsing
+
+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");
+
+#- --list <date> and --list-all
+
+if ($listdate) {
+ my $listtime = -1;
+ if ($listdate ne -1) {
+ #- convert to timestamp
+ $listtime = date_to_tid($listdate);
+ }
+ my %tids;
+
+ my $db = URPM::DB::open();
+ $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";
+ for 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) {
+
+ my $db = URPM::DB::open(); #- to load macros
+ my $repackage_dir = URPM::expand("%_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);
+ my $unsafe_rollbacks = time();
+
+ #- clean up repackage directory
+ unless ($noclean) {
+ print N("Cleaning up repackage directory [%s]...\n", $repackage_dir);
+ my $nb = unlink grep !-d, glob("$repackage_dir/*");
+ print N("%d files removed\n", $nb);
+ }
+
+ #- 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
+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();
+ $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;
+}