summaryrefslogtreecommitdiffstats
path: root/perl-install/fs
diff options
context:
space:
mode:
Diffstat (limited to 'perl-install/fs')
-rw-r--r--perl-install/fs/dmraid.pm3
-rw-r--r--perl-install/fs/format.pm42
-rw-r--r--perl-install/fs/get.pm10
-rw-r--r--perl-install/fs/loopback.pm28
-rw-r--r--perl-install/fs/mount.pm197
-rw-r--r--perl-install/fs/type.pm5
-rw-r--r--perl-install/fs/wild_device.pm101
7 files changed, 361 insertions, 25 deletions
diff --git a/perl-install/fs/dmraid.pm b/perl-install/fs/dmraid.pm
index 7166ce12d..6916ab324 100644
--- a/perl-install/fs/dmraid.pm
+++ b/perl-install/fs/dmraid.pm
@@ -10,6 +10,7 @@ use common;
use modules;
use devices;
use fs::type;
+use fs::wild_device;
use run_program;
@@ -44,7 +45,7 @@ sub vgs() {
my %vg2pv; push @{$vg2pv{$_->{vg}}}, $_->{pv} foreach @l;
map {
my $dev = "mapper/$_->{vg}";
- my $vg = fs::subpart_from_wild_device_name("/dev/$dev");
+ my $vg = fs::wild_device::to_subpart("/dev/$dev");
add2hash($vg, { media_type => 'hd', prefix => $dev, bus => "dm_$_->{format}", disks => $vg2pv{$_->{vg}} });
#- device should exist, created by dmraid(8) using libdevmapper
diff --git a/perl-install/fs/format.pm b/perl-install/fs/format.pm
index 3238df33c..93882788f 100644
--- a/perl-install/fs/format.pm
+++ b/perl-install/fs/format.pm
@@ -52,14 +52,14 @@ sub check_package_is_installed {
}
sub part {
- my ($raids, $part, $prefix, $wait_message) = @_;
+ my ($all_hds, $part, $wait_message) = @_;
if (isRAID($part)) {
$wait_message->(N("Formatting partition %s", $part->{device})) if $wait_message;
require raid;
- raid::format_part($raids, $part);
+ raid::format_part($all_hds->{raids}, $part);
} elsif (isLoopback($part)) {
$wait_message->(N("Creating and formatting file %s", $part->{loopback_file})) if $wait_message;
- fs::loopback::format_part($part, $prefix);
+ fs::loopback::format_part($part);
} else {
$wait_message->(N("Formatting partition %s", $part->{device})) if $wait_message;
part_raw($part, $wait_message);
@@ -72,8 +72,7 @@ sub part_raw {
$part->{isFormatted} and return;
if ($part->{encrypt_key}) {
- require fs;
- fs::set_loop($part);
+ fs::mount::set_loop($part);
}
my $dev = $part->{real_device} || $part->{device};
@@ -179,4 +178,37 @@ sub wait_message {
};
}
+
+sub formatMount_part {
+ my ($part, $all_hds, $fstab, $wait_message) = @_;
+
+ if (isLoopback($part)) {
+ formatMount_part($part->{loopback_device}, $all_hds, $fstab, $wait_message);
+ }
+ if (my $p = fs::get::up_mount_point($part->{mntpoint}, $fstab)) {
+ formatMount_part($p, $all_hds, $fstab, $wait_message) if !fs::type::carry_root_loopback($part);
+ }
+ if ($part->{toFormat}) {
+ fs::format::part($all_hds, $part, $wait_message);
+ }
+ fs::mount::part($part, 0, $wait_message);
+}
+
+sub formatMount_all {
+ my ($all_hds, $fstab, $wait_message) = @_;
+ formatMount_part($_, $all_hds, $fstab, $wait_message)
+ foreach sort { isLoopback($a) ? 1 : isSwap($a) ? -1 : 0 } grep { $_->{mntpoint} } @$fstab;
+
+ #- ensure the link is there
+ fs::loopback::carryRootCreateSymlink($_) foreach @$fstab;
+
+ #- for fun :)
+ #- that way, when install exits via ctrl-c, it gives hand to partition
+ eval {
+ my ($_type, $major, $minor) = devices::entry(fs::get::root($fstab)->{device});
+ output "/proc/sys/kernel/real-root-dev", makedev($major, $minor);
+ };
+}
+
+
1;
diff --git a/perl-install/fs/get.pm b/perl-install/fs/get.pm
index 5ea9071a8..1db2d3002 100644
--- a/perl-install/fs/get.pm
+++ b/perl-install/fs/get.pm
@@ -6,6 +6,7 @@ use strict;
use partition_table;
use fs::type;
use fs::loopback;
+use fs::wild_device;
use fs;
use common;
use log;
@@ -70,7 +71,7 @@ sub hds_fstab_and_holes {
sub device2part {
my ($dev, $fstab) = @_;
- my $subpart = fs::subpart_from_wild_device_name($dev);
+ my $subpart = fs::wild_device::to_subpart($dev);
my $part = find { is_same_hd($subpart, $_) } @$fstab;
log::l("fs::get::device2part: unknown device <<$dev>>") if !$part;
$part;
@@ -88,7 +89,7 @@ sub file2part {
$file = $b_keep_simple_symlinks ? common::expand_symlinks_but_simple("$::prefix$file") : expand_symlinks("$::prefix$file");
unless ($file =~ s/^$::prefix//) {
- my $part = find { fs::loopback::carryRootLoopback($_) } @$fstab or die;
+ my $part = find { fs::type::carry_root_loopback($_) } @$fstab or die;
log::l("found $part->{mntpoint}");
$file =~ s|/initrd/loopfs|$part->{mntpoint}|;
}
@@ -140,4 +141,9 @@ sub is_same_hd {
}
}
+sub mntpoint_prefixed {
+ my ($part) = @_;
+ $::prefix . $part->{mntpoint};
+}
+
1;
diff --git a/perl-install/fs/loopback.pm b/perl-install/fs/loopback.pm
index a7c6c913d..572c79f67 100644
--- a/perl-install/fs/loopback.pm
+++ b/perl-install/fs/loopback.pm
@@ -12,12 +12,6 @@ use fs;
use log;
-sub carryRootLoopback {
- my ($part) = @_;
- $_->{mntpoint} eq '/' and return 1 foreach @{$part->{loopback} || []};
- 0;
-}
-
sub check_circular_mounts {
my ($part, $all_hds) = @_;
@@ -30,7 +24,7 @@ sub check_circular_mounts {
@seen > 1 && $part->{mntpoint} eq $base_mntpoint and die N("Circular mounts %s\n", join(", ", @seen));
if (my $part = fs::get::up_mount_point($part->{mntpoint}, $fstab)) {
#- '/' carrier is a special case, it will be mounted first
- $check->($part, @seen) if !carryRootLoopback($part);
+ $check->($part, @seen) if !fs::type::carry_root_loopback($part);
}
if (isLoopback($part)) {
$check->($part->{loopback_device}, @seen);
@@ -40,34 +34,34 @@ sub check_circular_mounts {
}
sub carryRootCreateSymlink {
- my ($part, $prefix) = @_;
+ my ($part) = @_;
- carryRootLoopback($part) or return;
+ fs::type::carry_root_loopback($part) or return;
- my $mntpoint = "$prefix$part->{mntpoint}";
+ my $mntpoint = fs::get::mntpoint_prefixed($part);
unless (-e $mntpoint) {
eval { mkdir_p(dirname($mntpoint)) };
#- do non-relative link for install, should be changed to relative link before rebooting
symlink "/initrd/loopfs", $mntpoint;
mkdir_p("/initrd/loopfs/lnx4win/boot");
- symlink "/initrd/loopfs/lnx4win/boot", "$prefix/boot";
+ symlink "/initrd/loopfs/lnx4win/boot", "$::prefix/boot";
}
#- indicate kernel to keep initrd
- mkdir_p("$prefix/initrd");
+ mkdir_p("$::prefix/initrd");
}
sub format_part {
- my ($part, $prefix) = @_;
- fs::mount_part($part->{loopback_device}, $prefix);
- create($part, $prefix);
+ my ($part) = @_;
+ fs::mount::part($part->{loopback_device});
+ create($part);
fs::format::part_raw($part, undef);
}
sub create {
- my ($part, $prefix) = @_;
- my $f = $part->{device} = "$prefix$part->{loopback_device}{mntpoint}$part->{loopback_file}";
+ my ($part) = @_;
+ my $f = $part->{device} = fs::get::mntpoint_prefixed($part->{loopback_device}) . $part->{loopback_file};
return if -e $f;
eval { mkdir_p(dirname($f)) };
diff --git a/perl-install/fs/mount.pm b/perl-install/fs/mount.pm
new file mode 100644
index 000000000..40bc07f05
--- /dev/null
+++ b/perl-install/fs/mount.pm
@@ -0,0 +1,197 @@
+package fs::mount; # $Id$
+
+use diagnostics;
+use strict;
+
+use run_program;
+use common;
+use fs::type;
+use log;
+
+
+sub set_loop {
+ my ($part) = @_;
+ $part->{real_device} ||= devices::set_loop(devices::make($part->{device}), $part->{encrypt_key}, $part->{options} =~ /encryption=(\w+)/);
+}
+
+sub swapon {
+ my ($dev) = @_;
+ log::l("swapon called with $dev");
+ syscall_('swapon', devices::make($dev), 0) or die "swapon($dev) failed: $!";
+}
+
+sub swapoff {
+ my ($dev) = @_;
+ syscall_('swapoff', devices::make($dev)) or die "swapoff($dev) failed: $!";
+}
+
+sub mount {
+ my ($dev, $where, $fs, $b_rdonly, $o_options, $o_wait_message) = @_;
+ log::l("mounting $dev on $where as type $fs, options $o_options");
+
+ mkdir_p($where);
+
+ $fs or log::l("not mounting $dev partition"), return;
+
+ {
+ my @fs_modules = qw(ext3 hfs jfs nfs ntfs romfs reiserfs ufs xfs vfat);
+ my @types = (qw(ext2 proc sysfs usbfs usbdevfs iso9660 devfs devpts), @fs_modules);
+
+ push @types, 'smb', 'smbfs', 'davfs' if !$::isInstall;
+
+ if (!member($fs, @types) && !$::move) {
+ log::l("skipping mounting $dev partition ($fs)");
+ return;
+ }
+ if ($::isInstall) {
+ if (member($fs, @fs_modules)) {
+ eval { modules::load($fs) };
+ } elsif ($fs eq 'iso9660') {
+ eval { modules::load('isofs') };
+ }
+ }
+ }
+
+ $where =~ s|/$||;
+
+ my @mount_opt = split(',', $o_options || '');
+
+ if ($fs eq 'vfat') {
+ @mount_opt = 'check=relaxed';
+ } elsif ($fs eq 'nfs') {
+ push @mount_opt, 'nolock', 'soft', 'intr' if $::isInstall;
+ } elsif ($fs eq 'jfs' && !$b_rdonly) {
+ fsck_jfs($dev, $o_wait_message);
+ } elsif ($fs eq 'ext2' && !$b_rdonly) {
+ fsck_ext2($dev, $o_wait_message);
+ }
+
+ push @mount_opt, 'ro' if $b_rdonly;
+
+ log::l("calling mount -t $fs $dev $where @mount_opt");
+ $o_wait_message->(N("Mounting partition %s", $dev)) if $o_wait_message;
+ run_program::run('mount', '-t', $fs, $dev, $where, if_(@mount_opt, '-o', join(',', @mount_opt))) or die N("mounting partition %s in directory %s failed", $dev, $where);
+}
+
+sub fsck_ext2 {
+ my ($dev, $o_wait_message) = @_;
+ $o_wait_message->(N("Checking %s", $dev)) if $o_wait_message;
+ foreach ('-a', '-y') {
+ run_program::raw({ timeout => 60 * 60 }, "fsck.ext2", $_, $dev);
+ my $err = $?;
+ if ($err & 0x0100) {
+ log::l("fsck corrected partition $dev");
+ }
+ if ($err & 0xfeff) {
+ my $txt = sprintf("fsck failed on %s with exit code %d or signal %d", $dev, $err >> 8, $err & 255);
+ $_ eq '-y' ? die($txt) : cdie($txt);
+ } else {
+ last;
+ }
+ }
+}
+sub fsck_jfs {
+ my ($dev, $o_wait_message) = @_;
+ $o_wait_message->(N("Checking %s", $dev)) if $o_wait_message;
+ #- needed if the system is dirty otherwise mounting read-write simply fails
+ run_program::raw({ timeout => 60 * 60 }, "fsck.jfs", $dev) or do {
+ my $err = $?;
+ die "fsck.jfs failed" if $err & 0xfc00;
+ };
+}
+
+#- takes the mount point to umount (can also be the device)
+sub umount {
+ my ($mntpoint) = @_;
+ $mntpoint =~ s|/$||;
+ log::l("calling umount($mntpoint)");
+
+ syscall_('umount2', $mntpoint, 0) or do {
+ kill 15, fuzzy_pidofs('^fam\b');
+ syscall_('umount2', $mntpoint, 0) or die N("error unmounting %s: %s", $mntpoint, $!);
+ };
+
+ substInFile { $_ = '' if /(^|\s)$mntpoint\s/ } '/etc/mtab'; #- do not care about error, if we can not read, we will not manage to write... (and mess mtab)
+}
+
+sub part {
+ my ($part, $b_rdonly, $o_wait_message) = @_;
+
+ log::l("mount_part: " . join(' ', map { "$_=$part->{$_}" } 'device', 'mntpoint', 'isMounted', 'real_mntpoint'));
+ if ($part->{isMounted} && $part->{real_mntpoint} && $part->{mntpoint}) {
+ log::l("remounting partition on " . fs::get::mntpoint_prefixed($part) . " instead of $part->{real_mntpoint}");
+ if ($::isInstall) { #- ensure partition will not be busy.
+ require install_any;
+ install_any::getFile('XXX');
+ }
+ eval {
+ umount($part->{real_mntpoint});
+ rmdir $part->{real_mntpoint};
+ symlinkf fs::get::mntpoint_prefixed($part), $part->{real_mntpoint};
+ delete $part->{real_mntpoint};
+ $part->{isMounted} = 0;
+ };
+ }
+
+ return if $part->{isMounted};
+
+ unless ($::testing) {
+ if (isSwap($part)) {
+ $o_wait_message->(N("Enabling swap partition %s", $part->{device})) if $o_wait_message;
+ swapon($part->{device});
+ } else {
+ $part->{mntpoint} or die "missing mount point for partition $part->{device}";
+
+ my $mntpoint = fs::get::mntpoint_prefixed($part);
+ if (isLoopback($part) || $part->{encrypt_key}) {
+ set_loop($part);
+ } elsif ($part->{options} =~ /encrypted/) {
+ log::l("skip mounting $part->{device} since we do not have the encrypt_key");
+ return;
+ } elsif (fs::type::carry_root_loopback($part)) {
+ $mntpoint = "/initrd/loopfs";
+ }
+ my $dev = $part->{real_device} || fs::wild_device::from_part('', $part);
+ mount($dev, $mntpoint, $part->{fs_type}, $b_rdonly, $part->{options}, $o_wait_message);
+ }
+ }
+ $part->{isMounted} = 1;
+ set_isFormatted($part, 1); #- assume that if mount works, partition is formatted
+}
+
+sub umount_part {
+ my ($part) = @_;
+
+ $part->{isMounted} || $part->{real_mntpoint} or return;
+
+ unless ($::testing) {
+ if (isSwap($part)) {
+ swapoff($part->{device});
+ } elsif (fs::type::carry_root_loopback($part)) {
+ umount("/initrd/loopfs");
+ } else {
+ umount(fs::get::mntpoint_prefixed($part) || devices::make($part->{device}));
+ devices::del_loop(delete $part->{real_device}) if $part->{real_device};
+ }
+ }
+ $part->{isMounted} = 0;
+}
+
+sub umount_all {
+ my ($fstab) = @_;
+
+ log::l("unmounting all filesystems");
+
+ foreach (sort { $b->{mntpoint} cmp $a->{mntpoint} } @$fstab) {
+ $_->{mntpoint} and umount_part($_);
+ }
+}
+
+sub usbfs {
+ my ($prefix) = @_;
+
+ my $fs = cat_('/proc/filesystems') =~ /usbfs/ ? 'usbfs' : 'usbdevfs';
+ mount('none', "$prefix/proc/bus/usb", $fs);
+}
+
+1;
diff --git a/perl-install/fs/type.pm b/perl-install/fs/type.pm
index 51b0e8503..1d036d7bb 100644
--- a/perl-install/fs/type.pm
+++ b/perl-install/fs/type.pm
@@ -380,3 +380,8 @@ sub guessed_by_mount() {
sub directories_needed_to_boot() {
qw(/ /usr /var /boot /tmp);
}
+
+sub carry_root_loopback {
+ my ($part) = @_;
+ any { $_->{mntpoint} eq '/' } @{$part->{loopback} || []};
+}
diff --git a/perl-install/fs/wild_device.pm b/perl-install/fs/wild_device.pm
new file mode 100644
index 000000000..8fd38b0ce
--- /dev/null
+++ b/perl-install/fs/wild_device.pm
@@ -0,0 +1,101 @@
+package fs::wild_device; # $Id$
+
+use diagnostics;
+use strict;
+
+use common;
+
+
+sub analyze {
+ my ($dev) = @_;
+
+ if ($dev =~ m!^/u?dev/(.*)!) {
+ 'dev', $dev;
+ } elsif ($dev !~ m!^/! && (-e "/dev/$dev" || -e "$::prefix/dev/$dev")) {
+ 'dev', "/dev/$dev";
+ } elsif ($dev =~ /^LABEL=(.*)/) {
+ 'label', $1;
+ } elsif ($dev eq 'none' || $dev eq 'rootfs') {
+ 'virtual';
+ } elsif ($dev =~ m!^(\S+):/\w!) {
+ 'nfs';
+ } elsif ($dev =~ m!^//\w!) {
+ 'smb';
+ } elsif ($dev =~ m!^http://!) {
+ 'dav';
+ }
+}
+
+sub to_subpart {
+ my ($dev) = @_;
+
+ my $part = { device => $dev, faked_device => 1 }; #- default
+
+ if (my ($kind, $val) = analyze($dev)) {
+ if ($kind eq 'label') {
+ $part->{device_LABEL} = $val;
+ } elsif ($kind eq 'dev') {
+ my %part = (faked_device => 0);
+ if (my $rdev = (stat "$::prefix$dev")[6]) {
+ ($part{major}, $part{minor}) = unmakedev($rdev);
+ }
+
+ my $symlink = readlink("$::prefix$dev");
+ $dev =~ s!/u?dev/!!;
+
+ if ($symlink && $symlink =~ m|^[^/]+$|) {
+ $part{device_alias} = $dev;
+ $dev = $symlink;
+ }
+
+ if (my (undef, $part_number) = $dev =~ m!/(disc|part(\d+))$!) {
+ $part{part_number} = $part_number if $part_number;
+ $part{devfs_device} = $dev;
+ } else {
+ my $part_number = devices::part_number(\%part);
+ $part{part_number} = $part_number if $part_number;
+ }
+ $part{device} = $dev;
+ return \%part;
+ }
+ } else {
+ if ($dev =~ m!^/! && -f "$::prefix$dev") {
+ #- it must be a loopback file or directory to bind
+ } else {
+ log::l("part_from_wild_device_name: unknown device $dev");
+ }
+ }
+ $part;
+}
+
+sub from_part {
+ my ($prefix, $part) = @_;
+
+ if ($part->{prefer_device_LABEL}) {
+ 'LABEL=' . $part->{device_LABEL};
+ } elsif ($part->{prefer_devfs_name}) {
+ "/dev/$part->{devfs_device}";
+ } elsif ($part->{device_alias}) {
+ "/dev/$part->{device_alias}";
+ } else {
+ my $faked_device = exists $part->{faked_device} ?
+ $part->{faked_device} :
+ do {
+ #- in case $part has been created without using fs::wild_device::to_subpart()
+ my ($kind) = analyze($part->{device});
+ $kind ? $kind ne 'dev' : $part->{device} =~ m!^/!;
+ };
+ if ($faked_device) {
+ $part->{device};
+ } elsif ($part->{device} =~ m!^/dev/!) {
+ log::l("ERROR: i have a full device $part->{device}, this should not happen. use fs::wild_device::to_subpart() instead of creating bad part data-structures!");
+ $part->{device};
+ } else {
+ my $dev = "/dev/$part->{device}";
+ eval { devices::make("$prefix$dev") };
+ $dev;
+ }
+ }
+}
+
+1;