1 |
#!/usr/bin/perl |
2 |
################################################################################ |
3 |
# Mandriva Online Distribution Upgrade Helper # |
4 |
# # |
5 |
# Copyright (C) 2008-2010 Mandriva # |
6 |
# # |
7 |
# Thierry Vignaud <tvignaud at mandriva dot com> # |
8 |
# # |
9 |
# This program is free software; you can redistribute it and/or modify # |
10 |
# it under the terms of the GNU General Public License Version 2 as # |
11 |
# published by the Free Software Foundation. # |
12 |
# # |
13 |
# This program is distributed in the hope that it will be useful, # |
14 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of # |
15 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # |
16 |
# GNU General Public License for more details. # |
17 |
# # |
18 |
# You should have received a copy of the GNU General Public License # |
19 |
# along with this program; if not, write to the Free Software # |
20 |
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # |
21 |
################################################################################ |
22 |
|
23 |
use strict; |
24 |
use POSIX ":sys_wait_h"; |
25 |
use lib qw(/usr/lib/libDrakX); |
26 |
use standalone; # for explanations |
27 |
use common; |
28 |
BEGIN { require_root_capability() } |
29 |
use run_program; |
30 |
use feature 'state'; |
31 |
|
32 |
BEGIN { unshift @::textdomains, 'mgaonline' } |
33 |
|
34 |
use mygtk2 qw(gtknew); #- do not import gtkadd which conflicts with ugtk2 version |
35 |
use ugtk2 qw(:all); |
36 |
use lib qw(/usr/lib/libDrakX/drakfirsttime); |
37 |
use mgaonline; |
38 |
use Rpmdrake::open_db; |
39 |
use lang; |
40 |
use mgaapplet_gui qw(run_ask_credentials_dialog); |
41 |
|
42 |
ugtk2::add_icon_path("/usr/share/mgaonline/pixmaps/"); |
43 |
my ($log_file); |
44 |
|
45 |
my ($new_distro_version, $download_dir); |
46 |
foreach my $opt (@ARGV) { |
47 |
if ($opt =~ /--(rpm-root|urpmi-root)=(.*)/) { |
48 |
$::rpmdrake_options{$1}[0] = $2; |
49 |
} elsif ($opt =~ /--new_distro_version=(.*)/) { |
50 |
$new_distro_version = $1; |
51 |
} elsif ($opt =~ /--download-all=(.*)/) { |
52 |
$download_dir = $1; |
53 |
} |
54 |
} |
55 |
|
56 |
my $root = Rpmdrake::open_db::fast_open_urpmi_db()->{root}; |
57 |
|
58 |
my $product_id = common::parse_LDAP_namespace_structure(cat_("$root/etc/product.id")); |
59 |
|
60 |
if (!$ENV{URPMI_IGNORESIZE}) { |
61 |
check_available_free_space('/usr', 800) && |
62 |
check_available_free_space('/var', 800) |
63 |
or exit(1); |
64 |
} |
65 |
|
66 |
run_program::raw({ detach => 1 }, 'ionice', '-p', $$, '-n7'); |
67 |
|
68 |
upgrade(); |
69 |
|
70 |
my ($refork_gurpmi); |
71 |
|
72 |
sub check_available_free_space { |
73 |
my ($dir, $wanted_MB) = @_; |
74 |
|
75 |
my (undef, $free_KB) = MDK::Common::System::df($dir); |
76 |
|
77 |
if ($free_KB / 1024 < $wanted_MB) { |
78 |
my $msg = ugtk2::escape_text_for_TextView_markup_format( |
79 |
N("Your system does not have enough space left in %s for upgrade (%dMB < %dMB)", |
80 |
$dir, |
81 |
$free_KB / 1024, $wanted_MB)); |
82 |
ugtk2::ask_warn(N("Error"), $msg); |
83 |
0; |
84 |
} else { |
85 |
1; |
86 |
} |
87 |
} |
88 |
|
89 |
sub run_gurpmi() { |
90 |
my @initial_args = ('--replacefiles', '--clean'); |
91 |
push @initial_args, "--download-all=$download_dir" if $download_dir; |
92 |
|
93 |
# Windows are created before upgrading packages, to guarantee that |
94 |
# any possible related GTK upgrade won't affect us... |
95 |
my $succeeded_win = create_upgrade_succeeded_window(); |
96 |
my $failed_win = create_upgrade_failed_window(); |
97 |
|
98 |
while ($refork_gurpmi) { |
99 |
|
100 |
my $ok = fork_gurpmi(@initial_args); |
101 |
if ($refork_gurpmi && !$ok) { |
102 |
$refork_gurpmi--; |
103 |
} else { |
104 |
undef $refork_gurpmi; |
105 |
} |
106 |
|
107 |
# update media in case mirrors got updated if needed: |
108 |
update_media() if $refork_gurpmi; |
109 |
|
110 |
if (!$refork_gurpmi) { |
111 |
if (!$ok) { |
112 |
$failed_win->main && upgrade(); |
113 |
} else { |
114 |
rm_rf(get_stale_upgrade_filename()); |
115 |
$succeeded_win->main and !$::testing and any::reboot(); |
116 |
my $mgaapp_pid = common::is_running('mgaapplet'); |
117 |
defined($mgaapp_pid) && kill('HUP', $mgaapp_pid); |
118 |
} |
119 |
} |
120 |
} |
121 |
} |
122 |
|
123 |
my $width = 500; |
124 |
my @common = ( |
125 |
# explicitely wrap (for 2008.1): |
126 |
line_wrap => 1, |
127 |
# workaround infamous 6 years old gnome bug #101968: |
128 |
width => $width - 50, |
129 |
); |
130 |
|
131 |
sub create_upgrade_failed_window() { |
132 |
local $mygtk2::left_padding = 0; |
133 |
my $w = ugtk2->new(N("Error")); |
134 |
gtkadd($w->{window}, |
135 |
gtknew('VBox', children_tight => [ |
136 |
get_banner(), |
137 |
gtknew('Label_Left', text => N("Installation failed"), @common), |
138 |
gtknew('Label_Left', text => N("Installation logs can be found in '%s'", $log_file), @common), |
139 |
create_okcancel($w, N("Retry"), N("Cancel")), |
140 |
]), |
141 |
); |
142 |
$w->{ok}->grab_focus; |
143 |
return $w; |
144 |
} |
145 |
|
146 |
sub create_upgrade_succeeded_window() { |
147 |
local $mygtk2::left_padding = 0; |
148 |
my $w = ugtk2->new(N("Congratulations")); |
149 |
gtkadd($w->{window}, |
150 |
gtknew('VBox', children_tight => [ |
151 |
get_banner(), |
152 |
gtknew('Label_Left', text => N("Upgrade to Mageia %s release was successfull.", $new_distro_version), |
153 |
@common), |
154 |
gtknew('Label_Left', text => N("You must restart your system."), @common), |
155 |
create_okcancel($w, N("Reboot"), N("Cancel")), |
156 |
]), |
157 |
); |
158 |
$w->{ok}->grab_focus; |
159 |
return $w; |
160 |
} |
161 |
|
162 |
# Returns: undef if failed to authenticate, [$email, $passwd] otherwise |
163 |
sub powerpack_auth_callback { |
164 |
my ($email, $passwd) = @_; |
165 |
my $profile = mgaonline::get_my_mdv_profile($email, $passwd); |
166 |
|
167 |
# Checking for profile retrieving errors... |
168 |
if ($profile->{code} != 0) { |
169 |
my $in = interactive->vnew; |
170 |
$in->ask_warn(N("Error"), |
171 |
N("An error occurred") . "\n" . $profile->{message}); |
172 |
return; |
173 |
} |
174 |
|
175 |
# Checking rights to powerpack media... |
176 |
# |
177 |
# level 2 => mandriva group |
178 |
# level 6 => powerpack subscriber group |
179 |
# data.families => acces to especific version if matches |
180 |
# powerpack-VERSION |
181 |
# |
182 |
my $level = $profile->{data}{club}{level}; |
183 |
if ($level == 2 || $level == 6) { |
184 |
return [$email, $passwd]; |
185 |
} |
186 |
elsif ($profile->{data}{families} =~ /powerpack-$new_distro_version/i) { |
187 |
return [$email, $passwd]; |
188 |
} |
189 |
else { |
190 |
mgaapplet_gui::run_no_rights_dialog( |
191 |
N("Powerpack Media Configuration"), |
192 |
N("You current Mageia account does not have Powerpack subscription enabled."), |
193 |
'https://my.mandriva.com/powerpack/', |
194 |
); |
195 |
return; |
196 |
} |
197 |
} |
198 |
|
199 |
sub try_to_add_powerpack_media() { |
200 |
my $is_powerpack = mgaonline::is_restricted_media_supported(); |
201 |
my $auth_info; |
202 |
|
203 |
# Validating current product for offering powerpack medias... |
204 |
|
205 |
if ($is_powerpack) { |
206 |
# Verifying rights of current powerpack users... |
207 |
my $title = N("Powerpack Media Configuration"); |
208 |
my $description = N("Please fill your My.Mageia login and password to add additional package media for Powerpack."); |
209 |
|
210 |
# If no rights @auth_info == ()... |
211 |
$auth_info = run_ask_credentials_dialog( |
212 |
$title, |
213 |
$description, |
214 |
\&powerpack_auth_callback, |
215 |
); |
216 |
} |
217 |
elsif ($product_id->{product} !~ /flash|free|one/i) { |
218 |
return; # don't offer pwp for any other product |
219 |
} |
220 |
|
221 |
my $choice; # will be 'powerpack', 'free' or undef |
222 |
while ($auth_info |
223 |
|| ($choice = mgaapplet_gui::open_ask_powerpack_dialog( |
224 |
$product_id->{product}, |
225 |
$new_distro_version))) { |
226 |
$auth_info and return $auth_info; |
227 |
|
228 |
# Get the new authentication info from user... |
229 |
my $title = N("Powerpack Media Configuration"); |
230 |
my $description = N("Please fill your account ID to add Powerpack %s version packages media once you have subscribed online", |
231 |
$new_distro_version); |
232 |
$auth_info = run_ask_credentials_dialog( |
233 |
$title, |
234 |
$description, |
235 |
\&powerpack_auth_callback, |
236 |
top_extra => $mgaapplet_gui::powerpack_ad, |
237 |
); |
238 |
} |
239 |
defined $choice or exit 0; # means user has canceled upgrade |
240 |
return; |
241 |
} |
242 |
|
243 |
sub upgrade() { |
244 |
my $xid = gtkroot()->XWINDOW; |
245 |
|
246 |
run_program::raw({ detach => 1 }, 'xdg-screensaver', 'suspend', $xid); |
247 |
my $_w = before_leaving { run_program::raw({ detach => 1 }, 'xdg-screensaver', 'resume', $xid) }; |
248 |
|
249 |
my $file = "$ENV{HOME}/.MgaOnline/urpmi.cfg.backup." . int(rand 100000); |
250 |
log::explanations("backuping urpmi configuration in $file"); |
251 |
cp_af("$root/etc/urpmi/urpmi.cfg", $file); |
252 |
|
253 |
my $urpm = Rpmdrake::open_db::fast_open_urpmi_db(); |
254 |
|
255 |
my $urpmi_lock = eval { |
256 |
local $urpm->{fatal} = sub { die @_ }; |
257 |
urpm::lock::urpmi_db($urpm, 'exclusive'); |
258 |
}; |
259 |
|
260 |
if (my $err = $@) { |
261 |
log::explanations(sprintf("locking urpmi database failed: %s"), $err); |
262 |
ugtk2::ask_warn(N("Error"), |
263 |
N("Installation failed"), |
264 |
'', |
265 |
formatAlaTeX(N("Packages database is locked. Please close other applications |
266 |
working with packages database (do you have another media |
267 |
manager on another desktop, or are you currently installing |
268 |
packages as well?).")) |
269 |
); |
270 |
exit(1); |
271 |
} |
272 |
undef $urpmi_lock; |
273 |
|
274 |
touch(get_stale_upgrade_filename()); |
275 |
|
276 |
# disabled for mageia, should be cleaned |
277 |
#log::explanations( |
278 |
# "checking if restricted (powerpack) media is to be addded"); |
279 |
# add_pwp_auth != undef, means user asked for pwp with good credentials |
280 |
#my $add_pwp_auth = try_to_add_powerpack_media(); |
281 |
my $add_pwp_auth; |
282 |
|
283 |
log::explanations("removing all existing urpmi media for upgrade"); |
284 |
run_program::run('urpmi.removemedia', if_($root, '--urpmi-root', $root), '-a'); |
285 |
|
286 |
$urpm = Rpmdrake::open_db::fast_open_urpmi_db(); |
287 |
if ($urpm->{global_config}{downloader}) { |
288 |
log::explanations("disabling custom downloader in order to use aria2"); |
289 |
delete $urpm->{global_config}{downloader}; |
290 |
urpm::media::write_config($urpm); |
291 |
} |
292 |
|
293 |
log::explanations("adding urpmi media for new distribution"); |
294 |
|
295 |
$ENV{URPMI_ADDMEDIA_REASON} = join(',', 'reason=upgrade', 'upgrade_by=mgaapplet', "upgrade_from=$product_id->{version}"); |
296 |
# the following modifies $MIRRORLIST expansion in urpm/mirrors.pm, |
297 |
# it must be set for gurpmi.addmedia, but also for gurpmi |
298 |
$ENV{URPMI_ADDMEDIA_PRODUCT_VERSION} = $new_distro_version; |
299 |
|
300 |
system('gurpmi.addmedia', '--silent-success', if_($root, "--urpmi-root=$root"), '--distrib', '--mirrorlist', '$MIRRORLIST') and do { |
301 |
log::explanations("adding media for new distribution failed"); |
302 |
rm_rf(get_stale_upgrade_filename()); |
303 |
log::explanations("restoringing urpmi configuration from $file"); |
304 |
cp_af($file, "$root/etc/urpmi/urpmi.cfg"); |
305 |
update_media(); |
306 |
ugtk2::ask_warn(N("Error"), |
307 |
N("Installation failed"), |
308 |
N("Failure when adding medium"), |
309 |
); |
310 |
exit(2); |
311 |
}; |
312 |
|
313 |
if ($add_pwp_auth) { |
314 |
log::explanations("adding restricted (powerpack) media"); |
315 |
|
316 |
my ($email, $passwd) = @$add_pwp_auth; |
317 |
unless (mgaonline::add_medium_powerpack( |
318 |
$email, |
319 |
$passwd, |
320 |
$new_distro_version, |
321 |
urpm::cfg::get_arch() |
322 |
)) { |
323 |
# FIXME Don't replicate code like this! |
324 |
log::explanations("adding media for new distribution failed"); |
325 |
rm_rf(get_stale_upgrade_filename()); |
326 |
log::explanations("restoringing urpmi configuration from $file"); |
327 |
cp_af($file, "$root/etc/urpmi/urpmi.cfg"); |
328 |
update_media(); |
329 |
ugtk2::ask_warn(N("Error"), |
330 |
N("Installation failed"), |
331 |
N("Failed to add powerpack restricted medium"), |
332 |
); |
333 |
exit(2); |
334 |
} |
335 |
# Media was added, update it and move along... |
336 |
update_media(); |
337 |
} |
338 |
|
339 |
log::explanations("upgrading urpmi and rpmdrake"); |
340 |
log::explanations("upgrading the whole system"); |
341 |
|
342 |
# rerun gurpmi in case there was an issue (with eg: big transactions: |
343 |
$refork_gurpmi = 4; |
344 |
{ |
345 |
# force PATH: |
346 |
local $ENV{TMPDIR} = undef; |
347 |
my $log_template = |
348 |
"gurpmi_upgrade_to_${new_distro_version}_XXXXXXXX"; |
349 |
$log_file = chomp_(`mktemp -u --tmpdir=$ENV{HOME}/.MgaOnline/ --suffix=.log $log_template`); |
350 |
log::explanations("logging gurpmi message in '$log_file'"); |
351 |
} |
352 |
|
353 |
# we cannot use installUpdates() as MandrivaUpdate needs the media |
354 |
# flaged as update (or else, we need to add a new option to MandrivaUpdate): |
355 |
run_gurpmi(); |
356 |
} |
357 |
|
358 |
sub fork_gurpmi { |
359 |
run_program::raw({ timeout => 'never' }, |
360 |
'gurpmi', '>>', $log_file, '2>>', $log_file, '--auto', '--auto-select', |
361 |
if_($root, "--urpmi-root=$root"), @_); |
362 |
} |
363 |
|
364 |
sub update_media() { |
365 |
run_program::run('urpmi.update', if_($root, '--urpmi-root', $root), '-a', '--nocheck'); |
366 |
} |