summaryrefslogtreecommitdiffstats
path: root/urpm
diff options
context:
space:
mode:
Diffstat (limited to 'urpm')
-rw-r--r--urpm/media.pm9
-rw-r--r--urpm/removable.pm195
2 files changed, 200 insertions, 4 deletions
diff --git a/urpm/media.pm b/urpm/media.pm
index e32ae406..c823a8d5 100644
--- a/urpm/media.pm
+++ b/urpm/media.pm
@@ -5,6 +5,7 @@ package urpm::media;
use urpm 'file_from_local_url';
use urpm::msg;
use urpm::util;
+use urpm::removable;
our @PER_MEDIA_OPT = qw(
@@ -334,7 +335,7 @@ sub probe_removable_device {
$urpm->{log}(N("too many mount points for removable medium \"%s\"", $medium->{name}));
$urpm->{log}(N("taking removable device as \"%s\"", join ',', map { $infos{$_}{device} } @mntpoints));
}
- if (urpm::is_iso($medium->{removable})) {
+ if (urpm::removable::is_iso($medium->{removable})) {
$urpm->{log}(N("Medium \"%s\" is an ISO image, will be mounted on-the-fly", $medium->{name}));
} elsif (@mntpoints) {
if ($medium->{removable} && $medium->{removable} ne $infos{$mntpoints[-1]}{device}) {
@@ -663,7 +664,7 @@ sub add_distrib_media {
my $distribconf;
if (my $dir = file_from_local_url($url)) {
- $urpm->try_mounting($dir)
+ urpm::removable::try_mounting($urpm, $dir)
or $urpm->{error}(N("unable to mount the distribution medium")), return ();
$distribconf = MDV::Distribconf->new($dir, undef);
$distribconf->load
@@ -1272,11 +1273,11 @@ sub _update_medium__parse_if_unmodified__local {
#- 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.
- $urpm->try_mounting(
+ urpm::removable::try_mounting($urpm,
!$options->{force_building_hdlist} && $medium->{with_hdlist}
? _hdlist_dir($medium) : $dir,
#- in case of an iso image, pass its name
- urpm::is_iso($medium->{removable}) && $medium->{removable},
+ urpm::removable::is_iso($medium->{removable}) && $medium->{removable},
) or $urpm->{error}(N("unable to access medium \"%s\",
this could happen if you mounted manually the directory when creating the medium.", $medium->{name})), return 'unmodified';
}
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;