/[soft]/rpm/urpmi/trunk/urpm/media.pm
ViewVC logotype

Contents of /rpm/urpmi/trunk/urpm/media.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3999 - (show annotations) (download)
Sun Apr 8 11:19:04 2012 UTC (11 years, 11 months ago) by tv
File size: 64474 byte(s)
s/cooker/cauldron/
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;

  ViewVC Help
Powered by ViewVC 1.1.30