File Coverage

blib/lib/urpm/media.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


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