diff options
Diffstat (limited to 'urpm/cdrom.pm')
-rw-r--r-- | urpm/cdrom.pm | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/urpm/cdrom.pm b/urpm/cdrom.pm new file mode 100644 index 00000000..ccbd29dd --- /dev/null +++ b/urpm/cdrom.pm @@ -0,0 +1,237 @@ +package urpm::cdrom; + +# $Id$ + +use urpm::msg; +use urpm::sys; +use urpm::util; +use urpm::get_pkgs; +use urpm::removable; +use urpm 'file_from_local_medium'; + + + +#- side-effects: $blists_url->[_]{medium}{mntpoint} +sub _find_blist_url_matching { + my ($urpm, $blists_url, $mntpoint) = @_; + + my @l; + foreach my $blist (@$blists_url) { + $blist->{medium}{mntpoint} and next; + + # set it, then verify + $blist->{medium}{mntpoint} = $mntpoint; + if (-r urpm::removable::_file_or_synthesis_dir($blist->{medium}, $blist->{url})) { + $urpm->{log}("found cdrom $blist->{medium}{name} mounted in $mntpoint"); + push @l, $blist; + } else { + delete $blist->{medium}{mntpoint}; + } + } + @l; +} + +#- side-effects: none +sub _look_for_mounted_cdrom_in_mtab() { + + map { $_->{mntpoint} } + grep { $_->{fs} eq 'iso9660' || $_->{fs} eq 'udf' } urpm::sys::read_mtab(); +} + +#- side-effects: +#- + those of _try_mounting_cdrom_using_hal ($urpm->{cdrom_mounted}, "hal_mount") +#- + those of _find_blist_url_matching ($blists_url->[_]{medium}{mntpoint}) +sub try_mounting_cdrom { + my ($urpm, $blists_url) = @_; + + my @blists_url; + + # first try without hal, it allows users where hal fails to work (with one CD only) + my @mntpoints = _look_for_mounted_cdrom_in_mtab(); + @blists_url = map { _find_blist_url_matching($urpm, $blists_url, $_) } @mntpoints; + + if (!@blists_url) { + @mntpoints = _try_mounting_cdrom_using_hal($urpm); + @blists_url = map { _find_blist_url_matching($urpm, $blists_url, $_) } @mntpoints; + } + @blists_url; +} + +#- side-effects: $urpm->{cdrom_mounted}, "hal_mount" +sub _try_mounting_cdrom_using_hal { + my ($urpm) = @_; + + $urpm->{cdrom_mounted} = {}; # reset + + require Hal::Cdroms; + my $hal_cdroms = Hal::Cdroms->new; + foreach my $hal_path ($hal_cdroms->list) { + my $mntpoint; + if ($mntpoint = $hal_cdroms->get_mount_point($hal_path)) { + } else { + $urpm->{log}("trying to mount $hal_path"); + $mntpoint = $hal_cdroms->ensure_mounted($hal_path) + or $urpm->{error}("failed to mount $hal_path: $hal_cdroms->{error}"), next; + } + $urpm->{cdrom_mounted}{$hal_path} = $mntpoint; + } + values %{$urpm->{cdrom_mounted}}; +} + +#- side-effects: +#- + those of try_mounting_cdrom ($urpm->{cdrom_mounted}, $blists_url->[_]{medium}{mntpoint}, "hal_mount") +#- + those of _try_mounting_medium ($urpm->{cdrom_mounted}, $blists_url->[_]{medium}{mntpoint}) +sub _mount_cdrom_and_check { + my ($urpm, $blists) = @_; + + my @matching_blists = try_mounting_cdrom($urpm, $blists) or return; + my @checked = grep { !_check_notfound($_) } @matching_blists; + $checked[0]; +} + +#- side-effects: none +sub _check_notfound { + my ($blist) = @_; + + $blist->{medium}{mntpoint} or return; + + foreach (values %{$blist->{list}}) { + my $dir_ = _filepath($blist->{medium}, $_) or next; + -r $dir_ or return 1; + } + 0; +} + +#- side-effects: +#- + those of _eject_cdrom ($urpm->{cdrom_mounted}, "hal_umount", "hal_eject") +sub _may_eject_cdrom { + my ($urpm) = @_; + + my @paths = keys %{$urpm->{cdrom_mounted}}; + @paths == 1 or return; + + # only one cdrom mounted, we know it is the one to umount/eject + _eject_cdrom($urpm, $paths[0]); +} + + +#- side-effects: $urpm->{cdrom_mounted}, "hal_umount", "hal_eject" +sub _eject_cdrom { + my ($urpm, $hal_path) = @_; + + my $mntpoint = delete $urpm->{cdrom_mounted}{$hal_path}; + $urpm->{debug} and $urpm->{debug}("umounting and ejecting $mntpoint (cdrom $hal_path)"); + + require Hal::Cdroms; + my $hal_cdroms = Hal::Cdroms->new; + $hal_cdroms->unmount($hal_path); + $hal_cdroms->eject($hal_path); + 1; +} + +#- side-effects: "eject" +#- + those of _mount_cdrom_and_check ($urpm->{cdrom_mounted}, $blists_url->[_]{medium}{mntpoint}, "hal_mount") +#- + those of _may_eject_cdrom ($urpm->{cdrom_mounted}, "hal_umount", "hal_eject") +sub _mount_cdrom { + my ($urpm, $blists, $ask_for_medium) = @_; + + my $retry; + + #- the directory given does not exist and may be accessible + #- by mounting some other directory. Try to figure it out and mount + #- everything that might be necessary. + while (1) { + + if (my $blist = _mount_cdrom_and_check($urpm, $blists)) { + return $blist; + } + + # ask for the first one, it's ok if the user insert another wanted cdrom + my $medium = $blists->[0]{medium}; + + $retry++ and $urpm->{log}("wrong CDROM, wanted $medium->{name}"); + + $ask_for_medium + or $urpm->{fatal}(4, N("medium \"%s\" is not available", $medium->{name})); + + _may_eject_cdrom($urpm); + + $ask_for_medium->(remove_internal_name($medium->{name})) + or $urpm->{fatal}(4, N("medium \"%s\" is not available", $medium->{name})); + } +} + +#- side-effects: none +sub _filepath { + my ($medium, $url) = @_; + + chomp $url; + my $filepath = file_from_local_medium($medium, $url) or return; + $filepath =~ m!/.*/! or return; #- is this really needed?? + $filepath; +} + +#- side-effects: "copy-move-files" +sub _do_the_copy { + my ($urpm, $filepath) = @_; + + #- we should assume a possibly buggy removable device... + #- First, copy in partial cache, and if the package is still good, + #- transfer it to the rpms cache. + my $filename = basename($filepath); + unlink "$urpm->{cachedir}/partial/$filename"; + $urpm->{log}("copying $filepath"); + copy_and_own($filepath, "$urpm->{cachedir}/partial/$filename") or return; + my $f = urpm::get_pkgs::verify_partial_rpm_and_move($urpm, $urpm->{cachedir}, $filename) or return; + $f; +} + +#- side-effects: $sources +#- + those of _do_the_copy: "copy-move-files" +sub _copy_from_cdrom__if_needed { + my ($urpm, $blist, $sources, $want_copy) = @_; + + while (my ($i, $url) = each %{$blist->{list}}) { + my $filepath = _filepath($blist->{medium}, $url) or next; + + if (-r $filepath) { + $sources->{$i} = $want_copy ? _do_the_copy($urpm, $filepath) : $filepath; + } else { + #- fallback to use other method for retrieving the file later. + $urpm->{error}(N("unable to read rpm file [%s] from medium \"%s\"", $filepath, $blist->{medium}{name})); + } + } +} + +#- $list is a [ { pkg_id1 => url1, ... }, { ... }, ... ] +#- where there is one hash for each medium in {media} +#- +#- side-effects: +#- + those of _may_eject_cdrom ($urpm->{cdrom_mounted}, "hal_umount", "hal_eject") +#- + those of _mount_cdrom ($urpm->{cdrom_mounted}, $blists_url->[_]{medium}{mntpoint}, "hal_mount", "hal_eject") +#- + those of _copy_from_cdrom__if_needed ("copy-move-files") +sub copy_packages_of_removable_media { + my ($urpm, $list, $sources, $o_ask_for_medium) = @_; + + my $blists = urpm::removable::create_blists($urpm->{media}, $list); + @$blists = grep { urpm::is_cdrom_url($_->{medium}{url}) } @$blists; + + # we prompt for CDs used less first, since the last CD will be used directly + @$blists = sort { values(%{$a->{list}}) <=> values(%{$b->{list}}) } @$blists; + + my $prev_medium; + while (@$blists) { + $prev_medium and delete $prev_medium->{mntpoint}; + _may_eject_cdrom($urpm); + + my $blist = _mount_cdrom($urpm, $blists, $o_ask_for_medium); + @$blists = grep { $_ != $blist } @$blists; + + _copy_from_cdrom__if_needed($urpm, $blist, $sources, @$blists > 0); + $prev_medium = $blist->{medium}; + } + + 1; +} + +1; |