diff options
Diffstat (limited to 'perl-install/diskdrake/interactive.pm')
| -rw-r--r-- | perl-install/diskdrake/interactive.pm | 416 | 
1 files changed, 269 insertions, 147 deletions
| diff --git a/perl-install/diskdrake/interactive.pm b/perl-install/diskdrake/interactive.pm index 0948c9a0c..59e79782c 100644 --- a/perl-install/diskdrake/interactive.pm +++ b/perl-install/diskdrake/interactive.pm @@ -1,9 +1,11 @@ -package diskdrake::interactive; # $Id$ +package diskdrake::interactive;  use diagnostics;  use strict;  use utf8; +use lib qw(/usr/lib/libDrakX);  # for perl_checker +use MDK::Common; # for perl_checker  use common;  use fs::type;  use fs::loopback; @@ -20,19 +22,16 @@ use raid;  use any;  use log; - -=begin -  =head1 SYNOPSYS -struct part { + struct part {    int active            # one of { 0 | 0x80 }  x86 only, primary only    int start             # in sectors    int size              # in sectors    int pt_type           # 0x82, 0x83, 0x6 ...    string fs_type        # 'ext2', 'nfs', ...    string type_name      # 'Linux RAID', 'Linux Logical Volume Manager', ... - +     int part_number       # 1 for hda1...    string device         # 'hda5', 'sdc1' ...    string device_LABEL   # volume label. LABEL=xxx or /dev/disk/by-label/xxx can be used in fstab instead of the device @@ -42,7 +41,7 @@ struct part {    bool prefer_device    # should the {device} be used in fstab    bool faked_device     # false if {device} is a real device, true for nfs/smb/dav/none devices. If the field does not exist, we do not know    bool device_LABEL_changed # true if device_LABEL is different from the one on the disk - +     string rootDevice     # 'sda', 'hdc' ... (can also be a VG_name)    string real_mntpoint  # directly on real /, '/tmp/hdimage' ...    string mntpoint       # '/', '/usr' ... @@ -51,32 +50,32 @@ struct part {    string encrypt_key    # [0-9A-Za-z./]{20,}    string comment        # comment to have in fstab    string volume_label   # - +     bool is_removable     # is the partition on a removable drive    bool isMounted - +     bool isFormatted    bool notFormatted      #  isFormatted                  means the device is formatted      # !isFormatted &&  notFormatted means the device is not formatted      # !isFormatted && !notFormatted means we do not know which state we're in - +     string raid       # for partitions of type isRawRAID and which isPartOfRAID, the raid device    string lvm        # partition used as a PV for the VG with {lvm} as VG_name  #-#    loopback loopback[]   # loopback living on this partition - +     string dmcrypt_key    string dm_name    bool dm_active - +     # internal    string real_device     # '/dev/loop0', '/dev/loop1' ... (used for encrypted loopback) - +     # internal CHS (Cylinder/Head/Sector)    int start_cyl, start_head, start_sec, end_cyl, end_head, end_sec,  } -struct part_allocate inherits part { + struct part_allocate inherits part {    int maxsize        # in sectors (alike "size")    int min_hd_size    # in sectors (do not allocate if the drive is smaller than the given size)    int ratio          # @@ -84,44 +83,44 @@ struct part_allocate inherits part {    string parts       # for creating raid partitions. eg: 'foo bar' where 'foo' and 'bar' are mntpoint  } -struct part_raid inherits part { + struct part_raid inherits part {    string chunk-size  # in KiB, usually '64'    string level       # one of { 0, 1, 4, 5, 'linear' }    string UUID - +     part disks[] - +     # invalid: active, start, rootDevice, device_windobe?, CHS  } -struct part_dmcrypt inherits part { + struct part_dmcrypt inherits part {    string dmcrypt_name - +     # rootDevice is special here: it is the device hosting the dm  } -struct part_loopback inherits part { + struct part_loopback inherits part {    string loopback_file   # absolute file name which is relative to the partition    part loopback_device   # where the loopback file live - +     # device is special here: it is the absolute filename of the loopback file. - +     # invalid: active, start, rootDevice, device_windobe, CHS  } -struct part_lvm inherits part { + struct part_lvm inherits part {    # invalid: active, start, device_windobe, CHS    string lv_name  } -struct partition_table_elem { + struct partition_table_elem {    part normal[]     #    part extended     # the main/next extended    part raw[4]       # primary partitions  } -struct geom { + struct geom {    int heads    int sectors    int cylinders @@ -129,14 +128,14 @@ struct geom {    int start          # always 0, forget it  } -struct hd { + struct hd {    int totalsectors      # size in sectors    string device         # 'hda', 'sdc' ...    string device_alias   # 'cdrom', 'floppy' ...    string media_type     # one of { 'hd', 'cdrom', 'fd', 'tape' }    string capacity       # contain of the strings of { 'burner', 'DVD' }    string info           # name of the hd, eg: 'QUANTUM ATLAS IV 9 WLS' - +     bool readonly         # is it allowed to modify the partition table    bool getting_rid_of_readonly_allowed # is it forbidden to write because the partition table is badly handled, or is it because we MUST not change the partition table    bool isDirty          # does it need to be written to the disk @@ -147,37 +146,37 @@ struct hd {                              # - add an extended partition which is the first extended partition    list allPartitionsRenumbered # used to update bootloader configuration    int bus, id - +     bool is_removable     # is it a removable drive - +     partition_table_elem primary    partition_table_elem extended[] - +     geom geom - +     # internal    string prefix         # for some RAID arrays device=>c0d0 and prefix=>c0d0p    string file           # '/dev/hda' ...  } -struct hd_lvm inherits hd { + struct hd_lvm inherits hd {    int PE_size           # block size (granularity, similar to cylinder size on x86)    string VG_name        # VG name - +     part_lvm disks[] - +     # invalid: bus, id, extended, geom  } -struct raw_hd inherits hd { + struct raw_hd inherits hd {    string fs_type       # 'ext2', 'nfs', ...    string mntpoint   # '/', '/usr' ...    string options    # 'defaults', 'noauto' - +     # invalid: isDirty, will_tell_kernel, rebootNeeded, primary, extended  } -struct all_hds { + struct all_hds {    hd hds[]    hd_lvm lvms[]    part_raid raids[] @@ -188,7 +187,7 @@ struct all_hds {    raw_hd smbs[]    raw_hd davs[]    raw_hd special[] - +     # internal: if fstab_to_string($all_hds) eq current_fstab then no need to save    string current_fstab  } @@ -291,14 +290,14 @@ sub Done {      }      if (!$::isInstall) {  	my $new = fs::fstab_to_string($all_hds); -	if ($new ne $all_hds->{current_fstab} && $in->ask_yesorno(N("Confirmation"), N("Do you want to save /etc/fstab modifications"), 1)) { +	if ($new ne $all_hds->{current_fstab} && $in->ask_yesorno(N("Confirmation"), N("Do you want to save the /etc/fstab modifications?"), 1)) {  	    $all_hds->{current_fstab} = $new;  	    fs::write_fstab($all_hds);  	}  	update_bootloader_for_renumbered_partitions($in, $all_hds);  	if (any { $_->{rebootNeeded} } @{$all_hds->{hds}}) { -	    $in->ask_warn(N("Partitioning"), N("You need to reboot for the partition table modifications to take place")); +	    $in->ask_warn(N("Partitioning"), N("You need to reboot for the partition table modifications to take effect"));  	    tell_wm_and_reboot();  	}      } @@ -323,7 +322,7 @@ sub hd_possible_actions_base {  sub hd_possible_actions_extra {      my ($_hd) = @_; -    $::expert ? N_("Toggle to normal mode") : N_("Toggle to expert mode"); +    $::expert ? N_("Normal mode") : N_("Expert mode");  } @@ -335,7 +334,7 @@ sub hd_possible_actions {  sub hd_possible_actions_interactive {      my ($_in, $_hd, $_all_hds) = @_; -    &hd_possible_actions, N_("Hard drive information"); +    &hd_possible_actions, N_("Hard disk drive information");  }  sub Clear_all { @@ -354,22 +353,23 @@ sub Clear_all {  	$hd->{getting_rid_of_readonly_allowed} = 0; #- we don't need this flag anymore  	fsedit::partition_table_clear_and_initialize($all_hds->{lvms}, $hd, $in);      } +    fsedit::init_mntpnt_suggestions($all_hds, $hd, 1);  }  sub Auto_allocate {      my ($in, $hd, $all_hds) = @_; -    my $suggestions = partitions_suggestions($in) or return; +    my $suggestions = partitions_suggestions($in, $all_hds, $hd) or return;      my %all_hds_ = %$all_hds;      $all_hds_{hds} = [ sort { $a == $hd ? -1 : 1 } fs::get::hds($all_hds) ]; -    eval { fsedit::auto_allocate(\%all_hds_, $suggestions) }; +    eval { fsedit::auto_allocate(\%all_hds_, $suggestions, $hd) };      if ($@) {  	$@ =~ /partition table already full/ or die;  	$in->ask_warn("", [  			   N("All primary partitions are used"), -			   N("I can not add any more partitions"), +			   N("I cannot add any more partitions"),  			   N("To have more partitions, please delete one to be able to create an extended partition"),  			  ]);      } @@ -395,6 +395,10 @@ sub Hd_info {  # per-part actions  ################################################################################ +sub is_LVM_resizable { +    my ($part) = @_; +    member($part->{fs_type}, qw(btrfs ext3 ext4 nilfs2 reiserfs xfs)); +}  sub part_possible_actions {      my ($_in, $hd, $part, $all_hds) = @_;      $part or return; @@ -405,8 +409,8 @@ sub part_possible_actions {          N_("Type")             => '!isBusy && $::expert && (!readonly || $part->{pt_type} == 0x83)',          N_("Options")          => '!isSwap($part) && !isNonMountable && $::expert',          N_("Label")            => '!isNonMountable && $::expert && fs::format::canEditLabel($part)', -        N_("Resize")	       => '!isBusy && !readonly && !isSpecial || isLVM($hd) && LVM_resizable', -        N_("Format")           => '!isBusy && !isRawLVM && !isPartOfLVM && (!readonly && ($::expert || $::isStandalone) || fs::type::isRawLUKS($part))', +        N_("Resize")	       => '!isBusy && !readonly && !isSpecial || isLVM($hd) && is_LVM_resizable', +        N_("Format")           => '!isBusy && isFormatable && (!readonly && ($::expert || $::isStandalone) || fs::type::isRawLUKS($part))',          N_("Mount")            => '!isBusy && (hasMntpoint || isSwap) && maybeFormatted && ($::expert || $::isStandalone)',          N_("Add to RAID")      => '!isBusy && isRawRAID && (!isSpecial || isRAID)',          N_("Add to LVM")       => '!isBusy && isRawLVM', @@ -424,7 +428,6 @@ sub part_possible_actions {      my %macros = (  	readonly => '$hd->{readonly}',          hasMntpoint => '$part->{mntpoint}', -	LVM_resizable => 'member($part->{fs_type}, qw(reiserfs xfs ext3 ext4))',  	canModifyRAID => 'isPartOfRAID($part) && !isMounted(fs::get::device2part($part->{raid}, $all_hds->{raids}))',      );      if (isEmpty($part)) { @@ -439,16 +442,20 @@ sub part_possible_actions {      	        $cond =~ s/$k/qq(($v))/e;      	    }      	    $cond =~ s/(^|[^:\$]) \b ([a-z]\w{3,}) \b ($|[\s&\)])/$1 . $2 . '($part)' . $3/exg; -    	    eval $cond; +    	    my $res = eval $cond; +	    if (my $err = $@)  { +		warn "ERROR: Bogus condition for '$actions{$_}': $err\n"; +	    } +	    $res;          } @$actions_names;      }  }  sub View { -    my ($in, $hd, $part, $all_hds) = @_; +    my ($in, $_hd, $part, $_all_hds) = @_;      my $handle = any::inspect($part, $::prefix);      if ($handle) { -      $in->ask_directory({'directory'=>$handle->{dir}}); +      $in->ask_directory({ 'directory' => $handle->{dir} });      } else {        $in->ask_warn(N("Error"), N("Failed to mount partition"));      } @@ -481,6 +488,8 @@ sub Create {      my $type_name = fs::type::part2type_name($part);      my $mb_size = to_Mb($part->{size});      my $has_startsector = ($::expert || arch() !~ /i.86/) && !isLVM($hd); +    my $use_dmcrypt; +    my $requested_type;      $in->ask_from(N("Create a new partition"), '',          [ @@ -494,22 +503,43 @@ sub Create {           { label => N("Filesystem type: "), val => \$type_name, list => [ fs::type::type_names($::expert, $hd) ],  	   sort => 0, if_($::expert, gtk => { wrap_width => 2 }, do_not_ellipsize => 1) },           { label => N("Mount point: "), val => \$part->{mntpoint}, list => [ fsedit::suggestions_mntpoint($all_hds), '' ], +           if_(isLVM($hd), changed => sub { +		   undef $part->{lv_name}; +		   lvm::suggest_lv_name($hd, $part); +	   }), type => 'combo', not_edit => 0,             disabled => sub { my $p = fs::type::type_name2subpart($type_name); isSwap($p) || isNonMountable($p) }, type => 'combo', not_edit => 0,           },             if_($::expert && $hd->hasExtended,           { label => N("Preference: "), val => \$primaryOrExtended, list => [ '', "Extended", "Primary", if_($::expert, "Extended_0x85") ] },             ), -	   if_($::expert && isLVM($hd), +	   if_(isLVM($hd),  	 { label => N("Logical volume name "), val => \$part->{lv_name}, list => [ qw(root swap usr home var), '' ], sort => 0, not_edit => 0 },             ), +        { label => N("Encrypt partition"), type => 'bool', val => \$use_dmcrypt, disabled => sub { $part->{mntpoint} eq "/boot" } }, +	 { label => N("Encryption key "), val => \$part->{dmcrypt_key}, disabled => sub { !$use_dmcrypt }, hidden => 1, weakness_check => 1 }, +	 { label => N("Encryption key (again)"), val => \$part->{dmcrypt_key2}, disabled => sub { !$use_dmcrypt }, hidden => 1 },          ], complete => sub {  	    $part->{size} = from_Mb($mb_size, min_partition_size($hd), $max - $part->{start}); #- need this to be able to get back the approximation of using MB -	    put_in_hash($part, fs::type::type_name2subpart($type_name));  	    $do_suggest_mount_point = 0 if !$part->{mntpoint}; +	    put_in_hash($part, fs::type::type_name2subpart($type_name));  	    $part->{mntpoint} = '' if isNonMountable($part);  	    $part->{mntpoint} = 'swap' if isSwap($part);  	    fs::mount_options::set_default($part, ignore_is_removable => 1); +	    # if user asked to encrypt the partition, use dm-crypt and create requested fs inside +	    if ($use_dmcrypt) { +		my $err; +		$err = N("The encryption keys do not match") unless $part->{dmcrypt_key} eq $part->{dmcrypt_key2}; +		$err = N("Missing encryption key") unless $part->{dmcrypt_key}; +		if ($err) { +		    $in->ask_warn(N("Error"), $err); +		    return 1; +	        } +		$requested_type = $type_name; +		$type_name = 'Encrypted'; +	    } + +	    put_in_hash($part, fs::type::type_name2subpart($type_name));  	    check($in, $hd, $part, $all_hds) or return 1;  	    $migrate_files = need_migration($in, $part->{mntpoint}) or return 1; @@ -520,7 +550,7 @@ sub Create {  	    };  	    if (my $err = $@) {  		if ($err =~ /raw_add/ && $hd->hasExtended && !$hd->{primary}{extended}) { -		    $in->ask_warn(N("Error"), N("You can not create a new partition +		    $in->ask_warn(N("Error"), N("You cannot create a new partition  (since you reached the maximal number of primary partitions).  First remove a primary partition and create an extended partition."));  		    return 0; @@ -533,9 +563,26 @@ First remove a primary partition and create an extended partition."));  	},      ) or return; +    if ($use_dmcrypt) { +	write_partitions($in, $hd) or return; +	# Initialize it and format it +	dmcrypt_format($in, $hd, $part, $all_hds); +	my $p = find { $part->{dm_name} eq $_->{dmcrypt_name} } @{$all_hds->{dmcrypts}}; +	my $p2 = fs::type::type_name2subpart($requested_type); +        $p->{fs_type} = $p2->{fs_type}; +	$p->{type_name} = $requested_type; +	$p->{mntpoint} = $part->{mntpoint}; +	$part->{mntpoint} = ''; +	if ($::isStandalone) { +	    fs::format::check_package_is_installed_format($in->do_pkgs, $p->{fs_type}) or log::l("Missing package"); +	} +        _format_raw($in, $p, $all_hds, isRawLVM($p)); +    } +      warn_if_renumbered($in, $hd);      if ($migrate_files eq 'migrate') { +        # FIXME check encrypt case  	format_($in, $hd, $part, $all_hds) or return;  	migrate_files($in, $hd, $part);  	fs::mount::part($part); @@ -544,6 +591,11 @@ First remove a primary partition and create an extended partition."));  sub Delete {      my ($in, $hd, $part, $all_hds) = @_; +    if (fs::type::isLUKS($part)) { +	my $p = find { $_->{dm_name} eq $part->{dmcrypt_name} } partition_table::get_normal_parts($hd); +	RemoveFromDm($in, $hd, $p, $all_hds); +	$part = $p; +    }      if (isRAID($part)) {  	raid::delete($all_hds->{raids}, $part);      } elsif (isLVM($hd)) { @@ -558,9 +610,6 @@ sub Delete {  	delete $part->{loopback_device}{loopback} if @$l == 0;  	fsedit::recompute_loopbacks($all_hds);      } else { -	if (arch() =~ /ppc/) { -	    undef $partition_table::mac::bootstrap_part if isAppleBootstrap($part) && ($part->{device} = $partition_table::mac::bootstrap_part); -	}  	partition_table::remove($hd, $part);  	warn_if_renumbered($in, $hd);      } @@ -572,11 +621,15 @@ sub Type {      my $warned;      my $warn = sub {  	$warned = 1; -	ask_alldatawillbelost($in, $part, N_("After changing type of partition %s, all data on this partition will be lost")); +	if (maybeFormatted($part)) { +	    ask_alldatawillbelost($in, $part, N_("After changing type of partition %s, all data on this partition will be lost")); +	} else { +	    1; +	}      }; -    #- for ext2, warn after choosing as ext2->ext3 can be achieved without loosing any data :) -    $part->{fs_type} eq 'ext2' || $part->{fs_type} =~ /ntfs/ or $warn->() or return; +    #- for ext2/ext3, warn after choosing as ext2->ext3 and ext*->ext4 can be achieved without loosing any data :) +    member($part->{fs_type}, qw(ext2 ext3)) || $part->{fs_type} =~ /ntfs/ or $warn->() or return;      my @types = fs::type::type_names($::expert, $hd); @@ -593,7 +646,7 @@ sub Type {      my $type = $type_name && fs::type::type_name2subpart($type_name); -    if (member($type->{fs_type}, qw(ext2 ext3 ext4))) { +    if ($part->{fs_type} eq 'ext2' && $type->{fs_type} eq 'ext3') {  	my $_w = $in->wait_message(N("Please wait"), N("Switching from %s to %s", 'ext2', $type->{fs_type}));  	if (run_program::run("tune2fs", "-j", devices::make($part->{device}))) {  	    put_in_hash($part, $type); @@ -603,8 +656,13 @@ sub Type {  	    fs::format::disable_forced_fsck($part->{device});  	    return;  	} +    } elsif (member($part->{fs_type}, qw(ext2 ext3)) && $type->{fs_type} eq 'ext4') { +	# FIXME enable some nice flags +	put_in_hash($part, $type); +	return;      } elsif ($type->{fs_type} =~ /ntfs/ && $part->{fs_type} =~ /ntfs/) {  	if ($type->{fs_type} eq 'ntfs-3g') { +	    local $::prefix = ''; # For draklive-install  	    $in->do_pkgs->ensure_binary_is_installed('ntfs-3g', 'mount.ntfs-3g') or return;  	}  	put_in_hash($part, $type); @@ -619,10 +677,10 @@ sub Type {  }  sub Label { -    my ($in, $_hd, $part) = @_; +    my ($in, $hd, $part) = @_;      my $new_label = $part->{device_LABEL} || ""; -    write_partitions($in, $_hd) or return; +    write_partitions($in, $hd) or return;      $in->ask_from(N("Set volume label"),                    maybeFormatted($part) ?  @@ -633,10 +691,10 @@ sub Label {  		   { label => N("Label:"), val => \$new_label } ]) or return;      fs::format::check_package_is_installed_label($in->do_pkgs, $part->{fs_type}) or return; +    $part->{prefer_device_LABEL} = to_bool($part->{device_LABEL}) && !isLVM($part);      return if $new_label eq $part->{device_LABEL};      $part->{device_LABEL} = $new_label;      $part->{device_LABEL_changed} = 1; -    $part->{prefer_device_LABEL} = to_bool($part->{device_LABEL}) && !isLVM($part);      fs::format::clean_label($part);      fs::format::write_label($part);  } @@ -657,7 +715,7 @@ sub Mount_point {  		     callbacks => {  		         complete => sub {  	    !isPartOfLoopback($part) || $mntpoint or $in->ask_warn(N("Error"), -N("Can not unset mount point as this partition is used for loop back. +N("Cannot unset mount point as this partition is used for loop back.  Remove the loopback first")), return 1;  	    $part->{mntpoint} eq $mntpoint || check_mntpoint($in, $mntpoint, $part, $all_hds) or return 1;      	    $migrate_files = need_migration($in, $mntpoint) or return 1; @@ -699,10 +757,36 @@ sub Mount_point_raw_hd {      $part->{mntpoint} = $mntpoint;  } +#- side-effects: mounts the fs +sub _get_dir_for_online_resize { +    my ($part) = @_; +    my $dir = "/tmp/tmp_resize_" . $part->{fs_type} . ".$$"; +    if ($part->{isMounted}) { +	$dir = ($::prefix || '') . $part->{mntpoint}; +    } else { +	mkdir_p($dir); +	fs::mount::mount(devices::make($part->{device}), $dir, $part->{fs_type}); +    } +    return $dir; +} + +sub _set_min_size_from_avail_space { +    my ($part, $min) = @_; +    if (defined(my $free = fs::df($part))) { +	$$min = max($$min, $part->{size} - $free); +    } +} +  sub Resize {      my ($in, $hd, $part) = @_; -    my (%nice_resize); -    my ($min, $max) = (min_partition_size($hd), max_partition_resize($hd, $part)); +    my (%nice_resize, $online_resize); +    my $low_part = $part; + +    if (isLUKS($part)) { +	$low_part = find { $_->{dm_name} eq $part->{dmcrypt_name} } partition_table::get_normal_parts($hd); +    } + +    my ($min, $max) = (min_partition_size($hd), max_partition_resize($hd, $low_part));      if (maybeFormatted($part)) {  	# here we may have a non-formatted or a formatted partition @@ -725,6 +809,9 @@ sub Resize {  	    } else {  		delete $nice_resize{ext2};  	    } +	} elsif ($part->{fs_type} eq 'f2fs') { +	    $min = $part->{size}; #- ensure the user can only increase +	    $nice_resize{f2fs} = 1;  	} elsif ($part->{fs_type} =~ /ntfs/) {  	    write_partitions($in, $hd) or return;  	    require diskdrake::resize_ntfs; @@ -733,17 +820,27 @@ sub Resize {  	    $min = $nice_resize{ntfs}->min_size or delete $nice_resize{ntfs};  	} elsif ($part->{fs_type} eq 'reiserfs') {  	    write_partitions($in, $hd) or return; +	    $nice_resize{reiserfs} = 1;  	    if ($part->{isMounted}) { -		$nice_resize{reiserfs} = 1;  		$min = $part->{size}; #- ensure the user can only increase -	    } elsif (defined(my $free = fs::df($part))) { -		$nice_resize{reiserfs} = 1; -		$min = max($min, $part->{size} - $free); +	    } else { +		_set_min_size_from_avail_space($part, \$min);  	    } -	} elsif ($part->{fs_type} eq 'xfs' && isLVM($hd) && $::isStandalone && $part->{isMounted}) { +	} elsif ($part->{fs_type} eq 'xfs') {  	    $min = $part->{size}; #- ensure the user can only increase -	    $nice_resize{xfs} = 1; +	    $online_resize = $part->{fs_type}; +	} elsif (member($part->{fs_type}, qw(btrfs nilfs2))) { +	    $online_resize = $part->{fs_type};  	} + +	# Btrf, nilfs2 && XFS only support online resizing +	# (Ext3/4 too but we can resize it offline so we don't care - though growing online is interesting) +	if ($online_resize) { +	    write_partitions($in, $hd) or return; +	    $nice_resize{$online_resize} = 1; +	    _set_min_size_from_avail_space($part, \$min); +	} +  	#- make sure that even after normalizing the size to cylinder boundaries, the minimun will be saved,  	#- this save at least a cylinder (less than 8Mb).  	$min += partition_table::raw::cylinder_size($hd); @@ -752,7 +849,7 @@ sub Resize {  	#- for these, we have tools to resize partition table  	#- without losing data (or at least we hope so :-)  	if (%nice_resize) { -	    ask_alldatamaybelost($in, $part, N_("All data on this partition should be backed-up")) or return; +	    ask_alldatamaybelost($in, $part, N_("All data on this partition should be backed up")) or return;  	} else {  	    ask_alldatawillbelost($in, $part, N_("After resizing partition %s, all data on this partition will be lost")) or return;  	} @@ -772,8 +869,8 @@ sub Resize {      $part->{size} == $size and return;      my $oldsize = $part->{size}; -    $part->{size} = $size; -    $hd->adjustEnd($part); +    $low_part->{size} = $part->{size} = $size; +    $hd->adjustEnd($low_part);      undef $@;      my $_b = before_leaving { $@ and $part->{size} = $oldsize }; @@ -782,12 +879,19 @@ sub Resize {  	my ($write_partitions) = @_;  	if (isLVM($hd)) { -	    lvm::lv_resize($part, $oldsize); +	    lvm::lv_resize($low_part, $oldsize);  	} else { -	    partition_table::will_tell_kernel($hd, resize => $part); -	    partition_table::adjust_local_extended($hd, $part); +	    if ($write_partitions && isLUKS($part)) { +		run_program::run('cryptsetup', 'luksClose', $part->{dmcrypt_name}) or die("Failed to resize partition, maybe it is mounted"); +	    } +	    partition_table::will_tell_kernel($hd, resize => $low_part); +	    partition_table::adjust_local_extended($hd, $low_part);  	    partition_table::adjust_main_extended($hd); -	    write_partitions($in, $hd) or return if $write_partitions && %nice_resize; +	    write_partitions($in, $hd) or return if $write_partitions && (%nice_resize || isLUKS($part)); +	    if ($write_partitions && isLUKS($part)) { +		require fs::dmcrypt; +		fs::dmcrypt::open_part([], $low_part); +	    }  	}  	1;      }; @@ -810,9 +914,29 @@ filesystem checks will be run on your next boot into Microsoft Windows®"));      } elsif ($nice_resize{reiserfs}) {  	log::l("reiser resize to $part->{size} sectors");  	run_program::run_or_die('resize_reiserfs', '-f', '-q', '-s' . int($part->{size}/2) . 'K', devices::make($part->{device})); -    } elsif ($nice_resize{xfs}) { -	#- happens only with mounted LVM, see above -	run_program::run_or_die("xfs_growfs", $part->{mntpoint}); +    } elsif ($online_resize) { +        my $dir = _get_dir_for_online_resize($part); +	my @cmd; +	if ($nice_resize{btrfs}) { +	    # FIXME: only works for a FS on a single device. Multi-device FS would need to specify the device to enlarge +	    @cmd = (qw(btrfs filesystem resize), $part->{size}*512, $dir); +	} elsif ($nice_resize{nilfs2}) { +	    @cmd = ('nilfs-resize', devices::make($part->{device}), $part->{size}*512); +	} elsif ($nice_resize{xfs}) { +	    @cmd = ("xfs_growfs", $dir); +	} else { +	    die("I don't know how to proceed"); +	} +	if (!run_program::run(@cmd)) { +	    $nice_resize{$part->{fs_type}} = undef; +        } +        # umount after online resize if it was mounted on demand: +        if (!$part->{isMounted}) { +	    fs::mount::umount($dir); +	    unlink($dir); +        } +    } elsif ($nice_resize{f2fs}) { +	run_program::run_or_die("resize.f2fs", devices::make($part->{device}));      }      if (%nice_resize) { @@ -820,11 +944,12 @@ filesystem checks will be run on your next boot into Microsoft Windows®"));      } else {  	set_isFormatted($part, 0);  	partition_table::verifyParts($hd) if !isLVM($hd); -	$part->{mntpoint} = '' if isNonMountable($part); #- mainly for ntfs, which we can not format +	$part->{mntpoint} = '' if isNonMountable($part); #- mainly for ntfs, which we cannot format      }      $adjust->(0) if $size < $oldsize;  } +  sub Format {      my ($in, $hd, $part, $all_hds) = @_;      format_($in, $hd, $part, $all_hds); @@ -847,7 +972,7 @@ sub dmcrypt_open {      my ($in, $_hd, $part, $all_hds) = @_;      $part->{dm_name} ||= do {  	my $s = $part->{device}; -	$s =~ s/[^\w]/_/g; +	$s =~ s/\W/_/g;  	"crypt_$s";      }; @@ -859,11 +984,26 @@ sub dmcrypt_open {  	       hidden => 1, focus => sub { 1 } } ]) or return;      } -    eval { fs::dmcrypt::open_part($all_hds->{dmcrypts}, $part) }; +    eval { require fs::dmcrypt; fs::dmcrypt::open_part($all_hds->{dmcrypts}, $part) };      if ($@) {  	delete $part->{dmcrypt_key};  	die(($? >> 8) == 255 ? N("Invalid key") : $@);      } +    detect_lvms_on_dmcrypt($all_hds); +} + +# Detect LVMs on top of dmcrypt +sub detect_lvms_on_dmcrypt { +    my ($all_hds) = @_, +    require File::Temp; +    require fs::dmcrypt; +    my (undef, $tmp_file) = File::Temp::mkstemp('/tmp/crypttab.XXXXXXX'); +    fs::dmcrypt::save_crypttab_($all_hds, $tmp_file); +    require lvm; +    lvm::detect_during_install(); +    $all_hds->{lvms} = [ fsedit::lvms($all_hds) ]; +    fs::dmcrypt::read_crypttab_($all_hds, $tmp_file); +    rm_rf($tmp_file);  }  sub Add2RAID { @@ -887,8 +1027,6 @@ sub Add2LVM {      my ($in, $hd, $part, $all_hds) = @_;      my $lvms = $all_hds->{lvms};      my @lvm_names = map { $_->{VG_name} } @$lvms; -    use Data::Dumper; -    print Dumper(@lvm_names);      write_partitions($in, $_) or return foreach isRAID($part) ? @{$all_hds->{hds}} : $hd;      my $lvm = $in->ask_from_listf_(N("Add to LVM"), N("Choose an existing LVM to add to"), @@ -897,12 +1035,12 @@ sub Add2LVM {      require lvm;      if (!ref $lvm) {  	# create new lvm -	my $n = 0; -	while (member("vg$n", @lvm_names)) { +	my $n; my $str = "vg-mga"; +	while (member("$str$n", @lvm_names)) {  	    $n++;  	} -	my $name = "vg$n"; +	my $name = "$str$n";  	$in->ask_from_({ title => N("LVM name"),   			messages => N("Enter a name for the new LVM volume group"),  		       	focus_first => 1, @@ -912,11 +1050,12 @@ sub Add2LVM {  				$in->ask_warn(N("Error"), N("\"%s\" already exists", $name));  				return 0;  			} }, -			[{label=>N("LVM name"),val=> \$name}]) or return; +			[ { label => N("LVM name"), val => \$name } ]) or return;  	$lvm = new lvm($name);  	push @$lvms, $lvm;      } +    my $_w = $in->wait_message(N("Please wait"), N("Setting up LVM"));      raid::make($all_hds->{raids}, $part) if isRAID($part);      lvm::check($in->do_pkgs) if $::isStandalone;      lvm::add_to_VG($part, $lvm); @@ -931,6 +1070,7 @@ sub RemoveFromRAID {  }  sub RemoveFromDm {      my ($_in, $_hd, $part, $all_hds) = @_; +    require fs::dmcrypt;      fs::dmcrypt::close_part($all_hds->{dmcrypts}, $part);  }  sub RemoveFromLVM { @@ -960,7 +1100,7 @@ sub Loopback {      write_partitions($in, $hd) or return; -    my $handle = any::inspect($real_part) or $in->ask_warn(N("Error"), N("This partition can not be used for loopback")), return; +    my $handle = any::inspect($real_part) or $in->ask_warn(N("Error"), N("This partition cannot be used for loopback")), return;      my ($min, $max) = (1, fs::loopback::getFree($handle->{dir}, $real_part));      $max = min($max, 1 << (31 - 9)) if $real_part->{fs_type} eq 'vfat'; #- FAT does not handle file size bigger than 2GB @@ -997,7 +1137,7 @@ sub Loopback {  }  sub Options { -    my ($in, $hd, $part, $all_hds) = @_; +    my ($in, $_hd, $part, $_all_hds) = @_;      my @simple_options = qw(users noauto username= password=); @@ -1031,27 +1171,6 @@ sub Options {  		      if (($options->{usrquota} || $options->{grpquota}) && !$::isInstall) {  			  $in->do_pkgs->ensure_binary_is_installed('quota', 'quotacheck');  		      } -		      if ($options->{encrypted}) { -			  # modify $part->{options} for the check -			  local $part->{options}; -			  fs::mount_options::pack($part, $options, $unknown); -			  if (!check($in, $hd, $part, $all_hds)) { -			      $options->{encrypted} = 0; -			  } elsif (!$part->{encrypt_key} && !isSwap($part)) { -			      if (my ($encrypt_key, $encrypt_algo) = choose_encrypt_key($in, $options, '')) { -				  $options->{'encryption='} = $encrypt_algo; -				  $part->{encrypt_key} = $encrypt_key; -			      } else { -				  $options->{encrypted} = 0; -			      } -			  } -			  #- don't be sure of anything -			  set_isFormatted($part, 0); -			  $part->{notFormatted} = 0; -		      } else { -			  delete $options->{'encryption='}; -			  delete $part->{encrypt_key}; -		      }  		  }) or return;      fs::mount_options::pack($part, $options, $unknown); @@ -1061,20 +1180,20 @@ sub Options {  {      no strict; -    *{'Toggle to normal mode'} = sub() { $::expert = 0 }; -    *{'Toggle to expert mode'} = sub() { $::expert = 1 }; +    *{'Normal mode'} = sub() { $::expert = 0 }; +    *{'Expert mode'} = sub() { $::expert = 1 };      *{'Clear all'} = \&Clear_all;      *{'Auto allocate'} = \&Auto_allocate;      *{'Mount point'} = \&Mount_point;      *{'Modify RAID'} = \&ModifyRAID;      *{'Add to RAID'} = \&Add2RAID;      *{'Remove from RAID'} = \&RemoveFromRAID; -    *{'Use'} = \&dmcrypt_open; +    *{Use} = \&dmcrypt_open;      *{'Remove from dm'} = \&RemoveFromDm;      *{'Add to LVM'} = \&Add2LVM;      *{'Remove from LVM'} = \&RemoveFromLVM;      *{'Use for loopback'} = \&Loopback; -    *{'Hard drive information'} = \&Hd_info; +    *{'Hard disk drive information'} = \&Hd_info;  } @@ -1093,7 +1212,7 @@ sub modifyRAID {      $in->ask_from(N("Options"), '',  		  [  { label => N("device"), val => \$new_device, list => [ $md_part->{device}, raid::free_mds($raids) ], sort => 0 }, -{ label => N("level"), val => \$md_part->{level}, list => [ qw(0 1 4 5 6 linear) ] }, +{ label => N("level"), val => \$md_part->{level}, list => [ qw(0 1 4 5 6 10 linear) ] },  { label => N("chunk size in KiB"), val => \$md_part->{'chunk-size'} },  		  ],  		 ) or return; @@ -1125,7 +1244,8 @@ sub ask_alldatawillbelost {  }  sub partitions_suggestions { -    my ($in) = @_; +    my ($in, $all_hds, $hd) = @_; +    fsedit::init_mntpnt_suggestions($all_hds, $hd);      my $t = $::expert ?        $in->ask_from_list_(N("Partitioning Type"), N("What type of partitioning?"), [ keys %fsedit::suggestions ]) :        'simple'; @@ -1165,7 +1285,7 @@ sub check {  sub check_rebootNeeded {      my ($_in, $hd) = @_; -    $hd->{rebootNeeded} and die N("You'll need to reboot before the modification can take place"); +    $hd->{rebootNeeded} and die N("You'll need to reboot before the modification can take effect");  }  sub write_partitions { @@ -1178,24 +1298,21 @@ sub write_partitions {      partition_table::write($hd) if !$::testing;      check_rebootNeeded($in, $hd) if !$b_skip_check_rebootNeeded;      # fix resizing's failures due to udev's race when writing the partition table -    run_program::run('udevadm', 'settle') unless $::isInstall; +    run_program::run('udevadm', 'settle');      1;  }  sub ensure_we_have_encrypt_key_if_needed {      my ($in, $part) = @_; -    if ($part->{options} =~ /encrypted/ && !$part->{encrypt_key}) { -	my ($options, $_unknown) = fs::mount_options::unpack($part); -	$part->{encrypt_key} = choose_encrypt_key($in, $options, 'skip_encrypt_algo') or return; -    } elsif (fs::type::isRawLUKS($part)) { +    if (fs::type::isRawLUKS($part)) {  	$part->{dmcrypt_key} ||= choose_encrypt_key($in, {}, 'skip_encrypt_algo') or return;      }      1;  }  sub dmcrypt_format { -    my ($in, $hd, $part, $all_hds) = @_; +    my ($in, $_hd, $part, $_all_hds) = @_;      my $_wait = $in->wait_message(N("Please wait"), N("Formatting partition %s", $part->{device}));      require fs::dmcrypt;      fs::dmcrypt::format_part($part); @@ -1217,12 +1334,18 @@ sub format_ {      if ($::isStandalone) {  	fs::format::check_package_is_installed_format($in->do_pkgs, $part->{fs_type}) or return;      } -    if ($::expert && !member($part->{fs_type}, 'reiserfs', 'reiser4', 'xfs', 'hfs', 'ntfs', 'ntfs-3g')) { -	$part->{toFormatCheck} = $in->ask_yesorno(N("Confirmation"), N("Check bad blocks?")); +    _format_raw($in, $part, $all_hds); +} + +sub _format_raw { +    my ($in, $part, $all_hds, $o_skip) = @_; +    if ($::expert && isBlockCheckable($part)) { +	$part->{toFormatCheck} = $in->ask_yesorno(N("Confirmation"), N("Check for bad blocks?"));      }      $part->{isFormatted} = 0; #- force format; +    # Wait for the newly created device to appear before formatting it      my ($_w, $wait_message) = $in->wait_message_with_progress_bar; -    fs::format::part($all_hds, $part, $wait_message); +    fs::format::part($all_hds, $part, $wait_message) if !$o_skip;      1;  } @@ -1300,23 +1423,17 @@ sub format_part_info {      $info .= N("Volume label: ") . "$part->{device_LABEL}\n" if $part->{device_LABEL};      $info .= N("UUID: ") . "$part->{device_UUID}\n" if $::expert && $part->{device_UUID};      $info .= N("DOS drive letter: %s (just a guess)\n", $part->{device_windobe}) if $part->{device_windobe}; -    if (arch() eq "ppc") { -	my $pType = $part->{pType}; -	$pType =~ s/[^A-Za-z0-9_]//g; -	$info .= N("Type: ") . $pType . ($::expert ? sprintf " (0x%x)", $part->{pt_type} : '') . "\n"; -	if (defined $part->{pName}) { -	    my $pName = $part->{pName}; -	    $pName =~ s/[^A-Za-z0-9_]//g; -	    $info .= N("Name: ") . $pName . "\n"; -	} -    } elsif (isEmpty($part)) { +    if (isEmpty($part)) {  	$info .= N("Empty") . "\n";      } else {  	$info .= N("Type: ") . (fs::type::part2type_name($part) || $part->{fs_type}) . ($::expert ? sprintf " (0x%x)", $part->{pt_type} : '') . "\n";      }      $info .= N("Start: sector %s\n", $part->{start}) if $::expert && !isSpecial($part) && !isLVM($hd); -    $info .= N("Size: %s", formatXiB($part->{size}, 512)); -    $info .= sprintf " (%s%%)", int 100 * $part->{size} / $hd->{totalsectors} if $hd->{totalsectors}; +    if ($hd->{totalsectors}) { +	$info .= N("Size: %s (%s%% of disk)", formatXiB($part->{size}, 512), int 100 * $part->{size} / $hd->{totalsectors}); +    } else { +	$info .= N("Size: %s", formatXiB($part->{size}, 512)); +    }      $info .= N(", %s sectors", $part->{size}) if $::expert;      $info .= "\n";      $info .= N("Cylinder %d to %d\n", $part->{start} / $hd->cylinder_size, ($part->{start} + $part->{size} - 1) / $hd->cylinder_size) if ($::expert || isEmpty($part)) && !isSpecial($part) && !isLVM($hd) && $hd->cylinder_size; @@ -1325,10 +1442,13 @@ sub format_part_info {      $info .= N("Not formatted\n") if !$part->{isFormatted} && $part->{notFormatted};      $info .= N("Mounted\n") if $part->{isMounted};      $info .= N("RAID %s\n", $part->{raid}) if isPartOfRAID($part); -    if (fs::type::isRawLUKS($part)) { -	$info .= N("Encrypted") . ($part->{dm_active} && $part->{dm_name} ? N(" (mapped on %s)", $part->{dm_name}) : -				     $part->{dm_name} ? N(" (to map on %s)", $part->{dm_name}) : -				       N(" (inactive)")) . "\n"; +    if (fs::type::isRawLUKS($part) || fs::type::isLUKS($part)) { +	$info .= N("Encrypted") . "\n"; +	if (fs::type::isRawLUKS($part)) { +	    $info .= ($part->{dm_active} && $part->{dm_name} ? N(" (mapped on %s)", $part->{dm_name}) : +		$part->{dm_name} ? N(" (to map on %s)", $part->{dm_name}) : +		N(" (inactive)")) . "\n"; +	}      }      if (isPartOfLVM($part)) {  	$info .= sprintf "LVM %s\n", $part->{lvm}; @@ -1373,6 +1493,8 @@ sub format_hd_info {      $info .= N("LVM-disks %s\n", join ", ", map { $_->{device} } @{$hd->{disks}}) if isLVM($hd) && $hd->{disks};      $info .= N("Partition table type: %s\n", $1) if $::expert && ref($hd) =~ /_([^_]+)$/;      $info .= N("on channel %d id %d\n", $hd->{channel}, $hd->{id}) if $::expert && exists $hd->{channel}; +    # restrict the length of the lines +    $info =~ s/(.{60}).*/$1.../mg;      $info;  } | 
