diff options
Diffstat (limited to 'perl-install/fs')
-rw-r--r-- | perl-install/fs/dmraid.pm | 3 | ||||
-rw-r--r-- | perl-install/fs/format.pm | 42 | ||||
-rw-r--r-- | perl-install/fs/get.pm | 10 | ||||
-rw-r--r-- | perl-install/fs/loopback.pm | 28 | ||||
-rw-r--r-- | perl-install/fs/mount.pm | 197 | ||||
-rw-r--r-- | perl-install/fs/type.pm | 5 | ||||
-rw-r--r-- | perl-install/fs/wild_device.pm | 101 |
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; |