diff options
Diffstat (limited to 'perl-install/fsedit.pm')
| -rw-r--r-- | perl-install/fsedit.pm | 926 | 
1 files changed, 405 insertions, 521 deletions
| diff --git a/perl-install/fsedit.pm b/perl-install/fsedit.pm index bd5597d7e..d209b0196 100644 --- a/perl-install/fsedit.pm +++ b/perl-install/fsedit.pm @@ -1,153 +1,134 @@ -package fsedit; # $Id$ +package fsedit;  use diagnostics;  use strict;  use vars qw(%suggestions); +use feature 'state';  #-######################################################################################  #- misc imports  #-######################################################################################  use common; -use partition_table qw(:types); +use partition_table;  use partition_table::raw; +use fs::get; +use fs::type; +use fs::loopback; +use fs::proc_partitions;  use detect_devices; -use fsedit;  use devices; -use loopback;  use log;  use fs; +# min_hd_size: only suggest this partition if the hd size is bigger than that  %suggestions = (    N_("simple") => [ -    { mntpoint => "/",     size => 300 << 11, type =>0x483, ratio => 5, maxsize => 5500 << 11 }, -    { mntpoint => "swap",  size =>  64 << 11, type => 0x82, ratio => 1, maxsize =>  250 << 11 }, -    { mntpoint => "/home", size => 300 << 11, type =>0x483, ratio => 3 }, +    { 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 => 150 << 11, type =>0x483, ratio => 1, maxsize => 1000 << 11 }, -    { mntpoint => "swap",  size =>  64 << 11, type => 0x82, ratio => 1, maxsize =>  250 << 11 }, -    { mntpoint => "/usr",  size => 300 << 11, type =>0x483, ratio => 4, maxsize => 4000 << 11 }, -    { mntpoint => "/home", size => 100 << 11, type =>0x483, ratio => 3 }, +    { 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 => 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 => 150 << 11, type =>0x483, ratio => 1, maxsize =>  250 << 11 }, -    { mntpoint => "swap",  size =>  64 << 11, type => 0x82, ratio => 2, maxsize =>  400 << 11 }, -    { mntpoint => "/usr",  size => 300 << 11, type =>0x483, ratio => 4, maxsize => 4000 << 11 }, -    { mntpoint => "/var",  size => 150 << 11, type =>0x483, ratio => 3 }, -    { mntpoint => "/home", size => 150 << 11, type =>0x483, ratio => 3 }, -    { mntpoint => "/tmp",  size => 150 << 11, type =>0x483, ratio => 2, maxsize =>  500 << 11 }, +    { 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 => 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 => 50 << 11, type => 0xb, ratio => 1, maxsize => 150 << 11 }, @$_); +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", -    arch() =~ /sparc/ ? "/mnt/sunos" : arch() =~ /ppc/ ? "/mnt/macos" : "/mnt/windows", -    #- RedHat also has /usr/local and /opt -); - -my @partitions_signatures = ( -    [ 0x8e, 0, "HM\1\0" ], -    [ 0x83, 0x438, "\x53\xEF" ], -    [ 0x183, 0x10034, "ReIsErFs" ], -    [ 0x183, 0x10034, "ReIsEr2Fs" ], -    [ 0x283, 0, 'XFSB', 0x200, 'XAGF', 0x400, 'XAGI' ], -    [ 0x383, 0x8000, 'JFS1' ], -    [ 0x82, 4086, "SWAP-SPACE" ], -    [ 0x82, 4086, "SWAPSPACE2" ], -    [ 0x7,  0x1FE, "\x55\xAA", 0x3, "NTFS" ], -    [ 0xc,  0x1FE, "\x55\xAA", 0x52, "FAT32" ], -if_(arch() !~ /^sparc/, -    [ 0x6,  0x1FE, "\x55\xAA", 0x36, "FAT" ], -), +    "/var/ftp", "/var/www", "/boot", '/usr/local', '/opt', +   "/mnt/windows",  ); -sub typeOfPart {  -    my $dev = devices::make($_[0]); -    my $t = typeFromMagic($dev, @partitions_signatures); -    if ($t == 0x83) { -	#- there is no magic to differentiate ext3 and ext2. Using libext2fs -	#- to check if it has a journal -	$t = 0x483 if c::is_ext3($dev); -    } -    $t; -} -  #-######################################################################################  #- Functions  #-###################################################################################### -sub empty_all_hds { -    { hds => [], lvms => [], raids => [], loopbacks => [], raw_hds => [], nfss => [], smbs => [], davs => [], special => [] }; -}  sub recompute_loopbacks {      my ($all_hds) = @_; -    my @fstab = get_all_fstab($all_hds); +    my @fstab = fs::get::fstab($all_hds);      @{$all_hds->{loopbacks}} = map { isPartOfLoopback($_) ? @{$_->{loopback}} : () } @fstab;  }  sub raids { -    my ($hds) = @_; +    my ($hds, $raw_hds) = @_; -    my @parts = get_fstab(@$hds); -    { -	my @l = grep { isRawRAID($_) } @parts or return []; -	detect_devices::raidAutoStart(@l); -    } +    my @parts = fs::get::hds_fstab(@$hds); -    fs::get_major_minor(@parts); -    my %devname2part = map { $_->{dev} => { %$_, device => $_->{dev} } } read_proc_partitions_raw(); - -    my @raids; -    my @mdstat = cat_("/proc/mdstat"); -    for (my $i = 0; $i < @mdstat; $i++) { - -	my ($nb, $level, $mdparts) =  -	  #- line format is: -	  #- md%d : {in}?active{ (read-only)}? {linear|raid1|raid4|raid5}{ DEVNAME[%d]{(F)}?}* -	  $mdstat[$i] =~ /^md(.).* ([^ \[\]]+) (\S+\[\d+\].*)/ or next; - -	$level =~ s/raid//; #- { linear | raid0 | raid1 | raid5 } -> { linear | 0 | 1 | 5 } - -	my $chunks = $mdstat[$i+1] =~ /(\S+) chunks/ ? $1 : "64k"; - -	my @raw_mdparts = map { /([^\[]+)/ } split ' ', $mdparts; -	my @mdparts =  -	  map {  -	      my $mdpart = $devname2part{$_} || { device => $_ }; -	      if (my ($part) = grep { is_same_hd($mdpart, $_) } @parts) { -		  $part->{raid} = $nb; -		  delete $part->{mntpoint}; -		  $part; -	      } else { -		  #- forget it when not found? that way it won't break much... beurk. -		  (); -	      } -	  } @raw_mdparts; - -	my $type = typeOfPart("md$nb"); -	log::l("RAID: found md$nb (raid $level) chunks $chunks ", if_($type, "type $type "), "with parts ", join(", ", @raw_mdparts)); -	$raids[$nb] = { 'chunk-size' => $chunks, type => $type || 0x83, disks => \@mdparts, -			device => "md$nb", notFormatted => !$type, level => $level }; -    } +    my @l = grep { isRawRAID($_) } ( @parts, @$raw_hds ) or return []; + +    log::l("looking for raids in " . join(' ', map { $_->{device} } @l)); +          require raid; -    raid::update(@raids); -    \@raids; +    raid::detect_during_install(@l) if $::isInstall; +    raid::get_existing(@l); +} + +sub dmcrypts { +    my ($all_hds) = @_; + +    my @parts = fs::get::fstab($all_hds); + +    my @l = grep { fs::type::isRawLUKS($_) } @parts or return; + +    log::l("using dm-crypt from " . join(' ', map { $_->{device} } @l)); +     +    require fs::dmcrypt; +    fs::dmcrypt::read_crypttab($all_hds); + +    fs::dmcrypt::get_existing(@l);  }  sub lvms {      my ($all_hds) = @_; -    my @pvs = grep { isRawLVM($_) } get_all_fstab($all_hds) or return; +    my @pvs = grep { isRawLVM($_) } fs::get::fstab($all_hds) or return; +    scan_pvs(@pvs); +} + +sub scan_pvs { +    my (@pvs) = @_; + +    log::l("looking for vgs in " . join(' ', map { $_->{device} } @pvs)); -    #- otherwise vgscan won't find them +    #- otherwise vgscan will not find them      devices::make($_->{device}) foreach @pvs;       require lvm;      my @lvms;      foreach (@pvs) { -	my $name = lvm::get_vg($_) or next; -	my ($lvm) = grep { $_->{VG_name} eq $name } @lvms; +	my $name = lvm::pv_to_vg($_) or next; +	my $lvm = find { $_->{VG_name} eq $name } @lvms;  	if (!$lvm) {  	    $lvm = new lvm($name);  	    lvm::update_size($lvm); @@ -160,274 +141,243 @@ sub lvms {      @lvms;  } -sub hds { -    my ($flags, $ask_before_blanking) = @_; -    $flags ||= {}; +sub handle_dmraid { +    my ($drives, $o_in) = @_; + +    @$drives > 1 or return; + +    devices::make($_->{device}) foreach @$drives; + +    require fs::dmraid;  +    eval { fs::dmraid::init() } or log::l("dmraid::init failed"), return; + +    my @vgs = fs::dmraid::vgs(); +    log::l(sprintf('dmraid: ' . join(' ', map { "$_->{device} [" . join(' ', @{$_->{disks}}) . "]" } @vgs))); + +    if ($o_in && @vgs && $::isInstall) { +	@vgs = grep { +	    $o_in->ask_yesorno('', N("BIOS software RAID detected on disks %s. Activate it?", join(' ', @{$_->{disks}})), 1); +	} @vgs or do { +	    fs::dmraid::call_dmraid('-an'); +	    return; +	}; +    } +    if (!$::isInstall) { +	fs::dmraid::migrate_device_names($_) foreach @vgs; +    } +    log::l("using dmraid on " . join(' ', map { $_->{device} } @vgs)); + +    my @used_hds = map { +	my $part = fs::get::device2part($_, $drives) or log::l("handle_dmraid: can't find $_ in known drives"); +	if_($part, $part); +    } map { @{$_->{disks}} } @vgs; + +    @$drives = difference2($drives, \@used_hds); + +    push @$drives, @vgs; +} + +sub get_hds { +    my ($o_flags, $o_in) = @_; +    my $flags = $o_flags || {};      $flags->{readonly} && ($flags->{clearall} || $flags->{clear}) and die "conflicting flags readonly and clear/clearall";      my @drives = detect_devices::hds(); -    my (@hds); +    #- replace drives used in dmraid by the merged name +    handle_dmraid(\@drives, $o_in) if !$flags->{nodmraid}; +      foreach my $hd (@drives) {  	$hd->{file} = devices::make($hd->{device}); -	$hd->{prefix} ||= $hd->{device}; +    } + +    @drives = partition_table::raw::get_geometries(@drives); + +    my (@hds, @raw_hds); +    foreach my $hd (@drives) {  	$hd->{readonly} = $flags->{readonly}; -	my $h = partition_table::raw::get_geometry($hd->{file}) or log::l("An error occurred while getting the geometry of block device $hd->{file}: $!"), next; -	add2hash_($hd, $h); +	#- 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 $::isInstall }; +	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");  	    if ($err =~ /write error:/) {  +		log::l("setting $hd->{device} readonly");  		$hd->{readonly} = 1; +	    } elsif ($err =~ /read error:/) { +		next;  	    } else { -		cdie $err if $err !~ /read error:/; +		$o_in and $o_in->ask_warn('', $err);  		next;  	    }  	}  	if ($flags->{clearall} || member($hd->{device}, @{$flags->{clear} || []})) { -	    partition_table::raw::zero_MBR_and_dirty($hd); +	    my $lvms = []; #- temporary one, will be re-created later in get_hds() +	    partition_table_clear_and_initialize($lvms, $hd, $o_in);  	} else { -	    eval {  -		partition_table::read($hd);  -		compare_with_proc_partitions($hd) if $::isInstall; +	    my $handle_die_and_cdie = sub { +		if (my $type = fs::type::type_subpart_from_magic($hd)) { +		    #- non partitioned drive? +		    if (exists $hd->{usb_description} && $type->{fs_type}) { +			#- USB keys +			put_in_hash($hd, $type); +			push @raw_hds, $hd; +			$hd = ''; +			1; +		    } else { +			0; +		    } +		} elsif ($hd->{readonly}) { +		    log::l("using /proc/partitions since diskdrake failed :("); +		    fs::proc_partitions::use_($hd); +		    1; +		} else { +		    0; +		} +	    }; +	    my $handled; +	    eval { +		catch_cdie { +		    partition_table::read($hd); +		    if (listlength(partition_table::get_normal_parts($hd)) == 0) { +			$handled = 1 if $handle_die_and_cdie->(); +		    } elsif ($::isInstall) { +			if (fs::type::is_dmraid($hd)) { +			    if (my $p = find { ! -e "/dev/$_->{device}" } partition_table::get_normal_parts($hd)) { +				#- dmraid should have created the device, so it means we don't agree +				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(); +			} +		    } +		} sub { +		    my $err = $@; +		    if ($handle_die_and_cdie->()) { +			$handled = 1; +			0; #- do not continue, transform cdie into die +		    } else { +			!$o_in || $o_in->ask_okcancel('', formatError($err)); +		    } +		};  	    };  	    if (my $err = $@) { -		if ($hd->{readonly}) { -		    use_proc_partitions($hd); -		} elsif ($ask_before_blanking && $ask_before_blanking->($hd->{device}, $err)) { +		if ($handled) { +		    #- already handled in cdie handler above +		} elsif ($handle_die_and_cdie->()) { +		} elsif ($o_in && $o_in->ask_yesorno(N("Error"),  +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) + +Do you agree to lose all the partitions? +", $hd->{device}, formatError($err)))) {  		    partition_table::raw::zero_MBR($hd);  		} else {  		    #- using it readonly -		    use_proc_partitions($hd); +		    log::l("using /proc/partitions since diskdrake failed :("); +		    fs::proc_partitions::use_($hd);  		}  	    } +	    $hd or next; +  	    member($_->{device}, @{$flags->{clear} || []}) and partition_table::remove($hd, $_)  	      foreach partition_table::get_normal_parts($hd);  	} -	# special case for Various type -	$_->{type} = typeOfPart($_->{device}) || 0x100 foreach grep { $_->{type} == 0x100 } partition_table::get_normal_parts($hd); +	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($_)) { +                $type->{pt_type} = $_->{pt_type}; #- keep {pt_type} +                put_in_hash($_, $type);  +	    } else { +		$_->{bad_fs_type_magic} = 1; +	    } +	} -	#- special case for type overloading (eg: reiserfs is 0x183) -	foreach (grep { isExt2($_) } partition_table::get_normal_parts($hd)) { -	    my $type = typeOfPart($_->{device}); -	    $_->{type} = $type if $type > 0x100 || $type && $hd->isa('partition_table::gpt'); +	if ($hd->{usb_media_type}) { +	    $hd->{is_removable} = 1; +	    $_->{is_removable} = 1 foreach @parts;  	} +  	push @hds, $hd;      }      #- detect raids before LVM allowing LVM on raid -    my $raids = raids(\@hds); -    my $all_hds = { %{ empty_all_hds() }, hds => \@hds, lvms => [], raids => $raids }; +    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) ]; -    fs::get_major_minor(get_all_fstab($all_hds)); - -    $all_hds; -} - -sub get_hds { -    #- $in is optional -    my ($flags, $in) = @_; - -    if ($in) { -	catch_cdie { hds($flags, sub { -	    my ($dev, $err) = @_; -            $in->ask_yesorno(N("Error"),  -N("I can't 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) - -Do you agree to loose all the partitions? -", $dev, formatError($err))); -        }) } sub { $in->ask_okcancel('', formatError($@)) }; -    } else { -	catch_cdie { hds($flags) } sub { 1 } -    } -} - -sub read_proc_partitions_raw() { -    my (undef, undef, @all) = cat_("/proc/partitions"); -    grep { -	$_->{size} != 1 &&	 # skip main extended partition -	$_->{size} != 0x3fffffff # skip cdroms (otherwise stops cd-audios) -    } map {  -	my %l;  -	@l{qw(major minor size dev)} = split;  -	\%l; -    } @all; -} - -sub read_proc_partitions { -    my ($hds) = @_; - -    my @all = read_proc_partitions_raw(); -    my @parts = grep { $_->{dev} =~ /\d$/ } @all; -    my @disks = grep { $_->{dev} !~ /\d$/ } @all; - -    my $devfs_like = grep { $_->{dev} =~ m|/disc$| } @disks; - -    my %devfs2normal = map { -	my (undef, $major, $minor) = devices::entry($_->{device}); -	my ($disk) = grep { $_->{major} == $major && $_->{minor} == $minor } @disks; -	$disk->{dev} => $_->{device}; -    } @$hds; +    fs::get_major_minor([ fs::get::fstab($all_hds) ]); -    my $prev_part; -    foreach my $part (@parts) { -	my $dev; -	if ($devfs_like) { -	    $dev = -e "/dev/$part->{dev}" ? $part->{dev} : sprintf("0x%x%02x", $part->{major}, $part->{minor}); -	    $part->{rootDevice} = $devfs2normal{dirname($part->{dev}) . '/disc'}; -	} else { -	    $dev = $part->{dev}; -	    foreach my $hd (@$hds) { -		$part->{rootDevice} = $hd->{device} if $part->{dev} =~ /^$hd->{device}./; -	    } -	} -	$part->{device} = $dev; -	$part->{size} *= 2;	# from KB to sectors -	$part->{type} = typeOfPart($dev);  -	$part->{start} = $prev_part ? $prev_part->{start} + $prev_part->{size} : 0; -	$prev_part = $part; -	delete $part->{dev}; # cleanup -    } -    @parts; -} +    # must be done after getting major/minor +    $all_hds->{dmcrypts} = [ dmcrypts($all_hds) ]; +    # allow lvm on dmcrypt +    $all_hds->{lvms} = [ lvms($all_hds) ]; -sub all_hds { -    my ($all_hds) = @_; -    (@{$all_hds->{hds}}, @{$all_hds->{lvms}}); -} -sub part2hd { -    my ($part, $all_hds) = @_; -    my ($hd) = grep { $part->{rootDevice} eq ($_->{device} || $_->{VG_name}) } all_hds($all_hds); -    $hd; -} +    $_->{faked_device} = 0 foreach fs::get::fstab($all_hds); -sub is_same_hd { -    my ($hd1, $hd2) = @_; -    if ($hd1->{major} && $hd2->{major}) { -	$hd1->{major} == $hd2->{major} && $hd1->{minor} == $hd2->{minor}; -    } elsif (my ($s1) = $hd1->{device} =~ m|https?://(.+?)/*$|) { -	my ($s2) = $hd2->{device} =~ m|https?://(.+?)/*$|; -	$s1 eq $s2; -    } else { -	$hd1->{device} eq $hd2->{device}; -    } +    $all_hds;  } -sub is_same_part { +#- are_same_partitions() do not look at the device name since things may have changed +sub are_same_partitions {      my ($part1, $part2) = @_; -    foreach ('start', 'size', 'type', 'rootDevice') { -	$part1->{$_} eq $part2->{$_} or return; +    foreach ('start', 'size', 'pt_type', 'fs_type', 'rootDevice') { +	$part1->{$_} eq $part2->{$_} or return 0;      }      1;  } -#- get all normal partition including special ones as found on sparc. -sub get_fstab { -    map { partition_table::get_normal_parts($_) } @_; -} - -#- get normal partition that should be visible for working on. -sub get_visible_fstab { -    grep { $_ && !partition_table::isWholedisk($_) && !partition_table::isHiddenMacPart($_) } -      map { partition_table::get_normal_parts($_) } @_; -} - -sub get_fstab_and_holes { -    map { -	if (isLVM($_)) { -	    my @parts = partition_table::get_normal_parts($_); -	    my $free = $_->{totalsectors} - sum map { $_->{size} } @parts; -	    my $free_part = { start => 0, size => $free, type => 0, rootDevice => $_->{VG_name} }; -	    @parts, if_($free >= $_->cylinder_size, $free_part); -	} else { -	    partition_table::get_normal_parts_and_holes($_); -	} -    } @_; -} -sub get_holes { -    grep { $_->{type} == 0 } get_fstab_and_holes(@_); -} - -sub get_all_fstab { -    my ($all_hds) = @_; -    my @parts = map { partition_table::get_normal_parts($_) } all_hds($all_hds); -    my @raids = grep { $_ } @{$all_hds->{raids}}; -    @parts, @raids, @{$all_hds->{loopbacks}}; -} -sub get_really_all_fstab { -    my ($all_hds) = @_; -    my @parts = map { partition_table::get_normal_parts($_) } all_hds($all_hds); -    my @raids = grep { $_ } @{$all_hds->{raids}}; -    @parts, @raids, @{$all_hds->{loopbacks}}, @{$all_hds->{raw_hds}}, @{$all_hds->{nfss}}, @{$all_hds->{smbs}}, @{$all_hds->{davs}}; -} -sub get_all_fstab_and_holes { -    my ($all_hds) = @_; -    my @raids = grep { $_ } @{$all_hds->{raids}}; -    get_fstab_and_holes(all_hds($all_hds)), @raids, @{$all_hds->{loopbacks}}; -} -sub get_all_holes { -    my ($all_hds) = @_; -    grep { $_->{type} == 0 } get_all_fstab_and_holes($all_hds); -} - -sub all_free_space { -    my ($all_hds) = @_; -    sum map { $_->{size} } get_all_holes($all_hds); -} -sub free_space { -    sum map { $_->{size} } get_holes(@_); -} - -sub is_one_big_fat { +sub is_one_big_fat_or_NT {      my ($hds) = @_; -    @$hds == 1 or return; - -    my @l = get_fstab(@$hds); -    @l == 1 && isFat($l[0]) && free_space(@$hds) < 10 << 11; -} - -sub file2part { -    my ($fstab, $file, $keep_simple_symlinks) = @_;     -    my $part; +    @$hds == 1 or return 0; -    $file = $keep_simple_symlinks ? common::expand_symlinks_but_simple("$::prefix$file") : expand_symlinks("$::prefix$file"); -    unless ($file =~ s/^$::prefix//) { -	my ($part) = grep { loopback::carryRootLoopback($_) } @$fstab or die; -	log::l("found $part->{mntpoint}"); -	$file =~ s|/initrd/loopfs|$part->{mntpoint}|; -    } -    foreach (@$fstab) { -	my $m = $_->{mntpoint}; -	$part = $_ if  -	  $file =~ /^\Q$m/ &&  -	    (!$part || length $part->{mntpoint} < length $m); -    } -    $part or die "file2part: not found $file"; -    $file =~ s|$part->{mntpoint}/?|/|; -    ($part, $file); +    my @l = fs::get::hds_fstab(@$hds); +    @l == 1 && isFat_or_NTFS($l[0]) && fs::get::hds_free_space(@$hds) < MB(10);  }  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}; -    my $free_space = all_free_space($all_hds); -    my @l = my @L = grep {  -	if (!has_mntpoint($_->{mntpoint}, $all_hds) && $free_space >= $_->{size}) { -	    $free_space -= $_->{size}; +    my %free_space; +    $free_space{$_->{rootDevice}} += $_->{size} foreach fs::get::holes($all_hds); + +    my @l = my @L = grep { +	my @possible = $_->{hd} ? $_->{hd} : keys %free_space; +	my $size = $_->{size}; +	if (my $dev = find { $free_space{$_} >= $size } @possible) { +	    $free_space{$dev} -= $size;  	    1;  	} else { 0 } } @$suggestions; +    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;      while (1) {  	my $old_free_space = $free_space; @@ -441,6 +391,9 @@ sub computeSize {  		$_->{size} + $_->{ratio} / $tot_ratios * $old_free_space >= $_->{maxsize}) {  		return min($max, $best->{maxsize}) if $best->{mntpoint} eq $_->{mntpoint};  		$free_space -= $_->{maxsize} - $_->{size}; +		if (!$cylinder_size_maxsize_adjusted++) { +		    eval { $free_space += fs::get::part2hd($part, $all_hds)->cylinder_size - 1 }; +		}  		0;  	    } else {  		$_->{ratio}; @@ -449,91 +402,95 @@ sub computeSize {      }      my $size = int min($max, $best->{size} + $free_space * ($tot_ratios && $best->{ratio} / $tot_ratios));      #- verify other entry can fill the hole -    if (grep { $_->{size} < $max - $size } @L) { $size } else { $max } +    (any { $_->{size} <= $max - $size } @L) ? $size : $max;  }  sub suggest_part { -    my ($part, $all_hds, $suggestions) = @_; -    $suggestions ||= $suggestions{server} || $suggestions{simple}; +    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 +    foreach (@$suggestions) { +	fs::type::set_pt_type($_, $_->{pt_type}) if !exists $_->{fs_type}; +    } + +    my $hd = fs::get::part2hd($part, $all_hds); +    my $hd_size = $hd && $hd->{totalsectors}; # nb: no $hd if $part is /dev/mdX +    my @fstab = $hd->{is_removable} ? partition_table::get_normal_parts($hd) : fs::get::fstab($all_hds); +    my $has_swap = any { isSwap($_) } @fstab; -    my $has_swap = grep { isSwap($_) } get_all_fstab($all_hds); +    my @local_suggestions = +      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; + +    #- this allows specifying the size using a relative size. +    #- one should rather use {ratio} instead +    foreach (@local_suggestions) { +	if ($_->{percent_size} && $_->{percent_size} =~ /(.+?)%?$/) { +	    $_->{size} = $1 / 100 * $hd_size; +	    log::l("in suggestion, setting size=$_->{size} for percent_size=$_->{percent_size}"); +	} +    }      my ($best) =        grep { !$_->{maxsize} || $part->{size} <= $_->{maxsize} }        grep { $_->{size} <= ($part->{maxsize} || $part->{size}) } -      grep { !has_mntpoint($_->{mntpoint}, $all_hds) || isSwap($_) && !$has_swap } -      grep { !$_->{hd} || $_->{hd} eq $part->{rootDevice} } -      grep { !$part->{type} || $part->{type} == $_->{type} || isTrueFS($part) && isTrueFS($_) } -	@$suggestions or return; +      grep { !$part->{fs_type} || $part->{fs_type} eq $_->{fs_type} || isTrueFS($part) && isTrueFS($_) } +	@local_suggestions; -    defined $best or return; #- sorry no suggestion :( +    defined $best or return 0; #- sorry no suggestion :(      $part->{mntpoint} = $best->{mntpoint}; -    $part->{type} = $best->{type} if !(isTrueFS($best) && isTrueFS($part)); -    $part->{size} = computeSize($part, $best, $all_hds, $suggestions); -    $part->{options} = $best->{options} if $best->{options}; -    1; +    fs::type::set_type_subpart($part, $best) if !isTrueFS($best) || !isTrueFS($part); +    $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->{$_}; +    } +    $best;  }  sub suggestions_mntpoint {      my ($all_hds) = @_; -    sort grep { !/swap/ && !has_mntpoint($_, $all_hds) } +    sort grep { !/swap/ && !fs::get::has_mntpoint($_, $all_hds) }        (@suggestions_mntpoints, map { $_->{mntpoint} } @{$suggestions{server} || $suggestions{simple}});  } -sub mntpoint2part { -    my ($mntpoint, $fstab) = @_; -    first(grep { $mntpoint eq $_->{mntpoint} } @$fstab); -} -sub has_mntpoint { -    my ($mntpoint, $all_hds) = @_; -    mntpoint2part($mntpoint, [ get_really_all_fstab($all_hds) ]); -} -sub get_root_ { -    my ($fstab, $boot) = @_; -    $boot && mntpoint2part("/boot", $fstab) || mntpoint2part("/", $fstab); -} -sub get_root { &get_root_ || {} } - -#- do this before modifying $part->{type} -sub check_type { -    my ($type, $_hd, $part) = @_; -    isThisFs("jfs", { type => $type }) && $part->{size} < 16 << 11 and die N("You can't use JFS for partitions smaller than 16MB"); -    isThisFs("reiserfs", { type => $type }) && $part->{size} < 32 << 11 and die N("You can't use ReiserFS for partitions smaller than 32MB"); -} - -sub package_needed_for_partition_type { -    my ($part) = @_; -    my %l = ( -	reiserfs => 'reiserfsprogs', -	xfs => 'xfsprogs', -        jfs => 'jfsprogs', -    ); -    $l{type2fs($part)}; -} - -#- do this before modifying $part->{mntpoint} -#- $part->{mntpoint} should not be used here, use $mntpoint instead +#- you can do this before modifying $part->{mntpoint} +#- so $part->{mntpoint} should not be used here, use $mntpoint instead  sub check_mntpoint { -    my ($mntpoint, $hd, $part, $all_hds) = @_; +    my ($mntpoint, $part, $all_hds) = @_; -    $mntpoint eq '' || isSwap($part) || isNonMountable($part) and return; +    $mntpoint eq '' || isSwap($part) || isNonMountable($part) and return 0;      $mntpoint =~ m|^/| or die N("Mount points must begin with a leading /"); -    $mntpoint ne $part->{mntpoint} && has_mntpoint($mntpoint, $all_hds) and die N("There is already a partition with mount point %s\n", $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 "/" && (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 separate /boot partition"); +    } + +    if ($mntpoint eq "/boot" && (isLUKS($part) || isRawLUKS($part)))  { +	die N("You cannot use an encrypted filesystem for mount point %s", "/boot"); +    } -    die "raid / with no /boot"  -      if $mntpoint eq "/" && isRAID($part) && !has_mntpoint("/boot", $all_hds); -    die N("You can't use a LVM Logical Volume for mount point %s", $mntpoint) -      if ($mntpoint eq '/' || $mntpoint eq '/boot') && isLVM($hd); +    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 /root /mnt)); -    die N("You need a true filesystem (ext2/ext3, reiserfs, xfs, or jfs) for this mount point\n") -      if !isTrueFS($part) && member($mntpoint, qw(/ /home /tmp /usr /var)); -    die N("You can't use an encrypted file system for mount point %s", $mntpoint) +      if member($mntpoint, qw(/bin /dev /etc /lib /sbin /mnt /media)); +    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/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; -    loopback::check_circular_mounts($hd, $part, $all_hds); +    fs::loopback::check_circular_mounts($part, $all_hds);  }  sub add { @@ -541,7 +498,7 @@ sub add {      isSwap($part) ?        ($part->{mntpoint} = 'swap') : -      $options->{force} || check_mntpoint($part->{mntpoint}, $hd, $part, $all_hds); +      $options->{force} || check_mntpoint($part->{mntpoint}, $part, $all_hds);      delete $part->{maxsize}; @@ -550,32 +507,44 @@ sub add {      } else {  	partition_table::add($hd, $part, $options->{primaryOrExtended});      } +    fs::get_major_minor([ $part ]);  }  sub allocatePartitions { -    my ($all_hds, $to_add) = @_; +    my ($all_hds, $to_add, $o_hd) = @_; -    foreach my $part_ (get_all_holes($all_hds)) { +    my @to_add = @$to_add; +  +    foreach my $part_ (fs::get::holes($all_hds, 'non_readonly')) {  	my ($start, $size, $dev) = @$part_{"start", "size", "rootDevice"}; -	my $part; -	while (suggest_part($part = { start => $start, size => 0, maxsize => $size, rootDevice => $dev },  -			    $all_hds, $to_add)) { -	    my ($hd) = fsedit::part2hd($part, $all_hds); -	    add($hd, $part, $all_hds); +	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, $o_hd)) { +	    my $hd = fs::get::part2hd($part, $all_hds); +	    add($hd, $part, $all_hds, { primaryOrExtended => $part->{primaryOrExtended} });  	    $size -= $part->{size} + $part->{start} - $start;  	    $start = $part->{start} + $part->{size}; + 	    @to_add = grep { $_ != $suggested } @to_add;  	}      }  }  sub auto_allocate { -    my ($all_hds, $suggestions) = @_; -    my $before = listlength(fsedit::get_all_fstab($all_hds)); +    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); +    } -    my $suggestions_ = $suggestions || $suggestions{simple}; -    allocatePartitions($all_hds, $suggestions_); +    auto_allocate_bios_boot_parts($all_hds, $o_target) if !is_uefi(); -    if ($suggestions) { +    my $suggestions = $o_suggestions || $suggestions{simple}; +    allocatePartitions($all_hds, $suggestions, $o_target); + +    if ($o_suggestions) {  	auto_allocate_raids($all_hds, $suggestions);  	if (auto_allocate_vgs($all_hds, $suggestions)) {  	    #- allocatePartitions needs to be called twice, once for allocating PVs, once for allocating LVs @@ -587,44 +556,68 @@ sub auto_allocate {      partition_table::assign_device_numbers($_) foreach @{$all_hds->{hds}}; -    if ($before == listlength(fsedit::get_all_fstab($all_hds))) { +    if ($before == listlength(fs::get::fstab($all_hds))) {  	# find out why auto_allocate failed -	if (grep { !has_mntpoint($_->{mntpoint}, $all_hds) } @$suggestions_) { +	if (any { !fs::get::has_mntpoint($_->{mntpoint}, $all_hds) } @$suggestions) {  	    die N("Not enough free space for auto-allocating");  	} else {  	    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 {      my ($all_hds, $suggestions) = @_; -    my @raids = grep { isRawRAID($_) } get_all_fstab($all_hds) or return; +    my @raids = grep { isRawRAID($_) } fs::get::fstab($all_hds) or return;      require raid;      my @mds = grep { $_->{hd} =~ /md/ } @$suggestions;      foreach my $md (@mds) {  	my @raids_ = grep { !$md->{parts} || $md->{parts} =~ /\Q$_->{mntpoint}/ } @raids;  	@raids = difference2(\@raids, \@raids_); -	my $nb = raid::new($all_hds->{raids}, @raids_); -	my $part = $all_hds->{raids}[$nb];  	my %h = %$md; -	delete @h{'hd', 'parts'}; -	put_in_hash($part, \%h); # mntpoint, level, chunk-size, type +	delete @h{'hd', 'parts'}; # keeping mntpoint, level, chunk-size, fs_type/pt_type +	$h{disks} = \@raids_; + +	my $part = raid::new($all_hds->{raids}, %h); +  	raid::updateSize($part); +	push @raids, $part; #- we can build raid over raid      }  }  sub auto_allocate_vgs {      my ($all_hds, $suggestions) = @_; -    my @pvs = grep { isRawLVM($_) } get_all_fstab($all_hds) or return; +    my @pvs = grep { isRawLVM($_) } fs::get::fstab($all_hds) or return 0; -    my @vgs = grep { $_->{VG_name} } @$suggestions or return; +    my @vgs = grep { $_->{VG_name} } @$suggestions or return 0; -    partition_table::write(@{$all_hds->{hds}}); +    partition_table::write($_) foreach @{$all_hds->{hds}};      require lvm; @@ -647,147 +640,38 @@ sub auto_allocate_vgs {      1;  } -sub undo_prepare { -    my ($all_hds) = @_; -    require Data::Dumper; -    $Data::Dumper::Purity = 1; -    foreach (@{$all_hds->{hds}}) { -	my @h = @{$_}{@partition_table::fields2save}; -	push @{$_->{undo}}, Data::Dumper->Dump([\@h], ['$h']); -    } -} -sub undo { -    my ($all_hds) = @_; -    foreach (@{$all_hds->{hds}}) { -	my $h; eval pop @{$_->{undo}} || next; -	@{$_}{@partition_table::fields2save} = @$h; - -	$_->{isDirty} = $_->{needKernelReread} = 1 if $_->{hasBeenDirty}; -    } -     -} - -sub move { -    my ($hd, $part, $hd2, $sector2) = @_; - -    die 'TODO'; # doesn't work for the moment -    my $part1 = { %$part }; -    my $part2 = { %$part }; -    $part2->{start} = $sector2; -    $part2->{size} += $hd2->cylinder_size() - 1; -    partition_table::remove($hd, $part); -    { -	local ($part2->{notFormatted}, $part2->{isFormatted}); #- do not allow partition::add to change this -	partition_table::add($hd2, $part2); -    } - -    return if $part2->{notFormatted} && !$part2->{isFormatted} || $::testing; - -    local (*F, *G); -    sysopen F, $hd->{file}, 0 or die ''; -    sysopen G, $hd2->{file}, 2 or die N("Error opening %s for writing: %s", $hd2->{file}, $!); - -    my $base = $part1->{start}; -    my $base2 = $part2->{start}; -    my $step = 10; -    if ($hd eq $hd2) { -	$base == $base2 and return; -	$step = min($step, abs($base2 - $base)); - -	if ($base < $base2) { -	    $base  += $part1->{size} - $step; -	    $base2 += $part1->{size} - $step; -	    $step = -$step; -	} -    } - -    my $f = sub { -	$base  < 0 and $base2 += -$base,  $base  = 0; -	$base2 < 0 and $base  += -$base2, $base2 = 0; -	c::lseek_sector(fileno(F), $base,  0) or die "seeking to sector $base failed on drive $hd->{device}"; -	c::lseek_sector(fileno(G), $base2, 0) or die "seeking to sector $base2 failed on drive $hd2->{device}"; - -	my $buf; -	sysread F, $buf, $SECTORSIZE * abs($_[0]) or die ''; -	syswrite G, $buf; -    }; - -    for (my $i = 0; $i < $part1->{size} / abs($step); $i++, $base += $step, $base2 += $step) { -	print "$base $base2\n"; -	&$f($step); -    } -    if (my $v = ($part1->{size} % abs($step)) * sign($step)) { -	$base += $v; -	$base2 += $v; -	&$f($v); -    } -} -  sub change_type {      my ($type, $hd, $part) = @_; -    $type != $part->{type} or return; -    check_type($type, $hd, $part); +    $type->{pt_type} != $part->{pt_type} || $type->{fs_type} ne $part->{fs_type} or return; +    fs::type::check($type->{fs_type}, $hd, $part); +    delete $part->{device_UUID};      $hd->{isDirty} = 1;      $part->{mntpoint} = '' if isSwap($part) && $part->{mntpoint} eq "swap"; -    $part->{mntpoint} = '' if isRawLVM({ type => $type }) || isRawRAID({ type => $type }); -    $part->{type} = $type; -    $part->{notFormatted} = 1; -    $part->{isFormatted} = 0;     +    $part->{mntpoint} = '' if fs::type::cannotBeMountable($part); +    set_isFormatted($part, 0); +    fs::type::set_type_subpart($part, $type); +    fs::mount_options::rationalize($part); +    1;  } -sub rescuept($) { -    my ($hd) = @_; -    my ($ext, @hd); - -    my $dev = devices::make($hd->{device}); -    open(my $F, "rescuept $dev|"); -    local $_; -    while (<$F>) { -	my ($st, $si, $id) = /start=\s*(\d+),\s*size=\s*(\d+),\s*Id=\s*(\d+)/ or next; -	my $part = { start => $st, size => $si, type => hex($id) }; -	if (isExtended($part)) { -	    $ext = $part; -	} else { -	    push @hd, $part; -	} -    } -    close $F or die "rescuept failed"; - -    partition_table::raw::zero_MBR($hd); -    foreach (@hd) { -	my $b = partition_table::verifyInside($_, $ext); -	if ($b) { -	    $_->{start}--; -	    $_->{size}++; -	} -	local $_->{notFormatted}; +=item partition_table_clear_and_initialize($lvms, $hd, $o_in, $o_type, $b_warn) = @_; -	partition_table::add($hd, $_, ($b ? 'Extended' : 'Primary'), 1); -    } -} +wrapper around partition_table::initialize() but which also create a singleton VG +automatically (so that it's easier for the user) -sub compare_with_proc_partitions { -    my ($hd) = @_; +=cut -    my @l1 = partition_table::get_normal_parts($hd); -    my @l2 = grep { $_->{rootDevice} eq $hd->{device} } read_proc_partitions([$hd]); -     -    if (int(@l1) != int(@l2) && arch() ne 'ppc') { -	die sprintf( -		    "/proc/partitions doesn't agree with drakx %d != %d:\n%s\n", int(@l1), int(@l2), -		    "/proc/partitions: " . join(", ", map { "$_->{device} ($_->{rootDevice})" } @l2)); +sub partition_table_clear_and_initialize { +    my ($lvms, $hd, $o_in, $o_type, $b_warn) = @_; +    partition_table::initialize($hd, $o_type); +    if ($hd->isa('partition_table::lvm')) { +	if ($b_warn && $o_in) { +	    $o_in->ask_okcancel_('', N("ALL existing partitions and their data will be lost on drive %s", partition_table::description($hd))) or return; +	} +	require lvm; +	lvm::check($o_in ? $o_in->do_pkgs : do_pkgs_standalone->new) if $::isStandalone; +	lvm::create_singleton_vg($lvms, fs::get::hds_fstab($hd));      } -    int @l2; -} - -sub use_proc_partitions { -    my ($hd) = @_; - -    log::l("using /proc/partitions since diskdrake failed :("); -    partition_table::raw::zero_MBR($hd); -    $hd->{readonly} = 1; -    $hd->{getting_rid_of_readonly_allowed} = 1; -    $hd->{primary} = { normal => [ grep { $_->{rootDevice} eq $hd->{device} } read_proc_partitions([$hd]) ] };  }  1; | 
