diff options
Diffstat (limited to 'perl-install/fsedit.pm')
| -rw-r--r-- | perl-install/fsedit.pm | 174 | 
1 files changed, 122 insertions, 52 deletions
| diff --git a/perl-install/fsedit.pm b/perl-install/fsedit.pm index 25d6ce9e5..d209b0196 100644 --- a/perl-install/fsedit.pm +++ b/perl-install/fsedit.pm @@ -1,8 +1,9 @@ -package fsedit; # $Id$ +package fsedit;  use diagnostics;  use strict;  use vars qw(%suggestions); +use feature 'state';  #-######################################################################################  #- misc imports @@ -19,34 +20,56 @@ use devices;  use log;  use fs; +# min_hd_size: only suggest this partition if the hd size is bigger than that  %suggestions = (    N_("simple") => [ -    { mntpoint => "/",     size => MB(300), fs_type => 'ext3', ratio => 20, maxsize => MB(8000) }, -    { mntpoint => "swap",  size => MB(128), fs_type => 'swap', ratio => 1,  maxsize => MB(4000) }, -    { mntpoint => "/home", size => MB(300), fs_type => 'ext3', ratio => 3,  min_hd_size => MB(7000) }, +    { mntpoint => "/",     size => MB(300), fs_type => defaultFS(), ratio => 6, maxsize => MB(51500) }, +    { mntpoint => "swap",  size => MB(256), fs_type => 'swap', ratio => 1, maxsize => MB(4096) }, +    { mntpoint => "/home", size => MB(300), fs_type => defaultFS(), ratio => 12, min_hd_size => MB(51200) },    ], N_("with /usr") => [ -    { mntpoint => "/",     size => MB(250), fs_type => 'ext3', ratio => 1, maxsize => MB(8000) }, +    { mntpoint => "/",     size => MB(250), fs_type => defaultFS(), ratio => 1, maxsize => MB(8000) },      { mntpoint => "swap",  size =>  MB(64), fs_type => 'swap', ratio => 1, maxsize => MB(4000) }, -    { mntpoint => "/usr",  size => MB(300), fs_type => 'ext3', ratio => 4, maxsize => MB(8000) }, -    { mntpoint => "/home", size => MB(100), fs_type => 'ext3', ratio => 3, min_hd_size => MB(7000) }, +    { mntpoint => "/usr",  size => MB(300), fs_type => defaultFS(), ratio => 4, maxsize => MB(8000) }, +    { mntpoint => "/home", size => MB(100), fs_type => defaultFS(), ratio => 3, min_hd_size => MB(10000) },    ], N_("server") => [ -    { mntpoint => "/",     size => MB(150), fs_type => 'ext3', ratio => 1, maxsize => MB(8000) }, +    { mntpoint => "/",     size => MB(150), fs_type => defaultFS(), ratio => 1, maxsize => MB(8000) },      { mntpoint => "swap",  size =>  MB(64), fs_type => 'swap', ratio => 2, maxsize => MB(4000) }, -    { mntpoint => "/usr",  size => MB(300), fs_type => 'ext3', ratio => 4, maxsize => MB(8000) }, -    { mntpoint => "/var",  size => MB(200), fs_type => 'ext3', ratio => 3 }, -    { mntpoint => "/home", size => MB(150), fs_type => 'ext3', ratio => 3, min_hd_size => MB(7000) }, -    { mntpoint => "/tmp",  size => MB(150), fs_type => 'ext3', ratio => 2, maxsize => MB(4000) }, +    { mntpoint => "/usr",  size => MB(300), fs_type => defaultFS(), ratio => 4, maxsize => MB(8000) }, +    { mntpoint => "/var",  size => MB(200), fs_type => defaultFS(), ratio => 3 }, +    { mntpoint => "/home", size => MB(150), fs_type => defaultFS(), ratio => 3, min_hd_size => MB(10000) }, +    { mntpoint => "/tmp",  size => MB(150), fs_type => defaultFS(), ratio => 2, maxsize => MB(4000) },    ],  ); -foreach (values %suggestions) { -    if (arch() =~ /ia64/) { -	@$_ = ({ mntpoint => "/boot/efi", size => MB(50), pt_type => 0xef, ratio => 1, maxsize => MB(150) }, @$_); +my %bck_suggestions = %suggestions; + +sub init_mntpnt_suggestions { +    my ($all_hds, $o_target, $o_force) = @_; + +    my $device = $o_target ? $o_target->{device} : 'all'; +    state $last_device; +    return if $device eq $last_device && !$o_force; +    $last_device = $device; + +    #- If installing on a removable device, assume that the user wants that device to be self-bootable. +    my $is_removable = $o_target && $o_target->{is_removable}; +    my @fstab = $is_removable ? partition_table::get_normal_parts($o_target) : fs::get::fstab($all_hds); + +    my $mntpoint; +    # only suggests /boot/EFI if there's not already one: +    require fs::any; +    if (is_uefi()) { +	if (!any { isESP($_) } @fstab) { +	    $mntpoint = { mntpoint => "/boot/EFI", size => MB(100), pt_type => 0xef, ratio => 1, maxsize => MB(300) }; +	} +    } +    foreach (keys %suggestions) { +	$suggestions{$_} = [ if_($mntpoint, $mntpoint), @{$bck_suggestions{$_}} ];      }  }  my @suggestions_mntpoints = (      "/var/ftp", "/var/www", "/boot", '/usr/local', '/opt', -    arch() =~ /sparc/ ? "/mnt/sunos" : arch() =~ /ppc/ ? "/mnt/macos" : "/mnt/windows", +   "/mnt/windows",  );  #-###################################################################################### @@ -59,11 +82,11 @@ sub recompute_loopbacks {  }  sub raids { -    my ($hds) = @_; +    my ($hds, $raw_hds) = @_;      my @parts = fs::get::hds_fstab(@$hds); -    my @l = grep { isRawRAID($_) } @parts or return []; +    my @l = grep { isRawRAID($_) } ( @parts, @$raw_hds ) or return [];      log::l("looking for raids in " . join(' ', map { $_->{device} } @l)); @@ -174,6 +197,20 @@ sub get_hds {      foreach my $hd (@drives) {  	$hd->{readonly} = $flags->{readonly}; +	#- We only create RAID components in disk partitions, but users may have used +	#- mdadm directly to create them on raw disk devices. Detect that now, before +	#- looking for a partition table (which is likely to fail badly - mga#26707). +	if (my $type = fs::type::type_subpart_from_magic($hd)) { +	    if (isRawRAID($type)) { +		#- Add the necessary information to the raw device to allow the RAID +		#- array to be properly characterised in diskdrake. +		put_in_hash($hd, $type); +		$hd->{size} = $hd->{totalsectors}; +		push @raw_hds, $hd; +		next; +	    } +	} +  	eval { partition_table::raw::test_for_bad_drives($hd) if !$flags->{no_bad_drives} };  	if (my $err = $@) {  	    log::l("test_for_bad_drives returned $err"); @@ -190,7 +227,7 @@ sub get_hds {  	if ($flags->{clearall} || member($hd->{device}, @{$flags->{clear} || []})) {  	    my $lvms = []; #- temporary one, will be re-created later in get_hds() -	    partition_table_initialize($lvms, $hd, $o_in); +	    partition_table_clear_and_initialize($lvms, $hd, $o_in);  	} else {  	    my $handle_die_and_cdie = sub {  		if (my $type = fs::type::type_subpart_from_magic($hd)) { @@ -225,7 +262,7 @@ sub get_hds {  				die sprintf(q(bad dmraid (missing partition %s), you may try rebooting install with option "nodmraid"), $p->{device});  			    }  			} else { -			    fs::proc_partitions::compare($hd) if !detect_devices::is_xbox() && arch() ne 'ppc'; +			    fs::proc_partitions::compare($hd) if !detect_devices::is_xbox();  			}  		    }  		} sub { @@ -243,7 +280,7 @@ sub get_hds {  		    #- already handled in cdie handler above  		} elsif ($handle_die_and_cdie->()) {  		} elsif ($o_in && $o_in->ask_yesorno(N("Error"),  -N("I can not read the partition table of device %s, it's too corrupted for me :( +N("I cannot read the partition table of device %s, it's too corrupted for me :(  I can try to go on, erasing over bad partitions (ALL DATA will be lost!).  The other solution is to not allow DrakX to modify the partition table.  (the error is %s) @@ -265,6 +302,9 @@ Do you agree to lose all the partitions?  	my @parts = partition_table::get_normal_parts($hd); +	# fix installer failures due to udev's race when run too early: +	run_program::run('udevadm', 'settle'); +  	# checking the magic of the filesystem, do not rely on pt_type  	foreach (@parts) {  	    if (my $type = fs::type::type_subpart_from_magic($_)) { @@ -284,7 +324,7 @@ Do you agree to lose all the partitions?      }      #- detect raids before LVM allowing LVM on raid -    my $raids = raids(\@hds); +    my $raids = raids(\@hds, \@raw_hds);      my $all_hds = { %{ fs::get::empty_all_hds() }, hds => \@hds, raw_hds => \@raw_hds, lvms => [], raids => $raids };      $all_hds->{lvms} = [ lvms($all_hds) ]; @@ -293,6 +333,8 @@ Do you agree to lose all the partitions?      # must be done after getting major/minor      $all_hds->{dmcrypts} = [ dmcrypts($all_hds) ]; +    # allow lvm on dmcrypt +    $all_hds->{lvms} = [ lvms($all_hds) ];      $_->{faked_device} = 0 foreach fs::get::fstab($all_hds); @@ -318,7 +360,7 @@ sub is_one_big_fat_or_NT {  sub computeSize { -    my ($part, $best, $all_hds, $suggestions) = @_; +    my ($part, $best, $all_hds, $suggestions, $o_target) = @_;      my $max = $part->{maxsize} || $part->{size};      return min($max, $best->{size}) unless $best->{ratio}; @@ -333,7 +375,7 @@ sub computeSize {  	    1;  	} else { 0 } } @$suggestions; -    my $free_space = $best->{hd} && $free_space{$best->{hd}} || sum(values %free_space); +    my $free_space = $o_target && $free_space{$o_target->{device}} || $best->{hd} && $free_space{$best->{hd}} || sum(values %free_space);      my $cylinder_size_maxsize_adjusted;      my $tot_ratios = 0; @@ -364,7 +406,7 @@ sub computeSize {  }  sub suggest_part { -    my ($part, $all_hds, $o_suggestions) = @_; +    my ($part, $all_hds, $o_suggestions, $o_target) = @_;      my $suggestions = $o_suggestions || $suggestions{server} || $suggestions{simple};      #- suggestions now use {fs_type}, but still keep compatibility @@ -374,10 +416,11 @@ sub suggest_part {      my $hd = fs::get::part2hd($part, $all_hds);      my $hd_size = $hd && $hd->{totalsectors}; # nb: no $hd if $part is /dev/mdX -    my $has_swap = any { isSwap($_) } fs::get::fstab($all_hds); +    my @fstab = $hd->{is_removable} ? partition_table::get_normal_parts($hd) : fs::get::fstab($all_hds); +    my $has_swap = any { isSwap($_) } @fstab;      my @local_suggestions = -      grep { !$_->{mntpoint} && !$_->{VG_name} || !fs::get::has_mntpoint($_->{mntpoint}, $all_hds) || isSwap($_) && !$has_swap } +      grep { $::auto_install || !$_->{mntpoint} && !$_->{VG_name} || !fs::get::has_mntpoint($_->{mntpoint}, $all_hds) || isSwap($_) && !$has_swap }        grep { !$_->{min_hd_size} || !$hd_size || $_->{min_hd_size} <= $hd_size }        grep { !$_->{hd} || $_->{hd} eq $part->{rootDevice} }  	@$suggestions; @@ -401,7 +444,7 @@ sub suggest_part {      $part->{mntpoint} = $best->{mntpoint};      fs::type::set_type_subpart($part, $best) if !isTrueFS($best) || !isTrueFS($part); -    $part->{size} = computeSize($part, $best, $all_hds, \@local_suggestions); +    $part->{size} = computeSize($part, $best, $all_hds, \@local_suggestions, $o_target);      foreach ('options', 'lv_name', 'encrypt_key', 'primaryOrExtended',  	     'device_LABEL', 'prefer_device_LABEL', 'device_UUID', 'prefer_device_UUID', 'prefer_device') {  	$part->{$_} = $best->{$_} if $best->{$_}; @@ -425,29 +468,25 @@ sub check_mntpoint {      $mntpoint =~ m|[\x7f-\xff]| and cdie N("Mount points should contain only alphanumerical characters");      fs::get::mntpoint2part($mntpoint, [ grep { $_ ne $part } fs::get::really_all_fstab($all_hds) ]) and die N("There is already a partition with mount point %s\n", $mntpoint); -    if ($mntpoint eq "/" && isRAID($part) && !fs::get::has_mntpoint("/boot", $all_hds)) { -	my $md_part = fs::get::device2part($part->{raid}, $all_hds->{raids}); -	cdie N("You've selected a software RAID partition as root (/). +    if ($mntpoint eq "/" && (isLUKS($part) || isRawLUKS($part)) && !fs::get::has_mntpoint("/boot", $all_hds)) { +	cdie N("You've selected an encrypted partition as root (/).  No bootloader is able to handle this without a /boot partition. -Please be sure to add a /boot partition") if $md_part->{level} ne '1'; # lilo handles / on RAID1 +Please be sure to add a separate /boot partition");      } -    #- NB: if the LV doesn't exist, lv_nb_pvs returns 0 -    die N("You can not use the LVM Logical Volume for mount point %s since it spans physical volumes", $mntpoint) -      if $mntpoint eq '/boot' && isLVM($part) && lvm::lv_nb_pvs($part) > 1; -    cdie N("You've selected the LVM Logical Volume as root (/). -The bootloader is not able to handle this when the volume spans physical volumes. -You should create a /boot partition first") if $mntpoint eq "/" && isLVM($part) && lvm::lv_nb_pvs($part) != 1 && !fs::get::has_mntpoint("/boot", $all_hds); +    if ($mntpoint eq "/boot" && (isLUKS($part) || isRawLUKS($part)))  { +	die N("You cannot use an encrypted filesystem for mount point %s", "/boot"); +    }      cdie N("This directory should remain within the root filesystem")        if member($mntpoint, qw(/root));      die N("This directory should remain within the root filesystem")        if member($mntpoint, qw(/bin /dev /etc /lib /sbin /mnt /media)); -    die N("You need a true filesystem (ext2/ext3, reiserfs, xfs, or jfs) for this mount point\n") +    die N("You need a true filesystem (ext2/3/4, reiserfs, xfs, or jfs) for this mount point\n")        if !isTrueLocalFS($part) && $mntpoint eq '/'; -    die N("You need a true filesystem (ext2/ext3, reiserfs, xfs, or jfs) for this mount point\n") -      if !isTrueFS($part) && member($mntpoint, '/home', fs::type::directories_needed_to_boot()); -    die N("You can not use an encrypted file system for mount point %s", $mntpoint) +    die N("You need a true filesystem (ext2/3/4, reiserfs, xfs, or jfs) for this mount point\n") . $mntpoint +      if !isTrueFS($part) && member($mntpoint, '/home', fs::type::directories_needed_to_boot_not_ESP()); +    die N("You cannot use an encrypted filesystem for mount point %s", $mntpoint)        if $part->{options} =~ /encrypted/ && member($mntpoint, qw(/ /usr /var /boot));      local $part->{mntpoint} = $mntpoint; @@ -472,15 +511,16 @@ sub add {  }  sub allocatePartitions { -    my ($all_hds, $to_add) = @_; +    my ($all_hds, $to_add, $o_hd) = @_;      my @to_add = @$to_add;      foreach my $part_ (fs::get::holes($all_hds, 'non_readonly')) {  	my ($start, $size, $dev) = @$part_{"start", "size", "rootDevice"}; +	next if $o_hd && (($o_hd->{device} || $o_hd->{VG_name}) ne $dev);  	my ($part, $suggested);  	while ($suggested = suggest_part($part = { start => $start, size => 0, maxsize => $size, rootDevice => $dev },  -					 $all_hds, \@to_add)) { +					 $all_hds, \@to_add, $o_hd)) {  	    my $hd = fs::get::part2hd($part, $all_hds);  	    add($hd, $part, $all_hds, { primaryOrExtended => $part->{primaryOrExtended} });  	    $size -= $part->{size} + $part->{start} - $start; @@ -491,11 +531,18 @@ sub allocatePartitions {  }  sub auto_allocate { -    my ($all_hds, $o_suggestions) = @_; +    my ($all_hds, $o_suggestions, $o_target) = @_;      my $before = listlength(fs::get::fstab($all_hds)); +    #- Make sure we don't finish with more than one /boot/EFI mount point +    if (is_uefi()) { +        delete $_->{mntpoint} foreach grep { $_->{mntpoint} eq '/boot/EFI' } fs::get::fstab($all_hds); +    } + +    auto_allocate_bios_boot_parts($all_hds, $o_target) if !is_uefi(); +      my $suggestions = $o_suggestions || $suggestions{simple}; -    allocatePartitions($all_hds, $suggestions); +    allocatePartitions($all_hds, $suggestions, $o_target);      if ($o_suggestions) {  	auto_allocate_raids($all_hds, $suggestions); @@ -517,6 +564,28 @@ sub auto_allocate {  	    die N("Nothing to do");  	}      } + +    #- Don't suggest mount points on other drives when installing on a removable disk +    return if $o_target && $o_target->{is_removable}; + +    my @fstab = fs::get::fstab($all_hds); +    fs::mount_point::suggest_mount_points_always(\@fstab); +} + +sub auto_allocate_bios_boot_parts { +    my ($all_hds, $o_hd) = @_; +    foreach my $hd (@{$all_hds->{hds}}) { +	# skip if not the selected device +	next if $o_hd && ($o_hd->{device} ne $hd->{device}); +	# skip non-GPT disks +	next if ($hd->{pt_table_type} || partition_table::default_type($hd)) ne 'gpt'; +	# check if a BIOS boot partition already exists +	my @parts = map { partition_table::get_normal_parts($_) } $hd; +	next if any { isBIOS_GRUB($_) } @parts; +	# try to allocate a BIOS boot partition +	my $suggest = { mntpoint => "", size => MB(1), pt_type => 'BIOS_GRUB', ratio => 1, maxsize => MB(2) }; +	allocatePartitions($all_hds, [ $suggest ], $hd); +    }  }  sub auto_allocate_raids { @@ -585,14 +654,15 @@ sub change_type {      1;  } +=item partition_table_clear_and_initialize($lvms, $hd, $o_in, $o_type, $b_warn) = @_; + +wrapper around partition_table::initialize() but which also create a singleton VG +automatically (so that it's easier for the user) + +=cut +  sub partition_table_clear_and_initialize {      my ($lvms, $hd, $o_in, $o_type, $b_warn) = @_; -    $hd->clear_existing; -    partition_table_initialize($lvms, $hd, $o_in, $o_type, $b_warn); -} - -sub partition_table_initialize { -    my ($lvms, $hd, $o_in, $b_warn, $o_type) = @_;      partition_table::initialize($hd, $o_type);      if ($hd->isa('partition_table::lvm')) {  	if ($b_warn && $o_in) { | 
