diff options
Diffstat (limited to 'urpm/removable.pm')
-rw-r--r-- | urpm/removable.pm | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/urpm/removable.pm b/urpm/removable.pm new file mode 100644 index 00000000..783a2ba5 --- /dev/null +++ b/urpm/removable.pm @@ -0,0 +1,195 @@ +package urpm::removable; + +# $Id$ + +use urpm::msg; +use urpm::sys; +use urpm::util; +use urpm 'file_from_local_url'; + + + +#- returns the removable device name if it corresponds to an iso image, '' otherwise +sub is_iso { + my ($removable_dev) = @_; + $removable_dev && $removable_dev =~ /\.iso$/i; +} + +sub try_mounting { + my ($urpm, $dir, $o_removable) = @_; + my %infos; + + my $is_iso = is_iso($o_removable); + my @mntpoints = $is_iso + #- note: for isos, we don't parse the fstab because it might not be declared in it. + #- so we try to remove suffixes from the dir name until the dir exists + ? ($dir = urpm::sys::trim_until_d($dir)) + : urpm::sys::find_mntpoints($dir = reduce_pathname($dir), \%infos); + foreach (grep { + ! $infos{$_}{mounted} && $infos{$_}{fs} ne 'supermount'; + } @mntpoints) + { + $urpm->{log}(N("mounting %s", $_)); + if ($is_iso) { + #- to mount an iso image, grab the first loop device + my $loopdev = urpm::sys::first_free_loopdev(); + sys_log("mount iso $_ on $o_removable"); + $loopdev and system('mount', $o_removable, $_, '-t', 'iso9660', '-o', "loop=$loopdev"); + } else { + sys_log("mount $_"); + system("mount '$_' 2>/dev/null"); + } + $o_removable && $infos{$_}{fs} ne 'supermount' and $urpm->{removable_mounted}{$_} = undef; + } + -e $dir; +} + +sub try_umounting { + my ($urpm, $dir) = @_; + my %infos; + + $dir = reduce_pathname($dir); + foreach (reverse grep { + $infos{$_}{mounted} && $infos{$_}{fs} ne 'supermount'; + } urpm::sys::find_mntpoints($dir, \%infos)) + { + $urpm->{log}(N("unmounting %s", $_)); + sys_log("umount $_"); + system("umount '$_' 2>/dev/null"); + delete $urpm->{removable_mounted}{$_}; + } + ! -e $dir; +} + +sub try_umounting_removables { + my ($urpm) = @_; + foreach (keys %{$urpm->{removable_mounted}}) { + try_umounting($urpm, $_); + } + delete $urpm->{removable_mounted}; +} + +#- $list is a [ { pkg_id1 => url1, ... }, { ... }, ... ] +#- where there is one hash for each medium in {media} +sub copy_packages_of_removable_media { + my ($urpm, $list, $sources, $o_ask_for_medium) = @_; + my %removables; + + #- make sure everything is correct on input... + $urpm->{media} or return; + @{$urpm->{media}} == @$list or return; + + #- examine if given medium is already inside a removable device. + my $check_notfound = sub { + my ($id, $dir, $removable) = @_; + if ($dir) { + try_mounting($urpm, $dir, $removable); + -e $dir or return 2; + } + foreach (values %{$list->[$id]}) { + chomp; + my $dir_ = file_from_local_url($_) or next; + $dir_ =~ m!/.*/! or next; #- is this really needed?? + unless ($dir) { + $dir = $dir_; + try_mounting($urpm, $dir, $removable); + } + -r $dir_ or return 1; + } + 0; + }; + #- removable media have to be examined to keep mounted the one that has + #- more packages than others. + my $examine_removable_medium = sub { + my ($id, $device) = @_; + my $medium = $urpm->{media}[$id]; + if (my $dir = file_from_local_url($medium->{url})) { + #- 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 ($check_notfound->($id, $dir, is_iso($medium->{removable}) ? $medium->{removable} : 'removable')) { + is_iso($medium->{removable}) || $o_ask_for_medium + or $urpm->{fatal}(4, N("medium \"%s\" is not selected", $medium->{name})); + try_umounting($urpm, $dir); + system("/usr/bin/eject '$device' 2>/dev/null"); + is_iso($medium->{removable}) + || $o_ask_for_medium->(remove_internal_name($medium->{name}), $medium->{removable}) + or $urpm->{fatal}(4, N("medium \"%s\" is not selected", $medium->{name})); + } + if (-e $dir) { + while (my ($i, $url) = each %{$list->[$id]}) { + chomp $url; + my ($filepath, $filename) = do { + my $f = file_from_local_url($url) or next; + $f =~ m!/.*/! or next; #- is this really needed?? + dirname($f), basename($f); + }; + if (-r $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. + unlink "$urpm->{cachedir}/partial/$filename"; + if (copy_and_own($filepath, "$urpm->{cachedir}/partial/$filename") && + URPM::verify_rpm("$urpm->{cachedir}/partial/$filename", nosignatures => 1)) + { + #- now we can consider the file to be fine. + unlink "$urpm->{cachedir}/rpms/$filename"; + urpm::util::move("$urpm->{cachedir}/partial/$filename", "$urpm->{cachedir}/rpms/$filename"); + -r "$urpm->{cachedir}/rpms/$filename" and $sources->{$i} = "$urpm->{cachedir}/rpms/$filename"; + } + } + unless ($sources->{$i}) { + #- fallback to use other method for retrieving the file later. + $urpm->{error}(N("unable to read rpm file [%s] from medium \"%s\"", $filepath, $medium->{name})); + } + } + } else { + $urpm->{error}(N("medium \"%s\" is not selected", $medium->{name})); + } + } else { + #- we have a removable device that is not removable, well... + $urpm->{error}(N("inconsistent medium \"%s\" marked removable but not really", $medium->{name})); + } + }; + + foreach (0..$#$list) { + values %{$list->[$_]} or next; + my $medium = $urpm->{media}[$_]; + #- examine non removable device but that may be mounted. + if ($medium->{removable}) { + push @{$removables{$medium->{removable}} ||= []}, $_; + } elsif (my $dir = file_from_local_url($medium->{url})) { + -e $dir || try_mounting($urpm, $dir) or + $urpm->{error}(N("unable to access medium \"%s\"", $medium->{name})), next; + } + } + foreach my $device (keys %removables) { + next if $device =~ m![^a-zA-Z0-9_./-]!; #- bad path + #- Here we have only removable devices. + #- If more than one media uses this device, we have to sort + #- needed packages to copy the needed rpm files. + if (@{$removables{$device}} > 1) { + my @sorted_media = sort { values(%{$list->[$a]}) <=> values(%{$list->[$b]}) } @{$removables{$device}}; + + #- check if a removable device is already mounted (and files present). + if (my ($already_mounted_medium) = grep { !$check_notfound->($_) } @sorted_media) { + @sorted_media = grep { $_ ne $already_mounted_medium } @sorted_media; + unshift @sorted_media, $already_mounted_medium; + } + + #- mount all except the biggest one. + my $biggest = pop @sorted_media; + foreach (@sorted_media) { + $examine_removable_medium->($_, $device); + } + #- now mount the last one... + $removables{$device} = [ $biggest ]; + } + + $examine_removable_medium->($removables{$device}[0], $device); + } + + 1; +} + +1; |