summaryrefslogtreecommitdiffstats
path: root/urpm/sys.pm
diff options
context:
space:
mode:
Diffstat (limited to 'urpm/sys.pm')
-rw-r--r--urpm/sys.pm109
1 files changed, 109 insertions, 0 deletions
diff --git a/urpm/sys.pm b/urpm/sys.pm
new file mode 100644
index 00000000..a0096a42
--- /dev/null
+++ b/urpm/sys.pm
@@ -0,0 +1,109 @@
+package urpm::sys;
+
+use strict;
+
+#- check if supermount is used.
+sub is_using_supermount {
+ my ($device_mntpoint) = @_;
+ local $_;
+ #- read /etc/fstab and check for existing mount point.
+ open my $f, "/etc/fstab" or die "Can't read fstab: $!\n";
+ while (<$f>) {
+ next if /^\s*#/;
+ my ($mntpoint, $fstype, $options) = m!^\s*\S+\s+(/\S+)\s+(\S+)\s+(\S+)!
+ or next;
+ $mntpoint =~ s,/+,/,g; $mntpoint =~ s,/$,,;
+ if ($fstype eq 'supermount') {
+ return 1 if $device_mntpoint eq $mntpoint;
+ $options =~ /^(?:.*[\s,])?dev=([^\s,]+)/ && $device_mntpoint eq $1
+ and return 1;
+ }
+ }
+ return 0;
+}
+
+#- find used mount point from a pathname, use a optional mode to allow
+#- filtering according the next operation (mount or umount).
+sub find_mntpoints {
+ my ($dir, $infos) = @_;
+ my (%fstab, @mntpoints);
+ local ($_);
+ #- read /etc/fstab and check for existing mount point.
+ open my $f, "/etc/fstab" or die "Can't read fstab: $!\n";
+ while (<$f>) {
+ next if /^\s*#/;
+ my ($device, $mntpoint, $fstype, $options) = m!^\s*(\S+)\s+(/\S+)\s+(\S+)\s+(\S+)!
+ or next;
+ $mntpoint =~ s,/+,/,g; $mntpoint =~ s,/$,,;
+ $fstab{$mntpoint} = 0;
+ if (ref($infos)) {
+ if ($fstype eq 'supermount') {
+ $options =~ /^(?:.*[\s,])?dev=([^\s,]+)/ and $infos->{$mntpoint} = {
+ mounted => 0,
+ device => $1,
+ fs => $fstype,
+ supermount => 1,
+ };
+ } else {
+ $infos->{$mntpoint} = { mounted => 0, device => $device, fs => $fstype };
+ }
+ }
+ }
+ close $f;
+ open $f, "/etc/mtab" or die "Can't read mtab: $!\n";
+ while (<$f>) {
+ my ($device, $mntpoint, $fstype, $options) = m!^\s*(\S+)\s+(/\S+)\s+(\S+)\s+(\S+)!
+ or next;
+ $mntpoint =~ s,/+,/,g; $mntpoint =~ s,/$,,;
+ $fstab{$mntpoint} = 1;
+ if (ref($infos)) {
+ if ($fstype eq 'supermount') {
+ $options =~ /^(?:.*[\s,])?dev=([^\s,]+)/ and $infos->{$mntpoint} = {
+ mounted => 1,
+ device => $1,
+ fs => $fstype,
+ supermount => 1,
+ };
+ } else {
+ $infos->{$mntpoint} = { mounted => 1, device => $device, fs => $fstype };
+ }
+ }
+ }
+ close $f;
+ #- try to follow symlink, too complex symlink graph may not be seen.
+ #- check the possible mount point.
+ my @paths = split '/', $dir;
+ while (defined ($_ = shift @paths)) {
+ length($_) or next;
+ my $pdir .= "/$_";
+ $pdir =~ s,/+,/,g; $pdir =~ s,/$,,;
+ if (exists($fstab{$pdir})) {
+ ref($infos) and push @mntpoints, $pdir;
+ $infos eq 'mount' && ! $fstab{$pdir} and push @mntpoints, $pdir;
+ $infos eq 'umount' && $fstab{$pdir} and unshift @mntpoints, $pdir;
+ #- following symlinks may be useless or dangerous for supermounted devices.
+ #- this means it is assumed no symlink inside a removable device
+ #- will go outside the device itself (or at least will go into
+ #- regular already mounted device like /).
+ #- for simplification we refuse also any other device and stop here.
+ last;
+ } elsif (-l $pdir) {
+ while (my $v = readlink $pdir) {
+ if ($pdir =~ m|^/|) {
+ $pdir = $v;
+ } else {
+ while ($v =~ m|^\.\./(.*)|) {
+ $v = $1;
+ $pdir =~ s|^(.*)/[^/]+/*|$1|;
+ }
+ $pdir .= "/$v";
+ }
+ }
+ unshift @paths, split '/', $pdir;
+ $pdir = '';
+ }
+ }
+ @mntpoints;
+}
+
+1;