1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
#!/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
@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");
#- --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) {
URPM::read_config_files();
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
# 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();
$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;
}
|