1 |
package urpm::media; |
2 |
|
3 |
# $Id: media.pm 270394 2010-07-30 00:48:07Z misc $ |
4 |
|
5 |
use strict; |
6 |
use urpm 'file_from_local_medium', 'is_local_medium'; |
7 |
use urpm::msg; |
8 |
use urpm::util; |
9 |
use urpm::removable; |
10 |
use urpm::lock; |
11 |
use urpm::md5sum; |
12 |
use MDV::Distribconf; |
13 |
|
14 |
|
15 |
our @PER_MEDIA_OPT = qw( |
16 |
disable-certificate-check |
17 |
downloader |
18 |
ignore |
19 |
key-ids |
20 |
list |
21 |
media_info_dir |
22 |
mirrorlist |
23 |
name |
24 |
no-media-info |
25 |
noreconfigure |
26 |
priority-upgrade |
27 |
removable |
28 |
static |
29 |
synthesis |
30 |
update |
31 |
url |
32 |
verify-rpm |
33 |
virtual |
34 |
with-dir |
35 |
with_hdlist |
36 |
with_synthesis |
37 |
xml-info |
38 |
); |
39 |
|
40 |
my @xml_media_info = ('info', 'files', 'changelog'); |
41 |
|
42 |
my @media_info_prefix_suffix = ( |
43 |
[ 'synthesis.hdlist', '.cz' ], |
44 |
[ 'hdlist', '.cz' ], |
45 |
[ 'descriptions', '' ], |
46 |
[ 'names', '' ], |
47 |
[ 'MD5SUM', '' ], |
48 |
(map { [ $_, '.xml.lzma' ] } @xml_media_info), |
49 |
); |
50 |
|
51 |
|
52 |
sub get_medium_option { |
53 |
my ($urpm, $medium, $option_name) = @_; |
54 |
|
55 |
defined $medium->{$option_name} ? $medium->{$option_name} : $urpm->{options}{$option_name}; |
56 |
} |
57 |
|
58 |
sub _is_iso { |
59 |
my ($removable_dev) = @_; |
60 |
$removable_dev && $removable_dev =~ /\.iso$/i; |
61 |
} |
62 |
|
63 |
sub only_media_opts { |
64 |
my ($m) = @_; |
65 |
my %m = map { $_ => $m->{$_} } grep { defined $m->{$_} } @PER_MEDIA_OPT; |
66 |
\%m; |
67 |
} |
68 |
sub _only_media_opts_read { |
69 |
my ($m) = @_; |
70 |
my $c = only_media_opts($m); |
71 |
$c->{media_info_dir} ||= 'media_info'; |
72 |
$c->{iso} = delete $c->{removable} if $c->{removable} && _is_iso($c->{removable}); |
73 |
$c; |
74 |
} |
75 |
sub _only_media_opts_write { |
76 |
my ($m) = @_; |
77 |
my $c = only_media_opts($m); |
78 |
delete $c->{media_info_dir} if $c->{media_info_dir} eq 'media_info'; |
79 |
delete $c->{url} if $c->{mirrorlist}; |
80 |
$c->{removable} = delete $c->{iso} if $c->{iso}; |
81 |
$c; |
82 |
} |
83 |
|
84 |
sub read_private_netrc { |
85 |
my ($urpm) = @_; |
86 |
|
87 |
my @words = split(/\s+/, scalar cat_($urpm->{private_netrc})); |
88 |
my @l; |
89 |
my $e; |
90 |
while (@words) { |
91 |
my $keyword = shift @words; |
92 |
if ($keyword eq 'machine') { |
93 |
push @l, $e = { machine => shift(@words) }; |
94 |
} elsif ($keyword eq 'default') { |
95 |
push @l, $e = { default => '' }; |
96 |
} elsif ($keyword eq 'login' || $keyword eq 'password' || $keyword eq 'account') { |
97 |
$e->{$keyword} = shift(@words); |
98 |
} else { |
99 |
$urpm->{error}("unknown netrc command $keyword"); |
100 |
} |
101 |
} |
102 |
@l; |
103 |
} |
104 |
|
105 |
sub read_config_add_passwords { |
106 |
my ($urpm, $config) = @_; |
107 |
|
108 |
my @netrc = read_private_netrc($urpm) or return; |
109 |
foreach (grep { $_->{url} } @{$config->{media}}) { |
110 |
my $u = urpm::download::parse_url_with_login($_->{url}) or next; |
111 |
if (my ($e) = grep { ($_->{default} || $_->{machine} eq $u->{machine}) && $_->{login} eq $u->{login} } @netrc) { |
112 |
$_->{url} = sprintf('%s://%s:%s@%s%s', $u->{proto}, $u->{login}, $e->{password}, $u->{machine}, $u->{dir}); |
113 |
} else { |
114 |
$urpm->{log}(sprintf('no password found for %s@%s', $u->{login}, $u->{machine})); |
115 |
} |
116 |
} |
117 |
} |
118 |
|
119 |
sub remove_passwords_and_write_private_netrc { |
120 |
my ($urpm, $config) = @_; |
121 |
|
122 |
my @l; |
123 |
foreach (grep { $_->{url} } @{$config->{media}}) { |
124 |
my $u = urpm::download::parse_url_with_login($_->{url}) or next; |
125 |
#- check whether a password is visible |
126 |
$u->{password} or next; |
127 |
|
128 |
push @l, $u; |
129 |
$_->{url} = sprintf('%s://%s@%s%s', $u->{proto}, $u->{login}, $u->{machine}, $u->{dir}); |
130 |
} |
131 |
{ |
132 |
my $fh = urpm::sys::open_safe($urpm, '>', $urpm->{private_netrc}) or return; |
133 |
foreach my $u (@l) { |
134 |
printf $fh "machine %s login %s password %s\n", $u->{machine}, $u->{login}, $u->{password}; |
135 |
} |
136 |
} |
137 |
chmod 0600, $urpm->{private_netrc}; |
138 |
} |
139 |
|
140 |
#- handle deprecated way of saving passwords |
141 |
sub recover_url_from_list { |
142 |
my ($urpm, $medium) = @_; |
143 |
|
144 |
my $list = delete $medium->{list} or return; |
145 |
my $statedir_list = "$urpm->{statedir}/$list"; |
146 |
|
147 |
#- /./ is end of url marker in list file (typically generated by a |
148 |
#- find . -name "*.rpm" > list |
149 |
#- for exportable list file. |
150 |
if (my @probe = map { m!^(.*)/\./! || m!^(.*)/[^/]*$! } cat_($statedir_list)) { |
151 |
$urpm->{log}("recovering url from $statedir_list"); |
152 |
($medium->{url}) = sort { length($a) <=> length($b) } @probe; |
153 |
$urpm->{modified} = 1; #- ensure urpmi.cfg is handled using only partially hidden url + netrc, since file list won't be generated anymore |
154 |
unlink $statedir_list; |
155 |
} |
156 |
} |
157 |
|
158 |
sub _read_config__read_media_info { |
159 |
my ($urpm) = @_; |
160 |
|
161 |
require File::Glob; |
162 |
# we can't use perl's glob() because there could be spaces in |
163 |
# $urpm->{mediacfgdir} |
164 |
my %url2mediamap; |
165 |
my %mirrorlist2mediamap; |
166 |
foreach my $media_dir (File::Glob::bsd_glob("$urpm->{mediacfgdir}/*")) { |
167 |
next if !-d $media_dir; |
168 |
|
169 |
$urpm->{debug} and $urpm->{debug}("parsing: $media_dir"); |
170 |
|
171 |
my $media_cfg = $media_dir . '/media.cfg'; |
172 |
my $distribconf = MDV::Distribconf->new($media_cfg, undef) or next; |
173 |
$distribconf->settree('mandriva'); |
174 |
$distribconf->parse_mediacfg($media_cfg) or next; |
175 |
|
176 |
if (open(my $URLS, '<', $media_dir . '/url')) { |
177 |
local $_; |
178 |
while (<$URLS>) { |
179 |
chomp($_); |
180 |
foreach my $medium ($distribconf->listmedia) { |
181 |
my $medium_path = reduce_pathname($_ . '/' . $distribconf->getpath($medium, 'path')); |
182 |
$url2mediamap{$medium_path} = [$distribconf, $medium]; |
183 |
} |
184 |
} |
185 |
} |
186 |
|
187 |
if (open(my $MIRRORLISTS, '<', $media_dir . '/mirrorlist')) { |
188 |
local $_; |
189 |
while (<$MIRRORLISTS>) { |
190 |
my $mirrorlist = $_; |
191 |
chomp($mirrorlist); |
192 |
foreach my $medium ($distribconf->listmedia) { |
193 |
my $medium_path = $distribconf->getpath($medium, 'path'); |
194 |
$mirrorlist2mediamap{$mirrorlist}{$medium_path} = [ $distribconf, $medium ]; |
195 |
} |
196 |
} |
197 |
} |
198 |
} |
199 |
(\%url2mediamap, \%mirrorlist2mediamap); |
200 |
} |
201 |
|
202 |
sub _associate_media_with_mediacfg { |
203 |
my ($urpm, $media) = @_; |
204 |
|
205 |
my ($url2mediamap, $mirrorlist2mediamap) = _read_config__read_media_info($urpm); |
206 |
foreach my $medium (@$media) { |
207 |
if ($medium->{mirrorlist}) { |
208 |
$medium->{mediacfg} = $mirrorlist2mediamap->{$medium->{mirrorlist}}{$medium->{'with-dir'}}; |
209 |
} elsif ($medium->{url}) { |
210 |
$medium->{mediacfg} = $url2mediamap->{$medium->{url}}; |
211 |
} |
212 |
} |
213 |
} |
214 |
|
215 |
#- Loads /etc/urpmi/urpmi.cfg and performs basic checks. |
216 |
#- Does not handle old format: <name> <url> [with <path_hdlist>] |
217 |
sub read_config { |
218 |
my ($urpm, $nocheck) = @_; |
219 |
return if $urpm->{media}; #- media already loaded |
220 |
$urpm->{media} = []; |
221 |
my $config = urpm::cfg::load_config($urpm->{config}) |
222 |
or $urpm->{fatal}(6, $urpm::cfg::err); |
223 |
|
224 |
#- per-media options |
225 |
read_config_add_passwords($urpm, $config); |
226 |
|
227 |
my @media; |
228 |
foreach my $m (@{$config->{media}}) { |
229 |
my $medium = _only_media_opts_read($m); |
230 |
|
231 |
if (!$medium->{url} && !$medium->{mirrorlist}) { |
232 |
#- recover the url the old deprecated way... |
233 |
#- only useful for migration, new urpmi.cfg will use netrc |
234 |
recover_url_from_list($urpm, $medium); |
235 |
$medium->{url} or $urpm->{error}("unable to find url in list file $medium->{name}, medium ignored"); |
236 |
} |
237 |
push @media, $medium; |
238 |
} |
239 |
|
240 |
# associate medias read from the config file with their description in a |
241 |
# media.cfg file |
242 |
# @media content will be modified and then add_existing medium will take |
243 |
# care of copying the media to $urpm |
244 |
_associate_media_with_mediacfg($urpm, \@media); |
245 |
|
246 |
add_existing_medium($urpm, $_, $nocheck) foreach @media; |
247 |
|
248 |
eval { require urpm::ldap; urpm::ldap::load_ldap_media($urpm) }; |
249 |
} |
250 |
|
251 |
#- if invalid, set {ignore} |
252 |
sub check_existing_medium { |
253 |
my ($urpm, $medium) = @_; |
254 |
|
255 |
my $err; |
256 |
if (!$medium->{url} && !$medium->{mirrorlist}) { |
257 |
$err = $medium->{virtual} ? |
258 |
N("virtual medium \"%s\" should have a clear url, medium ignored", |
259 |
$medium->{name}) : |
260 |
N("unable to access list file of \"%s\", medium ignored", $medium->{name}); |
261 |
} elsif (!$medium->{ignore} |
262 |
&& !-r any_synthesis($urpm, $medium)) { |
263 |
$err = N("unable to access synthesis file of \"%s\", medium ignored", $medium->{name}); |
264 |
} |
265 |
if ($err) { |
266 |
$medium->{ignore} = 1; |
267 |
$urpm->{error}($err); |
268 |
} |
269 |
} |
270 |
|
271 |
sub _migrate__with_synthesis { |
272 |
my ($medium, $with_synthesis) = @_; |
273 |
|
274 |
#- try to migrate to media_info_dir |
275 |
my $b = basename($with_synthesis); |
276 |
if ($b eq 'synthesis.hdlist.cz' || $b eq 'hdlist.cz') { |
277 |
$medium->{media_info_dir} = dirname($with_synthesis); |
278 |
} else { |
279 |
$with_synthesis =~ s/(synthesis\.)?(hdlist.*\.cz)$/synthesis.$2/; |
280 |
$medium->{with_synthesis} = $with_synthesis; |
281 |
} |
282 |
} |
283 |
|
284 |
#- probe medium to be used, take old medium into account too. |
285 |
sub add_existing_medium { |
286 |
my ($urpm, $medium, $nocheck) = @_; |
287 |
|
288 |
if (name2medium($urpm, $medium->{name})) { |
289 |
$urpm->{error}(N("trying to override existing medium \"%s\", skipping", $medium->{name})); |
290 |
return; |
291 |
} |
292 |
|
293 |
if ($medium->{with_hdlist}) { |
294 |
_migrate__with_synthesis($medium, delete $medium->{with_hdlist}); |
295 |
$urpm->{modified} = 1; |
296 |
} |
297 |
|
298 |
check_existing_medium($urpm, $medium) if !$nocheck; |
299 |
|
300 |
_migrate_removable_device($urpm, $medium); |
301 |
|
302 |
#- clear URLs for trailing /es. |
303 |
$medium->{url} and $medium->{url} =~ s|(.*?)/*$|$1|; |
304 |
|
305 |
push @{$urpm->{media}}, $medium; |
306 |
} |
307 |
|
308 |
sub file_from_file_url { |
309 |
my ($url) = @_; |
310 |
$url =~ m!^(?:file:/)?(/.*)! && $1; |
311 |
} |
312 |
|
313 |
sub _local_file { |
314 |
my ($medium) = @_; |
315 |
$medium->{url} && file_from_file_url($medium->{url}); |
316 |
} |
317 |
|
318 |
sub _is_local_virtual { |
319 |
my ($medium) = @_; |
320 |
$medium->{virtual} && _local_file($medium); |
321 |
} |
322 |
sub _is_remote_virtual { |
323 |
my ($medium) = @_; |
324 |
$medium->{virtual} && !_local_file($medium); |
325 |
} |
326 |
|
327 |
sub _url_with_synthesis_basename { |
328 |
my ($medium) = @_; |
329 |
|
330 |
$medium->{with_synthesis} |
331 |
? basename($medium->{with_synthesis}) |
332 |
: 'synthesis.hdlist.cz'; |
333 |
} |
334 |
sub _synthesis_dir_rel { |
335 |
my ($medium) = @_; |
336 |
$medium->{'no-media-info'} || $medium->{unknown_media_info} and return; |
337 |
|
338 |
$medium->{with_synthesis} |
339 |
? "$medium->{with_synthesis}/.." |
340 |
: $medium->{media_info_dir}; |
341 |
} |
342 |
sub _synthesis_dir { |
343 |
my ($medium) = @_; |
344 |
my $rel = _synthesis_dir_rel($medium) or return; |
345 |
|
346 |
my $base = file_from_local_medium($medium) || $medium->{url}; |
347 |
reduce_pathname("$base/$rel"); |
348 |
} |
349 |
|
350 |
# the difference between _valid_synthesis_dir and _synthesis_dir |
351 |
# is only to handle upgrades from older urpmi.cfg where no {media_info_dir} |
352 |
# meant no-media-info |
353 |
sub _valid_synthesis_dir { |
354 |
my ($medium) = @_; |
355 |
my $dir = _synthesis_dir($medium); |
356 |
$dir && -d $dir; |
357 |
} |
358 |
|
359 |
sub _url_with_synthesis_rel { |
360 |
my ($medium) = @_; |
361 |
|
362 |
$medium->{with_synthesis} || |
363 |
"$medium->{media_info_dir}/synthesis.hdlist.cz"; |
364 |
|
365 |
} |
366 |
sub _url_with_synthesis { |
367 |
my ($medium) = @_; |
368 |
my $rel = _url_with_synthesis_rel($medium) or return; |
369 |
|
370 |
my $base = file_from_local_medium($medium) || $medium->{url}; |
371 |
reduce_pathname("$base/$rel"); |
372 |
} |
373 |
|
374 |
sub synthesis { |
375 |
my ($medium) = @_; |
376 |
statedir_media_info_basename($medium, 'synthesis.hdlist', '.cz'); |
377 |
} |
378 |
|
379 |
sub statedir_media_info_basename { |
380 |
my ($medium, $prefix, $suffix) = @_; |
381 |
$medium->{name} && "$prefix.$medium->{name}$suffix"; |
382 |
} |
383 |
|
384 |
sub statedir_media_info_dir { |
385 |
my ($urpm, $medium) = @_; |
386 |
$medium->{name} && "$urpm->{statedir}/$medium->{name}"; |
387 |
} |
388 |
|
389 |
sub old_statedir_media_info_file { |
390 |
my ($urpm, $medium, $prefix, $suffix) = @_; |
391 |
$medium->{name} && "$urpm->{statedir}/" . statedir_media_info_basename($medium, $prefix, $suffix); |
392 |
} |
393 |
sub new_statedir_media_info_file { |
394 |
my ($urpm, $medium, $prefix, $suffix) = @_; |
395 |
my $dir = statedir_media_info_dir($urpm, $medium); |
396 |
$dir && "$dir/$prefix$suffix"; |
397 |
} |
398 |
sub statedir_media_info_file { |
399 |
my ($urpm, $medium, $prefix, $suffix) = @_; |
400 |
my $dir = statedir_media_info_dir($urpm, $medium); |
401 |
-d $dir ? "$dir/$prefix$suffix" : old_statedir_media_info_file($urpm, $medium, $prefix, $suffix); |
402 |
} |
403 |
sub statedir_synthesis { |
404 |
my ($urpm, $medium) = @_; |
405 |
statedir_media_info_file($urpm, $medium, 'synthesis.hdlist', '.cz'); |
406 |
} |
407 |
sub statedir_descriptions { |
408 |
my ($urpm, $medium) = @_; |
409 |
statedir_media_info_file($urpm, $medium, 'descriptions', ''); |
410 |
} |
411 |
sub statedir_names { |
412 |
my ($urpm, $medium) = @_; |
413 |
old_statedir_media_info_file($urpm, $medium, 'names', ''); |
414 |
} |
415 |
sub statedir_MD5SUM { |
416 |
my ($urpm, $medium) = @_; |
417 |
statedir_media_info_file($urpm, $medium, 'MD5SUM', ''); |
418 |
} |
419 |
sub statedir_hdlist { |
420 |
my ($urpm, $medium) = @_; |
421 |
statedir_media_info_file($urpm, $medium, 'hdlist', '.cz'); |
422 |
} |
423 |
sub statedir_xml_info { |
424 |
my ($urpm, $medium, $xml_info) = @_; |
425 |
statedir_media_info_file($urpm, $medium, $xml_info, '.xml.lzma'); |
426 |
} |
427 |
sub cachedir_with_synthesis { |
428 |
my ($urpm, $medium) = @_; |
429 |
_url_with_synthesis($medium) && "$urpm->{cachedir}/partial/synthesis.hdlist.cz"; |
430 |
} |
431 |
sub any_synthesis { |
432 |
my ($urpm, $medium) = @_; |
433 |
my $f = _is_local_virtual($medium) ? _url_with_synthesis($medium) |
434 |
: statedir_synthesis($urpm, $medium); |
435 |
-e $f && $f; |
436 |
} |
437 |
sub any_media_info_file { |
438 |
my ($urpm, $medium, $prefix, $suffix, $quiet, $o_callback) = @_; |
439 |
|
440 |
if (my $base = _local_file($medium)) { |
441 |
my $f = $medium->{with_synthesis} |
442 |
? reduce_pathname("$base/$prefix." . _synthesis_suffix($medium) . $suffix) |
443 |
: _synthesis_dir($medium) . "/$prefix$suffix"; |
444 |
|
445 |
if (! -e $f) { |
446 |
# in some weird cases (iso on disk), the hdlist is not available where it should be, |
447 |
# but we can use the statedir copy |
448 |
$f = statedir_media_info_file($urpm, $medium, $prefix, $suffix); |
449 |
} |
450 |
|
451 |
-e $f && $f; |
452 |
} else { |
453 |
_any_media_info__or_download($urpm, $medium, $prefix, $suffix, $quiet, $o_callback); |
454 |
} |
455 |
} |
456 |
sub any_hdlist { |
457 |
my ($urpm, $medium, $quiet) = @_; |
458 |
any_media_info_file($urpm, $medium, 'hdlist', '.cz', $quiet, \&urpm::download::sync_logger); |
459 |
} |
460 |
sub any_xml_info { |
461 |
my ($urpm, $medium, $xml_info, $quiet, $o_callback) = @_; |
462 |
any_media_info_file($urpm, $medium, $xml_info, '.xml.lzma', $quiet, $o_callback || \&urpm::download::sync_logger); |
463 |
} |
464 |
|
465 |
sub name2medium { |
466 |
my ($urpm, $name) = @_; |
467 |
my ($medium) = grep { $_->{name} eq $name } @{$urpm->{media}}; |
468 |
$medium; |
469 |
} |
470 |
|
471 |
sub userdirs { |
472 |
my ($urpm) = @_; |
473 |
my $prefix = urpm::userdir_prefix($urpm); |
474 |
grep { m!^\Q$prefix\E\d+$! && -d $_ && ! -l $_ } glob("$prefix*"); |
475 |
} |
476 |
|
477 |
sub remove_user_media_info_files { |
478 |
my ($urpm, $medium) = @_; |
479 |
|
480 |
foreach my $dir (userdirs($urpm)) { |
481 |
require File::Glob; |
482 |
# we can't use perl's glob() because $medium->{name} can contain spaces |
483 |
my @files = map { File::Glob::bsd_glob("$dir/*.$medium->{name}.$_") } 'cz', 'xml.lzma' or next; |
484 |
|
485 |
$urpm->{log}("cleaning $dir"); |
486 |
foreach (@files) { |
487 |
unlink $_ or $urpm->{error}("removing $_ failed"); |
488 |
} |
489 |
} |
490 |
} |
491 |
|
492 |
#- probe device associated with a removable device. |
493 |
sub _migrate_removable_device { |
494 |
my ($urpm, $medium) = @_; |
495 |
|
496 |
$medium->{url} or return; |
497 |
|
498 |
# always drop {removable}, it is obsolete |
499 |
# (nb: for iso files, {removable} has already been renamed into {iso} internally) |
500 |
delete $medium->{removable}; |
501 |
|
502 |
if (my $url = _migrate_removable_url($medium->{url})) { |
503 |
$medium->{url} = $url; |
504 |
} else { |
505 |
$urpm->{error}(N("failed to migrate removable device, ignoring media")); |
506 |
$medium->{ignore} = 1; |
507 |
} |
508 |
} |
509 |
|
510 |
sub _migrate_removable_url { |
511 |
my ($url) = @_; |
512 |
|
513 |
if ($url =~ /^removable/) { |
514 |
$url =~ s!^removable(.*?)://!/!; |
515 |
if ($url =~ s!/(mnt|media)/cd\w+/?!cdrom://!i) { |
516 |
# success! |
517 |
} else { |
518 |
return; |
519 |
} |
520 |
} |
521 |
$url; |
522 |
} |
523 |
|
524 |
|
525 |
#- Writes the urpmi.cfg file. |
526 |
sub write_urpmi_cfg { |
527 |
my ($urpm) = @_; |
528 |
|
529 |
#- avoid trashing exiting configuration if it wasn't loaded |
530 |
$urpm->{media} or return; |
531 |
|
532 |
my $config = { |
533 |
#- global config options found in the config file, without the ones |
534 |
#- set from the command-line |
535 |
global => $urpm->{global_config}, |
536 |
media => [ map { _only_media_opts_write($_) } grep { !$_->{external} } @{$urpm->{media}} ], |
537 |
}; |
538 |
remove_passwords_and_write_private_netrc($urpm, $config); |
539 |
|
540 |
urpm::cfg::dump_config($urpm->{config}, $config) |
541 |
or $urpm->{fatal}(6, N("unable to write config file [%s]", $urpm->{config})); |
542 |
|
543 |
$urpm->{log}(N("wrote config file [%s]", $urpm->{config})); |
544 |
|
545 |
#- everything should be synced now. |
546 |
delete $urpm->{modified}; |
547 |
} |
548 |
|
549 |
sub write_config { |
550 |
my ($urpm) = @_; |
551 |
|
552 |
write_urpmi_cfg($urpm); |
553 |
} |
554 |
|
555 |
|
556 |
sub _tempignore { |
557 |
my ($medium, $ignore) = @_; |
558 |
$medium->{ignore} = $ignore; |
559 |
} |
560 |
|
561 |
#- read urpmi.cfg file as well as necessary synthesis files |
562 |
#- options : |
563 |
#- root (deprecated, set directly $urpm->{root}) |
564 |
#- cmdline_skiplist |
565 |
#- download_callback (used by _auto_update_media) |
566 |
#- |
567 |
#- callback (urpmf) |
568 |
#- nodepslist (for urpmq, urpmf: when we don't need the synthesis) |
569 |
#- no_skiplist (urpmf) |
570 |
#- |
571 |
#- synthesis (use this synthesis file, and only this synthesis file) |
572 |
#- |
573 |
#- parallel |
574 |
#- usedistrib (otherwise uses urpmi.cfg) |
575 |
#- media |
576 |
#- excludemedia |
577 |
#- sortmedia |
578 |
#- |
579 |
#- update |
580 |
#- searchmedia |
581 |
sub configure { |
582 |
my ($urpm, %options) = @_; |
583 |
|
584 |
clean($urpm); |
585 |
|
586 |
$options{parallel} && $options{usedistrib} and $urpm->{fatal}(1, N("Can't use parallel mode with use-distrib mode")); |
587 |
|
588 |
if ($options{parallel}) { |
589 |
require urpm::parallel; |
590 |
urpm::parallel::configure($urpm, $options{parallel}); |
591 |
|
592 |
if (!$options{media} && $urpm->{parallel_handler}{media}) { |
593 |
$options{media} = $urpm->{parallel_handler}{media}; |
594 |
$urpm->{log}->(N("using associated media for parallel mode: %s", $options{media})); |
595 |
} |
596 |
} else { |
597 |
#- nb: can't have both parallel and root |
598 |
$urpm->{root} = $options{root} if $options{root}; |
599 |
} |
600 |
|
601 |
if ($urpm->{root} && ! -c "$urpm->{root}/dev/null") { |
602 |
mkdir "$urpm->{root}/dev"; |
603 |
system("/bin/cp", "-a", '/dev/null', "$urpm->{root}/dev"); |
604 |
} |
605 |
|
606 |
if ($options{synthesis}) { |
607 |
if ($options{synthesis} ne 'none') { |
608 |
#- synthesis take precedence over media, update options. |
609 |
$options{media} || $options{excludemedia} || $options{sortmedia} || $options{update} || $options{usedistrib} || $options{parallel} and |
610 |
$urpm->{fatal}(1, N("--synthesis cannot be used with --media, --excludemedia, --sortmedia, --update, --use-distrib or --parallel")); |
611 |
|
612 |
my $synthesis = $options{synthesis}; |
613 |
if ($synthesis !~ m!^/!) { |
614 |
require Cwd; |
615 |
$synthesis = Cwd::getcwd() . '/' . $synthesis; |
616 |
} |
617 |
my ($url, $with) = $synthesis =~ m!(.*)/+(media_info/+synthesis\.hdlist\.cz)$! ? ($1, $2) : |
618 |
(dirname($synthesis), basename($synthesis)); |
619 |
|
620 |
$urpm->{media} = []; |
621 |
add_medium($urpm, 'Virtual', $url, $with, %options, virtual => 1, on_the_fly => 1); |
622 |
} |
623 |
} elsif ($options{usedistrib}) { |
624 |
$urpm->{media} = []; |
625 |
add_distrib_media($urpm, "Virtual", $options{usedistrib}, %options, virtual => 1, on_the_fly => 1); |
626 |
} else { |
627 |
read_config($urpm, ''); |
628 |
if (!$options{media} && $urpm->{options}{'default-media'}) { |
629 |
$options{media} = $urpm->{options}{'default-media'}; |
630 |
} |
631 |
} |
632 |
|
633 |
if ($options{media}) { |
634 |
delete $_->{modified} foreach @{$urpm->{media} || []}; |
635 |
select_media($urpm, split /,/, $options{media}); |
636 |
foreach (@{$urpm->{media} || []}) { |
637 |
_tempignore($_, !$_->{modified}); |
638 |
} |
639 |
} |
640 |
if ($options{searchmedia}) { |
641 |
foreach (select_media_by_name($urpm, [ split /,/, $options{searchmedia} ])) { |
642 |
#- Ensure this media is selected |
643 |
$_->{modified} = 1; |
644 |
_tempignore($_, 0); |
645 |
$_->{searchmedia} = 1; |
646 |
} |
647 |
} |
648 |
if ($options{update}) { |
649 |
foreach (grep { !$_->{ignore} && $_->{update} } @{$urpm->{media} || []}) { |
650 |
#- Ensure update media are selected |
651 |
$_->{modified} = 1; |
652 |
_tempignore($_, 0); |
653 |
$_->{searchmedia} = 1; |
654 |
} |
655 |
} |
656 |
if ($options{excludemedia}) { |
657 |
delete $_->{modified} foreach @{$urpm->{media} || []}; |
658 |
foreach (select_media_by_name($urpm, [ split /,/, $options{excludemedia} ])) { |
659 |
$_->{modified} = 1; |
660 |
#- this is only a local ignore that will not be saved. |
661 |
_tempignore($_, 1); |
662 |
} |
663 |
} |
664 |
if ($options{sortmedia}) { |
665 |
my @sorted_media = map { select_media_by_name($urpm, [$_]) } split(/,/, $options{sortmedia}); |
666 |
my @remaining = difference2($urpm->{media}, \@sorted_media); |
667 |
$urpm->{media} = [ @sorted_media, @remaining ]; |
668 |
} |
669 |
_auto_update_media($urpm, %options); |
670 |
|
671 |
_pick_mirror_if_needed($urpm, $_, '') foreach non_ignored_media($urpm, $options{update}); |
672 |
|
673 |
parse_media($urpm, \%options) if !$options{nodepslist}; |
674 |
|
675 |
#- determine package to withdraw (from skip.list file) only if something should be withdrawn. |
676 |
if (!$options{nodepslist}) { |
677 |
_compute_flags_for_skiplist($urpm, $options{cmdline_skiplist}) if !$options{no_skiplist}; |
678 |
_compute_flags_for_instlist($urpm); |
679 |
} |
680 |
} |
681 |
|
682 |
#- for remote "virtual" media |
683 |
#- options: download_callback, nomd5sum, quiet, nopubkey |
684 |
sub _auto_update_media { |
685 |
my ($urpm, %options) = @_; |
686 |
|
687 |
$options{callback} = delete $options{download_callback}; |
688 |
|
689 |
foreach (grep { _is_remote_virtual($_) || $urpm->{options}{'auto-update'} } |
690 |
non_ignored_media($urpm, $options{update})) { |
691 |
_update_medium($urpm, $_, %options); |
692 |
} |
693 |
} |
694 |
|
695 |
sub non_ignored_media { |
696 |
my ($urpm, $b_only_marked_update) = @_; |
697 |
|
698 |
grep { !$_->{ignore} && (!$b_only_marked_update || $_->{update}) } @{$urpm->{media} || []}; |
699 |
} |
700 |
|
701 |
sub all_media_to_update { |
702 |
my ($urpm, $b_only_marked_update) = @_; |
703 |
|
704 |
grep { !$_->{ignore} |
705 |
&& !$_->{static} && !urpm::is_cdrom_url($_->{url}) && !$_->{iso} |
706 |
&& (!$b_only_marked_update || $_->{update}); |
707 |
} @{$urpm->{media} || []}; |
708 |
} |
709 |
|
710 |
sub parse_media { |
711 |
my ($urpm, $options) = @_; |
712 |
|
713 |
foreach (non_ignored_media($urpm, $options->{update})) { |
714 |
delete @$_{qw(start end)}; |
715 |
_parse_synthesis_or_ignore($urpm, $_, $options->{callback}); |
716 |
|
717 |
if ($_->{searchmedia}) { |
718 |
$urpm->{searchmedia} = 1; |
719 |
$urpm->{debug} and $urpm->{debug}(N("Search start: %s end: %s", $_->{start}, $_->{end})); |
720 |
} |
721 |
|
722 |
$< == 0 and _generate_medium_names($urpm, $_); |
723 |
} |
724 |
} |
725 |
|
726 |
sub _compute_flags_for_skiplist { |
727 |
my ($urpm, $cmdline_skiplist) = @_; |
728 |
my %uniq; |
729 |
$urpm->compute_flags( |
730 |
urpm::sys::get_packages_list($urpm->{skiplist}, $cmdline_skiplist), |
731 |
skip => 1, |
732 |
callback => sub { |
733 |
my ($urpm, $pkg) = @_; |
734 |
$pkg->is_arch_compat && ! exists $uniq{$pkg->fullname} or return; |
735 |
$uniq{$pkg->fullname} = undef; |
736 |
$urpm->{debug} and $urpm->{debug}(N("skipping package %s", scalar($pkg->fullname))); |
737 |
}, |
738 |
); |
739 |
} |
740 |
|
741 |
sub _compute_flags_for_instlist { |
742 |
my ($urpm) = @_; |
743 |
|
744 |
my %uniq; |
745 |
$urpm->compute_flags( |
746 |
urpm::sys::get_packages_list($urpm->{instlist}), |
747 |
disable_obsolete => 1, |
748 |
callback => sub { |
749 |
my ($urpm, $pkg) = @_; |
750 |
$pkg->is_arch_compat && ! exists $uniq{$pkg->fullname} or return; |
751 |
$uniq{$pkg->fullname} = undef; |
752 |
$urpm->{log}(N("would install instead of upgrade package %s", scalar($pkg->fullname))); |
753 |
}, |
754 |
); |
755 |
|
756 |
} |
757 |
|
758 |
sub maybe_find_zeroconf { |
759 |
my ($urpm, $url, $options) = @_; |
760 |
if (delete $options->{zeroconf}) { |
761 |
$url and die "unexpected url $url together with zeroconf\n"; |
762 |
$url = find_zeroconf_repository($urpm); |
763 |
if ($url) { |
764 |
$url = urpm::mirrors::_add__with_dir($url, delete $options->{"with-dir"}); |
765 |
delete $options->{mirrorlist}; |
766 |
} |
767 |
} |
768 |
return $url; |
769 |
} |
770 |
|
771 |
sub find_zeroconf_repository { |
772 |
my ($urpm) = @_; |
773 |
|
774 |
my $zeroconf_timeout = 10; |
775 |
my $res; |
776 |
eval { |
777 |
local $SIG{ALRM} = sub { die "timeout" }; |
778 |
alarm($zeroconf_timeout); |
779 |
|
780 |
$urpm->{debug} and $urpm->{debug}("trying to find a zeroconf repository"); |
781 |
require Net::Bonjour; |
782 |
$res = Net::Bonjour->new('mdv_urpmi'); |
783 |
|
784 |
alarm(0); |
785 |
}; |
786 |
|
787 |
if ($@) { |
788 |
$urpm->{error}("zeroconf error: $@"), return; |
789 |
} |
790 |
|
791 |
require urpm::mirrors; |
792 |
my $product_id = urpm::mirrors::parse_LDAP_namespace_structure(cat_('/etc/product.id')); |
793 |
my $path_suffix = join('/', lc($product_id->{branch}), $product_id->{version}, $product_id->{arch}); |
794 |
|
795 |
foreach my $entry ($res->entries) { |
796 |
my $base_url = $entry->attribute('protocol') . '://' . $entry->address . ':' . $entry->port . $entry->attribute('path'); |
797 |
my $url = $base_url . '/' . $path_suffix; |
798 |
my $distribconf = _new_distribconf_and_download($urpm, { url => $url }); |
799 |
if ($distribconf) { |
800 |
$urpm->{log}(sprintf("found zeroconf repository: %s", $url)); |
801 |
return $url; |
802 |
} |
803 |
} |
804 |
|
805 |
$urpm->{debug} and $urpm->{debug}("unable to find zeroconf repository"); |
806 |
return; |
807 |
} |
808 |
|
809 |
#- add a new medium, sync the config file accordingly. |
810 |
#- returns the new medium's name. (might be different from the requested |
811 |
#- name if index_name was specified) |
812 |
#- options: ignore, index_name, nolock, update, virtual, media_info_dir, mirrorlist, zeroconf, with-dir, xml-info, on_the_fly |
813 |
sub add_medium { |
814 |
my ($urpm, $name, $url, $with_synthesis, %options) = @_; |
815 |
|
816 |
#- make sure configuration has been read. |
817 |
$urpm->{media} or die "caller should have used ->read_config or ->configure first"; |
818 |
|
819 |
#- if a medium with that name has already been found, we have to exit now |
820 |
if (defined $options{index_name}) { |
821 |
my ($i, $basename) = ($options{index_name}, $name); |
822 |
while (1) { |
823 |
++$i; |
824 |
$name = $basename . ($i == 1 ? '' : $i); |
825 |
last if !name2medium($urpm, $name); |
826 |
} |
827 |
} else { |
828 |
name2medium($urpm, $name) and $urpm->{fatal}(5, N("medium \"%s\" already exists", $name)); |
829 |
} |
830 |
|
831 |
$url = maybe_find_zeroconf($urpm, $url, \%options); |
832 |
|
833 |
$url =~ s,/*$,,; #- clear URLs for trailing /es. |
834 |
|
835 |
#- creating the medium info. |
836 |
my $medium = { name => $name, |
837 |
url => $url, |
838 |
modified => !$options{ignore}, |
839 |
}; |
840 |
foreach (qw(downloader update ignore media_info_dir mirrorlist with-dir xml-info)) { |
841 |
$medium->{$_} = $options{$_} if exists $options{$_}; |
842 |
} |
843 |
|
844 |
#- those files must not be there (cf mdvbz#36267) |
845 |
_clean_statedir_medium_files($urpm, $medium); |
846 |
if (!($options{virtual} && _local_file($medium)) |
847 |
&& !$urpm->{urpmi_root}) { # with --urpmi-root, we do not use statedir_media_info_file to allow compatibility with older urpmi |
848 |
mkdir statedir_media_info_dir($urpm, $medium), 0755; |
849 |
} |
850 |
|
851 |
if ($options{virtual}) { |
852 |
$medium->{virtual} = 1; |
853 |
} else { |
854 |
_migrate_removable_device($urpm, $medium); |
855 |
} |
856 |
|
857 |
if ($with_synthesis) { |
858 |
_migrate__with_synthesis($medium, $with_synthesis); |
859 |
} elsif (!$medium->{media_info_dir}) { |
860 |
if (!is_local_medium($medium)) { |
861 |
$medium->{media_info_dir} = 'media_info'; |
862 |
} else { |
863 |
$medium->{unknown_media_info} = 1; |
864 |
} |
865 |
} |
866 |
|
867 |
#- local media have priority, other are added at the end. |
868 |
my $inserted; |
869 |
my $ignore_text = $medium->{ignore} ? ' ' . N("(ignored by default)") : ''; |
870 |
if (_local_file($medium)) { |
871 |
#- insert before first remote medium |
872 |
@{$urpm->{media}} = map { |
873 |
if (!_local_file($_) && !$inserted) { |
874 |
$inserted = 1; |
875 |
$urpm->{$options{on_the_fly} ? 'log' : 'info'}(N("adding medium \"%s\" before remote medium \"%s\"", $name, $_->{name}) . $ignore_text); |
876 |
$medium, $_; |
877 |
} else { $_ } |
878 |
} @{$urpm->{media}}; |
879 |
} |
880 |
if (!$inserted) { |
881 |
$urpm->{$options{on_the_fly} ? 'log' : 'info'}(N("adding medium \"%s\"", $name) . $ignore_text); |
882 |
push @{$urpm->{media}}, $medium; |
883 |
} |
884 |
|
885 |
$urpm->{modified} = 1; |
886 |
|
887 |
$name; |
888 |
} |
889 |
|
890 |
sub _register_media_cfg { |
891 |
my ($urpm, $url, $mirrorlist, $distribconf, $media_cfg) = @_; |
892 |
|
893 |
my $arch = $distribconf->getvalue('media_info', 'arch') || ''; |
894 |
my $branch = $distribconf->getvalue('media_info', 'branch') || ''; |
895 |
my $product = $distribconf->getvalue('media_info', 'product') || ''; |
896 |
my $version = $distribconf->getvalue('media_info', 'version') || ''; |
897 |
#official mirrors define $branch but not $product, other RPM repos do the |
898 |
#opposite :-/ |
899 |
my $media_dir = (($branch || $product) . '-' . $version . '-' . $arch); |
900 |
$media_dir =~ tr!/!-!; |
901 |
my $media_path = $urpm->{mediacfgdir} . '/' . $media_dir; |
902 |
require File::Path; |
903 |
File::Path::mkpath($media_path); |
904 |
copy_and_own($media_cfg, $media_path . '/media.cfg') |
905 |
or $urpm->{info}(1, N("failed to copy media.cfg to %s (%d)", $media_path, $? >> 8)); |
906 |
if ($url) { |
907 |
my $filename = $media_path . "/url"; |
908 |
my @urls = split(/\n/, scalar cat_($filename)); |
909 |
if (!grep { $url eq $_ } @urls) { |
910 |
append_to_file($filename, $url . "\n"); |
911 |
} |
912 |
} |
913 |
if ($mirrorlist) { |
914 |
if ($mirrorlist ne '$MIRRORLIST') { |
915 |
require urpm::cfg; |
916 |
$mirrorlist = urpm::cfg::expand_line($mirrorlist); |
917 |
} |
918 |
my $filename = $media_path . "/mirrorlist"; |
919 |
my @mirrorlists = split(/\n/, scalar cat_($filename)); |
920 |
if (!grep { $mirrorlist eq $_ } @mirrorlists) { |
921 |
append_to_file($filename, $mirrorlist . "\n"); |
922 |
} |
923 |
} |
924 |
} |
925 |
|
926 |
#- add distribution media, according to url given. |
927 |
#- returns the list of names of added media. |
928 |
#- options : |
929 |
#- - initial_number : when adding several numbered media, start with this number |
930 |
#- - probe_with : force use of rpms instead of using synthesis |
931 |
#- - ask_media : callback to know whether each media should be added |
932 |
#- - only_updates : only add "update" media (used by rpmdrake) |
933 |
#- - mirrorlist |
934 |
#- - zeroconf |
935 |
#- other options are passed to add_medium(): ignore, nolock, virtual |
936 |
sub add_distrib_media { |
937 |
my ($urpm, $name, $url, %options) = @_; |
938 |
|
939 |
#- make sure configuration has been read. |
940 |
$urpm->{media} or die "caller should have used ->read_config or ->configure first"; |
941 |
|
942 |
my $distribconf; |
943 |
|
944 |
if ($url && urpm::is_local_url($url)) { |
945 |
$url = _migrate_removable_url($url) or return(); |
946 |
my $m = { url => $url }; |
947 |
urpm::removable::try_mounting_medium_($urpm, $m) or $urpm->{error}(N("directory %s does not exist", $url)); |
948 |
|
949 |
$distribconf = MDV::Distribconf->new(file_from_file_url($url) || $url, undef); |
950 |
$distribconf->settree('mandriva'); |
951 |
|
952 |
my $dir = file_from_local_medium($m); |
953 |
my $media_cfg = reduce_pathname("$dir/" . $distribconf->getpath(undef, 'infodir') . '/media.cfg'); |
954 |
$distribconf->parse_mediacfg($media_cfg) |
955 |
or $urpm->{error}(N("this location doesn't seem to contain any distribution")), return (); |
956 |
if (!$options{virtual}) { |
957 |
_register_media_cfg($urpm, $dir, undef, $distribconf, $media_cfg); |
958 |
} |
959 |
} else { |
960 |
$url = maybe_find_zeroconf($urpm, $url, \%options); |
961 |
if ($options{mirrorlist}) { |
962 |
$url and die "unexpected url $url together with mirrorlist $options{mirrorlist}\n"; |
963 |
} |
964 |
|
965 |
my $m = { mirrorlist => $options{mirrorlist}, url => $url }; |
966 |
my $parse_ok; |
967 |
try__maybe_mirrorlist($urpm, $m, 'probe', sub { |
968 |
my $media_cfg = "$urpm->{cachedir}/partial/media.cfg"; |
969 |
$distribconf = _new_distribconf_and_download($urpm, $m); |
970 |
$parse_ok = $distribconf && $distribconf->parse_mediacfg($media_cfg); |
971 |
if ($parse_ok && !$options{virtual}) { |
972 |
_register_media_cfg($urpm, urpm::cfg::expand_line($m->{url}), $options{mirrorlist}, $distribconf, $media_cfg); |
973 |
} |
974 |
$parse_ok; |
975 |
}); |
976 |
$url = $m->{url}; |
977 |
|
978 |
if ($distribconf) { |
979 |
$parse_ok or $urpm->{error}(N("unable to parse media.cfg")), return(); |
980 |
} else { |
981 |
$urpm->{error}(N("...retrieving failed: %s", $@)); |
982 |
$urpm->{error}(N("unable to access the distribution medium (no media.cfg file found)")); |
983 |
return (); |
984 |
} |
985 |
} |
986 |
|
987 |
#- cosmetic update of name if it contains spaces. |
988 |
$name =~ /\s/ and $name .= ' '; |
989 |
|
990 |
my @newnames; |
991 |
#- at this point, we have found a media.cfg file, so parse it |
992 |
#- and create all necessary media according to it. |
993 |
my $medium_index = $options{initial_number} || 1; |
994 |
|
995 |
require urpm::mirrors; |
996 |
my $product_id = urpm::mirrors::parse_LDAP_namespace_structure(cat_('/etc/product.id')); |
997 |
|
998 |
foreach my $media ($distribconf->listmedia) { |
999 |
my $media_name = $distribconf->getvalue($media, 'name') || ''; |
1000 |
|
1001 |
if (my $media_arch = $distribconf->getvalue($media, 'arch')) { |
1002 |
if (!URPM::archscore($media_arch)) { |
1003 |
$urpm->{log}(N("skipping non compatible media `%s' (for %s)", |
1004 |
$media, $media_arch)); |
1005 |
next; |
1006 |
} |
1007 |
} |
1008 |
|
1009 |
my $is_update_media = $distribconf->getvalue($media, 'updates_for'); |
1010 |
if ($options{only_updates}) { |
1011 |
$is_update_media or next; |
1012 |
} |
1013 |
|
1014 |
my $add_by_default = !$distribconf->getvalue($media, 'noauto'); |
1015 |
my @media_types = split(':', $distribconf->getvalue($media, 'media_type')); |
1016 |
if ($product_id->{product} eq 'Free') { |
1017 |
if (member('non-free', @media_types)) { |
1018 |
$urpm->{log}(N("ignoring non-free medium `%s'", $media)); |
1019 |
$add_by_default = 0; |
1020 |
} |
1021 |
} |
1022 |
my $ignore; |
1023 |
if ($options{ask_media}) { |
1024 |
$options{ask_media}->($media_name, $add_by_default) or next; |
1025 |
} else { |
1026 |
my $simple_rpms = !$distribconf->getvalue($media, 'rpms'); |
1027 |
$add_by_default || $simple_rpms or next; |
1028 |
$ignore = !$add_by_default; |
1029 |
} |
1030 |
|
1031 |
my $use_copied_synthesis = urpm::is_cdrom_url($url) || $urpm->{options}{use_copied_hdlist} || $distribconf->getvalue($media, 'use_copied_hdlist'); |
1032 |
my $with_synthesis = $use_copied_synthesis && offset_pathname( |
1033 |
$url, |
1034 |
$distribconf->getpath($media, 'path'), |
1035 |
) . '/' . $distribconf->getpath($media, 'synthesis'); |
1036 |
|
1037 |
push @newnames, add_medium($urpm, |
1038 |
$name ? "$media_name ($name$medium_index)" : $media_name, |
1039 |
reduce_pathname($distribconf->getfullpath($media, 'path')), |
1040 |
$with_synthesis, |
1041 |
!$use_copied_synthesis ? (media_info_dir => 'media_info') : @{[]}, |
1042 |
!$use_copied_synthesis && $options{probe_with} ? ($options{probe_with} => 1) : (), |
1043 |
index_name => $name ? undef : 0, |
1044 |
$ignore ? (ignore => 1) : @{[]}, |
1045 |
%options, |
1046 |
# the following override %options |
1047 |
$options{mirrorlist} ? ('with-dir' => $distribconf->getpath($media, 'path')) : (), |
1048 |
update => $is_update_media ? 1 : undef, |
1049 |
); |
1050 |
++$medium_index; |
1051 |
} |
1052 |
return @newnames; |
1053 |
} |
1054 |
|
1055 |
sub _new_distribconf_and_download { |
1056 |
my ($urpm, $medium) = @_; |
1057 |
|
1058 |
my $distribconf = MDV::Distribconf->new($medium->{url}, undef); |
1059 |
$distribconf->settree('mandriva'); |
1060 |
|
1061 |
$urpm->{log}(N("retrieving media.cfg file...")); |
1062 |
my $url = $medium->{url}; |
1063 |
$medium->{url} = urpm::cfg::expand_line($url); |
1064 |
urpm::download::sync_rel_one($urpm, $medium, $distribconf->getpath(undef, 'infodir') . '/media.cfg', |
1065 |
quiet => 1, preclean => 1) or return; |
1066 |
$medium->{url} = urpm::cfg::substitute_back($medium->{url}, $url); |
1067 |
$distribconf; |
1068 |
} |
1069 |
|
1070 |
#- deprecated, use select_media_by_name instead |
1071 |
sub select_media { |
1072 |
my $urpm = shift; |
1073 |
my $options = {}; |
1074 |
if (ref $_[0]) { $options = shift } |
1075 |
foreach (select_media_by_name($urpm, [ @_ ], $options->{strict_match})) { |
1076 |
#- select medium by setting the modified flag, do not check ignore. |
1077 |
$_->{modified} = 1; |
1078 |
} |
1079 |
} |
1080 |
|
1081 |
sub select_media_by_name { |
1082 |
my ($urpm, $names, $b_strict_match) = @_; |
1083 |
|
1084 |
my %wanted = map { $_ => 1 } @$names; |
1085 |
|
1086 |
#- first the exact matches |
1087 |
my @l = grep { delete $wanted{$_->{name}} } @{$urpm->{media}}; |
1088 |
|
1089 |
#- check if some arguments don't correspond to the medium name. |
1090 |
#- in such case, try to find the unique medium (or list candidate |
1091 |
#- media found). |
1092 |
foreach (keys %wanted) { |
1093 |
my $q = quotemeta; |
1094 |
my (@found, @foundi); |
1095 |
my $regex = $b_strict_match ? qr/^$q$/ : qr/$q/; |
1096 |
my $regexi = $b_strict_match ? qr/^$q$/i : qr/$q/i; |
1097 |
foreach my $medium (@{$urpm->{media}}) { |
1098 |
$medium->{name} =~ $regex and push @found, $medium; |
1099 |
$medium->{name} =~ $regexi and push @foundi, $medium; |
1100 |
} |
1101 |
@found = @foundi if !@found; |
1102 |
|
1103 |
if (@found == 0) { |
1104 |
$urpm->{error}(N("trying to select nonexistent medium \"%s\"", $_)); |
1105 |
} else { |
1106 |
if (@found > 1) { |
1107 |
$urpm->{log}(N("selecting multiple media: %s", join(", ", map { qq("$_->{name}") } @found))); |
1108 |
} |
1109 |
#- changed behaviour to select all occurences by default. |
1110 |
push @l, @found; |
1111 |
} |
1112 |
} |
1113 |
@l; |
1114 |
} |
1115 |
|
1116 |
#- deprecated, use remove_media instead |
1117 |
sub remove_selected_media { |
1118 |
my ($urpm) = @_; |
1119 |
|
1120 |
remove_media($urpm, [ grep { $_->{modified} } @{$urpm->{media}} ]); |
1121 |
} |
1122 |
|
1123 |
sub _remove_medium_from_mediacfg { |
1124 |
my ($urpm, $mediacfg_dir, $url, $is_mirrorlist) = @_; |
1125 |
|
1126 |
my $filename = $mediacfg_dir; |
1127 |
$filename .= $is_mirrorlist ? "/mirrorlist" : "/url"; |
1128 |
|
1129 |
my @urls = split(/\n/, scalar cat_($filename)); |
1130 |
$urpm->{debug} and $urpm->{debug}("removing $url from $filename"); |
1131 |
output_safe($filename, join('\n', grep { $url ne $_ } @urls)); |
1132 |
} |
1133 |
|
1134 |
sub _cleanup_mediacfg_dir { |
1135 |
my ($urpm, $to_remove) = @_; |
1136 |
|
1137 |
foreach my $medium (@$to_remove) { |
1138 |
$medium->{mediacfg} or next; |
1139 |
#this should never happen but dirname(undef) returns . on which we call |
1140 |
#clean_dir so better be safe than sorry |
1141 |
$medium->{mediacfg}[0]{root} or next; |
1142 |
my $dir = reduce_pathname(dirname($medium->{mediacfg}[0]{root})); |
1143 |
begins_with($medium->{mediacfg}[0]{root}, $dir) or next; |
1144 |
if (!grep { $_->{mediacfg}[0]{root} == $medium->{mediacfg}[0]{root} } @{$urpm->{media}}) { |
1145 |
$urpm->{debug} and $urpm->{debug}("removing no longer used $dir"); |
1146 |
-d $dir and urpm::sys::clean_dir($dir); |
1147 |
next; |
1148 |
} |
1149 |
|
1150 |
if ($medium->{mirrorlist}) { |
1151 |
if (!grep { $_->{mirrorlist} eq $medium->{mirrorlist} } @{$urpm->{media}}) { |
1152 |
_remove_medium_from_mediacfg($urpm, $dir, $medium->{mirrorlist}, 1); |
1153 |
} |
1154 |
} elsif ($medium->{url}) { |
1155 |
if (!grep { $_->{url} eq $medium->{url} } @{$urpm->{media}}) { |
1156 |
_remove_medium_from_mediacfg($urpm, $dir, $medium->{url}, 0); |
1157 |
} |
1158 |
} |
1159 |
} |
1160 |
} |
1161 |
|
1162 |
sub remove_media { |
1163 |
my ($urpm, $to_remove) = @_; |
1164 |
|
1165 |
foreach my $medium (@$to_remove) { |
1166 |
$urpm->{info}(N("removing medium \"%s\"", $medium->{name})); |
1167 |
|
1168 |
#- mark to re-write configuration. |
1169 |
$urpm->{modified} = 1; |
1170 |
|
1171 |
_clean_statedir_medium_files($urpm, $medium); |
1172 |
|
1173 |
#- remove proxy settings for this media |
1174 |
urpm::download::remove_proxy_media($medium->{name}); |
1175 |
} |
1176 |
$urpm->{media} = [ difference2($urpm->{media}, $to_remove) ]; |
1177 |
_cleanup_mediacfg_dir($urpm, $to_remove); |
1178 |
} |
1179 |
|
1180 |
sub _clean_statedir_medium_files { |
1181 |
my ($urpm, $medium) = @_; |
1182 |
|
1183 |
#- remove files associated with this medium. |
1184 |
unlink grep { $_ } map { old_statedir_media_info_file($urpm, $medium, $_->[0], $_->[1]) } @media_info_prefix_suffix; |
1185 |
|
1186 |
my $dir = statedir_media_info_dir($urpm, $medium); |
1187 |
-d $dir and urpm::sys::clean_dir($dir); |
1188 |
|
1189 |
remove_user_media_info_files($urpm, $medium); |
1190 |
} |
1191 |
|
1192 |
sub _probe_with_try_list { |
1193 |
my ($urpm, $medium, $f) = @_; |
1194 |
|
1195 |
$medium->{mirrorlist} and die "_probe_with_try_list does not handle mirrorlist\n"; |
1196 |
|
1197 |
my @media_info_dirs = ('media_info', '.'); |
1198 |
|
1199 |
my $base = file_from_local_medium($medium) || $medium->{url}; |
1200 |
|
1201 |
foreach my $media_info_dir (@media_info_dirs) { |
1202 |
my $file = "$media_info_dir/synthesis.hdlist.cz"; |
1203 |
my $url = reduce_pathname("$base/$file"); |
1204 |
if ($f->($url, $file)) { |
1205 |
$urpm->{debug} and $urpm->{debug}("found synthesis: $url"); |
1206 |
$medium->{media_info_dir} = $media_info_dir; |
1207 |
delete $medium->{unknown_media_info}; |
1208 |
return 1; |
1209 |
} |
1210 |
} |
1211 |
undef; |
1212 |
} |
1213 |
|
1214 |
sub may_reconfig_urpmi { |
1215 |
my ($urpm, $medium) = @_; |
1216 |
|
1217 |
$medium->{url} && !urpm::is_cdrom_url($medium->{url}) or return; # we should handle mirrorlist? |
1218 |
|
1219 |
my $f; |
1220 |
if (my $dir = file_from_file_url($medium->{url})) { |
1221 |
$f = reduce_pathname("$dir/reconfig.urpmi"); |
1222 |
} else { |
1223 |
$f = urpm::download::sync_rel_one($urpm, $medium, 'reconfig.urpmi', |
1224 |
quiet => 1, preclean => 1) or return; |
1225 |
} |
1226 |
my $reconfigured = -s $f && reconfig_urpmi($urpm, $f, $medium); |
1227 |
unlink $f if !is_local_medium($medium); |
1228 |
$reconfigured; |
1229 |
} |
1230 |
|
1231 |
#- read a reconfiguration file for urpmi, and reconfigure media accordingly |
1232 |
#- $rfile is the reconfiguration file (local), $name is the media name |
1233 |
#- |
1234 |
#- the format is similar to the RewriteRule of mod_rewrite, so: |
1235 |
#- PATTERN REPLACEMENT [FLAG] |
1236 |
#- where FLAG can be L or N |
1237 |
#- |
1238 |
#- example of reconfig.urpmi: |
1239 |
#- # this is an urpmi reconfiguration file |
1240 |
#- /cauldron /cauldron/$ARCH |
1241 |
sub reconfig_urpmi { |
1242 |
my ($urpm, $rfile, $medium) = @_; |
1243 |
-r $rfile or return; |
1244 |
|
1245 |
my ($magic, @lines) = cat_($rfile); |
1246 |
#- the first line of reconfig.urpmi must be magic, to be sure it's not an error file |
1247 |
$magic =~ /^# this is an urpmi reconfiguration file/ or return undef; |
1248 |
|
1249 |
$urpm->{info}(N("reconfiguring urpmi for media \"%s\"", $medium->{name})); |
1250 |
|
1251 |
my @replacements; |
1252 |
foreach (@lines) { |
1253 |
chomp; |
1254 |
s/^\s*//; s/#.*$//; s/\s*$//; |
1255 |
$_ or next; |
1256 |
my ($p, $r, $f) = split /\s+/, $_, 3; |
1257 |
push @replacements, [ quotemeta $p, $r, $f || 1 ]; |
1258 |
} |
1259 |
|
1260 |
my $reconfigured = 0; |
1261 |
my @reconfigurable = qw(url with_synthesis media_info_dir); |
1262 |
|
1263 |
my %orig = %$medium; |
1264 |
|
1265 |
URLS: |
1266 |
foreach my $k (@reconfigurable) { |
1267 |
foreach my $r (@replacements) { |
1268 |
if ($medium->{$k} =~ s/$r->[0]/$r->[1]/) { |
1269 |
$reconfigured = 1; |
1270 |
#- Flags stolen from mod_rewrite: L(ast), N(ext) |
1271 |
if ($r->[2] =~ /L/) { |
1272 |
last; |
1273 |
} elsif ($r->[2] =~ /N/) { #- dangerous option |
1274 |
redo URLS; |
1275 |
} |
1276 |
} |
1277 |
} |
1278 |
#- check that the new url exists before committing changes (local mirrors) |
1279 |
my $file = urpm::file_from_local_url($medium->{$k}); |
1280 |
if ($file && !-e $file) { |
1281 |
%$medium = %orig; |
1282 |
$reconfigured = 0; |
1283 |
$urpm->{log}(N("...reconfiguration failed")); |
1284 |
return; |
1285 |
} |
1286 |
} |
1287 |
|
1288 |
if ($reconfigured) { |
1289 |
$urpm->{log}(N("reconfiguration done")); |
1290 |
$urpm->{modified} = 1; |
1291 |
} |
1292 |
$reconfigured; |
1293 |
} |
1294 |
|
1295 |
#- names.<media_name> is used by external progs (namely for bash-completion) |
1296 |
sub _generate_medium_names { |
1297 |
my ($urpm, $medium) = @_; |
1298 |
|
1299 |
-e statedir_names($urpm, $medium) and return; |
1300 |
|
1301 |
my $fh = urpm::sys::open_safe($urpm, ">", statedir_names($urpm, $medium)) or return; |
1302 |
|
1303 |
foreach ($medium->{start} .. $medium->{end}) { |
1304 |
my $pkg = $urpm->{depslist}[$_] or |
1305 |
$urpm->{error}(N("Error generating names file: dependency %d not found", $_)), return; |
1306 |
|
1307 |
print $fh $pkg->name . "\n"; |
1308 |
} |
1309 |
} |
1310 |
|
1311 |
sub _guess_synthesis_suffix { |
1312 |
my ($url) = @_; |
1313 |
$url =~ m!\bmedia/(\w+)/*\Z! && $1; |
1314 |
} |
1315 |
|
1316 |
sub _synthesis_suffix { |
1317 |
my ($medium) = @_; |
1318 |
$medium->{with_synthesis} =~ /synthesis\.hdlist(.*?)(?:\.src)?\.cz$/ ? $1 : ''; |
1319 |
} |
1320 |
|
1321 |
sub _medium_is_up_to_date { |
1322 |
my ($urpm, $medium) = @_; |
1323 |
|
1324 |
unlink cachedir_with_synthesis($urpm, $medium); |
1325 |
|
1326 |
$urpm->{info}(N("medium \"%s\" is up-to-date", $medium->{name})); |
1327 |
|
1328 |
#- the medium is now considered not modified. |
1329 |
$medium->{modified} = 0; |
1330 |
} |
1331 |
|
1332 |
sub _parse_synthesis { |
1333 |
my ($urpm, $medium, $synthesis_file, $o_callback) = @_; |
1334 |
|
1335 |
-e $synthesis_file or return; |
1336 |
|
1337 |
$urpm->{log}(N("examining synthesis file [%s]", $synthesis_file)); |
1338 |
($medium->{start}, $medium->{end}) = |
1339 |
$urpm->parse_synthesis($synthesis_file, $o_callback ? (callback => $o_callback) : @{[]}); |
1340 |
} |
1341 |
|
1342 |
sub _parse_synthesis_or_ignore { |
1343 |
my ($urpm, $medium, $o_callback) = @_; |
1344 |
|
1345 |
_parse_synthesis($urpm, $medium, any_synthesis($urpm, $medium), $o_callback) or |
1346 |
_ignore_medium_on_parse_error($urpm, $medium); |
1347 |
} |
1348 |
|
1349 |
sub is_valid_medium { |
1350 |
my ($medium) = @_; |
1351 |
defined $medium->{start} && defined $medium->{end}; |
1352 |
} |
1353 |
|
1354 |
sub _ignore_medium_on_parse_error { |
1355 |
my ($urpm, $medium) = @_; |
1356 |
|
1357 |
$urpm->{error}(N("problem reading synthesis file of medium \"%s\"", $medium->{name})); |
1358 |
$medium->{ignore} = 1; |
1359 |
} |
1360 |
|
1361 |
sub _copy_media_info_file { |
1362 |
my ($urpm, $medium, $prefix, $suffix) = @_; |
1363 |
|
1364 |
my $name = "$prefix$suffix"; |
1365 |
my $path = _synthesis_dir($medium) . "/$prefix" . _synthesis_suffix($medium) . $suffix; |
1366 |
-e $path or $path = file_from_local_medium($medium) . "/media_info/$name"; |
1367 |
|
1368 |
my $result_file = "$urpm->{cachedir}/partial/$name"; |
1369 |
if (-e $path) { |
1370 |
$urpm->{log}(N("copying [%s] for medium \"%s\"...", $path, $medium->{name})); |
1371 |
copy_and_own($path, $result_file) |
1372 |
or $urpm->{error}(N("...copying failed")), return; |
1373 |
} |
1374 |
-s $result_file && $result_file; |
1375 |
} |
1376 |
|
1377 |
sub _get_pubkey__local { |
1378 |
my ($urpm, $medium) = @_; |
1379 |
|
1380 |
_copy_media_info_file($urpm, $medium, 'pubkey', ''); |
1381 |
} |
1382 |
|
1383 |
sub _download_pubkey { |
1384 |
my ($urpm, $medium) = @_; |
1385 |
|
1386 |
_download_media_info_file($urpm, $medium, 'pubkey', '', { quiet => 1 }); |
1387 |
} |
1388 |
|
1389 |
# known options: quiet, callback |
1390 |
sub _download_media_info_file { |
1391 |
my ($urpm, $medium, $prefix, $suffix, $options) = @_; |
1392 |
|
1393 |
my $versioned_prefix = do { |
1394 |
my $version = urpm::md5sum::versioned_media_info_file($urpm, $medium, "$prefix$suffix"); |
1395 |
$version and $options->{is_versioned} = 1; |
1396 |
$version ? "$version-$prefix" : $prefix; |
1397 |
}; |
1398 |
|
1399 |
my $tmp = _download_media_info_file_raw($urpm, $medium, |
1400 |
$versioned_prefix, $suffix, $options) or return; |
1401 |
my $result = dirname($tmp) . "/$prefix$suffix"; |
1402 |
$tmp eq $result or rename($tmp, $result) or return; |
1403 |
$result; |
1404 |
} |
1405 |
|
1406 |
sub _download_media_info_file_raw { |
1407 |
my ($urpm, $medium, $prefix, $suffix, $options) = @_; |
1408 |
|
1409 |
my $name = "$prefix$suffix"; |
1410 |
my $result_file = "$urpm->{cachedir}/partial/$name"; |
1411 |
my $found; |
1412 |
if (_synthesis_suffix($medium)) { |
1413 |
my $local_name = $prefix . _synthesis_suffix($medium) . $suffix; |
1414 |
|
1415 |
if (urpm::download::sync_rel_to($urpm, $medium, |
1416 |
_synthesis_dir_rel($medium) . "/$local_name", $result_file, |
1417 |
%$options)) { |
1418 |
$found = 1; |
1419 |
} |
1420 |
} |
1421 |
if (!$found) { |
1422 |
urpm::download::sync_rel_one($urpm, $medium, _synthesis_dir_rel($medium) . "/$name", |
1423 |
%$options); |
1424 |
} |
1425 |
-s $result_file && $result_file; |
1426 |
} |
1427 |
|
1428 |
sub get_descriptions_local { |
1429 |
my ($urpm, $medium) = @_; |
1430 |
|
1431 |
unlink statedir_descriptions($urpm, $medium); |
1432 |
|
1433 |
my $dir = file_from_local_medium($medium); |
1434 |
my $description_file = "$dir/media_info/descriptions"; #- new default location |
1435 |
-e $description_file or $description_file = "$dir/../descriptions"; |
1436 |
-e $description_file or return; |
1437 |
|
1438 |
$urpm->{log}(N("copying description file of \"%s\"...", $medium->{name})); |
1439 |
if (copy_and_own($description_file, statedir_descriptions($urpm, $medium))) { |
1440 |
$urpm->{log}(N("...copying done")); |
1441 |
} else { |
1442 |
$urpm->{error}(N("...copying failed")); |
1443 |
$medium->{ignore} = 1; |
1444 |
} |
1445 |
} |
1446 |
#- not handling different mirrors since the file is not always available |
1447 |
sub get_descriptions_remote { |
1448 |
my ($urpm, $medium) = @_; |
1449 |
|
1450 |
if (-e statedir_descriptions($urpm, $medium)) { |
1451 |
unlink "$urpm->{cachedir}/partial/descriptions"; |
1452 |
urpm::sys::move_or_die($urpm, statedir_descriptions($urpm, $medium), "$urpm->{cachedir}/partial/descriptions"); |
1453 |
} |
1454 |
my $result = urpm::download::sync_rel_one($urpm, $medium, 'media_info/descriptions', quiet => 1, preclean => 1); |
1455 |
|
1456 |
if ($result) { |
1457 |
urpm::sys::move_or_die($urpm, $result, statedir_descriptions($urpm, $medium)); |
1458 |
} |
1459 |
} |
1460 |
sub get_synthesis__local { |
1461 |
my ($urpm, $medium, $callback) = @_; |
1462 |
|
1463 |
my $f = cachedir_with_synthesis($urpm, $medium); |
1464 |
unlink $f; |
1465 |
$urpm->{log}(N("copying [%s] for medium \"%s\"...", _url_with_synthesis($medium), $medium->{name})); |
1466 |
$callback and $callback->('copy', $medium->{name}); |
1467 |
if (copy_and_own(_url_with_synthesis($medium), $f)) { |
1468 |
$callback and $callback->('done', $medium->{name}); |
1469 |
$urpm->{log}(N("...copying done")); |
1470 |
if (file_size($f) < 20) { |
1471 |
$urpm->{error}(N("copy of [%s] failed (file is suspiciously small)", $f)); |
1472 |
0; |
1473 |
} else { |
1474 |
1; |
1475 |
} |
1476 |
} else { |
1477 |
$callback and $callback->('failed', $medium->{name}); |
1478 |
#- force error, reported afterwards |
1479 |
unlink $f; |
1480 |
0; |
1481 |
} |
1482 |
} |
1483 |
sub get_synthesis__remote { |
1484 |
my ($urpm, $medium, $is_a_probe, $options) = @_; |
1485 |
|
1486 |
my $ok = try__maybe_mirrorlist($urpm, $medium, $is_a_probe, sub { |
1487 |
_download_media_info_file($urpm, $medium, 'synthesis.hdlist', '.cz', |
1488 |
$options) |
1489 |
&& _check_synthesis(cachedir_with_synthesis($urpm, $medium)); |
1490 |
}); |
1491 |
if (!$ok) { |
1492 |
chomp(my $err = $@); |
1493 |
$urpm->{error}(N("...retrieving failed: %s", $err)); |
1494 |
} |
1495 |
|
1496 |
$ok &&= check_synthesis_md5sum($urpm, $medium) if !$options->{force} && !$options->{nomd5sum}; |
1497 |
|
1498 |
$ok; |
1499 |
} |
1500 |
|
1501 |
sub _check_synthesis { |
1502 |
my ($synthesis_file) = @_; |
1503 |
|
1504 |
file_size($synthesis_file) >= 20 or return; |
1505 |
|
1506 |
# check first 2 lines do not contain typical html code |
1507 |
# this is useful for servers not returning a valid HTTP error (#39918) |
1508 |
open(my $F, '<', $synthesis_file) or return; |
1509 |
my $s = <$F>; $s .= <$F>; |
1510 |
$s !~ /<html>|<!DOCTYPE\s/i; |
1511 |
} |
1512 |
|
1513 |
#- check copied/downloaded file has right signature. |
1514 |
sub check_synthesis_md5sum { |
1515 |
my ($urpm, $medium) = @_; |
1516 |
|
1517 |
my $wanted_md5sum = urpm::md5sum::from_MD5SUM__or_warn($urpm, $medium->{parsed_md5sum}, 'synthesis.hdlist.cz'); |
1518 |
if ($wanted_md5sum) { |
1519 |
$urpm->{log}(N("computing md5sum of retrieved source synthesis")); |
1520 |
urpm::md5sum::compute(cachedir_with_synthesis($urpm, $medium)) eq $wanted_md5sum or |
1521 |
$urpm->{error}(N("retrieval of [%s] failed (md5sum mismatch)", _url_with_synthesis($medium))), return; |
1522 |
} |
1523 |
1; |
1524 |
} |
1525 |
|
1526 |
sub _call_genhdlist2 { |
1527 |
my ($urpm, $medium) = @_; |
1528 |
|
1529 |
!$medium->{with_synthesis} or $urpm->{fatal}(1, 'with_synthesis not handled with --probe-rpms'); |
1530 |
|
1531 |
my $dir = file_from_local_medium($medium); |
1532 |
|
1533 |
system('genhdlist2', |
1534 |
$urpm->{debug} ? '--verbose' : @{[]}, '--no-hdlist', |
1535 |
'--media_info-dir', "$urpm->{cachedir}/partial", $dir) == 0 |
1536 |
or $urpm->{error}(N("genhdlist2 failed on %s", $dir)), return; |
1537 |
|
1538 |
1; |
1539 |
} |
1540 |
|
1541 |
sub _is_statedir_MD5SUM_uptodate { |
1542 |
my ($urpm, $medium, $new_MD5SUM) = @_; |
1543 |
|
1544 |
my $current_MD5SUM = statedir_MD5SUM($urpm, $medium); |
1545 |
|
1546 |
$urpm->{log}(N("comparing %s and %s", $new_MD5SUM, $current_MD5SUM)); |
1547 |
|
1548 |
cat_($new_MD5SUM) eq cat_($current_MD5SUM); |
1549 |
} |
1550 |
|
1551 |
#- options: callback, force, nomd5sum, probe_with |
1552 |
sub _update_medium__parse_if_unmodified__local { |
1553 |
my ($urpm, $medium, $options) = @_; |
1554 |
|
1555 |
if ($options->{probe_with} ne 'rpms') { |
1556 |
#- the directory given does not exist and may be accessible |
1557 |
#- by mounting some other directory. Try to figure it out and mount |
1558 |
#- everything that might be necessary. |
1559 |
urpm::removable::try_mounting_medium($urpm, $medium) or return; |
1560 |
} |
1561 |
|
1562 |
#- check for a reconfig.urpmi file (if not already reconfigured) |
1563 |
if (!$medium->{noreconfigure}) { |
1564 |
may_reconfig_urpmi($urpm, $medium); |
1565 |
} |
1566 |
|
1567 |
#- try to probe for possible with_synthesis parameter, unless |
1568 |
#- it is already defined (and valid). |
1569 |
if (!_valid_synthesis_dir($medium) && $options->{probe_with} ne 'rpms') { |
1570 |
_probe_with_try_list($urpm, $medium, sub { |
1571 |
my ($url) = @_; |
1572 |
-e $url or return; |
1573 |
if (file_size($url) >= 20) { |
1574 |
1; |
1575 |
} else { |
1576 |
$urpm->{error}(N("invalid hdlist file %s for medium \"%s\"", $url, $medium->{name})); |
1577 |
0; |
1578 |
} |
1579 |
}); |
1580 |
} |
1581 |
|
1582 |
if (_is_local_virtual($medium)) { |
1583 |
#- syncing a local virtual medium is very simple :) |
1584 |
1; |
1585 |
} elsif ($options->{probe_with} eq 'rpms' || !_valid_synthesis_dir($medium)) { |
1586 |
_call_genhdlist2($urpm, $medium) or return ''; |
1587 |
if (!$medium->{'no-media-info'}) { |
1588 |
$medium->{'no-media-info'} = 1; |
1589 |
$urpm->{modified} = 1; |
1590 |
} |
1591 |
1; |
1592 |
} elsif (_valid_synthesis_dir($medium)) { |
1593 |
my $new_MD5SUM = _synthesis_dir($medium) . '/MD5SUM'; |
1594 |
unlink "$urpm->{cachedir}/partial/MD5SUM"; |
1595 |
|
1596 |
if (!$options->{nomd5sum} && file_size($new_MD5SUM) > 32) { |
1597 |
if (!$options->{force} && _is_statedir_MD5SUM_uptodate($urpm, $medium, $new_MD5SUM)) { |
1598 |
_medium_is_up_to_date($urpm, $medium); |
1599 |
return 'unmodified'; |
1600 |
} |
1601 |
|
1602 |
$urpm->{log}(N("copying MD5SUM file of \"%s\"...", $medium->{name})); |
1603 |
copy_and_own($new_MD5SUM, "$urpm->{cachedir}/partial/MD5SUM"); |
1604 |
$medium->{parsed_md5sum} = urpm::md5sum::parse($new_MD5SUM); |
1605 |
} |
1606 |
|
1607 |
my $ok = get_synthesis__local($urpm, $medium, $options->{callback}); |
1608 |
$ok &&= check_synthesis_md5sum($urpm, $medium) if !$options->{force} && !$options->{nomd5sum}; |
1609 |
|
1610 |
if ($ok) { |
1611 |
1; |
1612 |
} elsif ($urpm->{options}{'build-hdlist-on-error'}) { |
1613 |
#- if copying synthesis has failed, try to build it directly. |
1614 |
_call_genhdlist2($urpm, $medium) or return ''; |
1615 |
1; |
1616 |
} else { |
1617 |
_ignore_medium_on_parse_error($urpm, $medium); |
1618 |
''; |
1619 |
} |
1620 |
} |
1621 |
} |
1622 |
|
1623 |
sub _download_MD5SUM { |
1624 |
my ($urpm, $medium) = @_; |
1625 |
|
1626 |
urpm::download::sync_rel_one($urpm, $medium, |
1627 |
_synthesis_dir_rel($medium) . '/MD5SUM', |
1628 |
quiet => 1, preclean => 1); |
1629 |
} |
1630 |
|
1631 |
sub _download_MD5SUM_and_check { |
1632 |
my ($urpm, $medium, $is_a_probe) = @_; |
1633 |
|
1634 |
my ($err, $cachedir_MD5SUM); |
1635 |
require urpm::mirrors; |
1636 |
try__maybe_mirrorlist($urpm, $medium, $is_a_probe, sub { |
1637 |
$cachedir_MD5SUM = _download_MD5SUM($urpm, $medium) or $err = $@; |
1638 |
$cachedir_MD5SUM && urpm::md5sum::check_file($cachedir_MD5SUM); |
1639 |
}) and return $cachedir_MD5SUM; |
1640 |
|
1641 |
if ($cachedir_MD5SUM) { |
1642 |
$urpm->{error}(N("invalid MD5SUM file (downloaded from %s)", _synthesis_dir($medium))); |
1643 |
} else { |
1644 |
$urpm->{error}(N("...retrieving failed: %s", $err)); |
1645 |
$is_a_probe and $urpm->{error}(N("no metadata found for medium \"%s\"", $medium->{name})); |
1646 |
} |
1647 |
undef; |
1648 |
} |
1649 |
|
1650 |
#- options: callback, ask_retry, force, nomd5sum, probe_with, quiet |
1651 |
sub _update_medium__parse_if_unmodified__remote { |
1652 |
my ($urpm, $medium, $options) = @_; |
1653 |
|
1654 |
my $updating = -e statedir_synthesis($urpm, $medium); |
1655 |
|
1656 |
#- examine if a distant MD5SUM file is available. |
1657 |
if (!$options->{nomd5sum}) { |
1658 |
my $new_MD5SUM = _download_MD5SUM_and_check($urpm, $medium, !$updating); |
1659 |
|
1660 |
if (!$new_MD5SUM) { |
1661 |
#- check for a reconfig.urpmi file (if not already reconfigured) |
1662 |
if (!$medium->{noreconfigure}) { |
1663 |
may_reconfig_urpmi($urpm, $medium) |
1664 |
and goto &_update_medium__parse_if_unmodified__remote; |
1665 |
} |
1666 |
return; |
1667 |
} |
1668 |
if (($options->{force} || 0) < 2 && _is_statedir_MD5SUM_uptodate($urpm, $medium, $new_MD5SUM)) { |
1669 |
_medium_is_up_to_date($urpm, $medium); |
1670 |
return 'unmodified'; |
1671 |
} |
1672 |
$medium->{parsed_md5sum} = urpm::md5sum::parse($new_MD5SUM); |
1673 |
} |
1674 |
|
1675 |
#- try to probe for possible with_synthesis parameter, unless |
1676 |
#- it is already defined (and valid). |
1677 |
$urpm->{log}(N("retrieving source synthesis of \"%s\"...", $medium->{name})); |
1678 |
$options->{callback} and $options->{callback}('retrieve', $medium->{name}); |
1679 |
my $error = sub { |
1680 |
my ($msg) = @_; |
1681 |
$urpm->{error}($msg); |
1682 |
unlink cachedir_with_synthesis($urpm, $medium); |
1683 |
$options->{callback} and $options->{callback}('failed', $medium->{name}); |
1684 |
}; |
1685 |
|
1686 |
if ($options->{force}) { |
1687 |
unlink cachedir_with_synthesis($urpm, $medium); |
1688 |
} else { |
1689 |
#- for rsync, try to sync (copy if needed) local copy after restored the previous one. |
1690 |
my $previous_synthesis = statedir_synthesis($urpm, $medium); |
1691 |
if (-e $previous_synthesis && urpm::protocol_from_url($medium->{url}) eq 'rsync') { |
1692 |
copy_and_own( |
1693 |
$previous_synthesis, |
1694 |
cachedir_with_synthesis($urpm, $medium), |
1695 |
) or $error->(N("...copying failed")), return; |
1696 |
} |
1697 |
} |
1698 |
my $ok = get_synthesis__remote($urpm, $medium, !$updating, $options); |
1699 |
|
1700 |
$options->{callback} and $options->{callback}('done', $medium->{name}); |
1701 |
|
1702 |
if (!$ok) { |
1703 |
_ignore_medium_on_parse_error($urpm, $medium); |
1704 |
return; |
1705 |
} |
1706 |
1; |
1707 |
} |
1708 |
|
1709 |
sub _get_pubkey { |
1710 |
my ($urpm, $medium, $b_wait_lock) = @_; |
1711 |
|
1712 |
my $local = file_from_local_medium($medium); |
1713 |
|
1714 |
#- examine if a pubkey file is available. |
1715 |
($local ? \&_get_pubkey__local : \&_download_pubkey)->($urpm, $medium); |
1716 |
|
1717 |
$medium->{'key-ids'} = _read_cachedir_pubkey($urpm, $medium, $b_wait_lock); |
1718 |
$urpm->{modified} = 1; |
1719 |
} |
1720 |
|
1721 |
sub _get_descriptions { |
1722 |
my ($urpm, $medium) = @_; |
1723 |
|
1724 |
my $local = file_from_local_medium($medium); |
1725 |
|
1726 |
# do not get "descriptions" on non "update" media since it's useless and potentially slow |
1727 |
if ($medium->{update}) { |
1728 |
($local ? \&get_descriptions_local : \&get_descriptions_remote)->($urpm, $medium); |
1729 |
} |
1730 |
} |
1731 |
|
1732 |
# options: wait_lock, nopubkey, forcekey |
1733 |
sub _may_get_pubkey { |
1734 |
my ($urpm, $medium, %options) = @_; |
1735 |
|
1736 |
_get_pubkey($urpm, $medium, $options{wait_lock}) if !$options{nopubkey} && (!$medium->{'key-ids'} || $options{forcekey}); |
1737 |
} |
1738 |
|
1739 |
sub _read_cachedir_pubkey { |
1740 |
my ($urpm, $medium, $b_wait_lock) = @_; |
1741 |
-s "$urpm->{cachedir}/partial/pubkey" or return; |
1742 |
|
1743 |
$urpm->{log}(N("examining pubkey file of \"%s\"...", $medium->{name})); |
1744 |
|
1745 |
my $_rpm_lock = urpm::lock::rpm_db($urpm, 'exclusive', wait => $b_wait_lock); |
1746 |
my $db = urpm::db_open_or_die_($urpm, 'rw'); |
1747 |
|
1748 |
my %key_ids; |
1749 |
URPM::import_needed_pubkeys_from_file($db, |
1750 |
"$urpm->{cachedir}/partial/pubkey", |
1751 |
sub { |
1752 |
my ($id, $imported) = @_; |
1753 |
if ($id) { |
1754 |
$key_ids{$id} = undef; |
1755 |
$imported and $urpm->{log}(N("...imported key %s from pubkey file of \"%s\"", |
1756 |
$id, $medium->{name})); |
1757 |
$imported or $urpm->{debug}("pubkey $id already imported") if $urpm->{debug}; |
1758 |
} else { |
1759 |
$urpm->{error}(N("unable to import pubkey file of \"%s\"", $medium->{name})); |
1760 |
} |
1761 |
}); |
1762 |
|
1763 |
unlink "$urpm->{cachedir}/partial/pubkey"; |
1764 |
|
1765 |
join(',', keys %key_ids); |
1766 |
} |
1767 |
|
1768 |
#- options: callback, ask_retry, force, nomd5sum, probe_with, quiet, forcekey, nopubkey, wait_lock |
1769 |
#- (from _update_medium__parse_if_unmodified__local and _update_medium__parse_if_unmodified__remote) |
1770 |
sub _update_medium_ { |
1771 |
my ($urpm, $medium, %options) = @_; |
1772 |
|
1773 |
#- always delete a remaining list file or pubkey file in cache. |
1774 |
foreach (qw(list pubkey)) { |
1775 |
unlink "$urpm->{cachedir}/partial/$_"; |
1776 |
} |
1777 |
|
1778 |
_pick_mirror_if_needed($urpm, $medium, 'allow-cache-update'); |
1779 |
|
1780 |
{ |
1781 |
my $rc = |
1782 |
is_local_medium($medium) |
1783 |
? _update_medium__parse_if_unmodified__local($urpm, $medium, \%options) |
1784 |
: _update_medium__parse_if_unmodified__remote($urpm, $medium, \%options); |
1785 |
|
1786 |
if ($options{forcekey} && $rc eq 'unmodified') { |
1787 |
_get_pubkey($urpm, $medium, $options{wait_lock}); # we must do it now, quite hackish... |
1788 |
return 1; |
1789 |
} |
1790 |
|
1791 |
if (!$rc || $rc eq 'unmodified') { |
1792 |
return $rc; |
1793 |
} |
1794 |
} |
1795 |
|
1796 |
my $is_updating = -e statedir_synthesis($urpm, $medium); |
1797 |
|
1798 |
if (!_is_local_virtual($medium)) { |
1799 |
if (file_size(cachedir_with_synthesis($urpm, $medium)) < 20) { |
1800 |
$urpm->{error}(N("no synthesis file found for medium \"%s\"", $medium->{name})); |
1801 |
return; |
1802 |
} |
1803 |
|
1804 |
#- use new files |
1805 |
|
1806 |
unlink statedir_synthesis($urpm, $medium); |
1807 |
urpm::sys::move_or_die($urpm, cachedir_with_synthesis($urpm, $medium), |
1808 |
statedir_synthesis($urpm, $medium)); |
1809 |
|
1810 |
unlink statedir_MD5SUM($urpm, $medium); |
1811 |
if (!$medium->{with_synthesis}) { # no MD5SUM when using with_synthesis, urpmi.update will update everytime! |
1812 |
urpm::sys::move_or_die($urpm, "$urpm->{cachedir}/partial/MD5SUM", |
1813 |
statedir_MD5SUM($urpm, $medium)) if -e "$urpm->{cachedir}/partial/MD5SUM"; |
1814 |
} |
1815 |
|
1816 |
# we never download hdlist by default. urpmf will download it via any_hdlist() if really needed |
1817 |
unlink statedir_hdlist($urpm, $medium); |
1818 |
|
1819 |
remove_user_media_info_files($urpm, $medium); |
1820 |
|
1821 |
if (!_local_file($medium)) { |
1822 |
_retrieve_xml_media_info_or_remove($urpm, $medium, $options{quiet}) or return; |
1823 |
} |
1824 |
} |
1825 |
$medium->{modified} = 0; |
1826 |
|
1827 |
# generated on first _parse_media() |
1828 |
unlink statedir_names($urpm, $medium); |
1829 |
|
1830 |
_get_descriptions($urpm, $medium); |
1831 |
_may_get_pubkey($urpm, $medium, %options); |
1832 |
|
1833 |
$is_updating and $urpm->{info}(N("updated medium \"%s\"", $medium->{name})); |
1834 |
|
1835 |
1; |
1836 |
} |
1837 |
|
1838 |
sub _update_medium { |
1839 |
my ($urpm, $medium, %options) = @_; |
1840 |
|
1841 |
my $rc = _update_medium_($urpm, $medium, %options); |
1842 |
|
1843 |
if (!$rc && !_is_local_virtual($medium)) { |
1844 |
#- an error has occured for updating the medium, we have to remove temporary files. |
1845 |
unlink(glob("$urpm->{cachedir}/partial/*")); |
1846 |
} |
1847 |
$rc; |
1848 |
} |
1849 |
|
1850 |
#- Update the urpmi database w.r.t. the current configuration. |
1851 |
#- Takes care of modifications, and tries some tricks to bypass |
1852 |
#- the recomputation of base files. |
1853 |
#- Recognized options : |
1854 |
#- all : all medias are being rebuilt |
1855 |
#- allow_failures: whereas failing to update a medium is non fatal |
1856 |
#- ask_retry : function called when a download fails. if it returns true, the download is retried |
1857 |
#- callback : UI callback |
1858 |
#- forcekey : force retrieval of pubkey |
1859 |
#- force : try to force rebuilding base files |
1860 |
#- nomd5sum : don't verify MD5SUM of retrieved files |
1861 |
#- nopubkey : don't use rpm pubkeys |
1862 |
#- probe_with : probe synthesis or rpms |
1863 |
#- quiet : download synthesis quietly |
1864 |
#- wait_lock : block until lock can be acquired |
1865 |
sub update_media { |
1866 |
my ($urpm, %options) = @_; |
1867 |
|
1868 |
$urpm->{media} or return; # verify that configuration has been read |
1869 |
|
1870 |
if ($options{all}) { |
1871 |
$_->{modified} ||= 1 foreach all_media_to_update($urpm); |
1872 |
} |
1873 |
|
1874 |
update_those_media($urpm, [ grep { $_->{modified} } non_ignored_media($urpm, $options{update}) ], %options); |
1875 |
} |
1876 |
|
1877 |
sub update_those_media { |
1878 |
my ($urpm, $media, %options) = @_; |
1879 |
|
1880 |
$options{nopubkey} ||= $urpm->{options}{nopubkey}; |
1881 |
|
1882 |
#- examine each medium to see if one of them needs to be updated. |
1883 |
#- if this is the case and if not forced, try to use a pre-calculated |
1884 |
#- synthesis file, else build it from rpm files. |
1885 |
clean($urpm); |
1886 |
|
1887 |
my %updates_result; |
1888 |
foreach my $medium (@$media) { |
1889 |
|
1890 |
#- don't ever update static media |
1891 |
$medium->{static} and next; |
1892 |
|
1893 |
my $unsubstituted_url = $medium->{url}; |
1894 |
$medium->{url} = urpm::cfg::expand_line($medium->{url}) if $medium->{url}; |
1895 |
my $rc = _update_medium($urpm, $medium, %options); |
1896 |
$medium->{url} = urpm::cfg::substitute_back($medium->{url}, $unsubstituted_url); |
1897 |
$rc or return if !$options{allow_failures}; |
1898 |
$updates_result{$rc || 'error'}++; |
1899 |
} |
1900 |
|
1901 |
$urpm->{debug} and $urpm->{debug}('update_medium: ' . join(' ', map { "$_=$updates_result{$_}" } keys %updates_result)); |
1902 |
|
1903 |
if ($updates_result{1} == 0) { |
1904 |
#- only errors/unmodified, leave now |
1905 |
#- (this ensures buggy added medium is not added to urpmi.cfg) |
1906 |
return $updates_result{error} == 0; |
1907 |
} |
1908 |
|
1909 |
if ($urpm->{modified}) { |
1910 |
#- write config files in any case |
1911 |
write_config($urpm); |
1912 |
urpm::download::dump_proxy_config(); |
1913 |
} |
1914 |
|
1915 |
$updates_result{error} == 0; |
1916 |
} |
1917 |
|
1918 |
sub _maybe_in_statedir_MD5SUM { |
1919 |
my ($urpm, $medium, $file) = @_; |
1920 |
|
1921 |
my $md5sum_file = statedir_MD5SUM($urpm, $medium); |
1922 |
-e $md5sum_file && urpm::md5sum::parse($md5sum_file)->{$file}; |
1923 |
} |
1924 |
|
1925 |
sub _retrieve_xml_media_info_or_remove { |
1926 |
my ($urpm, $medium, $quiet) = @_; |
1927 |
|
1928 |
my $ok = 1; |
1929 |
|
1930 |
foreach my $xml_info (@xml_media_info) { |
1931 |
my $f = statedir_xml_info($urpm, $medium, $xml_info); |
1932 |
|
1933 |
my $get_it = urpm::is_cdrom_url($medium->{url}) || |
1934 |
get_medium_option($urpm, $medium, 'xml-info') eq 'always' || |
1935 |
get_medium_option($urpm, $medium, 'xml-info') eq 'update-only' && -e $f; |
1936 |
if ($get_it && _maybe_in_statedir_MD5SUM($urpm, $medium, "$xml_info.xml.lzma")) { |
1937 |
$ok &&= _retrieve_media_info_file_and_check_MD5SUM($urpm, $medium, $xml_info, '.xml.lzma', $quiet); |
1938 |
$ok = 1 if urpm::is_cdrom_url($medium->{url}); |
1939 |
} else { |
1940 |
#- "on-demand" |
1941 |
unlink $f; |
1942 |
} |
1943 |
} |
1944 |
$ok; |
1945 |
} |
1946 |
|
1947 |
sub _retrieve_media_info_file_and_check_MD5SUM { |
1948 |
my ($urpm, $medium, $prefix, $suffix, $quiet) = @_; |
1949 |
|
1950 |
my $name = "$prefix$suffix"; |
1951 |
my $cachedir_file = |
1952 |
is_local_medium($medium) ? |
1953 |
_copy_media_info_file($urpm, $medium, $prefix, $suffix) : |
1954 |
_download_media_info_file($urpm, $medium, $prefix, $suffix, { quiet => $quiet, callback => \&urpm::download::sync_logger }) or |
1955 |
$urpm->{error}(N("retrieval of [%s] failed", _synthesis_dir($medium) . "/$name")), return; |
1956 |
|
1957 |
my $wanted_md5sum = urpm::md5sum::from_MD5SUM__or_warn($urpm, $medium->{parsed_md5sum}, $name); |
1958 |
if ($wanted_md5sum) { |
1959 |
$urpm->{debug}("computing md5sum of retrieved $name") if $urpm->{debug}; |
1960 |
urpm::md5sum::compute($cachedir_file) eq $wanted_md5sum or |
1961 |
$urpm->{error}(N("retrieval of [%s] failed (md5sum mismatch)", _synthesis_dir($medium) . "/$name")), return; |
1962 |
|
1963 |
urpm::util::move($cachedir_file, statedir_media_info_file($urpm, $medium, $prefix, $suffix)) or return; |
1964 |
} |
1965 |
1; |
1966 |
} |
1967 |
|
1968 |
sub _download_temp_md5sum_and_parse { |
1969 |
my ($urpm, $medium) = @_; |
1970 |
|
1971 |
$urpm->{debug}("downloading MD5SUM to know updated versioned metadata filename") if $urpm->{debug}; |
1972 |
my $md5sum_file = _download_MD5SUM($urpm, $medium); |
1973 |
urpm::md5sum::parse($md5sum_file); |
1974 |
} |
1975 |
|
1976 |
sub _any_media_info__or_download { |
1977 |
my ($urpm, $medium, $prefix, $suffix, $quiet, $o_callback) = @_; |
1978 |
|
1979 |
my $f = statedir_media_info_file($urpm, $medium, $prefix, $suffix); |
1980 |
-s $f and return $f; |
1981 |
|
1982 |
if ($<) { |
1983 |
urpm::ensure_valid_cachedir($urpm); |
1984 |
$f = "$urpm->{cachedir}/" . statedir_media_info_basename($medium, $prefix, $suffix); |
1985 |
-s $f and return $f; |
1986 |
} |
1987 |
|
1988 |
get_medium_option($urpm, $medium, 'xml-info') ne 'never' or return; |
1989 |
|
1990 |
_maybe_in_statedir_MD5SUM($urpm, $medium, "$prefix$suffix") or return; |
1991 |
|
1992 |
$medium->{parsed_md5sum} ||= _download_temp_md5sum_and_parse($urpm, $medium); |
1993 |
|
1994 |
my $file_in_partial = |
1995 |
_download_media_info_file($urpm, $medium, $prefix, $suffix, |
1996 |
{ quiet => $quiet, callback => $o_callback }) or return; |
1997 |
|
1998 |
urpm::util::move($file_in_partial, $f) or return; |
1999 |
|
2000 |
$f; |
2001 |
} |
2002 |
|
2003 |
#- side-effects: |
2004 |
#- + those of urpm::mirrors::pick_one ($urpm->{mirrors_cache}, $medium->{url}) |
2005 |
sub _pick_mirror_if_needed { |
2006 |
my ($urpm, $medium, $allow_cache_update) = @_; |
2007 |
|
2008 |
$medium->{mirrorlist} && !$medium->{url} or return; |
2009 |
|
2010 |
require urpm::mirrors; |
2011 |
urpm::mirrors::pick_one($urpm, $medium, $allow_cache_update); |
2012 |
} |
2013 |
|
2014 |
#- side-effects: |
2015 |
#- + those of urpm::mirrors::try ($urpm->{mirrors_cache}, $medium->{url}) |
2016 |
sub try__maybe_mirrorlist { |
2017 |
my ($urpm, $medium, $is_a_probe, $try) = @_; |
2018 |
|
2019 |
if ($medium->{mirrorlist}) { |
2020 |
if (urpm::download::use_metalink($urpm, $medium)) { |
2021 |
#- help things... |
2022 |
_pick_mirror_if_needed($urpm, $medium, 'allow-cache-update'); |
2023 |
|
2024 |
$try->(); |
2025 |
} else { |
2026 |
require urpm::mirrors; |
2027 |
$is_a_probe |
2028 |
? urpm::mirrors::try_probe($urpm, $medium, $try) |
2029 |
: urpm::mirrors::try($urpm, $medium, $try); |
2030 |
} |
2031 |
} else { |
2032 |
$try->(); |
2033 |
} |
2034 |
} |
2035 |
|
2036 |
#- clean params and depslist computation zone. |
2037 |
sub clean { |
2038 |
my ($urpm) = @_; |
2039 |
|
2040 |
$urpm->{depslist} = []; |
2041 |
$urpm->{provides} = {}; |
2042 |
|
2043 |
foreach (@{$urpm->{media} || []}) { |
2044 |
delete $_->{start}; |
2045 |
delete $_->{end}; |
2046 |
} |
2047 |
} |
2048 |
|
2049 |
1; |