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   1196 use strict;
  1         1  
  1         30  
5 1     1   31 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             urpm::cfg::dump_config($urpm->{config}, $config)
555             or $urpm->{fatal}(6, N("unable to write config file [%s]", $urpm->{config}));
556              
557             $urpm->{log}(N("wrote config file [%s]", $urpm->{config}));
558              
559             #- everything should be synced now.
560             delete $urpm->{modified};
561             }
562              
563             sub write_config {
564             my ($urpm) = @_;
565              
566             write_urpmi_cfg($urpm);
567             }
568              
569              
570             sub _tempignore {
571             my ($medium, $ignore) = @_;
572             $medium->{ignore} = $ignore;
573             }
574              
575             =item configure($urpm, %options)
576              
577             Read urpmi.cfg file as well as necessary synthesis files.
578              
579             Options :
580              
581             =over
582              
583             =item *
584              
585             root (deprecated, set directly $urpm->{root})
586              
587             =item *
588              
589             cmdline_skiplist
590              
591             =item *
592              
593             download_callback (used by _auto_update_media)
594              
595             =item *
596              
597             callback (urpmf)
598              
599             =item *
600              
601             nodepslist (for urpmq, urpmf: when we don't need the synthesis)
602              
603             =item *
604              
605             no_skiplist (urpmf)
606              
607             =item *
608              
609             synthesis (use this synthesis file, and only this synthesis file)
610              
611             =item *
612              
613             parallel
614              
615             =item *
616              
617             usedistrib (otherwise uses urpmi.cfg)
618              
619             =item *
620              
621             media
622              
623             =item *
624              
625             excludemedia
626              
627             =item *
628              
629             sortmedia
630              
631             =item *
632              
633             update
634              
635             =item *
636              
637             searchmedia
638              
639             =back
640              
641             =cut
642              
643             sub configure {
644             my ($urpm, %options) = @_;
645              
646             clean($urpm);
647              
648             $options{parallel} && $options{usedistrib} and $urpm->{fatal}(1, N("Can't use parallel mode with use-distrib mode"));
649              
650             if ($options{parallel}) {
651             require urpm::parallel;
652             urpm::parallel::configure($urpm, $options{parallel});
653              
654             if (!$options{media} && $urpm->{parallel_handler}{media}) {
655             $options{media} = $urpm->{parallel_handler}{media};
656             $urpm->{log}->(N("using associated media for parallel mode: %s", $options{media}));
657             }
658             } else {
659             #- nb: can't have both parallel and root
660             $urpm->{root} = $options{root} if $options{root};
661             }
662              
663             if ($urpm->{root} && ! -c "$urpm->{root}/dev/null") {
664             mkdir "$urpm->{root}/dev";
665             system("/bin/cp", "-a", '/dev/null', "$urpm->{root}/dev");
666             }
667              
668             if ($options{synthesis}) {
669             if ($options{synthesis} ne 'none') {
670             #- synthesis take precedence over media, update options.
671             $options{media} || $options{excludemedia} || $options{sortmedia} || $options{update} || $options{usedistrib} || $options{parallel} and
672             $urpm->{fatal}(1, N("--synthesis cannot be used with --media, --excludemedia, --sortmedia, --update, --use-distrib or --parallel"));
673              
674             my $synthesis = $options{synthesis};
675             if ($synthesis !~ m!^/!) {
676             require Cwd;
677             $synthesis = Cwd::getcwd() . '/' . $synthesis;
678             }
679             my ($url, $with) = $synthesis =~ m!(.*)/+(media_info/+synthesis\.hdlist\.cz)$! ? ($1, $2) :
680             (dirname($synthesis), basename($synthesis));
681              
682             $urpm->{media} = [];
683             add_medium($urpm, 'Virtual', $url, $with, %options, virtual => 1, on_the_fly => 1);
684             }
685             } elsif ($options{usedistrib}) {
686             $urpm->{media} = [];
687             add_distrib_media($urpm, "Virtual", $options{usedistrib}, %options, virtual => 1, on_the_fly => 1);
688             } else {
689             read_config($urpm, '');
690             if (!$options{media} && $urpm->{options}{'default-media'}) {
691             $options{media} = $urpm->{options}{'default-media'};
692             }
693             }
694              
695             if ($options{media}) {
696             delete $_->{modified} foreach @{$urpm->{media} || []};
697             select_media($urpm, split /,/, $options{media});
698             foreach (@{$urpm->{media} || []}) {
699             _tempignore($_, !$_->{modified});
700             }
701             }
702             if ($options{searchmedia}) {
703             foreach (select_media_by_name($urpm, [ split /,/, $options{searchmedia} ])) {
704             #- Ensure this media is selected
705             $_->{modified} = 1;
706             _tempignore($_, 0);
707             $_->{searchmedia} = 1;
708             }
709             }
710             if ($options{update}) {
711             foreach (grep { !$_->{ignore} && $_->{update} } @{$urpm->{media} || []}) {
712             #- Ensure update media are selected
713             $_->{modified} = 1;
714             _tempignore($_, 0);
715             $_->{searchmedia} = 1;
716             }
717             }
718             if ($options{excludemedia}) {
719             delete $_->{modified} foreach @{$urpm->{media} || []};
720             foreach (select_media_by_name($urpm, [ split /,/, $options{excludemedia} ])) {
721             $_->{modified} = 1;
722             #- this is only a local ignore that will not be saved.
723             _tempignore($_, 1);
724             }
725             }
726             if ($options{sortmedia}) {
727             my @sorted_media = map { select_media_by_name($urpm, [$_]) } split(/,/, $options{sortmedia});
728             my @remaining = difference2($urpm->{media}, \@sorted_media);
729             $urpm->{media} = [ @sorted_media, @remaining ];
730             }
731             _auto_update_media($urpm, %options);
732              
733             _pick_mirror_if_needed($urpm, $_, '') foreach non_ignored_media($urpm);
734              
735             if (!$options{nodepslist}) {
736             parse_media($urpm, \%options);
737              
738             #- determine package to withdraw (from skip.list file) only if something should be withdrawn.
739             _compute_flags_for_skiplist($urpm, $options{cmdline_skiplist}) if !$options{no_skiplist};
740             _compute_flags_for_instlist($urpm);
741             }
742             }
743              
744             #- for remote "virtual" media
745             #- options: download_callback, nomd5sum, quiet, nopubkey
746             sub _auto_update_media {
747             my ($urpm, %options) = @_;
748              
749             $options{callback} = delete $options{download_callback};
750              
751             foreach (grep { _is_remote_virtual($_) || $urpm->{options}{'auto-update'} }
752             non_ignored_media($urpm)) {
753             _update_medium($urpm, $_, %options);
754             }
755             }
756              
757              
758             =item needed_extra_media($urpm)
759              
760             Return 2 booleans telling whether nonfree & tainted packages are installed respectively.
761              
762             =cut
763              
764             sub needed_extra_media {
765             my ($urpm) = @_;
766             my $db = urpm::db_open_or_die_($urpm);
767             my ($nonfree, $tainted);
768             $db->traverse(sub {
769             my ($pkg) = @_;
770             return if $nonfree && $tainted;
771             my $rel = $pkg->release;
772             $nonfree ||= $rel =~ /nonfree$/;
773             $tainted ||= $rel =~ /tainted$/;
774             });
775             ($nonfree, $tainted);
776             }
777              
778             sub is_media_to_add_by_default {
779             my ($urpm, $distribconf, $medium, $product_id, $nonfree, $tainted) = @_;
780             my $add_by_default = !$distribconf->getvalue($medium, 'noauto');
781             my @media_types = split(':', $distribconf->getvalue($medium, 'media_type'));
782             return $add_by_default if !@media_types;
783             if ($product_id->{product} eq 'Free') {
784             if (member('non-free', @media_types)) {
785             $urpm->{log}(N("ignoring non-free medium `%s'", $medium));
786             $add_by_default = 0;
787             }
788             } else {
789             my $non_regular_medium = intersection(\@media_types, [ qw(backports debug source testing) ]);
790             if (!$add_by_default && !$non_regular_medium) {
791             my $medium_name = $distribconf->getvalue($medium, 'name') || '';
792             if ($medium_name =~ /Nonfree/ && $nonfree) {
793             $add_by_default = 1;
794             $urpm->{log}(N("un-ignoring non-free medium `%s' b/c nonfree packages are installed", $medium_name));
795             }
796             if ($medium_name =~ /Tainted/ && $tainted) {
797             $add_by_default = 1;
798             $urpm->{log}(N("un-ignoring tainted medium `%s' b/c tainted packages are installed", $medium_name));
799             }
800             }
801             }
802             $add_by_default;
803             }
804              
805             sub non_ignored_media {
806             my ($urpm, $b_only_marked_update) = @_;
807              
808             grep { !$_->{ignore} && (!$b_only_marked_update || $_->{update}) } @{$urpm->{media} || []};
809             }
810              
811             sub all_media_to_update {
812             my ($urpm, $b_only_marked_update) = @_;
813              
814             grep { !$_->{static} && !urpm::is_cdrom_url($_->{url}) && !$_->{iso} } non_ignored_media($urpm, $b_only_marked_update);
815             }
816              
817             sub parse_media {
818             my ($urpm, $options) = @_;
819              
820             foreach (non_ignored_media($urpm)) {
821             delete @$_{qw(start end)};
822             _parse_synthesis_or_ignore($urpm, $_, $options->{callback});
823              
824             if ($_->{searchmedia}) {
825             $urpm->{searchmedia} = 1;
826             $urpm->{debug} and $urpm->{debug}(N("Search start: %s end: %s", $_->{start}, $_->{end}));
827             }
828              
829             $< == 0 and _generate_medium_names($urpm, $_);
830             }
831             }
832              
833             sub _compute_flags_for_skiplist {
834             my ($urpm, $cmdline_skiplist) = @_;
835             my %uniq;
836             $urpm->compute_flags(
837             urpm::sys::get_packages_list($urpm->{skiplist}, $cmdline_skiplist),
838             skip => 1,
839             callback => sub {
840             my ($urpm, $pkg) = @_;
841             $pkg->is_arch_compat && ! exists $uniq{$pkg->fullname} or return;
842             $uniq{$pkg->fullname} = undef;
843             $urpm->{debug} and $urpm->{debug}(N("skipping package %s", scalar($pkg->fullname)));
844             },
845             );
846             }
847              
848             sub _compute_flags_for_instlist {
849             my ($urpm) = @_;
850              
851             my %uniq;
852             $urpm->compute_flags(
853             urpm::sys::get_packages_list($urpm->{instlist}),
854             disable_obsolete => 1,
855             callback => sub {
856             my ($urpm, $pkg) = @_;
857             $pkg->is_arch_compat && ! exists $uniq{$pkg->fullname} or return;
858             $uniq{$pkg->fullname} = undef;
859             $urpm->{log}(N("would install instead of upgrade package %s", scalar($pkg->fullname)));
860             },
861             );
862              
863             }
864              
865             sub maybe_find_zeroconf {
866             my ($urpm, $url, $options) = @_;
867             if (delete $options->{zeroconf}) {
868             $url and die "unexpected url $url together with zeroconf\n";
869             $url = find_zeroconf_repository($urpm);
870             if ($url) {
871             $url = urpm::mirrors::_add__with_dir($url, delete $options->{"with-dir"});
872             delete $options->{mirrorlist};
873             }
874             }
875             return $url;
876             }
877              
878             sub find_zeroconf_repository {
879             my ($urpm) = @_;
880              
881             my $zeroconf_timeout = 10;
882             my $res;
883             eval {
884             local $SIG{ALRM} = sub { die "timeout" };
885             alarm($zeroconf_timeout);
886              
887             $urpm->{debug} and $urpm->{debug}("trying to find a zeroconf repository");
888             require Net::Bonjour;
889             $res = Net::Bonjour->new('mdv_urpmi');
890              
891             alarm(0);
892             };
893              
894             if ($@) {
895             $urpm->{error}("zeroconf error: $@"), return;
896             }
897              
898             require urpm::mirrors;
899             my $product_id = urpm::mirrors::parse_LDAP_namespace_structure(cat_('/etc/product.id'));
900             my $path_suffix = join('/', lc($product_id->{branch}), $product_id->{version}, $product_id->{arch});
901              
902             foreach my $entry ($res->entries) {
903             my $base_url = $entry->attribute('protocol') . '://' . $entry->address . ':' . $entry->port . $entry->attribute('path');
904             my $url = $base_url . '/' . $path_suffix;
905             my $distribconf = _new_distribconf_and_download($urpm, { url => $url });
906             if ($distribconf) {
907             $urpm->{log}(sprintf("found zeroconf repository: %s", $url));
908             return $url;
909             }
910             }
911              
912             $urpm->{debug} and $urpm->{debug}("unable to find zeroconf repository");
913             return;
914             }
915              
916             =item add_medium($urpm, $name, $url, $with_synthesis, %options)
917              
918             Add a new medium and sync the config file accordingly.
919              
920             It returns the new medium's name (might be different from the requested
921             name if index_name was specified).
922              
923             Options: ignore, index_name, nolock, update, virtual, media_info_dir, mirrorlist, zeroconf, with-dir, xml-info, on_the_fly
924              
925             =cut
926              
927             sub add_medium {
928             my ($urpm, $name, $url, $with_synthesis, %options) = @_;
929              
930             #- make sure configuration has been read.
931             $urpm->{media} or die "caller should have used ->read_config or ->configure first";
932              
933             #- if a medium with that name has already been found, we have to exit now
934             if (defined $options{index_name}) {
935             my ($i, $basename) = ($options{index_name}, $name);
936             while (1) {
937             ++$i;
938             $name = $basename . ($i == 1 ? '' : $i);
939             last if !name2medium($urpm, $name);
940             }
941             } else {
942             name2medium($urpm, $name) and $urpm->{fatal}(5, N("medium \"%s\" already exists", $name));
943             }
944              
945             $url = maybe_find_zeroconf($urpm, $url, \%options);
946              
947             $url =~ s,/*$,,; #- clear URLs for trailing /es.
948              
949             #- creating the medium info.
950             my $medium = { name => $name,
951             url => $url,
952             modified => !$options{ignore},
953             (defined $options{'verify-rpm'} ? ('verify-rpm' => $options{'verify-rpm'}) : ()),
954             };
955             foreach (qw(downloader update ignore media_info_dir mirrorlist with-dir xml-info)) {
956             $medium->{$_} = $options{$_} if exists $options{$_};
957             }
958              
959             #- those files must not be there (cf mdvbz#36267)
960             _clean_statedir_medium_files($urpm, $medium);
961             if (!($options{virtual} && _local_file($medium))
962             && !$urpm->{urpmi_root}) { # with --urpmi-root, we do not use statedir_media_info_file to allow compatibility with older urpmi
963             mkdir statedir_media_info_dir($urpm, $medium), 0755;
964             }
965              
966             if ($options{virtual}) {
967             $medium->{virtual} = 1;
968             } else {
969             _migrate_removable_device($urpm, $medium);
970             }
971              
972             if ($with_synthesis) {
973             _migrate__with_synthesis($medium, $with_synthesis);
974             } elsif (!$medium->{media_info_dir}) {
975             if (!is_local_medium($medium)) {
976             $medium->{media_info_dir} = 'media_info';
977             } else {
978             $medium->{unknown_media_info} = 1;
979             }
980             }
981              
982             #- local media have priority, other are added at the end.
983             my $inserted;
984             my $ignore_text = $medium->{ignore} ? ' ' . N("(ignored by default)") : '';
985             if (_local_file($medium)) {
986             #- insert before first remote medium
987             @{$urpm->{media}} = map {
988             if (!_local_file($_) && !$inserted) {
989             $inserted = 1;
990             $urpm->{$options{on_the_fly} ? 'log' : 'info'}(N("adding medium \"%s\" before remote medium \"%s\"", $name, $_->{name}) . $ignore_text);
991             $medium, $_;
992             } else { $_ }
993             } @{$urpm->{media}};
994             }
995             if (!$inserted) {
996             $urpm->{$options{on_the_fly} ? 'log' : 'info'}(N("adding medium \"%s\"", $name) . $ignore_text);
997             push @{$urpm->{media}}, $medium;
998             }
999              
1000             $urpm->{modified} = 1;
1001              
1002             $name;
1003             }
1004              
1005             sub _register_media_cfg {
1006             my ($urpm, $url, $mirrorlist, $distribconf, $media_cfg) = @_;
1007              
1008             my $arch = $distribconf->getvalue('media_info', 'arch') || '';
1009             my $branch = $distribconf->getvalue('media_info', 'branch') || '';
1010             my $product = $distribconf->getvalue('media_info', 'product') || '';
1011             my $version = $distribconf->getvalue('media_info', 'version') || '';
1012             #official mirrors define $branch but not $product, other RPM repos do the
1013             #opposite :-/
1014             my $media_dir = (($branch || $product) . '-' . $version . '-' . $arch);
1015             $media_dir =~ tr!/!-!;
1016             my $media_path = $urpm->{mediacfgdir} . '/' . $media_dir;
1017             require File::Path;
1018             File::Path::mkpath($media_path);
1019             copy_and_own($media_cfg, $media_path . '/media.cfg')
1020             or $urpm->{info}(1, N("failed to copy media.cfg to %s (%d)", $media_path, $? >> 8));
1021             if ($url) {
1022             my $filename = $media_path . "/url";
1023             my @urls = split(/\n/, scalar cat_($filename));
1024             if (!member($url, @urls)) {
1025             append_to_file($filename, $url . "\n");
1026             }
1027             }
1028             if ($mirrorlist) {
1029             if ($mirrorlist ne '$MIRRORLIST') {
1030             require urpm::cfg;
1031             $mirrorlist = urpm::cfg::expand_line($mirrorlist);
1032             }
1033             my $filename = $media_path . "/mirrorlist";
1034             my @mirrorlists = split(/\n/, scalar cat_($filename));
1035             if (!member($mirrorlist, @mirrorlists)) {
1036             append_to_file($filename, $mirrorlist . "\n");
1037             }
1038             }
1039             }
1040              
1041             =item add_distrib_media($urpm, $name, $url, %options)
1042              
1043             Add distribution media, according to url given.
1044             Returns the list of names of added media.
1045              
1046             Options :
1047              
1048             =over
1049              
1050             =item *
1051              
1052             initial_number : when adding several numbered media, start with this number
1053              
1054             =item *
1055              
1056             probe_with : force use of rpms instead of using synthesis
1057              
1058             =item *
1059              
1060             ask_media : callback to know whether each media should be added
1061              
1062             =item *
1063              
1064             only_updates : only add "update" media (used by rpmdrake)
1065              
1066             =item *
1067              
1068             mirrorlist
1069              
1070             =item *
1071              
1072             zeroconf
1073              
1074             =back
1075              
1076             Other options are passed to add_medium(): ignore, nolock, virtual
1077              
1078             =cut
1079              
1080             sub add_distrib_media {
1081             my ($urpm, $name, $url, %options) = @_;
1082              
1083             #- make sure configuration has been read.
1084             $urpm->{media} or die "caller should have used ->read_config or ->configure first";
1085              
1086             my $distribconf;
1087              
1088             if ($url && urpm::is_local_url($url)) {
1089             $url = _migrate_removable_url($url) or return();
1090             my $m = { url => $url };
1091             urpm::removable::try_mounting_medium_($urpm, $m) or $urpm->{error}(N("directory %s does not exist", $url));
1092              
1093             $distribconf = MDV::Distribconf->new(file_from_file_url($url) || $url, undef);
1094             $distribconf->settree('mageia');
1095              
1096             my $dir = file_from_local_medium($m);
1097             my $media_cfg = reduce_pathname("$dir/" . $distribconf->getpath(undef, 'infodir') . '/media.cfg');
1098             $distribconf->parse_mediacfg($media_cfg)
1099             or $urpm->{error}(N("this location doesn't seem to contain any distribution")), return ();
1100             if (!$options{virtual}) {
1101             _register_media_cfg($urpm, $dir, undef, $distribconf, $media_cfg);
1102             }
1103             } else {
1104             $url = maybe_find_zeroconf($urpm, $url, \%options);
1105             if ($options{mirrorlist}) {
1106             $url and die "unexpected url $url together with mirrorlist $options{mirrorlist}\n";
1107             }
1108              
1109             my $m = { mirrorlist => $options{mirrorlist}, url => $url };
1110             my $parse_ok;
1111             try__maybe_mirrorlist($urpm, $m, 'probe', sub {
1112             my $media_cfg = "$urpm->{cachedir}/partial/media.cfg";
1113             $distribconf = _new_distribconf_and_download($urpm, $m);
1114             $parse_ok = $distribconf && $distribconf->parse_mediacfg($media_cfg);
1115             if ($parse_ok && !$options{virtual}) {
1116             _register_media_cfg($urpm, urpm::cfg::expand_line($m->{url}), $options{mirrorlist}, $distribconf, $media_cfg);
1117             }
1118             $parse_ok;
1119             });
1120             $url = $m->{url};
1121              
1122             if ($distribconf) {
1123             $parse_ok or $urpm->{error}(N("unable to parse media.cfg")), return();
1124             } else {
1125             $urpm->{error}(N("...retrieving failed: %s", $@));
1126             $urpm->{error}(N("unable to access the distribution medium (no media.cfg file found)"));
1127             return ();
1128             }
1129             }
1130              
1131             #- cosmetic update of name if it contains spaces.
1132             $name =~ /\s/ and $name .= ' ';
1133              
1134             my @newnames;
1135             #- at this point, we have found a media.cfg file, so parse it
1136             #- and create all necessary media according to it.
1137             my $medium_index = $options{initial_number} || 1;
1138              
1139             require urpm::mirrors;
1140             my $product_id = urpm::mirrors::parse_LDAP_namespace_structure(cat_('/etc/product.id'));
1141             my ($nonfree, $tainted) = needed_extra_media($urpm);
1142              
1143             foreach my $media ($distribconf->listmedia) {
1144             my $media_name = $distribconf->getvalue($media, 'name') || '';
1145              
1146             if (my $media_arch = $distribconf->getvalue($media, 'arch')) {
1147             if (!URPM::archscore($media_arch)) {
1148             $urpm->{log}(N("skipping non compatible media `%s' (for %s)",
1149             $media, $media_arch));
1150             next;
1151             }
1152             }
1153              
1154             my $is_update_media = $distribconf->getvalue($media, 'updates_for');
1155             if ($options{only_updates}) {
1156             $is_update_media or next;
1157             }
1158              
1159             my $add_by_default = is_media_to_add_by_default($urpm, $distribconf, $media, $product_id, $nonfree, $tainted);
1160              
1161             my $ignore;
1162             if ($options{ask_media}) {
1163             $options{ask_media}->($media_name, $add_by_default) or next;
1164             } else {
1165             my $simple_rpms = !$distribconf->getvalue($media, 'rpms');
1166             $add_by_default || $simple_rpms or next;
1167             $ignore = !$add_by_default;
1168             }
1169              
1170             my $use_copied_synthesis = urpm::is_cdrom_url($url) || $urpm->{options}{use_copied_hdlist} || $distribconf->getvalue($media, 'use_copied_hdlist');
1171             my $with_synthesis = $use_copied_synthesis && offset_pathname(
1172             $url,
1173             $distribconf->getpath($media, 'path'),
1174             ) . '/' . $distribconf->getpath($media, 'synthesis');
1175              
1176             push @newnames, add_medium($urpm,
1177             $name ? "$media_name ($name$medium_index)" : $media_name,
1178             reduce_pathname($distribconf->getfullpath($media, 'path')),
1179             $with_synthesis,
1180             !$use_copied_synthesis ? (media_info_dir => 'media_info') : @{[]},
1181             !$use_copied_synthesis && $options{probe_with} ? ($options{probe_with} => 1) : (),
1182             index_name => $name ? undef : 0,
1183             $ignore ? (ignore => 1) : @{[]},
1184             %options,
1185             # the following override %options
1186             $options{mirrorlist} ? ('with-dir' => $distribconf->getpath($media, 'path')) : (),
1187             update => $is_update_media ? 1 : undef,
1188             );
1189             ++$medium_index;
1190             }
1191              
1192             # associate newly added medias with their description in a media.cfg file
1193             # @media content will be modified and then add_existing medium will take
1194             # care of copying the media to $urpm
1195             _associate_media_with_mediacfg($urpm, [ map { name2medium($urpm, $_) } @newnames ]);
1196              
1197             return @newnames;
1198             }
1199              
1200             sub _new_distribconf_and_download {
1201             my ($urpm, $medium) = @_;
1202              
1203             my $distribconf = MDV::Distribconf->new($medium->{url}, undef);
1204             $distribconf->settree('mageia');
1205              
1206             $urpm->{log}(N("retrieving media.cfg file..."));
1207             my $url = $medium->{url};
1208             $medium->{url} = urpm::cfg::expand_line($url);
1209             urpm::download::sync_rel_one($urpm, $medium, $distribconf->getpath(undef, 'infodir') . '/media.cfg',
1210             quiet => 1, preclean => 1) or return;
1211             $medium->{url} = urpm::cfg::substitute_back($medium->{url}, $url);
1212             $distribconf;
1213             }
1214              
1215             #- deprecated, use select_media_by_name instead
1216             sub select_media {
1217             my $urpm = shift;
1218             my $options = {};
1219             if (ref $_[0]) { $options = shift }
1220             foreach (select_media_by_name($urpm, [ @_ ], $options->{strict_match})) {
1221             #- select medium by setting the modified flag, do not check ignore.
1222             $_->{modified} = 1;
1223             }
1224             }
1225              
1226             sub select_media_by_name {
1227             my ($urpm, $names, $b_strict_match) = @_;
1228              
1229             my %wanted = map { $_ => 1 } @$names;
1230              
1231             #- first the exact matches
1232             my @l = grep { delete $wanted{$_->{name}} } @{$urpm->{media}};
1233              
1234             #- check if some arguments don't correspond to the medium name.
1235             #- in such case, try to find the unique medium (or list candidate
1236             #- media found).
1237             foreach (keys %wanted) {
1238             my $q = quotemeta;
1239             my (@found, @foundi);
1240             my $regex = $b_strict_match ? qr/^$q$/ : qr/$q/;
1241             my $regexi = $b_strict_match ? qr/^$q$/i : qr/$q/i;
1242             foreach my $medium (@{$urpm->{media}}) {
1243             $medium->{name} =~ $regex and push @found, $medium;
1244             $medium->{name} =~ $regexi and push @foundi, $medium;
1245             }
1246             @found = @foundi if !@found;
1247              
1248             if (@found == 0) {
1249             $urpm->{error}(N("trying to select nonexistent medium \"%s\"", $_));
1250             } else {
1251             if (@found > 1) {
1252             $urpm->{log}(N("selecting multiple media: %s", join(", ", map { qq("$_->{name}") } @found)));
1253             }
1254             #- changed behaviour to select all occurences by default.
1255             push @l, @found;
1256             }
1257             }
1258             @l;
1259             }
1260              
1261             #- deprecated, use remove_media instead
1262             sub remove_selected_media {
1263             my ($urpm) = @_;
1264              
1265             remove_media($urpm, [ grep { $_->{modified} } @{$urpm->{media}} ]);
1266             }
1267              
1268             sub _remove_medium_from_mediacfg {
1269             my ($urpm, $mediacfg_dir, $url, $is_mirrorlist) = @_;
1270              
1271             my $filename = $mediacfg_dir;
1272             $filename .= $is_mirrorlist ? "/mirrorlist" : "/url";
1273              
1274             my @urls = split(/\n/, scalar cat_($filename));
1275             $urpm->{debug} and $urpm->{debug}("removing $url from $filename");
1276             output_safe($filename, join('\n', grep { $url ne $_ } @urls));
1277             }
1278              
1279             sub _cleanup_mediacfg_dir {
1280             my ($urpm, $to_remove) = @_;
1281              
1282             foreach my $medium (@$to_remove) {
1283             $medium->{mediacfg} or next;
1284             #this should never happen but dirname(undef) returns . on which we call
1285             #clean_dir so better be safe than sorry
1286             $medium->{mediacfg}[0]{root} or next;
1287             my $dir = reduce_pathname(dirname($medium->{mediacfg}[0]{root}));
1288             begins_with($medium->{mediacfg}[0]{root}, $dir) or next;
1289             if (!any { $_->{mediacfg}[0]{root} == $medium->{mediacfg}[0]{root} } @{$urpm->{media}}) {
1290             $urpm->{debug} and $urpm->{debug}("removing no longer used $dir");
1291             -d $dir and urpm::sys::clean_dir($dir);
1292             next;
1293             }
1294              
1295             if ($medium->{mirrorlist}) {
1296             if (!any { $_->{mirrorlist} eq $medium->{mirrorlist} } @{$urpm->{media}}) {
1297             _remove_medium_from_mediacfg($urpm, $dir, $medium->{mirrorlist}, 1);
1298             }
1299             } elsif ($medium->{url}) {
1300             if (!any { $_->{url} eq $medium->{url} } @{$urpm->{media}}) {
1301             _remove_medium_from_mediacfg($urpm, $dir, $medium->{url}, 0);
1302             }
1303             }
1304             }
1305             }
1306              
1307             sub remove_media {
1308             my ($urpm, $to_remove) = @_;
1309              
1310             foreach my $medium (@$to_remove) {
1311             $urpm->{info}(N("removing medium \"%s\"", $medium->{name}));
1312              
1313             #- mark to re-write configuration.
1314             $urpm->{modified} = 1;
1315              
1316             _clean_statedir_medium_files($urpm, $medium);
1317              
1318             #- remove proxy settings for this media
1319             urpm::download::remove_proxy_media($medium->{name});
1320             }
1321             $urpm->{media} = [ difference2($urpm->{media}, $to_remove) ];
1322             _cleanup_mediacfg_dir($urpm, $to_remove);
1323             }
1324              
1325             sub _clean_statedir_medium_files {
1326             my ($urpm, $medium) = @_;
1327              
1328             #- remove files associated with this medium.
1329             unlink grep { $_ } map { old_statedir_media_info_file($urpm, $medium, $_->[0], $_->[1]) } @media_info_prefix_suffix;
1330              
1331             my $dir = statedir_media_info_dir($urpm, $medium);
1332             -d $dir and urpm::sys::clean_dir($dir);
1333              
1334             remove_user_media_info_files($urpm, $medium);
1335             }
1336              
1337             sub _probe_with_try_list {
1338             my ($urpm, $medium, $f) = @_;
1339              
1340             $medium->{mirrorlist} and die "_probe_with_try_list does not handle mirrorlist\n";
1341              
1342             my @media_info_dirs = ('media_info', '.');
1343              
1344             my $base = file_from_local_medium($medium) || $medium->{url};
1345              
1346             foreach my $media_info_dir (@media_info_dirs) {
1347             my $file = "$media_info_dir/synthesis.hdlist.cz";
1348             my $url = reduce_pathname("$base/$file");
1349             if ($f->($url, $file)) {
1350             $urpm->{debug} and $urpm->{debug}("found synthesis: $url");
1351             $medium->{media_info_dir} = $media_info_dir;
1352             delete $medium->{unknown_media_info};
1353             return 1;
1354             }
1355             }
1356             undef;
1357             }
1358              
1359             sub may_reconfig_urpmi {
1360             my ($urpm, $medium) = @_;
1361              
1362             $medium->{url} && !urpm::is_cdrom_url($medium->{url}) or return; # we should handle mirrorlist?
1363              
1364             my $f;
1365             if (my $dir = file_from_file_url($medium->{url})) {
1366             $f = reduce_pathname("$dir/reconfig.urpmi");
1367             } else {
1368             $f = urpm::download::sync_rel_one($urpm, $medium, 'reconfig.urpmi',
1369             quiet => 1, preclean => 1) or return;
1370             }
1371             my $reconfigured = -s $f && reconfig_urpmi($urpm, $f, $medium);
1372             unlink $f if !is_local_medium($medium);
1373             $reconfigured;
1374             }
1375              
1376             =item reconfig_urpmi($urpm, $rfile, $medium)
1377              
1378             Read a reconfiguration file for urpmi, and reconfigure media accordingly.
1379             $rfile is the reconfiguration file (local), $name is the media name
1380              
1381             the format is similar to the RewriteRule of mod_rewrite, so:
1382              
1383             PATTERN REPLACEMENT [FLAG]
1384              
1385             where FLAG can be L or N
1386              
1387             example of reconfig.urpmi:
1388              
1389             # this is an urpmi reconfiguration file
1390             /cauldron /cauldron/$ARCH
1391              
1392             =cut
1393              
1394             sub reconfig_urpmi {
1395             my ($urpm, $rfile, $medium) = @_;
1396             -r $rfile or return;
1397              
1398             my ($magic, @lines) = cat_($rfile);
1399             #- the first line of reconfig.urpmi must be magic, to be sure it's not an error file
1400             $magic =~ /^# this is an urpmi reconfiguration file/ or return undef;
1401              
1402             $urpm->{info}(N("reconfiguring urpmi for media \"%s\"", $medium->{name}));
1403              
1404             my @replacements;
1405             foreach (@lines) {
1406             chomp;
1407             s/^\s*//; s/#.*$//; s/\s*$//;
1408             $_ or next;
1409             my ($p, $r, $f) = split /\s+/, $_, 3;
1410             push @replacements, [ quotemeta $p, $r, $f || 1 ];
1411             }
1412              
1413             my $reconfigured = 0;
1414             my @reconfigurable = qw(url with_synthesis media_info_dir);
1415              
1416             my %orig = %$medium;
1417              
1418             URLS:
1419             foreach my $k (@reconfigurable) {
1420             foreach my $r (@replacements) {
1421             if ($medium->{$k} =~ s/$r->[0]/$r->[1]/) {
1422             $reconfigured = 1;
1423             #- Flags stolen from mod_rewrite: L(ast), N(ext)
1424             if ($r->[2] =~ /L/) {
1425             last;
1426             } elsif ($r->[2] =~ /N/) { #- dangerous option
1427             redo URLS;
1428             }
1429             }
1430             }
1431             #- check that the new url exists before committing changes (local mirrors)
1432             my $file = urpm::file_from_local_url($medium->{$k});
1433             if ($file && !-e $file) {
1434             %$medium = %orig;
1435             $reconfigured = 0;
1436             $urpm->{log}(N("...reconfiguration failed"));
1437             return;
1438             }
1439             }
1440              
1441             if ($reconfigured) {
1442             $urpm->{log}(N("reconfiguration done"));
1443             $urpm->{modified} = 1;
1444             }
1445             $reconfigured;
1446             }
1447              
1448             #- names. is used by external progs (namely for bash-completion)
1449             sub _generate_medium_names {
1450             my ($urpm, $medium) = @_;
1451              
1452             -e statedir_names($urpm, $medium) and return;
1453              
1454             my $fh = urpm::sys::open_safe($urpm, ">", statedir_names($urpm, $medium)) or return;
1455              
1456             foreach ($medium->{start} .. $medium->{end}) {
1457             my $pkg = $urpm->{depslist}[$_] or
1458             $urpm->{error}(N("Error generating names file: dependency %d not found", $_)), return;
1459              
1460             print $fh $pkg->name . "\n";
1461             }
1462             }
1463              
1464             sub _guess_synthesis_suffix {
1465             my ($url) = @_;
1466             $url =~ m!\bmedia/(\w+)/*\Z! && $1;
1467             }
1468              
1469             sub _synthesis_suffix {
1470             my ($medium) = @_;
1471             $medium->{with_synthesis} =~ /synthesis\.hdlist(.*?)(?:\.src)?\.cz$/ ? $1 : '';
1472             }
1473              
1474             sub _medium_is_up_to_date {
1475             my ($urpm, $medium) = @_;
1476              
1477             unlink cachedir_with_synthesis($urpm, $medium);
1478              
1479             $urpm->{info}(N("medium \"%s\" is up-to-date", $medium->{name}));
1480              
1481             #- the medium is now considered not modified.
1482             $medium->{modified} = 0;
1483             }
1484              
1485             sub _parse_synthesis {
1486             my ($urpm, $medium, $synthesis_file, $o_callback) = @_;
1487              
1488             -e $synthesis_file or return;
1489              
1490             $urpm->{log}(N("examining synthesis file [%s]", $synthesis_file));
1491             ($medium->{start}, $medium->{end}) =
1492             $urpm->parse_synthesis($synthesis_file, $o_callback ? (callback => $o_callback) : @{[]});
1493             }
1494              
1495             sub _parse_synthesis_or_ignore {
1496             my ($urpm, $medium, $o_callback) = @_;
1497              
1498             _parse_synthesis($urpm, $medium, any_synthesis($urpm, $medium), $o_callback) or
1499             _ignore_medium_on_parse_error($urpm, $medium);
1500             }
1501              
1502             sub is_valid_medium {
1503             my ($medium) = @_;
1504             defined $medium->{start} && defined $medium->{end};
1505             }
1506              
1507             sub _ignore_medium_on_parse_error {
1508             my ($urpm, $medium) = @_;
1509              
1510             $urpm->{error}(N("problem reading synthesis file of medium \"%s\"", $medium->{name}));
1511             $medium->{ignore} = 1;
1512             }
1513              
1514             sub _copy_media_info_file {
1515             my ($urpm, $medium, $prefix, $suffix) = @_;
1516              
1517             my $name = "$prefix$suffix";
1518             my $path = _synthesis_dir($medium) . "/$prefix" . _synthesis_suffix($medium) . $suffix;
1519             -e $path or $path = file_from_local_medium($medium) . "/media_info/$name";
1520              
1521             my $result_file = "$urpm->{cachedir}/partial/$name";
1522             if (-e $path) {
1523             $urpm->{log}(N("copying [%s] for medium \"%s\"...", $path, $medium->{name}));
1524             copy_and_own($path, $result_file)
1525             or $urpm->{error}(N("...copying failed")), return;
1526             }
1527             -s $result_file && $result_file;
1528             }
1529              
1530             sub _get_pubkey__local {
1531             my ($urpm, $medium) = @_;
1532              
1533             _copy_media_info_file($urpm, $medium, 'pubkey', '');
1534             }
1535              
1536             sub _download_pubkey {
1537             my ($urpm, $medium) = @_;
1538              
1539             _download_media_info_file($urpm, $medium, 'pubkey', '', { quiet => 1 });
1540             }
1541              
1542             # known options: quiet, callback
1543             sub _download_media_info_file {
1544             my ($urpm, $medium, $prefix, $suffix, $options) = @_;
1545              
1546             my $versioned_prefix = do {
1547             my $version = urpm::md5sum::versioned_media_info_file($urpm, $medium, "$prefix$suffix");
1548             $version and $options->{is_versioned} = 1;
1549             $version ? "$version-$prefix" : $prefix;
1550             };
1551              
1552             my $tmp = _download_media_info_file_raw($urpm, $medium,
1553             $versioned_prefix, $suffix, $options) or return;
1554             my $result = dirname($tmp) . "/$prefix$suffix";
1555             $tmp eq $result or rename($tmp, $result) or return;
1556             $result;
1557             }
1558              
1559             sub _download_media_info_file_raw {
1560             my ($urpm, $medium, $prefix, $suffix, $options) = @_;
1561              
1562             my $name = "$prefix$suffix";
1563             my $result_file = "$urpm->{cachedir}/partial/$name";
1564             my $found;
1565             if (_synthesis_suffix($medium)) {
1566             my $local_name = $prefix . _synthesis_suffix($medium) . $suffix;
1567              
1568             if (urpm::download::sync_rel_to($urpm, $medium,
1569             _synthesis_dir_rel($medium) . "/$local_name", $result_file,
1570             %$options)) {
1571             $found = 1;
1572             }
1573             }
1574             if (!$found) {
1575             urpm::download::sync_rel_one($urpm, $medium, _synthesis_dir_rel($medium) . "/$name",
1576             %$options);
1577             }
1578             -s $result_file && $result_file;
1579             }
1580              
1581             sub get_descriptions_local {
1582             my ($urpm, $medium) = @_;
1583              
1584             unlink statedir_descriptions($urpm, $medium);
1585              
1586             my $dir = file_from_local_medium($medium);
1587             my $description_file = "$dir/media_info/descriptions"; #- new default location
1588             -e $description_file or $description_file = "$dir/../descriptions";
1589             -e $description_file or return;
1590              
1591             $urpm->{log}(N("copying description file of \"%s\"...", $medium->{name}));
1592             if (copy_and_own($description_file, statedir_descriptions($urpm, $medium))) {
1593             $urpm->{log}(N("...copying done"));
1594             } else {
1595             $urpm->{error}(N("...copying failed"));
1596             $medium->{ignore} = 1;
1597             }
1598             }
1599             #- not handling different mirrors since the file is not always available
1600             sub get_descriptions_remote {
1601             my ($urpm, $medium) = @_;
1602              
1603             if (-e statedir_descriptions($urpm, $medium)) {
1604             unlink "$urpm->{cachedir}/partial/descriptions";
1605             urpm::sys::move_or_die($urpm, statedir_descriptions($urpm, $medium), "$urpm->{cachedir}/partial/descriptions");
1606             }
1607             my $result = urpm::download::sync_rel_one($urpm, $medium, 'media_info/descriptions', quiet => 1, preclean => 1);
1608              
1609             if ($result) {
1610             urpm::sys::move_or_die($urpm, $result, statedir_descriptions($urpm, $medium));
1611             }
1612             }
1613             sub get_synthesis__local {
1614             my ($urpm, $medium, $callback) = @_;
1615              
1616             my $f = cachedir_with_synthesis($urpm, $medium);
1617             unlink $f;
1618             $urpm->{log}(N("copying [%s] for medium \"%s\"...", _url_with_synthesis($medium), $medium->{name}));
1619             $callback and $callback->('copy', $medium->{name});
1620             if (copy_and_own(_url_with_synthesis($medium), $f)) {
1621             $callback and $callback->('done', $medium->{name});
1622             $urpm->{log}(N("...copying done"));
1623             if (file_size($f) < 20) {
1624             $urpm->{error}(N("copy of [%s] failed (file is suspiciously small)", $f));
1625             0;
1626             } else {
1627             1;
1628             }
1629             } else {
1630             $callback and $callback->('failed', $medium->{name});
1631             #- force error, reported afterwards
1632             unlink $f;
1633             0;
1634             }
1635             }
1636             sub get_synthesis__remote {
1637             my ($urpm, $medium, $is_a_probe, $options) = @_;
1638              
1639             my $ok = try__maybe_mirrorlist($urpm, $medium, $is_a_probe, sub {
1640             _download_media_info_file($urpm, $medium, 'synthesis.hdlist', '.cz',
1641             $options)
1642             && _check_synthesis(cachedir_with_synthesis($urpm, $medium));
1643             });
1644             if (!$ok) {
1645             chomp(my $err = $@);
1646             $urpm->{error}(N("...retrieving failed: %s", $err));
1647             }
1648              
1649             $ok &&= check_synthesis_md5sum($urpm, $medium) if !$options->{force} && !$options->{nomd5sum};
1650              
1651             $ok;
1652             }
1653              
1654             sub _check_synthesis {
1655             my ($synthesis_file) = @_;
1656              
1657             file_size($synthesis_file) >= 20 or return;
1658              
1659             # check first 2 lines do not contain typical html code
1660             # this is useful for servers not returning a valid HTTP error (#39918)
1661             open(my $F, '<', $synthesis_file) or return;
1662             my $s = <$F>; $s .= <$F>;
1663             $s !~ /|
1664             }
1665              
1666             #- check copied/downloaded file has right signature.
1667             sub check_synthesis_md5sum {
1668             my ($urpm, $medium) = @_;
1669              
1670             my $wanted_md5sum = urpm::md5sum::from_MD5SUM__or_warn($urpm, $medium->{parsed_md5sum}, 'synthesis.hdlist.cz');
1671             if ($wanted_md5sum) {
1672             $urpm->{log}(N("computing md5sum of retrieved source synthesis"));
1673             urpm::md5sum::compute(cachedir_with_synthesis($urpm, $medium)) eq $wanted_md5sum or
1674             $urpm->{error}(N("retrieval of [%s] failed (md5sum mismatch)", _url_with_synthesis($medium))), return;
1675             }
1676             1;
1677             }
1678              
1679             sub _call_genhdlist2 {
1680             my ($urpm, $medium) = @_;
1681              
1682             !$medium->{with_synthesis} or $urpm->{fatal}(1, 'with_synthesis not handled with --probe-rpms');
1683              
1684             my $dir = file_from_local_medium($medium);
1685              
1686             system('genhdlist2',
1687             $urpm->{debug} ? '--verbose' : @{[]}, '--no-hdlist',
1688             '--media_info-dir', "$urpm->{cachedir}/partial", $dir) == 0
1689             or $urpm->{error}(N("genhdlist2 failed on %s", $dir)), return;
1690              
1691             1;
1692             }
1693              
1694             sub _is_statedir_MD5SUM_uptodate {
1695             my ($urpm, $medium, $new_MD5SUM) = @_;
1696              
1697             my $current_MD5SUM = statedir_MD5SUM($urpm, $medium);
1698              
1699             $urpm->{log}(N("comparing %s and %s", $new_MD5SUM, $current_MD5SUM));
1700              
1701             cat_($new_MD5SUM) eq cat_($current_MD5SUM);
1702             }
1703              
1704             #- options: callback, force, nomd5sum, probe_with
1705             sub _update_medium__parse_if_unmodified__local {
1706             my ($urpm, $medium, $options) = @_;
1707              
1708             if ($options->{probe_with} ne 'rpms') {
1709             #- the directory given does not exist and may be accessible
1710             #- by mounting some other directory. Try to figure it out and mount
1711             #- everything that might be necessary.
1712             urpm::removable::try_mounting_medium($urpm, $medium) or return;
1713             }
1714              
1715             #- check for a reconfig.urpmi file (if not already reconfigured)
1716             if (!$medium->{noreconfigure}) {
1717             may_reconfig_urpmi($urpm, $medium);
1718             }
1719              
1720             #- try to probe for possible with_synthesis parameter, unless
1721             #- it is already defined (and valid).
1722             if (!_valid_synthesis_dir($medium) && $options->{probe_with} ne 'rpms') {
1723             _probe_with_try_list($urpm, $medium, sub {
1724             my ($url) = @_;
1725             -e $url or return;
1726             if (file_size($url) >= 20) {
1727             1;
1728             } else {
1729             $urpm->{error}(N("invalid hdlist file %s for medium \"%s\"", $url, $medium->{name}));
1730             0;
1731             }
1732             });
1733             }
1734              
1735             if (_is_local_virtual($medium)) {
1736             #- syncing a local virtual medium is very simple :)
1737             1;
1738             } elsif ($options->{probe_with} eq 'rpms' || !_valid_synthesis_dir($medium)) {
1739             _call_genhdlist2($urpm, $medium) or return '';
1740             if (!$medium->{'no-media-info'}) {
1741             $medium->{'no-media-info'} = 1;
1742             $urpm->{modified} = 1;
1743             }
1744             1;
1745             } elsif (_valid_synthesis_dir($medium)) {
1746             my $new_MD5SUM = _synthesis_dir($medium) . '/MD5SUM';
1747             unlink "$urpm->{cachedir}/partial/MD5SUM";
1748              
1749             if (!$options->{nomd5sum} && file_size($new_MD5SUM) > 32) {
1750             if (!$options->{force} && _is_statedir_MD5SUM_uptodate($urpm, $medium, $new_MD5SUM)) {
1751             _medium_is_up_to_date($urpm, $medium);
1752             return 'unmodified';
1753             }
1754              
1755             $urpm->{log}(N("copying MD5SUM file of \"%s\"...", $medium->{name}));
1756             copy_and_own($new_MD5SUM, "$urpm->{cachedir}/partial/MD5SUM");
1757             $medium->{parsed_md5sum} = urpm::md5sum::parse($new_MD5SUM);
1758             }
1759              
1760             my $ok = get_synthesis__local($urpm, $medium, $options->{callback});
1761             $ok &&= check_synthesis_md5sum($urpm, $medium) if !$options->{force} && !$options->{nomd5sum};
1762            
1763             if ($ok) {
1764             1;
1765             } elsif ($urpm->{options}{'build-hdlist-on-error'}) {
1766             #- if copying synthesis has failed, try to build it directly.
1767             _call_genhdlist2($urpm, $medium) or return '';
1768             1;
1769             } else {
1770             _ignore_medium_on_parse_error($urpm, $medium);
1771             '';
1772             }
1773             }
1774             }
1775              
1776             sub _download_MD5SUM {
1777             my ($urpm, $medium) = @_;
1778              
1779             urpm::download::sync_rel_one($urpm, $medium,
1780             _synthesis_dir_rel($medium) . '/MD5SUM',
1781             quiet => 1, preclean => 1);
1782             }
1783              
1784             sub _download_MD5SUM_and_check {
1785             my ($urpm, $medium, $is_a_probe) = @_;
1786              
1787             my ($err, $cachedir_MD5SUM);
1788             require urpm::mirrors;
1789             try__maybe_mirrorlist($urpm, $medium, $is_a_probe, sub {
1790             $cachedir_MD5SUM = _download_MD5SUM($urpm, $medium) or $err = $@;
1791             $cachedir_MD5SUM && urpm::md5sum::check_file($cachedir_MD5SUM);
1792             }) and return $cachedir_MD5SUM;
1793              
1794             if ($cachedir_MD5SUM) {
1795             $urpm->{error}(N("invalid MD5SUM file (downloaded from %s)", _synthesis_dir($medium)));
1796             } else {
1797             $urpm->{error}(N("...retrieving failed: %s", $err));
1798             $is_a_probe and $urpm->{error}(N("no metadata found for medium \"%s\"", $medium->{name}));
1799             }
1800             undef;
1801             }
1802              
1803             #- options: callback, ask_retry, force, nomd5sum, probe_with, quiet
1804             sub _update_medium__parse_if_unmodified__remote {
1805             my ($urpm, $medium, $options) = @_;
1806              
1807             my $updating = -e statedir_synthesis($urpm, $medium);
1808              
1809             #- examine if a distant MD5SUM file is available.
1810             if (!$options->{nomd5sum}) {
1811             my $new_MD5SUM = _download_MD5SUM_and_check($urpm, $medium, !$updating);
1812              
1813             if (!$new_MD5SUM) {
1814             #- check for a reconfig.urpmi file (if not already reconfigured)
1815             if (!$medium->{noreconfigure}) {
1816             may_reconfig_urpmi($urpm, $medium)
1817             and goto &_update_medium__parse_if_unmodified__remote;
1818             }
1819             return;
1820             }
1821             if (($options->{force} || 0) < 2 && _is_statedir_MD5SUM_uptodate($urpm, $medium, $new_MD5SUM)) {
1822             _medium_is_up_to_date($urpm, $medium);
1823             return 'unmodified';
1824             }
1825             $medium->{parsed_md5sum} = urpm::md5sum::parse($new_MD5SUM);
1826             }
1827              
1828             #- try to probe for possible with_synthesis parameter, unless
1829             #- it is already defined (and valid).
1830             $urpm->{log}(N("retrieving source synthesis of \"%s\"...", $medium->{name}));
1831             $options->{callback} and $options->{callback}('retrieve', $medium->{name});
1832             my $error = sub {
1833             my ($msg) = @_;
1834             $urpm->{error}($msg);
1835             unlink cachedir_with_synthesis($urpm, $medium);
1836             $options->{callback} and $options->{callback}('failed', $medium->{name});
1837             };
1838              
1839             if ($options->{force}) {
1840             unlink cachedir_with_synthesis($urpm, $medium);
1841             } else {
1842             #- for rsync, try to sync (copy if needed) local copy after restored the previous one.
1843             my $previous_synthesis = statedir_synthesis($urpm, $medium);
1844             if (-e $previous_synthesis && urpm::protocol_from_url($medium->{url}) eq 'rsync') {
1845             copy_and_own(
1846             $previous_synthesis,
1847             cachedir_with_synthesis($urpm, $medium),
1848             ) or $error->(N("...copying failed")), return;
1849             }
1850             }
1851             my $ok = get_synthesis__remote($urpm, $medium, !$updating, $options);
1852              
1853             $options->{callback} and $options->{callback}('done', $medium->{name});
1854              
1855             if (!$ok) {
1856             _ignore_medium_on_parse_error($urpm, $medium);
1857             return;
1858             }
1859             1;
1860             }
1861              
1862             sub _get_pubkey {
1863             my ($urpm, $medium, $b_wait_lock) = @_;
1864            
1865             my $local = file_from_local_medium($medium);
1866              
1867             #- examine if a pubkey file is available.
1868             ($local ? \&_get_pubkey__local : \&_download_pubkey)->($urpm, $medium);
1869              
1870             $medium->{'key-ids'} = _read_cachedir_pubkey($urpm, $medium, $b_wait_lock);
1871             $urpm->{modified} = 1;
1872             }
1873              
1874             sub _get_descriptions {
1875             my ($urpm, $medium) = @_;
1876              
1877             my $local = file_from_local_medium($medium);
1878              
1879             # do not get "descriptions" on non "update" media since it's useless and potentially slow
1880             if ($medium->{update}) {
1881             ($local ? \&get_descriptions_local : \&get_descriptions_remote)->($urpm, $medium);
1882             }
1883             }
1884              
1885             # options: wait_lock, nopubkey, forcekey
1886             sub _may_get_pubkey {
1887             my ($urpm, $medium, %options) = @_;
1888            
1889             _get_pubkey($urpm, $medium, $options{wait_lock}) if !$options{nopubkey} && (!$medium->{'key-ids'} || $options{forcekey});
1890             }
1891              
1892             sub _read_cachedir_pubkey {
1893             my ($urpm, $medium, $b_wait_lock) = @_;
1894             -s "$urpm->{cachedir}/partial/pubkey" or return;
1895              
1896             $urpm->{log}(N("examining pubkey file of \"%s\"...", $medium->{name}));
1897              
1898             my $_rpm_lock = urpm::lock::rpm_db($urpm, 'exclusive', wait => $b_wait_lock);
1899             my $db = urpm::db_open_or_die_($urpm, 'rw');
1900              
1901             my %key_ids;
1902             URPM::import_needed_pubkeys_from_file($db,
1903             "$urpm->{cachedir}/partial/pubkey",
1904             sub {
1905             my ($id, $imported) = @_;
1906             if ($id) {
1907             $key_ids{$id} = undef;
1908             $imported and $urpm->{log}(N("...imported key %s from pubkey file of \"%s\"",
1909             $id, $medium->{name}));
1910             $imported or $urpm->{debug}("pubkey $id already imported") if $urpm->{debug};
1911             } else {
1912             $urpm->{error}(N("unable to import pubkey file of \"%s\"", $medium->{name}));
1913             }
1914             });
1915              
1916             unlink "$urpm->{cachedir}/partial/pubkey";
1917            
1918             join(',', keys %key_ids);
1919             }
1920              
1921             #- options: callback, ask_retry, force, nomd5sum, probe_with, quiet, forcekey, nopubkey, wait_lock
1922             #- (from _update_medium__parse_if_unmodified__local and _update_medium__parse_if_unmodified__remote)
1923             sub _update_medium_ {
1924             my ($urpm, $medium, %options) = @_;
1925              
1926             #- always delete a remaining list file or pubkey file in cache.
1927             foreach (qw(list pubkey)) {
1928             unlink "$urpm->{cachedir}/partial/$_";
1929             }
1930              
1931             _pick_mirror_if_needed($urpm, $medium, 'allow-cache-update');
1932              
1933             {
1934             my $rc =
1935             is_local_medium($medium)
1936             ? _update_medium__parse_if_unmodified__local($urpm, $medium, \%options)
1937             : _update_medium__parse_if_unmodified__remote($urpm, $medium, \%options);
1938              
1939             if ($options{forcekey} && $rc eq 'unmodified') {
1940             _get_pubkey($urpm, $medium, $options{wait_lock}); # we must do it now, quite hackish...
1941             return 1;
1942             }
1943              
1944             if (!$rc || $rc eq 'unmodified') {
1945             return $rc;
1946             }
1947             }
1948              
1949             my $is_updating = -e statedir_synthesis($urpm, $medium);
1950              
1951             if (!_is_local_virtual($medium)) {
1952             if (file_size(cachedir_with_synthesis($urpm, $medium)) < 20) {
1953             $urpm->{error}(N("no synthesis file found for medium \"%s\"", $medium->{name}));
1954             return;
1955             }
1956              
1957             #- use new files
1958              
1959             unlink statedir_synthesis($urpm, $medium);
1960             urpm::sys::move_or_die($urpm, cachedir_with_synthesis($urpm, $medium),
1961             statedir_synthesis($urpm, $medium));
1962              
1963             unlink statedir_MD5SUM($urpm, $medium);
1964             if (!$medium->{with_synthesis}) { # no MD5SUM when using with_synthesis, urpmi.update will update everytime!
1965             urpm::sys::move_or_die($urpm, "$urpm->{cachedir}/partial/MD5SUM",
1966             statedir_MD5SUM($urpm, $medium)) if -e "$urpm->{cachedir}/partial/MD5SUM";
1967             }
1968              
1969             # we never download hdlist by default. urpmf will download it via any_hdlist() if really needed
1970             unlink statedir_hdlist($urpm, $medium);
1971              
1972             remove_user_media_info_files($urpm, $medium);
1973              
1974             if (!_local_file($medium)) {
1975             _retrieve_xml_media_info_or_remove($urpm, $medium, $options{quiet}) or return;
1976             }
1977             }
1978             $medium->{modified} = 0;
1979              
1980             # generated on first _parse_media()
1981             unlink statedir_names($urpm, $medium);
1982              
1983             _get_descriptions($urpm, $medium);
1984             _may_get_pubkey($urpm, $medium, %options);
1985              
1986             $is_updating and $urpm->{info}(N("updated medium \"%s\"", $medium->{name}));
1987              
1988             1;
1989             }
1990              
1991             sub _update_medium {
1992             my ($urpm, $medium, %options) = @_;
1993              
1994             my $rc = _update_medium_($urpm, $medium, %options);
1995              
1996             if (!$rc && !_is_local_virtual($medium)) {
1997             #- an error has occured for updating the medium, we have to remove temporary files.
1998             unlink(glob("$urpm->{cachedir}/partial/*"));
1999             }
2000             $rc;
2001             }
2002              
2003             =item update_media($urpm, %options)
2004              
2005             Update the urpmi database w.r.t. the current configuration.
2006             Takes care of modifications, and tries some tricks to bypass
2007             the recomputation of base files.
2008              
2009             Recognized options :
2010              
2011             =over
2012              
2013             =item *
2014              
2015             all : all medias are being rebuilt
2016              
2017             =item *
2018              
2019             allow_failures: whereas failing to update a medium is non fatal
2020              
2021             =item *
2022              
2023             ask_retry : function called when a download fails. if it returns true, the download is retried
2024              
2025             =item *
2026              
2027             callback : UI callback
2028              
2029             =item *
2030              
2031             forcekey : force retrieval of pubkey
2032              
2033             =item *
2034              
2035             force : try to force rebuilding base files
2036              
2037             =item *
2038              
2039             nomd5sum : don't verify MD5SUM of retrieved files
2040              
2041             =item *
2042              
2043             nopubkey : don't use rpm pubkeys
2044              
2045             =item *
2046              
2047             probe_with : probe synthesis or rpms
2048              
2049             =item *
2050              
2051             quiet : download synthesis quietly
2052              
2053             =item *
2054              
2055             wait_lock : block until lock can be acquired
2056              
2057             =back
2058              
2059             =cut
2060              
2061             sub update_media {
2062             my ($urpm, %options) = @_;
2063              
2064             $urpm->{media} or return; # verify that configuration has been read
2065              
2066             if ($options{all}) {
2067             $_->{modified} ||= 1 foreach all_media_to_update($urpm);
2068             }
2069              
2070             update_those_media($urpm, [ grep { $_->{modified} } non_ignored_media($urpm) ], %options);
2071             }
2072              
2073             sub update_those_media {
2074             my ($urpm, $media, %options) = @_;
2075              
2076             $options{nopubkey} ||= $urpm->{options}{nopubkey};
2077              
2078             #- examine each medium to see if one of them needs to be updated.
2079             #- if this is the case and if not forced, try to use a pre-calculated
2080             #- synthesis file, else build it from rpm files.
2081             clean($urpm);
2082              
2083             my %updates_result;
2084             foreach my $medium (@$media) {
2085              
2086             #- don't ever update static media
2087             $medium->{static} and next;
2088              
2089             my $unsubstituted_url = $medium->{url};
2090             $medium->{url} = urpm::cfg::expand_line($medium->{url}) if $medium->{url};
2091             my $rc = _update_medium($urpm, $medium, %options);
2092             $medium->{url} = urpm::cfg::substitute_back($medium->{url}, $unsubstituted_url);
2093             $rc or return if !$options{allow_failures};
2094             $updates_result{$rc || 'error'}++;
2095             }
2096              
2097             $urpm->{debug} and $urpm->{debug}('update_medium: ' . join(' ', map { "$_=$updates_result{$_}" } keys %updates_result));
2098              
2099             if ($updates_result{1} == 0) {
2100             #- only errors/unmodified, leave now
2101             #- (this ensures buggy added medium is not added to urpmi.cfg)
2102             return $updates_result{error} == 0;
2103             }
2104              
2105             if ($urpm->{modified}) {
2106             #- write config files in any case
2107             write_config($urpm);
2108             urpm::download::dump_proxy_config();
2109             }
2110              
2111             $updates_result{error} == 0;
2112             }
2113              
2114             sub _maybe_in_statedir_MD5SUM {
2115             my ($urpm, $medium, $file) = @_;
2116            
2117             my $md5sum_file = statedir_MD5SUM($urpm, $medium);
2118             -e $md5sum_file && urpm::md5sum::parse($md5sum_file)->{$file};
2119             }
2120              
2121             sub _retrieve_xml_media_info_or_remove {
2122             my ($urpm, $medium, $quiet) = @_;
2123              
2124             my $ok = 1;
2125              
2126             foreach my $xml_info (@xml_media_info) {
2127             my $f = statedir_xml_info($urpm, $medium, $xml_info);
2128              
2129             my $get_it = urpm::is_cdrom_url($medium->{url}) ||
2130             get_medium_option($urpm, $medium, 'xml-info') eq 'always' ||
2131             get_medium_option($urpm, $medium, 'xml-info') eq 'update-only' && -e $f;
2132             if ($get_it && _maybe_in_statedir_MD5SUM($urpm, $medium, "$xml_info.xml.lzma")) {
2133             $ok &&= _retrieve_media_info_file_and_check_MD5SUM($urpm, $medium, $xml_info, '.xml.lzma', $quiet);
2134             $ok = 1 if urpm::is_cdrom_url($medium->{url});
2135             } else {
2136             #- "on-demand"
2137             unlink $f;
2138             }
2139             }
2140             $ok;
2141             }
2142              
2143             sub _retrieve_media_info_file_and_check_MD5SUM {
2144             my ($urpm, $medium, $prefix, $suffix, $quiet) = @_;
2145              
2146             my $name = "$prefix$suffix";
2147             my $cachedir_file =
2148             is_local_medium($medium) ?
2149             _copy_media_info_file($urpm, $medium, $prefix, $suffix) :
2150             _download_media_info_file($urpm, $medium, $prefix, $suffix, { quiet => $quiet, callback => \&urpm::download::sync_logger }) or
2151             $urpm->{error}(N("retrieval of [%s] failed", _synthesis_dir($medium) . "/$name")), return;
2152              
2153             my $wanted_md5sum = urpm::md5sum::from_MD5SUM__or_warn($urpm, $medium->{parsed_md5sum}, $name);
2154             if ($wanted_md5sum) {
2155             $urpm->{debug}("computing md5sum of retrieved $name") if $urpm->{debug};
2156             urpm::md5sum::compute($cachedir_file) eq $wanted_md5sum or
2157             $urpm->{error}(N("retrieval of [%s] failed (md5sum mismatch)", _synthesis_dir($medium) . "/$name")), return;
2158              
2159             urpm::util::move($cachedir_file, statedir_media_info_file($urpm, $medium, $prefix, $suffix)) or return;
2160             }
2161             1;
2162             }
2163              
2164             sub _download_temp_md5sum_and_parse {
2165             my ($urpm, $medium) = @_;
2166              
2167             $urpm->{debug}("downloading MD5SUM to know updated versioned metadata filename") if $urpm->{debug};
2168             my $md5sum_file = _download_MD5SUM($urpm, $medium);
2169             urpm::md5sum::parse($md5sum_file);
2170             }
2171              
2172             sub _any_media_info__or_download {
2173             my ($urpm, $medium, $prefix, $suffix, $quiet, $o_callback) = @_;
2174              
2175             my $f = statedir_media_info_file($urpm, $medium, $prefix, $suffix);
2176             -s $f and return $f;
2177              
2178             if ($<) {
2179             urpm::ensure_valid_cachedir($urpm);
2180             $f = "$urpm->{cachedir}/" . statedir_media_info_basename($medium, $prefix, $suffix);
2181             -s $f and return $f;
2182             }
2183              
2184             get_medium_option($urpm, $medium, 'xml-info') ne 'never' or return;
2185            
2186             _maybe_in_statedir_MD5SUM($urpm, $medium, "$prefix$suffix") or return;
2187              
2188             $medium->{parsed_md5sum} ||= _download_temp_md5sum_and_parse($urpm, $medium);
2189              
2190             my $file_in_partial =
2191             _download_media_info_file($urpm, $medium, $prefix, $suffix,
2192             { quiet => $quiet, callback => $o_callback }) or return;
2193              
2194             urpm::util::move($file_in_partial, $f) or return;
2195              
2196             $f;
2197             }
2198              
2199             #- side-effects:
2200             #- + those of urpm::mirrors::pick_one ($urpm->{mirrors_cache}, $medium->{url})
2201             sub _pick_mirror_if_needed {
2202             my ($urpm, $medium, $allow_cache_update) = @_;
2203              
2204             $medium->{mirrorlist} && !$medium->{url} or return;
2205              
2206             require urpm::mirrors;
2207             urpm::mirrors::pick_one($urpm, $medium, $allow_cache_update);
2208             }
2209              
2210             #- side-effects:
2211             #- + those of urpm::mirrors::try ($urpm->{mirrors_cache}, $medium->{url})
2212             sub try__maybe_mirrorlist {
2213             my ($urpm, $medium, $is_a_probe, $try) = @_;
2214              
2215             if ($medium->{mirrorlist}) {
2216             if (urpm::download::use_metalink($urpm, $medium)) {
2217             #- help things...
2218             _pick_mirror_if_needed($urpm, $medium, 'allow-cache-update');
2219              
2220             $try->();
2221             } else {
2222             require urpm::mirrors;
2223             $is_a_probe
2224             ? urpm::mirrors::try_probe($urpm, $medium, $try)
2225             : urpm::mirrors::try($urpm, $medium, $try);
2226             }
2227             } else {
2228             $try->();
2229             }
2230             }
2231              
2232             =item clean($urpm)
2233              
2234             Clean params and depslist computation zone.
2235              
2236             =cut
2237              
2238             sub clean {
2239             my ($urpm) = @_;
2240              
2241             $urpm->{depslist} = [];
2242             $urpm->{provides} = {};
2243              
2244             foreach (@{$urpm->{media} || []}) {
2245             delete $_->{start};
2246             delete $_->{end};
2247             }
2248             }
2249              
2250             1;
2251              
2252              
2253             =back
2254              
2255             =head1 COPYRIGHT
2256              
2257             Copyright (C) 2005 MandrakeSoft SA
2258              
2259             Copyright (C) 2005-2010 Mandriva SA
2260              
2261             Copyright (C) 2011-2015 Mageia
2262              
2263             =cut