diff options
Diffstat (limited to 'perl-install/install/media.pm')
| -rw-r--r-- | perl-install/install/media.pm | 907 | 
1 files changed, 907 insertions, 0 deletions
| diff --git a/perl-install/install/media.pm b/perl-install/install/media.pm new file mode 100644 index 000000000..149deffc3 --- /dev/null +++ b/perl-install/install/media.pm @@ -0,0 +1,907 @@ +package install::media; + +use strict; + +our @ISA = qw(Exporter); +our @EXPORT_OK = qw(getFile_ getAndSaveFile_ getAndSaveFile_media_info packageMedium); + +use common; +use Data::Dumper; +# Make sure report.bug are more easily comparable: +$Data::Dumper::Sortkeys = 1; +use fs::type; +use urpm::download; +use urpm::media; + +#- list of fields for {phys_medium} : +#-	device +#-	fs_type +#-	is_suppl (is a supplementary media) +#-	isMounted +#-	loopback_device +#-	loopback_file +#-	method +#-	mntpoint +#-	name (text description, same as first medium {name}) +#-	real_mntpoint +#-	rel_path (for isofiles and cdrom) +#-	url + +#- list of fields for {media} : +#-	end (last rpm id, undefined if not selected) +#-	fakemedium ("$name ($rpmsdir)", used locally by urpmi) +#-	rel_hdlist +#-	key-ids +#-	name (text description) +#-	pubkey (array containing all the keys to import) +#-	phys_medium +#-	rpmsdir +#-	ignore +#-	size (in MB) +#-	start (first rpm id, undefined if ignored) +#-	update (for install_urpmi) + + +our $postinstall_rpms = ''; +my %mounted_media; + +sub allMediums { +    my ($packages) = @_; + +    @{$packages->{media}}; +} + +sub _phys_media { +    my ($packages) = @_; + +    uniq(map { $_->{phys_medium} } @{$packages->{media}}); +} + +sub packageMedium { +   my ($packages, $p) = @_; +   URPM::pkg2media($packages->{media}, $p) || {}; +} + +sub packagesOfMedium { +    my ($packages, $medium) = @_; + +    @{$packages->{depslist}}[$medium->{start} .. $medium->{end}]; +} + +sub first_medium { +    my ($packages) = @_; +    $packages->{media}[0]; +} + +sub path { +    my ($phys_m, $f) = @_; + +    ($phys_m->{real_mntpoint} || fs::get::mntpoint_prefixed($phys_m)) . $phys_m->{rel_path} . '/' . $f; +} + +sub umount_phys_medium { +    my ($phys_m) = @_; + +    my $ok = eval {  +	fs::mount::umount_part($phys_m);  +	delete $phys_m->{real_mntpoint}; #- next time, we can mount it in the dest dir +	1; +    }; +    if ($@) { +	log::l("umount phys_medium $phys_m->{url} failed ($@)"); +	log::l("files still open: ", readlink($_)) foreach map { glob_("$_/fd/*") } glob_("/proc/*"); +    } +    $ok; +} + +sub _mount_phys_medium { +    my ($phys_m, $o_rel_file, $b_force_change) = @_; + +    if (!$b_force_change) { +	eval { fs::mount::part($phys_m) }; +	return if $@; +    } +    my $ok = !$o_rel_file || -e path($phys_m, $o_rel_file); + +    if ($phys_m->{method} eq 'cdrom' && ($b_force_change || !$ok)) { +	$ok = $::o->ask_change_cd($phys_m, $o_rel_file); +    } +    $ok; +} + +sub umount_media { +    my ($packages) = @_; + +    #- we don't bother umounting first phys medium if clp is not on disk +    #- (this is mainly for nfs installs using install/stage2/live) +    my @l = _phys_media($packages); +    shift @l if !$install::any::compressed_image_on_disk && $l[0]{is_stage2_phys_medium}; + +    umount_phys_medium($_) foreach @l; +    umount_phys_medium($_) foreach grep { $_ } map { $_->{loopback_device} } @l; +} + +sub phys_medium_to_string { +    my ($phys_m) = @_; +    urpm::download::url_obscuring_password($phys_m->{url}) . ($phys_m->{name} ? " ($phys_m->{name})" : ''); +} + +sub _stage2_mounted_medium { +    my ($method, $rel_path) = @_; + +    my ($device, $real_mntpoint, $fs_type, $url); +    if ($method eq 'nfs') { +	(my $server, my $nfs_path, $real_mntpoint, $fs_type) = cat_("/proc/mounts") =~ m!(\S+):(\S+)\s+(/tmp/media)\s+(\S+)!; +	$device = "$server:$nfs_path"; +	$url = "nfs://$server$nfs_path$rel_path"; +    } elsif ($method eq 'disk') { +	($device, $real_mntpoint, $fs_type) = cat_("/proc/mounts") =~ m!/dev/(\S+)\s+(/tmp/media)\s+(\S+)!; +	$url = "disk://$device$rel_path"; +    } elsif ($method eq 'cdrom') { +	($device, $real_mntpoint, $fs_type) = cat_("/proc/mounts") =~ m!/dev/(\S+)\s+(/tmp/media)\s+(\S+)!; +	$url = "cdrom:/" . ($rel_path || '/'); +    } else { +	($device, $real_mntpoint, $fs_type) = cat_("/proc/mounts") =~ m!(?:/dev/)?(\S+)\s+(/tmp/media)\s+(\S+)!; +	$url = "file:/" . ($rel_path || '/'); +    } +    $real_mntpoint or internal_error("no real_mntpoint"); +    +{  +	method => $method, rel_path => $rel_path, isMounted => 1, +	device => $device, url => $url, +	real_mntpoint => $real_mntpoint, fs_type => $fs_type, +    }; +} + +#- used once at beginning of install +sub stage2_phys_medium { +    my ($method) = @_; + +    if ($method eq 'ftp' && !$ENV{URLPREFIX}) { +	my $user = $ENV{LOGIN} && ($ENV{LOGIN} . ($ENV{PASSWORD} && ":$ENV{PASSWORD}") . '@'); +	$ENV{URLPREFIX} = "ftp://$user$ENV{HOST}/$ENV{PREFIX}"; +    } +    if (member($method, qw(http ftp))) { +	{ method => $method, url => $ENV{URLPREFIX} }; +    } elsif ($method =~ /(.*)-iso$/) { +	my $dir_method = $1; +	my $rel_path = readlink('/tmp/image') =~ m!loop/*(/.*)! ? $1 : ''; + +	my $rel_iso = $ENV{ISOPATH} =~ m!media/*(/.*)! ? $1 : ''; +	my ($dir_url, $iso) = (dirname($rel_iso), basename($rel_iso)); + +	my $dir_medium = _stage2_mounted_medium($dir_method, $dir_url eq '/' ? '' : $dir_url); +	my $phys_m = _iso_phys_media($dir_medium, $iso, ''); +	$phys_m->{real_mntpoint} = '/tmp/loop'; +	$phys_m->{real_device} = cat_("/proc/mounts") =~ m!(/dev/\S+)\s+/tmp/loop\s! && $1; +	$phys_m->{isMounted} = 1; +	$phys_m->{rel_path} = $rel_path; +	$phys_m; +    } else { +	my $rel_path = readlink('/tmp/image') =~ m!media/*(/.*)! ? $1 : ''; +	_stage2_mounted_medium($method, $rel_path); +    } +} + +#- return true if the medium is available +#- ($o_rel_file is only used for removable media) +sub change_phys_medium { +    my ($phys_m, $o_rel_file, $o_packages) = @_; + +    undef $o_rel_file if $phys_m->{unknown_CD}; #- don't take into account the wanted file + +    log::l("change_phys_medium " . phys_medium_to_string($phys_m) . +	     ($o_rel_file ? " for file $o_rel_file" : '')); + +    !$phys_m->{isMounted} && $phys_m->{mntpoint} or return 1; #- nothing to do in such case. + +    #- if a cdrom was mounted and we want another one, do not try to mount cdrom just after umounting it +    my $force_change = $phys_m->{method} eq 'cdrom' && $mounted_media{cdrom}; + +    if (my $current = $mounted_media{$phys_m->{method}}) { +	_setup_postinstall_rpms($::o, $o_packages, $current) if $o_packages && $phys_m->{method} eq 'cdrom' && $::o->isa('interactive'); +	umount_phys_medium($current) or return; +	delete $mounted_media{$phys_m->{method}}; +    } +    _mount_phys_medium($phys_m, $o_rel_file, $force_change) or return; +    _phys_medium_is_mounted($phys_m); +    1; +} + +sub _phys_medium_is_mounted { +    my ($phys_m) = @_; +    if (member($phys_m->{method}, 'cdrom', 'iso')) { +	#- we can't have more than one cdrom mounted at once +	#- we limit the number of iso files mounted at once +	$mounted_media{$phys_m->{method}} = $phys_m; +    } +} + +sub _associate_phys_media { +    my ($all_hds, $main_phys_medium, $hdlists) = @_; + +    my ($main_name, @other_names) = uniq(map { $_->{name} } @$hdlists); + +    my @other_phys_media =  +      $main_phys_medium->{method} eq 'iso' ? +	_get_phys_media_iso($all_hds, $main_phys_medium, \@other_names) : +      $main_phys_medium->{method} eq 'cdrom' ? +	(map { _get_phys_media_cdrom($main_phys_medium, $_) } @other_names) : +	  (); + +    if (@other_phys_media) { +	$main_phys_medium->{name} = $main_name; + +	my @phys_media = ($main_phys_medium, @other_phys_media); + +	foreach my $medium (@$hdlists) { +	    if (my $phys_m = find { $_->{name} eq $medium->{name} } @phys_media) { +		$medium->{phys_medium} and log::l("$medium->{name} has already phys_medium $medium->{phys_medium}{url}"); +		log::l("setting medium $medium->{name} phys_medium to $phys_m->{url}"); +		$medium->{phys_medium} = $phys_m; +	    } else { +		$medium->{ignore} = 1; +		log::l("deselecting missing medium $medium->{rpmsdir}"); +	    } +	} +    } else { +	foreach my $medium (@$hdlists) { +	    $medium->{phys_medium} = $main_phys_medium; +	} +    } +} + +sub _get_phys_media_cdrom { +    my ($main_phys_m, $name) = @_; + +    #- exactly the same as $main_phys_m, but for {name}, {isMounted} and {real_mntpoint} +    +{ %$main_phys_m, name => $name, isMounted => 0, real_mntpoint => undef }; +} + +sub _iso_phys_media { +    my ($dir_medium, $iso, $rel_path) = @_; + +    my $mntpoint = "/mnt/$iso"; +    $mntpoint =~ s/\.iso$//; #- make the mount point a little nicer + +    my $rel_file = $dir_medium->{rel_path} . "/$iso"; + +    +{  +	url => $dir_medium->{url} . "/$iso", #- only used for printing +	method => 'iso',  +	fs_type => 'iso9660', options => 'noauto,loop', +	loopback_device => $dir_medium, loopback_file => $rel_file,  +	device => ($dir_medium->{real_mntpoint} || $::prefix . $dir_medium->{mntpoint}) . $rel_file, +	mntpoint => $mntpoint, rel_path => $rel_path, +    }; +} + +sub _get_phys_media_iso { +    my ($all_hds, $main_phys_m, $names) = @_; + +    my @ISOs = grep { member($_->{app_id}, @$names) } _look_for_ISO_images($main_phys_m->{device}); + +    map { +	my $m = _iso_phys_media($main_phys_m->{loopback_device}, $_->{file}, $main_phys_m->{rel_path}); +	$m->{name} = $_->{app_id}; +	push @{$all_hds->{loopbacks}}, $m; +	$m; +    } @ISOs; +} + +sub _look_for_ISO_images { +    my ($main_iso) = @_; + +    my $iso_dir = dirname($main_iso); + +    my @media = map { +	if (sysopen(my $F, "$iso_dir/$_", 0)) { +	    my ($vol_id, $app_id) = c::get_iso_volume_ids(fileno $F); +	    #- the ISO volume names must end in -CD\d+ if they belong (!) to a set +	    #- otherwise use the full volume name as CD set identifier +	    my $cd_set = $vol_id =~ /^(.*)-(disc|cd|dvd)\d+$/i ? $1 : $vol_id; + +	    log::l("found ISO: file=$_ cd_set=$cd_set app_id=$app_id"); +	    { cd_set => $cd_set, app_id => $app_id, file => $_ }; +	} else { +	    (); +	} +    } grep { /\.iso$/ } all($iso_dir); + +    my $main = find { basename($main_iso) eq $_->{file} } @media or return; + +    grep { $_->{cd_set} eq $main->{cd_set} } @media; +} + + +sub _getFile_media_info { +    my ($packages, $f) = @_; +    getFile_(first_medium($packages)->{phys_medium}, $f); +} + +sub _open_file_and_size { +    my ($f) = @_; +    my $size = -s $f; +    my $fh = common::open_file($f) or return; +    $size, $fh; +} + +sub getFile_ { +    my ($phys_m, $f) = @_; +    log::l("getFile $f on " . phys_medium_to_string($phys_m) . ""); + +    my ($_size, $fh) = get_file_and_size($phys_m, $f) or return; +    $fh; +} + +sub get_file_and_size { +    my ($phys_m, $f) = @_; + +    if ($f =~ m|^https?://|) { +	require install::http; +	install::http::get_file_and_size($f); +    } elsif (member($phys_m->{method}, qw(ftp http https))) { +	require install::http; +	install::http::get_file_and_size_($f, $phys_m->{url}); +    } elsif ($f =~ m!^/!) { +	_open_file_and_size($f); +    } elsif ($postinstall_rpms && -e "$postinstall_rpms/$f") { +	_open_file_and_size("$postinstall_rpms/$f"); +    } else { +	my $f2 = path($phys_m, $f); + +	if (! -f $f2) { +	    change_phys_medium($phys_m, $f, $::o->{packages}); +	} +	_open_file_and_size($f2); +    } +} + +sub getAndSaveFile_ { +    my ($phys_m, $file, $local) = @_; +    my $fh = getFile_($phys_m, $file) or return; +    _getAndSaveFile_raw($fh, $local); +} + +sub _getAndSaveFile_progress { +    my ($in_wait, $msg, $phys_m, $file, $local) = @_; +    my ($size, $fh) = get_file_and_size($phys_m, $file) or return; +    if ($size) { +	_getAndSaveFile_progress_raw($in_wait, $msg, $size, $fh, $local); +    } else { +	_getAndSaveFile_raw($fh, $local); +    } +} + +sub _getAndSaveFile_raw { +    my ($fh, $local) = @_; + +    local $/ = \ (16 * 1024); +    unlink $local; +    open(my $F, ">$local") or log::l("getAndSaveFile(opening $local): $!"), return; +    local $_; +    while (<$fh>) { syswrite($F, $_) or unlink($local), die("getAndSaveFile($local): $!") } +    1; +} + +sub _getAndSaveFile_progress_raw { +    my ($in_wait, $msg, $size, $fh, $local) = @_; + +    unlink $local; +    open(my $out, ">$local") or log::l("getAndSaveFile(opening $local): $!"), return; +    _print_with_progress($in_wait, $msg, $size, $fh, $out) or unlink($local), die("getAndSaveFile($local): $!"); +} + +sub _print_with_progress { +    my ($in_wait, $msg, $size, $in, $out) = @_; + +    my ($_wait, $wait_message) = $in_wait->wait_message_with_progress_bar(N("Please wait, retrieving file")); +    $wait_message->($msg); + +    my $current = 0; + +    require Time::HiRes; +    my $time = Time::HiRes::time(); + +    local $/ = \ (64 * 1024); +    while (my $s = <$in>) {  +	syswrite($out, $s) or return; + +	$current += length($s); +	if (Time::HiRes::time() > $time + 0.1) { +	    $wait_message->('', $current, $size); +	    $time = Time::HiRes::time(); +	} +    } +    1; +} + +sub urpmidir() { +    my $v = "$::prefix/var/lib/urpmi"; +    -l $v && !-e $v and unlink $v and mkdir $v, 0755; #- dangling symlink +    -w $v ? $v : '/tmp'; +} + +sub _allow_copy_rpms_on_disk { +    my ($medium, $hdlists) = @_; + +    $medium->{device} && $medium->{method} ne 'iso' or return; + +    #- check available size for copying rpms from infos in media.cfg file +    my $totalsize = sum(map { $_->{size} } @$hdlists) || -1; #- don't check size, total medium size unknown + +    if ($totalsize >= 0) { +	my $availvar = fs::any::getAvailableSpace_mounted("$::prefix/var"); +	$availvar /= 1024 * 1024; #- Mo +	log::l("totalsize=$totalsize, avail on $::prefix/var=$availvar"); +	$totalsize < $availvar * 0.6; +    } else { +	#- we hope it will fit... +	1; +    } +} + +sub _parse_media_cfg { +    my ($cfg) = @_; + +    require MDV::Distribconf; +    my $d = MDV::Distribconf->new('', undef); +    $d->parse_mediacfg($cfg); + +    my $distribconf = { map { $_ => $d->getvalue(undef, $_) } 'suppl', 'askmedia' }; +    my @hdlists = map {  +	my ($size) = $d->getvalue($_, 'size') =~ /(\d+)MB?/i; +	my $name = $d->getvalue($_, 'name');  +	$name =~ s/^"(.*)"$/$1/; +	{  +	    rpmsdir => $_, +	    rel_hdlist => 'media_info/' . $d->getvalue($_, 'hdlist'), +	    name => $name, +	    size => $size, +	    selected => !$d->getvalue($_, 'noauto'), +	    update => $d->getvalue($_, 'updates_for') ? 1 : undef, +	}; +    } $d->listmedia; + +    $distribconf, \@hdlists; +} + +sub select_only_some_media { +    my ($media_list, $selected_names) = @_; +    my @names = split(',', $selected_names); +    foreach my $m (@$media_list) { +        my $bool = !member($m->{name}, @names); +        # workaround urpmi transforming "ignore => ''" or "ignore => 0" into "ignore => 1": +        undef $bool if !$bool; +        log::l("disabling '$m->{name}' medium: " . to_bool($bool)); +        urpm::media::_tempignore($m, $bool); +        # make sure we update un-ignored media (eg: */Testing and the like): +        $m->{modified} = 1 if !$bool; +    } +} + +sub update_media { +    my ($packages) = @_; +    urpm::media::update_media($packages, distrib => 1, callback => \&urpm::download::sync_logger) or +        log::l('updating media failed'); +} + +sub get_media { +    my ($o, $media, $packages) = @_; + +    my ($suppl_CDs, $copy_rpms_on_disk, $phys_m); +    foreach (@$media) { +	if ($_->{type} eq 'media_cfg') { +	    $phys_m = url2mounted_phys_medium($o, $_->{url}, 'media_info'); +            local $phys_m->{is_suppl} = $_->{url} ne "drakx://media"; # so that _get_media_url() works +            ($suppl_CDs, $copy_rpms_on_disk) = get_media_cfg($o, $phys_m, $packages, $_->{selected_names}, $_->{force_rpmsrate}); +	} elsif ($_->{type} eq 'media') { +	    $phys_m = url2mounted_phys_medium($o, $_->{url}); +	    get_standalone_medium($o, $phys_m, $packages, { name => $_->{id} =~ /media=(.*)/ && $1 }); +	} elsif ($_->{type} eq 'media_cfg_isos') { +	    my ($dir_url, $iso, $rel_path) = $_->{url} =~ m!(.*)/(.*\.iso):(/.*)! or die "bad media_cfg_isos url $_->{url}"; +	    my $dir_medium = url2mounted_phys_medium($o, $dir_url); +	    $dir_medium->{options} =~ s/\bnoauto\b,?//; +	    $phys_m = _iso_phys_media($dir_medium, $iso, $rel_path); +	    push @{$o->{all_hds}{loopbacks}}, $phys_m; +	    ($suppl_CDs, $copy_rpms_on_disk) = get_media_cfg($o, $phys_m, $packages, $_->{selected_names}, $_->{force_rpmsrate}); +	} else { +	    log::l("unknown media type $_->{type}, skipping"); +	} +    } + +    log::l("suppl_CDs=$suppl_CDs copy_rpms_on_disk=$copy_rpms_on_disk"); +    $suppl_CDs, $copy_rpms_on_disk; +} + +sub adjust_paths_in_urpmi_cfg { +    my ($urpm) = @_; + +    require Clone; +    local $urpm->{media} = Clone::clone($urpm->{media}); +    foreach my $medium (@{$urpm->{media}}) { +        my $phys_m = $medium->{phys_medium}; +        if ($phys_m->{method} eq 'cdrom') { +            $medium->{url} =~ s!^.*?/media/!$phys_m->{url}/!; +        } elsif (member($phys_m->{method}, qw(disk nfs))) { +            # use the real mount point: +            if ($medium->{url} =~ m!/tmp/image(/media)?!) { +                $medium->{url} =~ s!/tmp/image(/media)?!$phys_m->{mntpoint}$phys_m->{rel_path}!; +            } else { +                # just remove $::prefix and we already have the real mount point: +                $medium->{url} =~ s!^$::prefix!!; +            } +        } +    } +    urpm::media::write_config($urpm); +} + +sub remove_from_fstab { +    my ($all_hds, $phys_m) = @_; + +    @{$all_hds->{nfss}} = grep { $_ != $phys_m } @{$all_hds->{nfss}} if $phys_m->{method} eq 'nfs'; +} + +sub _find_and_add_to_fstab { +    my ($all_hds, $phys_m, $b_force_mount) = @_; + +    if (my $existant = find { $_->{device} eq $phys_m->{device} } fs::get::really_all_fstab($all_hds)) { +	add2hash($existant, $phys_m); +	$phys_m = $existant; +    } else { +	push @{$all_hds->{nfss}}, $phys_m if $phys_m->{method} eq 'nfs'; +	push @{$all_hds->{loopbacks}}, $phys_m if isLoopback($phys_m); +    } + +    if (!$phys_m->{mntpoint}) { +	my @suggestions = $phys_m->{method} eq 'nfs' ? do { +	    my ($server) = $phys_m->{device} =~ /(.*?):/; +	    $phys_m->{options} = ($b_force_mount ? '' : 'noauto,') . 'ro,nosuid,soft,rsize=8192,wsize=8192'; +	    '/mnt/nfs', "/mnt/nfs_$server"; +	} : $phys_m->{method} eq 'cdrom' ? +	  ('/media/cdrom', "/media/$phys_m->{device}") : +	  ('/mnt/hd', "/mnt/$phys_m->{device}"); + +	my $last = $suggestions[-1]; +	push @suggestions, map { "$last$_" } 2 .. 30; +	$phys_m->{mntpoint} = find { !fs::get::has_mntpoint($_, $all_hds) } @suggestions or internal_error("no free dir available"); +    } +    $phys_m; +} + +sub url2mounted_phys_medium { +    my ($o, $url, $o_rel_file, $o_name) = @_; + +    my $phys_m = _url2phys_medium($o, $url); +    $phys_m->{name} = $o_name if $o_name; #- useful for CDs which prompts a name in change_phys_medium +    change_phys_medium($phys_m, $o_rel_file, $o->{packages}) or return; +    $phys_m; +} + +sub _url2phys_medium { +    my ($o, $url) = @_; +    my ($method, $path) = $url =~ m!([^:]*)://(.*)! or internal_error("bad url $url"); +    if ($method eq 'drakx') { +	my $m = { %{$o->{stage2_phys_medium}}, is_stage2_phys_medium => 1 }; +	if ($m->{loopback_device}) { +	    $m->{loopback_device} = _find_and_add_to_fstab($o->{all_hds}, $m->{loopback_device}, 'force_mount'); +	} +	$m->{url} .= "/$path"; +	$m->{rel_path} .= "/$path" if $m->{device}; +	$m = _find_and_add_to_fstab($o->{all_hds}, $m) if $m->{device}; +	_phys_medium_is_mounted($m); +	$m; +    } elsif ($method eq 'cdrom') { +	my $cdrom = first(detect_devices::cdroms()); +	my $m = {  +	    url => $url, method => $method, fs_type => 'iso9660', device => $cdrom->{device},  +	    rel_path => "/$path", +	}; +	my $m_ = _find_and_add_to_fstab($o->{all_hds}, $m); +	if ($m_->{name}) { +	    #- we need a new phys medium, different from current CD +	    $m_ = _get_phys_media_cdrom($m_, ''); +	    #- we also need to enforce what we want, especially rel_path +	    put_in_hash($m_, $m); +	} +	$m_; +    } elsif ($method eq 'nfs') { +	my ($server, $nfs_dir) = $path =~ m!(.*?)(/.*)!; + +	my $m = {  +	    url => $url, method => $method, +	    fs_type => 'nfs', device => "$server:$nfs_dir", faked_device => 1, +	}; +	_find_and_add_to_fstab($o->{all_hds}, $m); +    } else { +	{ url => $url, method => $method }; +    } +} + +sub _get_media_url { +    my ($o, $phys_medium) = @_; +    my $uri; +    if ($phys_medium->{is_suppl}) { +        if (member($phys_medium->{method}, qw(ftp http https))) { +            $uri = $phys_medium->{url}; +            $uri =~ s!/media$!!; +        } elsif (member($phys_medium->{method}, qw(cdrom nfs))) { +            $uri = "$::prefix/$phys_medium->{mntpoint}"; +            my $arch = arch() =~ /i.86/ ? $MDK::Common::System::compat_arch{arch()} : arch(); +            $uri .= "/$arch" if -d "$uri/$arch"; +        } +    } else { +        $uri = $o->{stage2_phys_medium}{url} =~ m!^(https?|ftp)://! && $o->{stage2_phys_medium}{url} || +          $phys_medium->{method} =~ m!^(ftp|https?)://! && $phys_medium->{method} || '/tmp/image'; +    } +    $uri; + } + +sub get_media_cfg { +    my ($o, $phys_medium, $packages, $selected_names, $force_rpmsrate) = @_; + +    my @media = @{$packages->{media}}; + +    my ($distribconf); +    if (getAndSaveFile_($phys_medium, 'media_info/media.cfg', '/tmp/media.cfg')) { +	($distribconf) = _parse_media_cfg('/tmp/media.cfg'); +    } else { +        die "media.cfg not found"; +    } + +    my $suppl_CDs = defined $o->{supplmedia} ? $o->{supplmedia} : $distribconf->{suppl} || 0; +    my $deselectionAllowed = $distribconf->{askmedia} || $o->{askmedia} || 0; + +    log::l(Data::Dumper->Dump([ $phys_medium ], [ 'phys_medium' ])); +    log::l(Data::Dumper->Dump([ $o->{stage2_phys_medium} ], [ 'stage2_phys_medium' ])); +    my $uri = _get_media_url($o, $phys_medium); +    log::l("adding distrib media from $uri"); + +    urpm::media::add_distrib_media($packages, undef, $uri, ask_media => undef); #allmedia => 1 + +    my @new_media = difference2($packages->{media}, \@media); +    _associate_phys_media($o->{all_hds}, $phys_medium, \@new_media); + +    select_only_some_media(\@new_media, $selected_names) if defined $selected_names; + +    if ($deselectionAllowed && !@{$packages->{media}}) { +	my $allow = _allow_copy_rpms_on_disk($phys_medium, $packages->{media}); +	$o->ask_deselect_media__copy_on_disk($packages->{media}, $allow && \$o->{copy_rpms_on_disk}) if $allow || @{$packages->{media}} > 1; +    } + +    log::l("get_media_cfg read " . int(@{$packages->{depslist}}) . " headers"); + +    _get_compsUsers_pl($phys_medium, $force_rpmsrate); + +    $suppl_CDs, $o->{copy_rpms_on_disk}; +} + +sub _get_compsUsers_pl { +    my ($phys_medium, $force_rpmsrate) = @_; +    #- copy latest compssUsers.pl and rpmsrate somewhere locally +    if ($force_rpmsrate || ! -e '/tmp/rpmsrate') { +	getAndSaveFile_($phys_medium, "media_info/rpmsrate", "/tmp/rpmsrate"); +    } +    if ($force_rpmsrate || ! -e '/tmp/compssUsers.pl') { +	getAndSaveFile_($phys_medium, "media_info/compssUsers.pl", "/tmp/compssUsers.pl"); +    } +} + +sub get_standalone_medium { +    my ($in, $phys_m, $packages, $m) = @_; + +    add2hash($m, { phys_medium => $phys_m, rel_hdlist => 'media_info/hdlist.cz' }); +    local $phys_m->{is_suppl} = 1; # so that _get_media_url() works +    _get_medium($in, $phys_m, $packages, $m); +} + +sub _get_medium { +    my ($_in_wait, $phys_m, $packages, $m) = @_; + +    !$m->{ignore} or log::l("ignoring packages in $m->{rel_hdlist}"), return; + +    my $url = _get_media_url({}, $phys_m); +    log::l("trying '$url'\n"); +    urpm::media::add_medium($packages, $m->{name} || 'Supplementary medium', $url, 0) or $packages->{fatal}(10, N("unable to add medium")); +} + + + +#-###################################################################################### +#- Post installation RPMS from cdrom only, functions +#-###################################################################################### +sub _setup_postinstall_rpms { +    my ($in, $packages, $current_phys_m) = @_; + +    $postinstall_rpms and return; +    $postinstall_rpms = "$::prefix/usr/postinstall-rpm"; + +    log::l("postinstall rpms directory set to $postinstall_rpms"); +    clean_postinstall_rpms(); #- make sure in case of previous upgrade problem. + +    my @toCopy; +    { +	#- compute closure of package that may be copied, use INSTALL category +	#- in rpmsrate. +	@toCopy = install::pkgs::select_by_package_names($packages, $packages->{needToCopy} || []); +	log::l("needToCopy the following packages: " . join(' ', map { $_->name } @toCopy)); +	$packages->disable_selected($packages->{rpmdb}, $packages->{state}, @toCopy); +	delete $packages->{rpmdb}; +    } + +    my $medium = find { $_->{phys_medium} == $current_phys_m } allMediums($packages); + +    my @l = map { path($current_phys_m, "$medium->{rpmsdir}/" . $_->filename) } @toCopy; + +    my ($l, $missing) = partition { -r $_ } @l; + +    @$missing and log::l("rpms not available: " . join(' ', @$missing)); + +    #- copy the package files in the postinstall RPMS directory. +    #- cp_af does not handle correctly a missing file. +    mkdir_p("$postinstall_rpms/$medium->{rpmsdir}"); +    eval {  +	my ($_w, $wait_message) = $in->wait_message_with_progress_bar; +	$wait_message->(N("Copying some packages on disks for future use")); +	install::any::cp_with_progress($wait_message, 0, int(@$l), @$l, "$postinstall_rpms/$medium->{rpmsdir}"); +    }; +    !$@ or log::l("copying to postinstall dir failed: $@"); + +    log::l("copying Auto Install Floppy"); +    getAndSaveInstallFloppies($::o, $postinstall_rpms, 'auto_install'); +} + +sub getAndSaveInstallFloppies { +    my ($o, $dest_dir, $name) = @_;     + +    if ($postinstall_rpms && -d $postinstall_rpms && -r "$postinstall_rpms/auto_install.img") { +	log::l("getAndSaveInstallFloppies: using file saved as $postinstall_rpms/auto_install.img"); +	cp_af("$postinstall_rpms/auto_install.img", "$dest_dir/$name.img"); +	"$dest_dir/$name.img"; +    } else { +	my $image = 'hd_grub'; + +	getAndSaveFile_($o->{stage2_phys_medium}, "install/images/$image.img", "$dest_dir/$name.img")  +	  or log::l("failed to write Install Floppy ($image.img) to $dest_dir/$name.img"), return; + +	"$dest_dir/$name.img"; +    } +} + +sub clean_postinstall_rpms() { +    if ($postinstall_rpms && -d $postinstall_rpms) { +	rm_rf($postinstall_rpms); +    } +} + +sub copy_rpms_on_disk { +    my ($o) = @_; + +    my $dest_dir = '/var/ftp/pub/Mageialinux/media'; +    #- don't be afraid, cleanup old RPMs if upgrade +    eval { rm_rf("$::prefix$dest_dir") if $o->{isUpgrade} }; +    mkdir_p("$::prefix$dest_dir"); + +    my $dest_phys_medium = do { +	my ($part, $rel_path) = fs::get::file2part($o->{fstab}, $dest_dir); +	$part->{method} = 'disk'; +	$part->{rel_path} = $rel_path; +	$part->{url} = "disk://$part->{device}$rel_path"; +	$part; +    }; + +    my ($wait, $wait_message) = $o->wait_message_with_progress_bar; + +    foreach my $m (allMediums($o->{packages})) { +	#- don't copy rpms of supplementary media +	next if $m->{phys_medium}{is_suppl}; +	$wait_message->(N("Copying in progress") . "\n($m->{name})"); #- XXX to be translated +	my $rpmsdir = path($m->{phys_medium}, $m->{rpmsdir}); +	if (! -d $rpmsdir) { +	    if (!change_phys_medium($m->{phys_medium}, $m->{rpmsdir})) { +		#- keep in mind the asked medium has been refused. +		#- this means it is no longer selected. +		#- (but do not unselect supplementary CDs.) +		$m->{ignore} = 1; +	    } +	} +	my $dest_medium_dir = $dest_dir . '/' . basename($rpmsdir); +	#- handle rpmsdir being ../../i586/media/main: we flatten it +	-e "$::prefix$dest_medium_dir" and $dest_medium_dir .= '32'; +	-e "$::prefix$dest_medium_dir" and next; + +	my $total = install::any::count_files($rpmsdir); +	log::l("copying $rpmsdir to $::prefix$dest_medium_dir ($total files)"); +	eval { +	    install::any::cp_with_progress_({}, $wait_message, $total, [$rpmsdir], "$::prefix$dest_medium_dir"); +	}; +	log::l($@) if $@; + +	$m->{rpmsdir} = basename($dest_medium_dir); +	$m->{phys_medium} = $dest_phys_medium; +    } +    undef $wait; + +    our $copied_rpms_on_disk = 1; +} + +sub _get_medium_dir { +    my ($phys_m) = @_; +    if (member($phys_m->{method}, qw(ftp http https cdrom))) { +        $phys_m->{url}; +    } else { +        "$phys_m->{mntpoint}$phys_m->{rel_path}"; +    } +} + +sub install_urpmi { +    my ($stage2_method, $packages) = @_; + +    my @media = @{$packages->{media}}; + +    log::l("install_urpmi $stage2_method"); +    #- clean to avoid opening twice the rpm db. +    delete $packages->{rpmdb}; + +    my (@cfg, @netrc); +    foreach my $medium (@media) { +	if (!$medium->{ignore}) { +            my ($dir, $removable_device); + +	    my $phys_m = $medium->{phys_medium}; +            $dir = _get_medium_dir($phys_m); + +            if ($phys_m->{method} eq 'iso') { +                $removable_device = $phys_m->{loopback_device}{mntpoint} . $phys_m->{loopback_file}; +            } + +	    $dir = MDK::Common::File::concat_symlink($dir, $medium->{rpmsdir}); + +	    my ($qname, $qdir) = ($medium->{fakemedium}, $dir); + +	    if (my $u = urpm::download::parse_url_with_login($qdir)) { +		$qdir = sprintf('%s://%s@%s%s', $u->{proto}, $u->{login}, $u->{machine}, $u->{dir}); +		push @netrc, sprintf("machine %s login %s password %s\n", $u->{machine}, $u->{login}, $u->{password}); +	    } + +	    s/(\s)/\\$1/g foreach $qname, $qdir; + +	    #- output new urpmi.cfg format here. +	    push @cfg, map { "$_\n" }  +	      "$qname $qdir {",  +		if_($medium->{'key-ids'}, +	      "  key-ids: " . $medium->{'key-ids'}), +		if_($removable_device,  +	      "  removable: $removable_device"), +		if_($medium->{update}, +	      "  update"),  +	      "}"; +	} else { +	    #- remove deselected media by removing copied hdlist and synthesis files +	    log::l("removing media $medium->{fakemedium}"); +	    unlink "$::prefix/var/lib/urpmi/hdlist.$medium->{fakemedium}.cz"; +	    unlink "$::prefix/var/lib/urpmi/synthesis.hdlist.$medium->{fakemedium}.cz"; +	} +    } +    eval { output("$::prefix/etc/urpmi/netrc", @netrc) }; +    #- touch a MD5SUM file and write config file +    eval { output("$::prefix/var/lib/urpmi/MD5SUM", '') }; +    eval { output "$::prefix/etc/urpmi/urpmi.cfg", @cfg }; +} + + +sub openCdromTray { +    my ($cdrom) = @_; +    log::l("ejecting cdrom $cdrom"); +    eval { ioctl(detect_devices::tryOpen($cdrom), c::CDROMEJECT(), 1) }; +    $@ and log::l("ejection failed: $@"); +} + +sub log_sizes() { +    my @df = MDK::Common::System::df($::prefix); +    log::l(sprintf "Installed: %dMB(df), %dMB(rpm)", +	   ($df[0] - $df[1]) / 1024, +	   sum(run_program::rooted_get_stdout($::prefix, 'rpm', '-qa', '--queryformat', '%{size}\n')) / 1024 / 1024) if -x "$::prefix/bin/rpm"; +    install::pkgs::clean_rpmdb_shared_regions(); +} + +1; | 
