diff options
Diffstat (limited to 'perl-install/fs')
| -rw-r--r-- | perl-install/fs/any.pm | 88 | ||||
| -rw-r--r-- | perl-install/fs/dmcrypt.pm | 216 | ||||
| -rw-r--r-- | perl-install/fs/dmraid.pm | 107 | ||||
| -rw-r--r-- | perl-install/fs/format.pm | 302 | ||||
| -rw-r--r-- | perl-install/fs/get.pm | 46 | ||||
| -rw-r--r-- | perl-install/fs/loopback.pm | 4 | ||||
| -rw-r--r-- | perl-install/fs/mount.pm | 28 | ||||
| -rw-r--r-- | perl-install/fs/mount_options.pm | 50 | ||||
| -rw-r--r-- | perl-install/fs/mount_point.pm | 39 | ||||
| -rw-r--r-- | perl-install/fs/partitioning.pm | 10 | ||||
| -rw-r--r-- | perl-install/fs/partitioning_wizard.pm | 631 | ||||
| -rw-r--r-- | perl-install/fs/proc_partitions.pm | 18 | ||||
| -rw-r--r-- | perl-install/fs/remote.pm | 2 | ||||
| -rw-r--r-- | perl-install/fs/remote/davfs.pm | 99 | ||||
| -rw-r--r-- | perl-install/fs/remote/nfs.pm | 44 | ||||
| -rw-r--r-- | perl-install/fs/remote/smb.pm | 11 | ||||
| -rw-r--r-- | perl-install/fs/type.pm | 189 | ||||
| -rw-r--r-- | perl-install/fs/wild_device.pm | 28 | 
18 files changed, 1539 insertions, 373 deletions
| diff --git a/perl-install/fs/any.pm b/perl-install/fs/any.pm index 0d8b3ba7d..ce4de2ca3 100644 --- a/perl-install/fs/any.pm +++ b/perl-install/fs/any.pm @@ -1,11 +1,15 @@ -package fs::any; # $Id$ +package fs::any;  use diagnostics;  use strict; +use c;  use common;  use fsedit; +use fs::get;  use fs::mount_point; +use fs::type; +use run_program;  sub get_hds {      my ($all_hds, $fstab, $manual_fstab, $partitioning_flags, $skip_mtab, $o_in) = @_; @@ -58,21 +62,26 @@ sub set_cdrom_symlink {  	my $alias = basename($_->{mntpoint}) or next;  	log::l("using alias $alias for $_->{device}");  	$_->{device_alias} = $alias; -	symlink($_->{device}, "/dev/$alias") if $::prefix; # do create the symlink to have it during install (otherwise fs::wild_device::from_part will give a non accessible device) -	symlink($_->{device}, "$::prefix/dev/$alias"); +	symlink($_->{device}, "/dev/$alias");      }  }  sub check_hds_boot_and_root { -    my ($all_hds, $fstab) = @_; +    my ($all_hds, $fstab, $isUpgrade, $o_match_all_hardware) = @_;      fs::get::root_($fstab) or die "Oops, no root partition"; -    if (arch() =~ /ppc/ && detect_devices::get_mac_generation() =~ /NewWorld/) { -	die "Need bootstrap partition to boot system!" if !(defined $partition_table::mac::bootstrap_part); -    } - -    if (arch() =~ /ia64/ && !fs::get::has_mntpoint("/boot/efi", $all_hds)) { -	die N("You must have a FAT partition mounted in /boot/efi"); +    return if $o_match_all_hardware || $::local_install; + +    if (is_uefi()) { +	if (!fs::get::has_mntpoint("/boot/EFI", $all_hds)) { +	    die N("You must have a ESP FAT32 partition mounted in /boot/EFI"); +	} +    } else { +	# if we are doing an upgrade, the user may still be using a legacy bootloader +	return if $isUpgrade; +	if (is_boot_bios_part_needed($all_hds)) { +	    die N("You must have a BIOS boot partition for non-UEFI GPT-partitioned disks. Please create one before continuing."); +	}      }  } @@ -81,31 +90,24 @@ sub create_minimal_files() {        qw(dev etc etc/profile.d etc/rpm etc/sysconfig etc/sysconfig/console   	etc/sysconfig/network-scripts etc/sysconfig/console/consolefonts   	etc/sysconfig/console/consoletrans -	home mnt tmp var var/tmp var/lib var/lib/rpm var/lib/urpmi); +	home mnt run tmp var var/tmp var/lib var/lib/rpm var/lib/urpmi);      mkdir "$::prefix/$_", 0700 foreach qw(root root/tmp root/drakx); - -    devices::make("$::prefix/dev/null"); -    chmod 0666, "$::prefix/dev/null";  } -sub prepare_minimal_root { -    my ($all_hds) = @_; +sub prepare_minimal_root() { -    fs::any::create_minimal_files(); +    create_minimal_files(); +    # ensure we've all needed devices, for bootloader install and mkinitrd: +    run_program::run('mount', '--bind', '/dev', "$::prefix/dev"); +    run_program::run('mount', '--bind', '/run', "$::prefix/run");      eval { fs::mount::mount('none', "$::prefix/proc", 'proc') };      eval { fs::mount::mount('none', "$::prefix/sys", 'sysfs') }; -    eval { fs::mount::usbfs($::prefix) }; - -    #- needed by lilo -    if (-d '/dev/mapper' && !$::local_install) { -	my @vgs = map { $_->{VG_name} } @{$all_hds->{lvms}}; -	-e "/dev/$_" and cp_af("/dev/$_", "$::prefix/dev") foreach 'mapper', @vgs; -    } +    eval { fs::mount::sys_kernel_debug($::prefix) };  } -sub getAvailableSpace { -    my ($fstab, $o_skip_mounted) = @_; +sub getNeededMinSpace { +    my ($n) = @_;      #- make sure of this place to be available for installation, this could help a lot.      #- currently doing a very small install use 36Mb of postinstall-rpm, but installing @@ -113,9 +115,15 @@ sub getAvailableSpace {      #- 65mb may be a good choice to avoid almost all problem of insuficient space left...      my $minAvailableSize = 65 * sqr(1024); +    max(0.1 * $n, $minAvailableSize); +} + +sub getAvailableSpace { +    my ($fstab, $o_skip_mounted, $o_skip_min_space) = @_; +      my $n = !$::testing && !$o_skip_mounted && getAvailableSpace_mounted($::prefix) ||               getAvailableSpace_raw($fstab) * 512 / 1.07; -    $n - max(0.1 * $n, $minAvailableSize); +    $o_skip_min_space ? $n : $n - getNeededMinSpace($n);  }  sub getAvailableSpace_mounted { @@ -139,4 +147,30 @@ sub getAvailableSpace_raw {      die "missing root partition";  } +=head3 is_boot_bios_part_needed($all_hds) + +Returns whether a Boot BIOS Partition is needed + +Returns true if all of the following are true: +  - legacy boot (not UEFI) +  - all disks are (or will be) GPT +  - no disks have a BIOS boot partition + +=cut + +sub is_boot_bios_part_needed { +    my ($all_hds) = @_; +    # never needed for UEFI boot +    return if is_uefi(); +    # do we already have one? +    my @parts = map { partition_table::get_normal_parts($_) } fs::get::hds($all_hds); +    return if any { isBIOS_GRUB($_) } @parts; +    # do we have any non-GPT disks? +    foreach my $hd (@{$all_hds->{hds}}) { +	my $type = $hd->{pt_table_type} || partition_table::default_type($hd); +	return if $type ne 'gpt'; +    } +    1; +} +  1; diff --git a/perl-install/fs/dmcrypt.pm b/perl-install/fs/dmcrypt.pm new file mode 100644 index 000000000..a78a495d1 --- /dev/null +++ b/perl-install/fs/dmcrypt.pm @@ -0,0 +1,216 @@ +package fs::dmcrypt; + +use diagnostics; +use strict; + +#-###################################################################################### +#- misc imports +#-###################################################################################### +use common; +use fs::type; +use fs::get; +use run_program; + +=head1 SYNOPSYS + +Manage encrypted file systems using cryptsetup + +=head1 Functions + +=over + +=cut + +sub _crypttab() { "$::prefix/etc/crypttab" } + +=item init() + +Load kernel modules and init device mapper. + +=cut + +sub init() { +    whereis_binary('cryptsetup') or die "cryptsetup not installed"; + +    eval { modules::load('dm-crypt', list_modules::category2modules('various/crypto')) }; +    devices::init_device_mapper(); +    1; +} +my $initialized; +sub _ensure_initialized() { +    $initialized++ or init(); +} + +sub read_crypttab_ { +    my ($all_hds, $crypttab) = @_; + +    -e $crypttab or return; + +    my @raw_parts = grep { fs::type::isRawLUKS($_) } fs::get::really_all_fstab($all_hds); + +    foreach (cat_($crypttab)) { +	next if /^#/; +	my ($dm_name, $dev) = split; + +	my $raw_part = fs::get::device2part($dev, \@raw_parts) +	  or log::l("crypttab: unknown device $dev for $dm_name"), next; + +	$raw_part->{dm_name} = $dm_name; +	_get_existing_one_with_state($raw_part); +    } +} + +=item read_crypttab($all_hds) + +Read /etc/crypttab + +=cut + +sub read_crypttab { +    my ($all_hds) = @_; +    read_crypttab_($all_hds, _crypttab()); +} + +sub save_crypttab_ { +    my ($all_hds, $crypttab) = @_; + +    my @raw_parts = grep { $_->{dm_name} } fs::get::really_all_fstab($all_hds) or return; + +    my %names = map { $_->{dm_name} => fs::wild_device::from_part('', $_) } @raw_parts; + +    substInFile { +	my ($name, $_dev) = split; +	if (my $new_dev = delete $names{$name}) { +	    $_ = "$name $new_dev\n"; +	} +	if (eof) { +	    $_ .= join('', map { "$_ $names{$_}\n" } sort keys %names); +	} +    } $crypttab; +} + +=item save_crypttab($all_hds) + +Save /etc/crypttab + +=cut + +sub save_crypttab { +    my ($all_hds) = @_; +    save_crypttab_($all_hds, _crypttab()); +} + +sub format_part { +    my ($part) = @_; + +    my $tmp_key_file = "/tmp/.dmcrypt_key-$$"; +    common::with_private_tmp_file($tmp_key_file, $part->{dmcrypt_key}, sub { +	_run_or_die('--cipher=aes-xts-benbi', '--key-size=512', 'luksFormat', '--batch-mode', devices::make($part->{device}), $_[0]); +    }); +    fs::format::after_formatting($part); +} + +sub open_part { +    my ($dmcrypts, $part) = @_; + +    my $tmp_key_file = "/tmp/.dmcrypt_key-$$"; +    common::with_private_tmp_file($tmp_key_file, $part->{dmcrypt_key}, sub { +	_run_or_die('luksOpen', devices::make($part->{device}),  +				$part->{dm_name}, '--key-file', $_[0]); +    }); +    run_program::run('udevadm', 'settle'); + +    push @$dmcrypts, _get_existing_one_with_state($part); +} + + +sub _get_existing_one_with_state { +    my ($part) = @_; +    my $active_dmcrypt = _parse_dmsetup_table($part->{dm_name},  +					      run_program::get_stdout('dmsetup', 'table', $part->{dm_name})); +    _get_existing_one([$part], $active_dmcrypt); +} + +sub close_part { +    my ($dmcrypts, $part) = @_; +    my $dm_part = fs::get::device2part("mapper/$part->{dm_name}", $dmcrypts); +    _run_or_die('luksClose', devices::make($dm_part->{device})); +    $part->{dm_active} = 0; +    @$dmcrypts = grep { $_ != $dm_part } @$dmcrypts; +    # remove partition from /etc/crypttab when deleted (mga#25891) +    substInFile { +	my ($name, $_dev) = split; +	undef $_ if $name eq $part->{dm_name}; +    } _crypttab(); +} + +sub _run_or_die { +    my ($command, @para) = @_; + +    _ensure_initialized(); + +    run_program::run_or_die('cryptsetup', $command, @para); +} + +sub get_existing { +    my $fstab = \@_; +    map { _get_existing_one($fstab, $_) } active_dmcrypts(); +} + +sub _get_existing_one { +    my ($fstab, $active_dmcrypt) = @_; + +    my $p = fs::wild_device::to_subpart("/dev/mapper/$active_dmcrypt->{name}"); + +    my $part = { device => "mapper/$active_dmcrypt->{name}", size => $active_dmcrypt->{size},  +		 options => 'noatime', dmcrypt_name => $active_dmcrypt->{name}, +		 major => $p->{major}, minor => $p->{minor} }; + +    if (my $raw_part = find { fs::get::is_same_hd($active_dmcrypt, $_) } @$fstab) { +	$part->{rootDevice} = $raw_part->{device}; +	$raw_part->{dm_name} = $active_dmcrypt->{name}; +	$raw_part->{dm_active} = 1; +    } else { +	log::l("could not find the device $active_dmcrypt->{major}:$active_dmcrypt->{minor} for $part->{device}"); +    } + +    if (my $type = fs::type::type_subpart_from_magic($part)) { +	put_in_hash($part, $type); +    } +    fs::type::set_isFormatted($part, to_bool($part->{fs_type})); + +    unless (fs::type::cannotBeMountable($part)) { +	$part->{fs_type} or fs::type::set_fs_type($part, defaultFS()); +    } + +    log::l("dmcrypt: found $part->{device} type $part->{fs_type} with rootDevice $part->{rootDevice}"); + +    $part; +} + +sub active_dmcrypts() { +    grep { $_->{type} eq 'crypt' } active_dm(); +} + +sub _parse_dmsetup_table { +    my ($name, $s) = @_; + +    my @l = split(' ', $s); +    my ($major, $minor) = split(':', $l[6]); +    { name => $name, size => $l[1], type => $l[2], major => $major, minor => $minor }; +} + +sub active_dm() { +    run_program::run('udevadm', 'settle'); + +    map { +	my $name = s/(.*?):\s*// && $1; +	_parse_dmsetup_table($name, $_); +    } run_program::get_stdout('dmsetup', 'table'); +} + +=back + +=cut + +1; diff --git a/perl-install/fs/dmraid.pm b/perl-install/fs/dmraid.pm index 7f9e0fbce..7a279abc7 100644 --- a/perl-install/fs/dmraid.pm +++ b/perl-install/fs/dmraid.pm @@ -1,4 +1,4 @@ -package fs::dmraid; # $Id$ +package fs::dmraid;  use diagnostics;  use strict; @@ -14,23 +14,54 @@ use fs::wild_device;  use run_program; +=head1 SYNOPSYS + +Manage fake RAIDs using dmraid + +=head1 Functions + +=over + +=item init() + +Load kernel modules, init device mapper then scan for fake RAIDs. + +=cut +  sub init() {      whereis_binary('dmraid') or die "dmraid not installed";      eval { modules::load('dm-mirror', 'dm-zero') };      devices::init_device_mapper();      if ($::isInstall) { -	call_dmraid('-ay'); +        foreach my $name (call_dmraid('-s', '-c', '-i')) { +	    chomp($name); +	    log::l("got: $name"); +	    call_dmraid('-ay', '-i', '--rm_partitions', '-p', $name); +	    run_program::run('/sbin/kpartx', '-u', '-a', '/dev/mapper/' . $name); +        }      }      1;  } -#- call_dmraid is overloaded when debugging, see the end of this file +=item call_dmraid($option, @args) + +Runs dmraid with $option & @args. +It is overloaded when debugging, see the end of this file. + +=cut +  sub call_dmraid {      my ($option, @args) = @_;      run_program::get_stdout('dmraid', $option, @args);  } +=item check($in) + +Ensures dmraid is installed. If yes, calls init(). + +=cut +  sub check {      my ($in) = @_; @@ -39,13 +70,36 @@ sub check {      1;  } +=item _raid_devices_raw() + +Get the real VG names, needed for ddf1, and safer than begins_with for raid10 + +=cut +  sub _raid_devices_raw() { +    log::l("_raid_devices_raw"); +    my %vgs; +    my %pv2vg = map { +	chomp(); +	log::l("got: $_"); +	my %l; @l{qw(name size stride level status subsets devs spares)} = split(':'); +	$vgs{$l{name}} = 1 if defined $l{spares}; +	if (/freeing device "(.*)", path "(.*)"/ && defined $vgs{$1}) { +	    log::l("$2 => $1"); +	    $2 => $1; +        } +    } call_dmraid(qw(-d -s -c -c)); +      map {  	chomp;  	log::l("got: $_");  	my %l; @l{qw(pv format vg level status size)} = split(':'); +	if (defined $l{size} && defined $l{vg} && defined $pv2vg{$l{pv}} && !defined $vgs{$l{vg}}) { +	    log::l("using $pv2vg{$l{pv}} instead of $l{vg}"); +	    $l{vg} = $pv2vg{$l{pv}}; +	}  	if_(defined $l{size}, \%l); -    } call_dmraid('-r', '-c', '-c'); +    } call_dmraid(qw(-r -c -c));  }  sub _raid_devices() { @@ -92,6 +146,12 @@ sub _sets() {      @sets;  } +=item vgs() + +Returns the list of VGs corresponding to dmraid + +=cut +  sub vgs() {      map {  	my $dev = "mapper/$_->{name}"; @@ -100,7 +160,12 @@ sub vgs() {  	#- device should exist, created by dmraid(8) using libdevmapper  	#- if it doesn't, we suppose it's not in use -	if_(-e "/dev/$dev", $vg);  +	if (-e "/dev/$dev") { +	    $vg;  +	} else { +	    log::l("ignoring $dev as /dev/$dev doesn't exist"); +	    (); +	}      } grep {   	if ($_->{status} eq 'ok') { @@ -112,6 +177,38 @@ sub vgs() {      } _sets();  } +=item migrate_device_names ($vg) + +Handles migration from /dev/mapper/xxx1 to /dev/mapper/xxxp1, as used by initrd/nash. +dmraid has been patched to follow xxxp1 device names. +So until the box has rebooted on new initrd/dmraid, we must cope with /dev/mapper/xxx1 device names +(cf mdk#44182) + +=cut + +sub migrate_device_names { +    my ($vg) = @_; + +    my $dev_name = basename($vg->{device}); +    foreach (all('/dev/mapper')) { +	my ($nb) = /^\Q$dev_name\E(\d+)$/ or next; +	my $new = $dev_name . 'p' . $nb; +	if (! -e "/dev/mapper/$new") { +	    log::l("migrating to $new, creating a compat symlink $_"); +	    rename "/dev/mapper/$_", "/dev/mapper/$new"; +	    symlink $new, "/dev/mapper/$_"; +	} +    } +} + +=back + +=head1 Debugging + +If $ENV{DRAKX_DEBUG_DMRAID} is set, debugging dmraid is done. +The C<call_dmraid()> function is overloaded and will spit out warnings. +=cut +  if ($ENV{DRAKX_DEBUG_DMRAID}) {      eval(<<'EOF');      my %debug_data = ( diff --git a/perl-install/fs/format.pm b/perl-install/fs/format.pm index 90f6cc89a..1fa90c29e 100644 --- a/perl-install/fs/format.pm +++ b/perl-install/fs/format.pm @@ -1,4 +1,4 @@ -package fs::format; # $Id$ +package fs::format;  use diagnostics;  use strict; @@ -10,26 +10,56 @@ use fs::type;  use fs::loopback;  use log; +=head1 SYNOPSYS + +B<fs::format> enables to format filesystems. + +=head1 Variables + +=over + +=item %cmds + +Commands to format filesystem: + +For each filesystem, list: [ package_name, command_to_use, options_to_use ] + +=cut +  my %cmds = (      ext2     => [ 'e2fsprogs', 'mkfs.ext2', '-F' ],      ext3     => [ 'e2fsprogs', 'mkfs.ext3', '-F' ], -    ext4dev     => [ 'e2fsprogs', 'mkfs.ext3', '-F', '-I', '256' ], # FIXME: enable more options once we've better mkfs support +    ext4     => [ 'e2fsprogs', 'mkfs.ext4', '-F' ], +    f2fs     => [ 'f2fs-tools', 'mkfs.f2fs', '-f' ],      reiserfs => [ 'reiserfsprogs', 'mkfs.reiserfs', '-ff' ], -    reiser4  => [ 'reiser4progs', 'mkfs.reiser4', '-f', '-y' ],      xfs      => [ 'xfsprogs', 'mkfs.xfs', '-f', '-q' ],      jfs      => [ 'jfsutils', 'mkfs.jfs', '-f' ],      hfs      => [ 'hfsutils', 'hformat' ], -    dos      => [ 'dosfstools', 'mkdosfs' ], -    vfat     => [ 'dosfstools', 'mkdosfs', '-F', '32' ], -    swap     => [ 'util-linux-ng', 'mkswap' ], -    ntfs     => [ 'ntfsprogs', 'mkntfs', '--fast' ], -   'ntfs-3g' => [ 'ntfsprogs', 'mkntfs', '--fast' ], +    dos      => [ 'dosfstools', 'mkfs.fat' ], +    vfat     => [ 'dosfstools', 'mkfs.fat', '-F', '32' ], +    exfat    => [ 'exfatprogs', 'mkfs.exfat' ], +    swap     => [ 'util-linux', 'mkswap' ], +    ntfs     => [ 'ntfs-3g', 'mkfs.ntfs', '--fast' ], +   'ntfs-3g' => [ 'ntfs-3g', 'mkfs.ntfs', '--fast' ], +    btrfs    => [ 'btrfs-progs', 'mkfs.btrfs', '-f' ], +    nilfs2   => [ 'nilfs-utils', 'mkfs.nilfs2', '-f' ],  ); -my %LABELs = ( #- option, length, handled_by_mount + +=item %LABELs + +mkfs option to use in order to set the label + label specs. + +For each filesystem, list: [ option, max_length, handled_by_mount ] + +=cut + +my %LABELs = (      ext2     => [ '-L', 16, 1 ],      ext3     => [ '-L', 16, 1 ], -    ext4dev     => [ '-L', 16, 1 ], +    ext4     => [ '-L', 16, 1 ], +    exfat    => [ '-L', 16, 1 ], +    f2fs     => [ '-l', 16, 1 ],      reiserfs => [ '-l', 16, 1 ],      xfs      => [ '-L', 12, 1 ],      jfs      => [ '-L', 16, 1 ], @@ -37,8 +67,69 @@ my %LABELs = ( #- option, length, handled_by_mount      dos      => [ '-n', 11, 0 ],      vfat     => [ '-n', 11, 0 ],      swap     => [ '-L', 15, 1 ], +    ntfs     => [ '-L', 128, 0 ], +   'ntfs-3g' => [ '-L', 128, 0 ], +    btrfs    => [ '-L', 256, 1 ], +    nilfs2   => [ '-L', 16, 1 ],  ); +=item %edit_LABEL + +Commands to set the file system label. + +For each filesystem, list: [ package, command, option ] + +If option is defined, run <command> <option> <label> <device> + +If no option, run <command> <device> <label> + +=cut + +my %edit_LABEL = ( #  +    ext2     => [ 'e2fsprogs', 'tune2fs', '-L' ], +    ext3     => [ 'e2fsprogs', 'tune2fs', '-L' ], +    ext4     => [ 'e2fsprogs', 'tune2fs', '-L' ], +    reiserfs => [ 'reiserfsprogs', 'reiserfstune', '-l' ], +    xfs      => [ 'xfsprogs', 'xfs_admin', '-L' ], +    jfs      => [ 'jfsutils', 'jfs_tune', '-L' ], +#    hfs +    dos      => [ 'mtools', 'mlabel', '-i' ], +    exfat    => [ 'exfatprogs', 'tune.exfat', '-L' ], +    vfat     => [ 'mtools', 'mlabel', '-i' ], +    swap     => [ 'util-linux', 'swaplabel', '-L' ], +    ntfs     => [ 'ntfs-3g', 'ntfslabel' ], +   'ntfs-3g' => [ 'ntfs-3g', 'ntfslabel' ], +    btrfs    => [ 'btrfs-progs', 'btrfs', 'filesystem', 'label' ], +    nilfs2   => [ 'nilfs-utils', 'nilfs-tune', '-L' ], +); + +=item %preserve_UUID + +For each filesystem, list: [ option, max_length, handled_by_mount ] + +Those are used in order to preserve UUID on fs where we couldn't enforce it while formatting. + +=cut + +my %preserve_UUID = ( # package, command +    jfs      => [ 'jfsutils', 'jfs_tune', ], +    xfs      => [ 'xfsprogs', 'xfs_admin' ], +    nilfs2   => [ 'nilfs-utils', 'nilfs-tune' ], +); + + +=back + +=head1 Functions + +=over + +=item package_needed_for_partition_type($part) + +Return the package needed for that partition's type. + +=cut +  sub package_needed_for_partition_type {      my ($part) = @_;      my $l = $cmds{$part->{fs_type}} or return; @@ -50,13 +141,31 @@ sub known_type {      to_bool($cmds{$part->{fs_type}});  } -sub check_package_is_installed { +sub check_package_is_installed_format {      my ($do_pkgs, $fs_type) = @_;      my ($pkg, $binary) = @{$cmds{$fs_type} || return}; -    whereis_binary($binary) || $do_pkgs->ensure_binary_is_installed($pkg, $binary); #- ensure_binary_is_installed checks binary chrooted, whereas we run the binary non-chrooted (pb for Mandriva One) +    whereis_binary($binary) || $do_pkgs->ensure_binary_is_installed($pkg, $binary); #- ensure_binary_is_installed checks binary chrooted, whereas we run the binary non-chrooted (pb for Mageia One) +} + +sub check_package_is_installed_label { +    my ($do_pkgs, $fs_type) = @_; + +    my ($pkg, $binary) = @{$edit_LABEL{$fs_type} || return}; +    whereis_binary($binary) || $do_pkgs->ensure_binary_is_installed($pkg, $binary); #- ensure_binary_is_installed checks binary chrooted, whereas we run the binary non-chrooted (pb for Mageia One) +} + +sub canEditLabel { +    my ($part) = @_; +    to_bool($edit_LABEL{$part->{fs_type}});  } +=item part($all_hds, $part, $wait_message) + +Frontend to part_raw() + +=cut +  sub part {      my ($all_hds, $part, $wait_message) = @_;      if (isRAID($part)) { @@ -70,8 +179,72 @@ sub part {  	$wait_message->(N("Formatting partition %s", $part->{device})) if $wait_message;  	part_raw($part, $wait_message);      } +    undef $part->{toFormat};  } +=item write_label($part) + +Set the label on the filesystem hold in $part. + +=cut + +sub write_label { +    my ($part) = @_; + +    $part->{device_LABEL_changed} or return; +    maybeFormatted($part) or return; + +    if ($part->{encrypt_key}) { +	fs::mount::set_loop($part); +    } + +    my $dev = $part->{real_device} || $part->{device}; +    my ($_pkg, $cmd, @first_options) = @{$edit_LABEL{$part->{fs_type}} || die N("I do not know how to set label on %s with type %s", $part->{device}, $part->{fs_type})}; +    my @args; +    if ($cmd eq 'mlabel') { +      @args = ($cmd, @first_options, devices::make($dev), '::' . $part->{device_LABEL}); +    } elsif ($cmd eq 'btrfs') { +      # btrfs needs reverse ordering +      @args = ($cmd, @first_options, devices::make($dev), $part->{device_LABEL}); +    } elsif (defined $first_options[0]) { +      @args = ($cmd, @first_options, $part->{device_LABEL}, devices::make($dev)); +    } else { +      @args = ($cmd, devices::make($dev), $part->{device_LABEL}); +    } +    run_program::raw({ timeout => 'never' }, @args) or die N("setting label on %s failed, is it formatted?", $dev); +    delete $part->{device_LABEL_changed}; +} + +sub write_btrfs_uuid { +    my ($UUID, $dev) = @_; +    $dev = devices::make($dev); +    my $status = system("echo y|btrfstune -U $UUID $dev") == 0; +    die "failed to set UUID to '$UUID' on $dev (status=$status)" if !$status; +} + +=item sub option_to_preserve_UUID_while_formating($part, $fs_type) + +Return the options needed to preserve UUID while formating + +=cut + +sub option_to_preserve_UUID_while_formating { +    my ($part, $fs_type) = @_; +    if (member($fs_type, qw(swap ext2 ext3 ext4))) { +	return '-U', $part->{device_UUID} if $part->{device_UUID}; +    } elsif ($fs_type eq 'reiserfs') { +	return '-u', $part->{device_UUID} if $part->{device_UUID}; +    } +    return (); +} + +=item part_raw($part, $wait_message) + +Actually format the $part partition disk. $wait_message is only used when formating ext3/4. +If not set, ext[3-4] will be formated without any progression bar, like other fses... + +=cut +  sub part_raw {      my ($part, $wait_message) = @_; @@ -88,7 +261,7 @@ sub part_raw {      my $fs_type = $part->{fs_type}; -    if (member($fs_type, qw(ext2 ext3 ext4dev))) { +    if (member($fs_type, qw(ext2 ext3 ext4))) {  	push @options, "-m", "0" if $part->{mntpoint} =~ m|^/home|;      } elsif (isDos($part)) {  	$fs_type = 'dos'; @@ -96,49 +269,72 @@ sub part_raw {          push @options, '-l', "Untitled";      } elsif (isAppleBootstrap($part)) {  	push @options, '-l', 'bootstrap'; -    } elsif ($fs_type eq 'swap') { -	push @options, '-U', $part->{device_UUID} if $part->{device_UUID};      } +    push @options, option_to_preserve_UUID_while_formating($part, $fs_type); +          if ($part->{device_LABEL}) { -	if ($LABELs{$fs_type}) { -	    my ($option, $length, $handled_by_mount) = @{$LABELs{$fs_type}}; -	    if (length $part->{device_LABEL} > $length) { -		my $short = substr($part->{device_LABEL}, 0, $length); -		log::l("shortening LABEL $part->{device_LABEL} to $short"); -		$part->{device_LABEL} = $short; -	    } -	    delete $part->{prefer_device_LABEL} -	      if !$handled_by_mount || $part->{mntpoint} eq '/' && !member($fs_type, qw(ext2 ext3 ext4dev)); - -	    push @options, $option, $part->{device_LABEL}; -	} else { -	    log::l("dropping LABEL=$part->{device_LABEL} since we don't know how to set labels for fs_type $part->{fs_type}"); -	    delete $part->{device_LABEL}; -	    delete $part->{prefer_device_LABEL}; -	} +	push @options, @{$LABELs{$fs_type}}[0], $part->{device_LABEL};      }      my ($_pkg, $cmd, @first_options) = @{$cmds{$fs_type} || die N("I do not know how to format %s in type %s", $part->{device}, $part->{fs_type})};      my @args = ($cmd, @first_options, @options, devices::make($dev)); -    if ($cmd eq 'mkfs.ext3' && $wait_message) { +    if ($cmd =~ /^mkfs.ext[34]$/ && $wait_message) {  	mkfs_ext3($wait_message, @args) or die N("%s formatting of %s failed", $fs_type, $dev);      } else {  	run_program::raw({ timeout => 'never' }, @args) or die N("%s formatting of %s failed", $fs_type, $dev);      } -    if (member($fs_type, qw(ext3 ext4dev))) { +    delete $part->{device_LABEL_changed}; + +    preserve_UUID_after_format($dev, $part, $fs_type); + +    if (member($fs_type, qw(ext3 ext4))) {  	disable_forced_fsck($dev);      } +    after_formatting($part); +} + +=item preserve_UUID_after_format($dev, $part, $fs_type) + +Preserve UUID on fs where we couldn't enforce it while formatting + +=cut + +sub preserve_UUID_after_format { +    my ($dev, $part, $fs_type) = @_; +    if (my $uuid_cmd = $preserve_UUID{$fs_type}) { +	my (undef, $cmd) = @$uuid_cmd; +	run_program::raw({}, $cmd, '-U', $part->{device_UUID}, devices::make($dev)) if $cmd; +    } elsif ($fs_type eq 'btrfs' && $part->{device_UUID}) { +	write_btrfs_uuid($part->{device_UUID}, $dev); +    } +} + +=item after_formatting($part) + +Misc post formating tags (rereading UUID & setting state) + +=cut + +sub after_formatting { +    my ($part) = @_; +      my $p = fs::type::type_subpart_from_magic($part);      $part->{device_UUID} = $p && $p->{device_UUID};      set_isFormatted($part, 1);  } +=item mkfs_ext3($wait_message, @args) + +Display a progression bar whike formating ext3/4 + +=cut +  sub mkfs_ext3 {      my ($wait_message, @args) = @_; @@ -155,11 +351,39 @@ sub mkfs_ext3 {      return close($F);  } +=item disable_forced_fsck($dev) + +Disable automatic fsck on extX (infinite number of mounts & duration between 2 fsck runs) + +=cut +  sub disable_forced_fsck {      my ($dev) = @_;      run_program::run("tune2fs", "-c0", "-i0", devices::make($dev));  } +sub clean_label { +    my ($part) = @_; +    if ($part->{device_LABEL}) { +	my $fs_type = $part->{fs_type}; +	if ($LABELs{$fs_type}) { +	    my ($_option, $length, $handled_by_mount) = @{$LABELs{$fs_type}}; +	    if (length $part->{device_LABEL} > $length) { +		my $short = substr($part->{device_LABEL}, 0, $length); +		log::l("shortening LABEL $part->{device_LABEL} to $short"); +		$part->{device_LABEL} = $short; +	    } +	    delete $part->{prefer_device_LABEL} +	      if !$handled_by_mount || $part->{mntpoint} eq '/' && !member($fs_type, qw(ext2 ext3 ext4)); +	} else { +	    log::l("dropping LABEL=$part->{device_LABEL} since we don't know how to set labels for fs_type $fs_type"); +	    delete $part->{device_LABEL}; +	    delete $part->{prefer_device_LABEL}; +	    delete $part->{device_LABEL_changed}; +	} +    } +} +  sub formatMount_part {      my ($part, $all_hds, $fstab, $wait_message) = @_; @@ -169,12 +393,17 @@ sub formatMount_part {      if (my $p = fs::get::up_mount_point($part->{mntpoint}, $fstab)) {  	formatMount_part($p, $all_hds, $fstab, $wait_message) if !fs::type::carry_root_loopback($part);      } + +    clean_label($part); +      if ($part->{toFormat}) {  	fs::format::part($all_hds, $part, $wait_message); +    } else { +	fs::format::write_label($part);      }      #- setting user_xattr on /home (or "/" if no /home) -    if (!$part->{isMounted} && member($part->{fs_type}, qw(ext3 ext4dev)) +    if (!$part->{isMounted} && member($part->{fs_type}, qw(ext2 ext3 ext4))  	  && ($part->{mntpoint} eq '/home' ||  		!fs::get::has_mntpoint('/home', $all_hds) && $part->{mntpoint} eq '/')) {  	run_program::run('tune2fs', '-o', 'user_xattr', devices::make($part->{real_device} || $part->{device})); @@ -185,7 +414,7 @@ sub formatMount_part {  sub formatMount_all {      my ($all_hds, $fstab, $wait_message) = @_; -    formatMount_part($_, $all_hds, $fstab, $wait_message)  +    formatMount_part($_, $all_hds, $fstab, $wait_message)        foreach sort { isLoopback($a) ? 1 : isSwap($a) ? -1 : 0 } grep { $_->{mntpoint} } @$fstab;      #- ensure the link is there @@ -199,5 +428,8 @@ sub formatMount_all {      };  } +=back + +=cut  1; diff --git a/perl-install/fs/get.pm b/perl-install/fs/get.pm index aa23d1c61..00c807738 100644 --- a/perl-install/fs/get.pm +++ b/perl-install/fs/get.pm @@ -1,4 +1,4 @@ -package fs::get; # $Id$ +package fs::get;  use diagnostics;  use strict; @@ -11,24 +11,35 @@ use fs;  use common;  use log; + +=head1 SYNOPSYS + +B<fs::get>  + +=head1 Functions + +=over + +=cut +  sub empty_all_hds() { -    { hds => [], lvms => [], raids => [], loopbacks => [], raw_hds => [], nfss => [], smbs => [], davs => [], special => [] }; +    { hds => [], lvms => [], raids => [], dmcrypts => [], loopbacks => [], raw_hds => [], nfss => [], smbs => [], davs => [], special => [] };  }  sub fstab {      my ($all_hds) = @_;      my @parts = map { partition_table::get_normal_parts($_) } hds($all_hds); -    @parts, @{$all_hds->{raids}}, @{$all_hds->{loopbacks}}; +    @parts, @{$all_hds->{raids}}, @{$all_hds->{dmcrypts}}, @{$all_hds->{loopbacks}};  }  sub really_all_fstab {      my ($all_hds) = @_;      my @l = fstab($all_hds); -    @l, @{$all_hds->{raw_hds}}, @{$all_hds->{nfss}}, @{$all_hds->{smbs}}, @{$all_hds->{davs}}; +    @l, (grep { !$_->{is_removable} } @{$all_hds->{raw_hds}}), @{$all_hds->{nfss}}, @{$all_hds->{smbs}}, @{$all_hds->{davs}};  }  sub fstab_and_holes {      my ($all_hds, $b_non_readonly) = @_;      my @hds = grep { !($b_non_readonly && $_->{readonly}) } hds($all_hds); -    hds_fstab_and_holes(@hds), @{$all_hds->{raids}}, @{$all_hds->{loopbacks}}; +    hds_fstab_and_holes(@hds), @{$all_hds->{raids}}, @{$all_hds->{dmcrypts}}, @{$all_hds->{loopbacks}};  }  sub holes { @@ -51,7 +62,12 @@ sub hds {      (@{$all_hds->{hds}}, @{$all_hds->{lvms}});  } -#- get all normal partition including special ones as found on sparc. +=item hds_fstab(@hds) + +Get all normal partition. + +=cut +  sub hds_fstab {      map { partition_table::get_normal_parts($_) } @_;  } @@ -119,6 +135,15 @@ sub has_mntpoint {      my ($mntpoint, $all_hds) = @_;      mntpoint2part($mntpoint, [ really_all_fstab($all_hds) ]);  } + +sub root_from_mounted() { +    foreach (`df -P`) { +        next if m!^[^/]!; # ignore tootfs +        my ($fs, undef, undef, undef, undef, $mntpnt) = split(/\s+/); +        return $fs if $mntpnt eq '/'; +    } +} +  sub root_ {      my ($fstab, $o_boot) = @_;      $o_boot && mntpoint2part("/boot", $fstab) || mntpoint2part("/", $fstab); @@ -144,7 +169,10 @@ sub is_same_hd {      } else {  	$hd1->{device_LABEL} && $hd2->{device_LABEL} && $hd1->{device_LABEL} eq $hd2->{device_LABEL}  	  || $hd1->{device_UUID} && $hd2->{device_UUID} && $hd1->{device_UUID} eq $hd2->{device_UUID} -	  || $hd1->{device} && $hd2->{device} && $hd1->{device} eq $hd2->{device}; +	  || $hd1->{device} && $hd2->{device} && $hd1->{device} eq $hd2->{device} +	  || $hd1->{device} && $hd2->{device_alias} && $hd1->{device} eq $hd2->{device_alias} +	  || $hd1->{device_alias} && $hd2->{device} && $hd1->{device_alias} eq $hd2->{device} +	  || $hd1->{device_alias} && $hd2->{device_alias} && $hd1->{device_alias} eq $hd2->{device_alias};      }  } @@ -153,4 +181,8 @@ sub mntpoint_prefixed {      $::prefix . $part->{mntpoint};  } +=back + +=cut +  1; diff --git a/perl-install/fs/loopback.pm b/perl-install/fs/loopback.pm index 572c79f67..8d0c729ec 100644 --- a/perl-install/fs/loopback.pm +++ b/perl-install/fs/loopback.pm @@ -1,4 +1,4 @@ -package fs::loopback; # $Id$ +package fs::loopback;  use diagnostics;  use strict; @@ -86,7 +86,7 @@ sub getFree {  }  #- returns the size of the loopback file if it already exists -#- returns -1 is the loopback file can not be used +#- returns -1 is the loopback file cannot be used  sub verifFile {      my ($dir, $file, $part) = @_;      -e "$dir$file" and return -s "$dir$file"; diff --git a/perl-install/fs/mount.pm b/perl-install/fs/mount.pm index 6dc312049..6afaa9260 100644 --- a/perl-install/fs/mount.pm +++ b/perl-install/fs/mount.pm @@ -1,4 +1,4 @@ -package fs::mount; # $Id$ +package fs::mount;  use diagnostics;  use strict; @@ -35,10 +35,10 @@ sub mount {      $fs or log::l("not mounting $dev partition"), return;      { -	my @fs_modules = qw(ext3 ext4dev hfs jfs nfs ntfs romfs reiserfs ufs xfs vfat); -	my @types = (qw(ext2 proc sysfs usbfs usbdevfs iso9660 devfs devpts auto ntfs-3g), @fs_modules); +	my @fs_modules = qw(btrfs ext3 ext4 f2fs hfs jfs nilfs2 nfs ntfs romfs reiserfs ufs xfs vfat); +	my @types = (qw(ext2 proc sysfs iso9660 devpts auto ntfs-3g), @fs_modules); -	push @types, 'smb', 'smbfs', 'davfs2' if !$::isInstall; +	push @types, 'smb', 'cifs', 'davfs2' if !$::isInstall;  	if (!member($fs, @types)) {  	    log::l("skipping mounting $dev partition ($fs)"); @@ -72,11 +72,18 @@ sub mount {  	fsck_jfs($dev, $o_wait_message);      } elsif ($fs eq 'ext2' && !$b_rdonly) {  	fsck_ext2($dev, $o_wait_message); +    } elsif ($fs eq 'davfs2') { +	require fs::remote::davfs; +	# We have to store credentials in davfs2 secret file before mounting +	fs::remote::davfs::mountpoint_credentials_save($where, \@mount_opt); +	# username and password options should be handled by /etc/davfs2/secrets file +	@mount_opt = grep { !/^(username|password)=/ } @mount_opt;      }      push @mount_opt, 'ro' if $b_rdonly;      $o_wait_message->(N("Mounting partition %s", $dev)) if $o_wait_message; +    modules::load("fuse") if $::isInstall && $fs eq 'ntfs-3g' && ! -e '/dev/fuse';      run_program::run('mount', '-t', $fs, $dev, $where, if_(@mount_opt, '-o', join(',', @mount_opt))) or die N("mounting partition %s in directory %s failed", $dev, $where);  } @@ -119,7 +126,7 @@ sub umount {  	run_program::run('umount', '2>', \$err, $mntpoint) or die N("error unmounting %s: %s", $mntpoint, common::to_utf8($err));      }; -    substInFile { $_ = '' if /(^|\s)$mntpoint\s/ } '/etc/mtab'; #- do not care about error, if we can not read, we will not manage to write... (and mess mtab) +    substInFile { $_ = '' if /(^|\s)$mntpoint\s/ } '/etc/mtab'; #- do not care about error, if we cannot read, we will not manage to write... (and mess mtab)  }  sub part { @@ -154,8 +161,6 @@ sub part {  		set_loop($part);  		$options = join(',', grep { !/^(encryption=|encrypted$|loop$)/ } split(',', $options)); #- we take care of this, don't let it mount see it  	    } elsif (isLoopback($part)) { -		#- mount will take care, but we must help it -		devices::make("loop$_") foreach 0 .. 7;  		$options = join(',', uniq('loop', split(',', $options))); #- ensure the loop options is used  	    } elsif ($part->{options} =~ /encrypted/) {  		log::l("skip mounting $part->{device} since we do not have the encrypt_key"); @@ -172,7 +177,7 @@ sub part {  	    }  	    mount($dev, $mntpoint, $fs_type, $b_rdonly, $options, $o_wait_message); -	    if ($options =~ /usrquota|grpquota/ && member($part->{fs_type}, qw(ext3 ext4dev))) { +	    if ($options =~ /usrquota|grpquota/ && member($part->{fs_type}, qw(ext3 ext4))) {  		if (! find { -e "$mntpoint/$_" } qw(aquota.user aquota.group quota.user quota.group)) {  		    #- quotacheck will create aquota.user and/or aquota.group,  		    #- needed for quotas on ext3/ext4. @@ -216,16 +221,15 @@ sub umount_all {      log::l("unmounting all filesystems");      foreach (sort { $b->{mntpoint} cmp $a->{mntpoint} }  -	       grep { $_->{mntpoint} && !$_->{real_mntpoint} } @$fstab) { +	       grep { $_->{mntpoint} && !$_->{real_mntpoint} || isSwap($_) } @$fstab) {  	umount_part($_);      }  } -sub usbfs { +sub sys_kernel_debug {      my ($prefix) = @_; -    my $fs = cat_('/proc/filesystems') =~ /usbfs/ ? 'usbfs' : 'usbdevfs'; -    mount('none', "$prefix/proc/bus/usb", $fs); +    mount('none', "$prefix/sys/kernel/debug/usb", 'debugfs');  }  1; diff --git a/perl-install/fs/mount_options.pm b/perl-install/fs/mount_options.pm index 6ac55584a..0b63f7260 100644 --- a/perl-install/fs/mount_options.pm +++ b/perl-install/fs/mount_options.pm @@ -1,4 +1,4 @@ -package fs::mount_options; # $Id$ +package fs::mount_options;  use diagnostics;  use strict; @@ -30,20 +30,19 @@ sub unpack {  		  vfat => [ qw(flush umask=0 umask=0022) ],  		  ntfs => [ qw(umask=0 umask=0022) ],  		  nfs => [ qw(rsize=8192 wsize=8192) ], -		  smbfs => [ qw(username= password=) ], +		  cifs => [ qw(username= password=) ],  		  davfs2 => [ qw(username= password= uid= gid=) ], -		  ext4dev => [ qw(extents) ],  		  reiserfs => [ 'notail' ],  		 ); -    push @{$per_fs{$_}}, 'usrquota', 'grpquota' foreach 'ext2', 'ext3', 'ext4dev', 'xfs'; +    push @{$per_fs{$_}}, 'usrquota', 'grpquota' foreach 'ext2', 'ext3', 'ext4', 'xfs'; +    push @{$per_fs{$_}}, 'acl' foreach 'ext2', 'ext3', 'ext4', 'reiserfs';      while (my ($fs, $l) = each %per_fs) { -	$part->{fs_type} eq $fs || $part->{fs_type} eq 'auto' && member($fs, @auto_fs) or next; +	member($part->{fs_type}, $fs, 'auto') && member($fs, @auto_fs) or next;  	$non_defaults->{$_} = 1 foreach @$l;      }      $non_defaults->{relatime} = 1 if isTrueLocalFS($part) || $part->{fs_type} eq 'ntfs-3g'; -    $non_defaults->{encrypted} = 1;      my $defaults = { reverse %$non_defaults };      my %options = map { $_ => '' } keys %$non_defaults; @@ -104,6 +103,7 @@ sub pack_ {  }  sub pack {      my ($part, $options, $unknown) = @_; +    $unknown =~ s/ /,/g;      $part->{options} = pack_($part, $options, $unknown) || 'defaults';      noreturn();  } @@ -111,39 +111,38 @@ sub pack {  # update me on each util-linux new release:  sub help() {      ( - -	'encrypted' => N("Use an encrypted file system"), +	'acl' => N("Enable POSIX Access Control Lists"),  	'flush' => N("Flush write cache on file close"),  	'grpquota' => N("Enable group disk quota accounting and optionally enforce limits"), -	'noatime' => N("Do not update inode access times on this file system +	'noatime' => N("Do not update inode access times on this filesystem  (e.g, for faster access on the news spool to speed up news servers)."),  	'relatime' => N("Update inode access times on this filesystem in a more efficient way  (e.g, for faster access on the news spool to speed up news servers)."),  	'noauto' => N("Can only be mounted explicitly (i.e., -the -a option will not cause the file system to be mounted)."), +the -a option will not cause the filesystem to be mounted)."), -	'nodev' => N("Do not interpret character or block special devices on the file system."), +	'nodev' => N("Do not interpret character or block special devices on the filesystem."),  	'noexec' => N("Do not allow execution of any binaries on the mounted -file system. This option might be useful for a server that has file systems +filesystem. This option might be useful for a server that has filesystems  containing binaries for architectures other than its own."),  	'nosuid' => N("Do not allow set-user-identifier or set-group-identifier  bits to take effect. (This seems safe, but is in fact rather unsafe if you  have suidperl(1) installed.)"), -	'ro' => N("Mount the file system read-only."), +	'ro' => N("Mount the filesystem read-only."), -	'sync' => N("All I/O to the file system should be done synchronously."), +	'sync' => N("All I/O to the filesystem should be done synchronously."), -	'users' => N("Allow every user to mount and umount the file system."),          +	'users' => N("Allow every user to mount and umount the filesystem."),          -	'user' => N("Allow an ordinary user to mount the file system."),          +	'user' => N("Allow an ordinary user to mount the filesystem."),           	'usrquota' => N("Enable user disk quota accounting, and optionally enforce limits"), @@ -164,7 +163,7 @@ sub rationalize {      if ($part->{fs_type} ne 'reiserfs') {  	$options->{notail} = 0;      } -    if (!fs::type::can_be_one_of_those_fs_types($part, 'vfat', 'smbfs', 'iso9660', 'udf')) { +    if (!fs::type::can_be_one_of_those_fs_types($part, 'vfat', 'cifs', 'iso9660', 'udf')) {  	delete $options->{'codepage='};      }      if (member($part->{mntpoint}, fs::type::directories_needed_to_boot())) { @@ -188,7 +187,6 @@ sub set_default {      if (!$opts{ignore_is_removable} && $part->{is_removable}   	  && !member($part->{mntpoint}, fs::type::directories_needed_to_boot())   	  && (!$part->{fs_type} || $part->{fs_type} eq 'auto' || $part->{fs_type} =~ /:/)) { -	$options->{supermount} = 0; #- always disable supermount  	$part->{fs_type} = 'auto';  	$options->{flush} = 1 if $part->{media_type} ne 'cdrom';      } @@ -206,17 +204,17 @@ sub set_default {  	#- noatime on laptops (do not wake up the hd)  	#- otherwise relatime (wake up the hd less often / better performances)  	#- Do  not  update  inode  access times on this -	#- file system (e.g, for faster access  on  the +	#- filesystem (e.g, for faster access  on  the  	#- news spool to speed up news servers).  	$options->{relatime} = $options->{noatime} = 0; -	$options->{detect_devices::isLaptop() ? 'noatime': 'relatime'} = 1 if !$opts{force_atime}; +	$options->{ detect_devices::isLaptop() ? 'noatime' : 'relatime' } = 1 if !$opts{force_atime};      }      if ($part->{fs_type} eq 'nfs') {  	put_in_hash($options, {   			       nosuid => 1, 'rsize=8192,wsize=8192' => 1, soft => 1,  			      });      } -    if ($part->{fs_type} eq 'smbfs') { +    if ($part->{fs_type} eq 'cifs') {  	add2hash($options, { 'username=' => '%' }) if !$options->{'credentials='};      }      if (fs::type::can_be_this_fs_type($part, 'vfat')) { @@ -226,16 +224,13 @@ sub set_default {  			      }) if $part->{is_removable};  	put_in_hash($options, { -			       'umask=0' => $opts{security} <= 3, +			       'umask=0' => $opts{security} <= 1 && !isESP($part),  			       'iocharset=' => $opts{iocharset}, 'codepage=' => $opts{codepage},  			      });      } -    if ($part->{fs_type} eq 'ext4dev') { -	put_in_hash($options, { extents => 1 }); -    }      if ($part->{fs_type} eq 'ntfs') {  	put_in_hash($options, { ro => 1, 'nls=' => $opts{iocharset}, -				'umask=0' => $opts{security} < 3, 'umask=0022' => $opts{security} < 4, +				'umask=0' => $opts{security} < 1, 'umask=0022' => $opts{security} < 2,  			      });      }      if (fs::type::can_be_this_fs_type($part, 'iso9660')) { @@ -245,6 +240,9 @@ sub set_default {  	$options->{notail} = 1;  	$options->{user_xattr} = 1;      } +    if (member($part->{fs_type}, qw(ext2 ext3 ext4))) { +	$options->{acl} = 1; +    }      if (isLoopback($part) && !isSwap($part)) { #- no need for loop option for swap files  	$options->{loop} = 1;      } diff --git a/perl-install/fs/mount_point.pm b/perl-install/fs/mount_point.pm index 4d4880f5d..56f2405e9 100644 --- a/perl-install/fs/mount_point.pm +++ b/perl-install/fs/mount_point.pm @@ -1,4 +1,4 @@ -package fs::mount_point; # $Id$ +package fs::mount_point;  use diagnostics;  use strict; @@ -13,16 +13,21 @@ sub guess_mount_point {      my %l = (  	     '/'     => 'etc/fstab',  	     '/boot' => 'vmlinuz', +	     '/boot' => 'vmlinux', +	     '/boot' => 'uImage',  	     '/tmp'  => '.X11-unix',  	     '/usr'  => 'src', -	     '/var'  => 'catman', +	     '/var'  => 'spool',  	    );      my $handle = any::inspect($part, $prefix) or return;      my $d = $handle->{dir};      my $mnt = find { -e "$d/$l{$_}" } keys %l;      $mnt ||= (stat("$d/.bashrc"))[4] ? '/root' : '/home/user' . ++$$user if -e "$d/.bashrc"; -    $mnt ||= (any { -d $_ && (stat($_))[4] >= 500 && -e "$_/.bashrc" } glob_($d)) ? '/home' : ''; +    $mnt ||= (any { -d $_ && (stat($_))[4] >= 1000 && -e "$_/.bashrc" } glob_($d)) ? '/home' : ''; +    # Keep uid 500 here for guesswork, but base it on .bash_history to increase +    # changes it's a real user. +    $mnt ||= (any { -d $_ && (stat($_))[4] >= 500 && -e "$_/.bash_history" } glob_($d)) ? '/home' : '';      ($mnt, $handle);  } @@ -41,30 +46,32 @@ sub suggest_mount_points {  	#- try to find other mount points via fstab  	fs::merge_info_from_fstab($fstab, $handle->{dir}, $uniq, 'loose') if $mnt eq '/';      } +    # reuse existing ESP under UEFI: +    my @ESP = if_(is_uefi(), grep { isESP($_) } @$fstab); +    if (@ESP) { +	$ESP[0]{mntpoint} = '/boot/EFI'; +	delete $ESP[0]{unsafeMntpoint}; +    }      $_->{mntpoint} and log::l("suggest_mount_points: $_->{device} -> $_->{mntpoint}") foreach @$fstab;  }  sub suggest_mount_points_always {      my ($fstab) = @_; -    my @win = grep { isFat_or_NTFS($_) && maybeFormatted($_) && !$_->{is_removable} && $_->{pt_type} != 0x12 } @$fstab; +    my @ESP = if_(is_uefi(), grep { isESP($_) && maybeFormatted($_) && !$_->{is_removable} } @$fstab); +    if (@ESP) { +	$ESP[0]{mntpoint} = "/boot/EFI"; +    } +    my @win = grep { isnormal_Fat_or_NTFS($_) && !$_->{isMounted} && maybeFormatted($_) && !$_->{is_removable} } @$fstab;      log::l("win parts: ", join ",", map { $_->{device} } @win) if @win;      if (@win == 1) { -	#- Suggest /boot/efi on ia64. -	$win[0]{mntpoint} = arch() =~ /ia64/ ? "/boot/efi" : "/mnt/windows"; +	$win[0]{mntpoint} = "/media/windows";      } else {  	my %w; foreach (@win) {  	    my $v = $w{$_->{device_windobe}}++; -	    $_->{mntpoint} = $_->{unsafeMntpoint} = "/mnt/win_" . lc($_->{device_windobe}) . ($v ? $v+1 : ''); #- lc cuz of StartOffice(!) cf dadou +	    $_->{mntpoint} = $_->{unsafeMntpoint} = "/media/win_" . lc($_->{device_windobe}) . ($v ? $v+1 : ''); #- lc cuz of StartOffice(!) cf dadou  	}      } - -    my @sunos = grep { $_->{pt_type} == 2 } @$fstab; #- take only into account root partitions. -    if (@sunos) { -	my $v = ''; -	map { $_->{mntpoint} = $_->{unsafeMntpoint} = "/mnt/sunos" . ($v && ++$v) } @sunos; -    } -    #- a good job is to mount SunOS root partition, and to use mount point described here in /etc/vfstab.  }  sub validate_mount_points { @@ -80,8 +87,8 @@ sub validate_mount_points {  	$m{$m} and die N("Duplicate mount point %s", $m);  	$m{$m} = 1; -	#- in case the type does not correspond, force it to ext3 -	fs::type::set_fs_type($_, 'ext3') if !isTrueFS($_) && !isOtherAvailableFS($_); +	#- in case the type does not correspond, force it to default fs (ext4 currently) +	fs::type::set_fs_type($_, defaultFS()) if !isTrueFS($_) && !isOtherAvailableFS($_);      }      1;  } diff --git a/perl-install/fs/partitioning.pm b/perl-install/fs/partitioning.pm index ab2b6733a..18fa7e114 100644 --- a/perl-install/fs/partitioning.pm +++ b/perl-install/fs/partitioning.pm @@ -1,16 +1,18 @@ -package fs::partitioning; # $Id$ +package fs::partitioning;  use diagnostics;  use strict;  use common;  use fs::format; +use fs::get;  use fs::type;  sub guess_partitions_to_format {      my ($fstab) = @_; +    my $root_part = fs::get::root($fstab);      foreach (@$fstab) { -	$_->{mntpoint} = "swap" if isSwap($_); +	$_->{mntpoint} = "swap" if isSwap($_) && ($_->{rootDevice} eq $root_part->{rootDevice} || !$_->{is_removable} && !$root_part->{is_removable});  	$_->{mntpoint} or next;  	add2hash_($_, { toFormat => $_->{notFormatted} }) if $_->{fs_type}; #- eg: do not set toFormat for isRawRAID (0xfd) @@ -45,14 +47,14 @@ sub choose_partitions_to_format {      $in->ask_from_(          { messages => N("Choose the partitions you want to format"),  	  interactive_help_id => 'formatPartitions', -          advanced_messages => N("Check bad blocks?"), +          advanced_messages => N("Check for bad blocks?"),          },          [ map {   	    my $e = $_;  	    ({  	      text => partition_table::description($e), type => 'bool',  	      val => \$e->{toFormatTmp} -	     }, if_(!isLoopback($_) && !member($_->{fs_type}, 'reiserfs', 'xfs', 'jfs'), { +	     }, if_(!isLoopback($_) && isBlockCheckable($_), {  	      text => partition_table::description($e), type => 'bool', advanced => 1,   	      disabled => sub { !$e->{toFormatTmp} },  	      val => \$e->{toFormatCheck} diff --git a/perl-install/fs/partitioning_wizard.pm b/perl-install/fs/partitioning_wizard.pm index 947bad0d0..6e77f3eff 100644 --- a/perl-install/fs/partitioning_wizard.pm +++ b/perl-install/fs/partitioning_wizard.pm @@ -1,4 +1,4 @@ -package fs::partitioning_wizard; # $Id$ +package fs::partitioning_wizard;  use diagnostics;  use strict; @@ -11,13 +11,29 @@ use fs::type;  use fs::mount_point;  use partition_table;  use partition_table::raw; +use partition_table::dos; +use POSIX qw(ceil); + + +=head1 SYNOPSYS + +B<fs::partitioning_wizard> implements the partitioning wizard. + +=head1 Functions + +=over + +=item from_Mb($mb, $min, $max) + +This function is used to convert back to sectors count the size of +a partition ($mb) given from the interface (on Resize or Create). +modified to take into account a true bounding with min and max. +Unit of $mb is mega bytes, min and max are in sectors. + +=cut -#- unit of $mb is mega bytes, min and max are in sectors, this -#- function is used to convert back to sectors count the size of -#- a partition ($mb) given from the interface (on Resize or Create). -#- modified to take into account a true bounding with min and max.  sub from_Mb { -    my ($mb, $min, $max) = @_; +    emy ($mb, $min, $max) = @_;      $mb <= to_Mb($min) and return $min;      $mb >= to_Mb($max) and return $max;      MB($mb); @@ -28,15 +44,28 @@ sub to_Mb {  }  sub partition_with_diskdrake { -    my ($in, $all_hds, $fstab, $manual_fstab, $partitions, $partitioning_flags, $skip_mtab) = @_; -    my $ok;  +    my ($in, $all_hds, $fstab, $manual_fstab, $_partitions, $partitioning_flags, $skip_mtab) = @_; +    my $ok; + +    # The classic installer sets $skip_mtab to either undef or 1. The live +    # installer sets it to 'skip_mtab'. If $skip_mtab is not set, this has +    # already been done by fs::any::get_hds. +    if ($skip_mtab eq 'skip_mtab') { +        fs::mount_point::suggest_mount_points_always($fstab); +    }      do {  	$ok = 1;  	my $do_force_reload = sub { +            require File::Temp; +            require fs::dmcrypt; +            my (undef, $tmp_file) = File::Temp::mkstemp('/tmp/crypttab.XXXXXXX'); +            fs::dmcrypt::save_crypttab_($all_hds, $tmp_file);              my $new_hds = fs::get::empty_all_hds();              fs::any::get_hds($new_hds, $fstab, $manual_fstab, $partitioning_flags, $skip_mtab, $in);              %$all_hds = %$new_hds; +            fs::dmcrypt::read_crypttab_($all_hds, $tmp_file); +            rm_rf($tmp_file);              $all_hds;  	};  	require diskdrake::interactive; @@ -45,43 +74,59 @@ sub partition_with_diskdrake {  	    diskdrake::interactive::main($in, $all_hds, $do_force_reload);  	}  	my @fstab = fs::get::fstab($all_hds); -	 +  	unless (fs::get::root_(\@fstab)) {  	    $ok = 0;  	    $in->ask_okcancel(N("Partitioning"), N("You must have a root partition. -For this, create a partition (or click on an existing one). +To accomplish this, create a partition (or click on an existing one).  Then choose action ``Mount point'' and set it to `/'"), 1) or return;  	} +  	if (!any { isSwap($_) } @fstab) {  	    $ok &&= $in->ask_okcancel('', N("You do not have a swap partition.\n\nContinue anyway?"));  	} -	if (arch() =~ /ia64/ && !fs::get::has_mntpoint("/boot/efi", $all_hds)) { -	    $in->ask_warn('', N("You must have a FAT partition mounted in /boot/efi")); +	if (is_uefi()) { +	  my $part = fs::get::has_mntpoint("/boot/EFI", $all_hds); +	  if (!$part || !isESP($part)) { +	    $in->ask_warn('', N("You must have a ESP FAT32 partition mounted in /boot/EFI"));  	    $ok = ''; +	  } +	} else { +	    if (fs::any::is_boot_bios_part_needed($all_hds)) { +		$in->ask_warn('', N("You must have a BIOS boot partition for non-UEFI GPT-partitioned disks. Please create one before continuing.")); +		$ok = ''; +	    }  	}      } until $ok;      1;  }  sub partitionWizardSolutions { -    my ($in, $all_hds, $all_fstab, $manual_fstab, $partitions, $partitioning_flags, $skip_mtab) = @_; +    my ($in, $all_hds, $all_fstab, $manual_fstab, $partitions, $partitioning_flags, $skip_mtab, $o_target) = @_;      my $hds = $all_hds->{hds}; -    my $fstab = [ fs::get::fstab($all_hds) ]; +    my $fstab; +    my $full_fstab = [ fs::get::fstab($all_hds) ]; +    if ($o_target) { +        $hds = [ $o_target ]; +        $fstab = [ grep { $_->{rootDevice} eq $o_target->{device} } fs::get::fstab($all_hds) ]; +    } else { +        $fstab = $full_fstab; +    } +      my @wizlog;      my (%solutions); -    my $min_linux = MB(400); -    my $max_linux = MB(2000); +    my $min_linux = MB(600);      my $min_swap = MB(50); -    my $max_swap = MB(300);      my $min_freewin = MB(100); +    fsedit::init_mntpnt_suggestions($all_hds, $o_target);      # each solution is a [ score, text, function ], where the function retunrs true if succeeded      my @hds_rw = grep { !$_->{readonly} } @$hds; -    my @hds_can_add = grep { $_->can_add } @hds_rw; +    my @hds_can_add = grep { $_->{type} ne 'hd' || $_->can_add } @hds_rw;      if (fs::get::hds_free_space(@hds_can_add) > $min_linux) { -	$solutions{free_space} = [ 30, N("Use free space"), sub { fsedit::auto_allocate($all_hds, $partitions); 1 } ]; +	$solutions{free_space} = [ 30, N("Use free space"), sub { fsedit::auto_allocate($all_hds, $partitions, $o_target); 1 } ];      } else {   	push @wizlog, N("Not enough free space to allocate new partitions") . ": " .  	  (@hds_can_add ?  @@ -91,67 +136,88 @@ sub partitionWizardSolutions {      if (my @truefs = grep { isTrueLocalFS($_) } @$fstab) {  	#- value twice the ext2 partitions -	$solutions{existing_part} = [ 20 + @truefs + @$fstab, N("Use existing partitions"), sub { fs::mount_point::ask_mount_points($in, $fstab, $all_hds) } ]; +	$solutions{existing_part} = [ 20 + @truefs + @$fstab, N("Use existing partitions"), sub { fs::mount_point::ask_mount_points($in, $full_fstab, $all_hds) } ];      } else {  	push @wizlog, N("There is no existing partition to use");      } -    my @fats = grep { $_->{fs_type} eq 'vfat' } @$fstab; -    fs::df($_) foreach @fats; -    if (my @ok_forloopback = sort { $b->{free} <=> $a->{free} } grep { $_->{free} > $min_linux + $min_swap + $min_freewin } @fats) { -	$solutions{loopback} =  -	  [ -10 - @fats, N("Use the Microsoft Windows® partition for loopback"),  -	    sub {  -		my ($s_root, $s_swap); -		my $part = $in->ask_from_listf('', N("Which partition do you want to use for Linux4Win?"), \&partition_table::description, \@ok_forloopback) or return; -		$max_swap = $min_swap + 1 if $part->{free} - $max_swap < $min_linux; -		$in->ask_from('', N("Choose the sizes"), [  -		   { label => N("Root partition size in MB: "), val => \$s_root, min => to_Mb($min_linux), max => to_Mb(min($part->{free} - $max_swap, $max_linux)), type => 'range' }, -		   { label => N("Swap partition size in MB: "), val => \$s_swap, min => to_Mb($min_swap),  max => to_Mb($max_swap), type => 'range' }, -		]) or return; -		push @{$part->{loopback}},  -		  { fs_type => 'ext3', loopback_file => '/lnx4win/linuxsys.img', mntpoint => '/',    size => $s_root * 2048, loopback_device => $part, notFormatted => 1 }, -		  { fs_type => 'swap', loopback_file => '/lnx4win/swapfile',     mntpoint => 'swap', size => $s_swap * 2048, loopback_device => $part, notFormatted => 1 }; -		fsedit::recompute_loopbacks($all_hds); -		1; -	    } ]; -    } else { -	push @wizlog, N("There is no FAT partition to use as loopback (or not enough space left)") . -	  (@fats ? "\nFAT partitions:" . join('', map { "\n  $_->{device} $_->{free} (" . ($min_linux + $min_swap + $min_freewin) . ")" } @fats) : ''); -    } - -     -    if (my @ok_for_resize_fat = grep { isFat_or_NTFS($_) && !fs::get::part2hd($_, $all_hds)->{readonly} -					 && fs::type::part2type_name($_) !~ /^Hidden/ } @$fstab) { -	$solutions{resize_fat} =  -	  [ 20 - @ok_for_resize_fat, N("Use the free space on a Microsoft Windows® partition"), -	    sub { -		my $part = $in->ask_from_listf_raw({ messages => N("Which partition do you want to resize?"), -						    interactive_help_id => 'resizeFATChoose', -						  }, \&partition_table::description, \@ok_for_resize_fat) or return; -		my $hd = fs::get::part2hd($part, $all_hds); -		my $resize_fat = eval { -		    my $pkg = $part->{fs_type} eq 'vfat' ? do {  -			require resize_fat::main; -			'resize_fat::main'; -		    } : do { -			require diskdrake::resize_ntfs; -			'diskdrake::resize_ntfs'; -		    }; -		    $pkg->new($part->{device}, devices::make($part->{device})); -		}; -		$@ and die N("The FAT resizer is unable to handle your partition,  -the following error occurred: %s", formatError($@)); -		my $min_win = do { -		    my $_w = $in->wait_message(N("Resizing"), N("Computing the size of the Microsoft Windows® partition")); -		    $resize_fat->min_size; -		}; -		#- 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_win += partition_table::raw::cylinder_size($hd); - -		$part->{size} > $min_linux + $min_swap + $min_freewin + $min_win or die N("Your Microsoft Windows® partition is too fragmented. Please reboot your computer under Microsoft Windows®, run the ``defrag'' utility, then restart the Mandriva Linux installation."); -		$in->ask_okcancel('', formatAlaTeX( +    if (my @ok_for_resize_fat = grep { isnormal_Fat_or_NTFS($_) && !fs::get::part2hd($_, $all_hds)->{readonly} +					 && $_->{size} > $min_linux + $min_swap + $min_freewin } @$fstab) { +        @ok_for_resize_fat = map { +            my $part = $_; +            my $hd = fs::get::part2hd($part, $all_hds); +            my $resize_fat = eval { +                my $pkg = $part->{fs_type} eq 'vfat' ? do {  +                    require resize_fat::main; +                    'resize_fat::main'; +                } : do { +                    require diskdrake::resize_ntfs; +                    'diskdrake::resize_ntfs'; +                }; +                $pkg->new($part->{device}, devices::make($part->{device})); +            }; +            if ($@) { +                log::l("The FAT resizer is unable to handle $part->{device} partition%s", formatError($@)); +                undef $part; +            } +            if ($part) { +                my $min_win = eval { +                    my $_w = $in->wait_message(N("Resizing"), N("Computing the size of the Microsoft Windows® partition")); +                    $resize_fat->min_size + $min_freewin; +                }; +                if ($@) { +                    log::l("The FAT resizer is unable to get minimal size for $part->{device} partition %s", formatError($@)); +                    undef $part; +                } else { +                    my $min_linux_all = $min_linux + $min_swap; +                    #- 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_win += partition_table::raw::cylinder_size($hd); + +                    if ($part->{size} <= $min_linux_all + $min_win) { +#                die N("Your Microsoft Windows® partition is too fragmented. Please reboot your computer under Microsoft Windows®, run the ``defrag'' utility, then restart the %s installation.", N("Mageia")); +                        undef $part; +                    } else { +                        $part->{resize_fat} = $resize_fat; +                        $part->{min_win} = $min_win; +                        $part->{min_linux} = $min_linux_all; +                        #- try to keep at least 1GB free for Windows +                        #- try to use from 20GB to 20% free space for Linux +                        my $suggested_size = max( +                            $part->{min_win} + 1 * MB(1024), +                            min( +                                $part->{size} - int(0.2 * ($part->{size} - $part->{min_win})), +                                $part->{size} - 20 * MB(1024), +                            ), +                        ); +                        $part->{req_size} = max(min($suggested_size, $part->{size} - $part->{min_linux}), $part->{min_win}); +                    } +                } +            } +            $part || (); +        } @ok_for_resize_fat; +	if (@ok_for_resize_fat) { +            $solutions{resize_fat} = +                [ 20 - @ok_for_resize_fat, N("Use the free space on a Microsoft Windows® partition"), +                  sub { +                      my $part; +                      if (!$in->isa('interactive::gtk')) { +                          $part = $in->ask_from_listf_raw({ messages => N("Which partition do you want to resize?"), +                                                               interactive_help_id => 'resizeFATChoose', +                                                             }, \&partition_table::description, \@ok_for_resize_fat) or return; +                          $part->{size} > $part->{min_linux} + $part->{min_win} or die N("Your Microsoft Windows® partition is too fragmented. Please reboot your computer under Microsoft Windows®, run the ``defrag'' utility, then restart the %s installation.", N("Mageia")); +                      } else { +                          my @selected = grep { +                              $_->{selected_for_resize} && +                              $o_target->{device} eq $_->{rootDevice}; # Not needed but let's be safe +                          } @ok_for_resize_fat; +                          my $nb_parts = @selected; +                          die N("Failed to find the partition to resize (%d choices)", $nb_parts) unless $nb_parts == 1; +                          $part = $selected[0]; +                      } +                      my $resize_fat = $part->{resize_fat}; +                      my $hd = fs::get::part2hd($part, $all_hds); +                      $in->ask_okcancel('', formatAlaTeX(                                              #-PO: keep the double empty lines between sections, this is formatted a la LaTeX                                              N("WARNING! @@ -164,54 +230,66 @@ Be careful: this operation is dangerous. If you have not already done so, you fi  When sure, press %s.", N("Next")))) or return; -		my $mb_size = to_Mb($part->{size}); -		$in->ask_from(N("Partitionning"), N("Which size do you want to keep for Microsoft Windows® on partition %s?", partition_table::description($part)), [ -                   { label => N("Size"), val => \$mb_size, min => to_Mb($min_win), max => to_Mb($part->{size} - $min_linux - $min_swap), type => 'range' }, -                ]) or return; - -		my $oldsize = $part->{size}; -		$part->{size} = from_Mb($mb_size, $min_win, $part->{size}); - -		$hd->adjustEnd($part); - -		eval {  -		    my $_w = $in->wait_message(N("Resizing"), N("Resizing Microsoft Windows® partition")); -		    $resize_fat->resize($part->{size}); -		}; -		if (my $err = $@) { -		    $part->{size} = $oldsize; -		    die N("FAT resizing failed: %s", formatError($err)); -		} - -		$in->ask_warn('', N("To ensure data integrity after resizing the partition(s),  +                      my $oldsize = $part->{size}; +                      if (!$in->isa('interactive::gtk')) { +                          my $mb_size = to_Mb($part->{req_size}); +                          my $max_win = $part->{size} - $part->{min_linux}; +                          $in->ask_from(N("Partitionning"), N("Which size do you want to keep for Microsoft Windows® on partition %s?", partition_table::description($part)), [ +                                        { label => N("Size"), val => \$mb_size, min => to_Mb($part->{min_win}), max => to_Mb($max_win), type => 'range' }, +                                    ]) or return; +                          $part->{req_size} = from_Mb($mb_size, $part->{min_win}, $part->{max_win}); +                      } +                      $part->{size} = $part->{req_size}; + +                      $hd->adjustEnd($part); + +                      eval { +                          my $_w = $in->wait_message(N("Resizing"), N("Resizing Microsoft Windows® partition")); +                          $resize_fat->resize($part->{size}); +                      }; +                      if (my $err = $@) { +                          $part->{size} = $oldsize; +                          die N("FAT resizing failed: %s", formatError($err)); +                      } + +                      $in->ask_warn('', N("To ensure data integrity after resizing the partition(s),  filesystem checks will be run on your next boot into Microsoft Windows®")) if $part->{fs_type} ne 'vfat'; -		set_isFormatted($part, 1); -		partition_table::will_tell_kernel($hd, resize => $part); #- down-sizing, write_partitions is not needed -		partition_table::adjust_local_extended($hd, $part); -		partition_table::adjust_main_extended($hd); +                      set_isFormatted($part, 1); +                      partition_table::will_tell_kernel($hd, resize => $part); #- down-sizing, write_partitions is not needed +                      partition_table::adjust_local_extended($hd, $part); +                      partition_table::adjust_main_extended($hd); -		fsedit::auto_allocate($all_hds, $partitions); -		1; -	    } ]; +                      fsedit::auto_allocate($all_hds, $partitions, $hd); +                      1; +                  }, \@ok_for_resize_fat ]; +        }      } else {  	push @wizlog, N("There is no FAT partition to resize (or not enough space left)");      }      if (@$fstab && @hds_rw) {  	$solutions{wipe_drive} = -	  [ 10, fsedit::is_one_big_fat_or_NT($hds) ? N("Remove Microsoft Windows®") : N("Erase and use entire disk"),  +	  [ 10, fsedit::is_one_big_fat_or_NT($hds) ? N("Remove Microsoft Windows®") : N("Erase and use entire disk"),  	    sub { -		my $hd = $in->ask_from_listf_raw({ messages => N("You have more than one hard drive, which one do you install linux on?"), -						  title => N("Partitioning"), -						  interactive_help_id => 'takeOverHdChoose', -						}, -						\&partition_table::description, \@hds_rw) or return; +                my $hd; +                if (!$in->isa('interactive::gtk')) { +                    $hd = $in->ask_from_listf_raw({ messages => N("You have more than one hard disk drive, which one do you want the installer to use?"), +                                                       title => N("Partitioning"), +                                                       interactive_help_id => 'takeOverHdChoose', +                                                     }, +                                                     \&partition_table::description, \@hds_rw) or return; +                } else { +                    $hd = $o_target; +                }  		$in->ask_okcancel_({ messages => N("ALL existing partitions and their data will be lost on drive %s", partition_table::description($hd)),  				    title => N("Partitioning"),  				    interactive_help_id => 'takeOverHdConfirm' }) or return;  		fsedit::partition_table_clear_and_initialize($all_hds->{lvms}, $hd, $in); -		fsedit::auto_allocate($all_hds, $partitions); +		# FIXME: reread all_hds: +		# re add suggestions if needed (as we might just have erased eg Boot BIOS partition): +		fsedit::init_mntpnt_suggestions($all_hds, $hd, 1); +		fsedit::auto_allocate($all_hds, $partitions, $hd);  		1;  	    } ];      } @@ -223,18 +301,14 @@ filesystem checks will be run on your next boot into Microsoft Windows®")) if $      }      $solutions{fdisk} = -      [ -10, N("Use fdisk"), sub {  +      [ -10, N("Use fdisk"), sub {  	    $in->enter_console;  	    foreach (@$hds) {  		print "\n" x 10, N("You can now partition %s.  When you are done, do not forget to save using `w'", partition_table::description($_));  		print "\n\n";  		my $pid = 0; -		if (arch() =~ /ppc/) { -			$pid = fork() or exec "pdisk", devices::make($_->{device}); -		} else { -			$pid = fork() or exec "fdisk", devices::make($_->{device}); -		}			 +		$pid = fork() or exec "fdisk", devices::make($_->{device});  		waitpid($pid, 0);  	    }  	    $in->leave_console; @@ -247,43 +321,326 @@ When you are done, do not forget to save using `w'", partition_table::descriptio  sub warn_reboot_needed {      my ($in) = @_; -    $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"));  } -sub main { -    my ($o, $all_hds, $fstab, $manual_fstab, $partitions, $partitioning_flags, $skip_mtab, $b_nodiskdrake) = @_; +sub create_display_box { +    my ($kind, $resize, $fill_empty, $button) = @_; + +    # Hide empty space < 2MB, wehave such holes due to alignment +    my @parts = grep { $_->{size} > MB(2) || !isEmpty($_) } diskdrake::hd_gtk::kind2parts($kind); + +    my $totalsectors = diskdrake::hd_gtk::kind2sectors($kind, @parts); + +    my $width = 520; +    my $minwidth = 40; -    my %solutions = partitionWizardSolutions($o, $all_hds, $fstab, $manual_fstab, $partitions, $partitioning_flags, $skip_mtab); +    my $display_box = ugtk3::gtkset_size_request(Gtk3::HBox->new(0,0), -1, 26); +    $display_box->set_spacing(1); -    delete $solutions{diskdrake} if $b_nodiskdrake; +    my $sep_count = @parts - 1; +    #- ratio used to compute initial partition pixel width (each partition should be > min_width) +    #- though, the pixel/sectors ratio cannot be the same for all the partitions +    my $initial_ratio = $totalsectors ? ($width - @parts * $minwidth - $sep_count) / $totalsectors : 1; -    my @solutions = sort { $b->[0] <=> $a->[0] } values %solutions; +    my $vbox = Gtk3::VBox->new; -    my @sol = grep { $_->[0] >= 0 } @solutions; +    my $desc; -    log::l(''  . "solutions found: " . join('', map { $_->[1] } @sol) .  -	   " (all solutions found: " . join('', map { $_->[1] } @solutions) . ")"); +    if ($resize) { +	my %resizable_parts; +	foreach my $entry (@$resize) { +	    # selected_for_resize may have been set on another disk, clear it +	    $entry->{selected_for_resize} = 0; +	    $resizable_parts{$entry->{device}} = $entry; +	} +	# find resizable parts on this disk +	my @choices = grep { $resizable_parts{$_->{device}} } @parts; +	my @sorted_resize = sort { +		$a->{size} - $a->{req_size} <=> $b->{size} - $b->{req_size}; +	    } @choices; +	$sorted_resize[-1]{selected_for_resize} = 1; +    } + +    foreach my $entry (@parts) { +	my $part_info = Gtk3::Label->new($entry->{device_LABEL}); +	my @colorized_fs_types = qw(ext2 ext3 ext4 xfs swap vfat ntfs ntfs-3g); +        my $part_widget = Gtk3::EventBox->new; +        $entry->{width} = int($entry->{size} * $initial_ratio) + $minwidth; +        if ($resize && $entry->{selected_for_resize}) { +            my $ratio; +            my $update_ratio = sub { $ratio = $entry->{width} / $entry->{size} }; +            $update_ratio->(); + +            $part_widget->set_name("PART_vfat"); +            $part_info->set_size_request(ceil($ratio * $entry->{min_win}), 0); + +            my $mdv_widget = gtkadd(gtkset_name(Gtk3::EventBox->new, "PART_new"), +                                    gtkset_size_request(gtknew("Image", file => "small-logo"), +                                                        $ratio * MB(600), 0)); + +            my $hpane = Gtk3::HPaned->new; +            $hpane->pack1($part_widget, 1, 0); +            $hpane->pack2($mdv_widget, 1, 0); +            $hpane->set_position(ceil($ratio * $entry->{req_size})); +            ugtk3::gtkset_size_request($hpane, $entry->{width}, 0); +            ugtk3::gtkpack__($display_box, $hpane); + +            my $add_part_size_info = sub { +                my ($name, $label) = @_; +                ugtk3::gtkpack__($desc, +                                 gtkadd(gtkset_name(Gtk3::EventBox->new, $name), +                                        Gtk3::Label->new(" " x 4)), +                                 gtkset_size_request(gtkset_alignment($label, 0, 0.5), +                                                     150, 20)); +            }; +            $desc = Gtk3::HBox->new(0,0); + +            my $win_size_label = Gtk3::Label->new; +            $add_part_size_info->("PART_vfat", $win_size_label); + +            my $mdv_size_label = Gtk3::Label->new; +            $add_part_size_info->("PART_new", $mdv_size_label); + +            my $update_size_labels = sub { +                $win_size_label->set_label(" Windows (" . formatXiB($entry->{req_size}, 512) . ")"); +                $mdv_size_label->set_label(" Mageia (" . formatXiB($entry->{size} - $entry->{req_size}, 512) . ")"); +                0; +            }; +            my $update_req_size = sub { +                $entry->{req_size} = int($hpane->get_position / $ratio); +                $update_size_labels->(); +            }; +            my $button_activate = sub { +                $button->activate; +                0; +            }; +            $hpane->signal_connect('size-allocate' => sub { +                my (undef, $alloc) = @_; +                $entry->{width} = $alloc->{width}; +                $update_ratio->(); +                0; +            }); +            $update_size_labels->(); +            $hpane->signal_connect('motion-notify-event' => $update_req_size); +            $hpane->signal_connect('move-handle' => $update_req_size); +            $hpane->signal_connect('button-press-event' => $button_activate); +            $vbox->signal_connect('button-press-event' => $button_activate); +            $button->signal_connect('focus-in-event' => sub { +                $hpane->grab_focus; +                0; +            }); +        } else { +            if ($fill_empty && isEmpty($entry)) { +                $part_info = gtknew("Image", file => "small-logo"); +                $part_widget->set_name("PART_new"); +            } else { +                $part_widget->set_name("PART_" . (isEmpty($entry) ? 'empty' : +                                         $entry->{fs_type} && member($entry->{fs_type}, @colorized_fs_types) ? $entry->{fs_type} : +                                         'other')); +            } +            $part_widget->set_size_request($entry->{width}, 0); +            ugtk3::gtkpack($display_box, $part_widget); +        } +	$part_widget->add($part_info); +    } +    unless ($resize || $fill_empty) { +        my @types = (N_("Ext2/3/4"), N_("XFS"), N_("Swap"), N_("Windows"), +                    N_("Other"), N_("Empty")); +        my %name2fs_type = ('Ext2/3/4' => 'ext3', 'XFS' => 'xfs', Swap => 'swap', Other => 'other', "Windows" => 'vfat', HFS => 'hfs'); +        $desc = ugtk3::gtkpack(Gtk3::HBox->new, +                map { +                     my $t = $name2fs_type{$_}; +                     my $ev = Gtk3::EventBox->new; +		     my $w = Gtk3::Label->new(translate($_)); +	             $ev->add($w); +		     $ev->set_name('PART_' . ($t || 'empty')); +                     $ev; +                } @types); +    } + +    $vbox->add($display_box); +    $vbox->add($desc) if $desc; + +    $vbox; +} + +sub display_choices { +    my ($o, $contentbox, $mainw, %solutions) = @_; +    my @solutions = sort { $solutions{$b}[0] <=> $solutions{$a}[0] } keys %solutions; +    my @sol = grep { $solutions{$_}[0] >= 0 } @solutions; + +    log::l(''  . "solutions found: " . join(', ', map { $solutions{$_}[1] } @sol) . +           " (all solutions found: " . join(', ', map { $solutions{$_}[1] } @solutions) . ")");      @solutions = @sol if @sol > 1;      log::l("solutions: ", int @solutions); -    @solutions or $o->ask_warn(N("Partitioning"), N("I can not find any room for installing")), die 'already displayed'; +    @solutions or $o->ask_warn(N("Partitioning"), N("I cannot find any room for installing")), die 'already displayed'; + +    log::l('HERE: ', join(',', map { $solutions{$_}[1] } @solutions)); + +    $contentbox->foreach(sub { $contentbox->remove($_[0]) }); + +    $mainw->{kind}{display_box} ||= create_display_box($mainw->{kind}); +    ugtk3::gtkpack2__($contentbox, $mainw->{kind}{display_box}); +    ugtk3::gtkpack__($contentbox, gtknew('Label', +                                         text => N("The DrakX Partitioning wizard found the following solutions:"), +                                         alignment => [0, 0])); + +    my $choicesbox = gtknew('VBox'); +    my $oldbutton; +    my $sep; +    foreach my $s (@solutions) { +        my $item; +        my $vbox = gtknew('VBox'); +        my $button = gtknew('RadioButton', child => $vbox); +        if ($s eq 'free_space') { +            $item = create_display_box($mainw->{kind}, undef, 1); +        } elsif ($s eq 'resize_fat') { +            $item = create_display_box($mainw->{kind}, $solutions{$s}[3], undef, $button); +        } elsif ($s eq 'existing_part') { +        } elsif ($s eq 'wipe_drive') { +            $item = Gtk3::EventBox->new; +            my $b2 = gtknew("Image", file => "small-logo"); +            $item->add($b2); +            $item->set_size_request(520,26); +            $item->set_name("PART_new"); +        } elsif ($s eq 'diskdrake') { +        } else { +            log::l($s); +            next; +        } +        ugtk3::gtkpack($vbox,  +                       gtknew('Label', +                              text => $solutions{$s}[1], +                              alignment => [0, 0])); +        ugtk3::gtkpack($vbox, $item) if defined($item); +        $button->join_group($oldbutton) if $oldbutton; +        $oldbutton = $button; +        $button->signal_connect('toggled', sub { $mainw->{sol} = $solutions{$s} if $_[0]->get_active }); +        ugtk3::gtkpack2__($choicesbox, $button); +        $sep = gtknew('HSeparator'); +        ugtk3::gtkpack2__($choicesbox, $sep); +    } +    $choicesbox->remove($sep); +    ugtk3::gtkadd($contentbox, $choicesbox); +    $mainw->{sol} = $solutions{@solutions[0]}; +} + +sub main { +    my ($o, $all_hds, $fstab, $manual_fstab, $partitions, $partitioning_flags, $skip_mtab, $b_nodiskdrake) = @_; -    log::l('HERE: ', join(',', map { $_->[1] } @solutions));      my $sol; -    $o->ask_from_({  -		    title => N("Partitioning"), -		    interactive_help_id => 'doPartitionDisks', -		  }, -		  [ -                      { label => N("The DrakX Partitioning wizard found the following solutions:"),  title => $::isInstall }, -                      { val => \$sol, list => \@solutions, format => sub { $_[0][1] }, type => 'list' }, -                  ]); + +    if ($o->isa('interactive::gtk')) { +        require mygtk3; +        mygtk3->import(qw(gtknew)); +        require ugtk3; +        ugtk3->import(qw(:wrappers)); + +        my $mainw = ugtk3->new(N("Partitioning"), %$o, if__($::main_window, transient => $::main_window)); +        $mainw->{box_allow_grow} = 1; + +        mygtk3::set_main_window_size($mainw->{rwindow}); + +        require diskdrake::hd_gtk; +        diskdrake::hd_gtk::load_theme(); + +        my $mainbox = Gtk3::VBox->new; + +        my @kinds = map { diskdrake::hd_gtk::hd2kind($_) } sort { $a->{is_removable} <=> $b->{is_removable} } @{ $all_hds->{hds} }; +        #push @kinds, diskdrake::hd_gtk::raid2real_kind($_) foreach @{$all_hds->{raids}}; +        push @kinds, map { diskdrake::hd_gtk::lvm2kind($_) } @{$all_hds->{lvms}}; + +        my $hdchoice = Gtk3::HBox->new; + +        my $hdchoicelabel = Gtk3::Label->new(N("Here is the content of your disk drive ")); + +        my $combobox = Gtk3::ComboBoxText->new; +        foreach (@kinds) { +            my $info = $_->{val}{info} || $_->{val}{device}; +            $info =~ s|^(?:.*/)?(.{24}).*|$1|; +            $info .= " (" . formatXiB($_->{val}{totalsectors}, 512) . ")" if $_->{val}{totalsectors}; +            $combobox->append_text($info); +        } +        $combobox->set_active(0); + +        ugtk3::gtkpack2__($hdchoice, $hdchoicelabel); +        $hdchoice->add($combobox); + +        ugtk3::gtkpack2__($mainbox, $hdchoice); + +        my $contentbox = Gtk3::VBox->new(0, 12); + +        my $scroll = Gtk3::ScrolledWindow->new; +        $scroll->set_policy('automatic', 'automatic'), +        my $vp = Gtk3::Viewport->new; +        $vp->set_shadow_type('none'); +        $vp->add($contentbox); +        $scroll->add($vp); +        $mainbox->add($scroll); + +        my $kind = $kinds[$combobox->get_active]; +        my %solutions = partitionWizardSolutions($o, $all_hds, $fstab, $manual_fstab, $partitions, $partitioning_flags, $skip_mtab, diskdrake::hd_gtk::kind2hd($kind)); +        delete $solutions{diskdrake} if $b_nodiskdrake; +        $mainw->{kind} = $kind; +        display_choices($o, $contentbox, $mainw, %solutions); + +        $combobox->signal_connect("changed", sub {         +            my $curr = $kinds[$combobox->get_active]; +            return if !$curr; +            $mainw->{kind} = $curr; +            my %solutions = partitionWizardSolutions($o, $all_hds, $fstab, $manual_fstab, $partitions, $partitioning_flags, $skip_mtab, diskdrake::hd_gtk::kind2hd($mainw->{kind})); +            delete $solutions{diskdrake} if $b_nodiskdrake; +            display_choices($o, $contentbox, $mainw, %solutions); +            $mainw->{window}->show_all; +        }); + +        my @more_buttons = ( +            if_($::isInstall,  +            [ gtknew('Install_Button', +                     text => N("Help"), +                     clicked => sub { interactive::gtk::display_help($o, {interactive_help_id => 'doPartitionDisks' }) }), +              undef, 1 ]), +            ); +        my $buttons_pack = $mainw->create_okcancel(N("Next"), undef, '', @more_buttons); +        $mainbox->pack_end($buttons_pack, 0, 0, 0); +        ugtk3::gtkadd($mainw->{window}, $mainbox); +        $mainw->{window}->show_all; + +        $mainw->main; + +        $sol=$mainw->{sol}; +    } else { +        my %solutions = partitionWizardSolutions($o, $all_hds, $fstab, $manual_fstab, $partitions, $partitioning_flags, $skip_mtab); + +        delete $solutions{diskdrake} if $b_nodiskdrake; + +        my @solutions = sort { $b->[0] <=> $a->[0] } values %solutions; + +        my @sol = grep { $_->[0] >= 0 } @solutions; +        log::l(''  . "solutions found: " . join(', ', map { $_->[1] } @sol) .  +               " (all solutions found: " . join(', ', map { $_->[1] } @solutions) . ")"); +        @solutions = @sol if @sol > 1; +        log::l("solutions: ", int @solutions); +        @solutions or $o->ask_warn(N("Partitioning"), N("I cannot find any room for installing")), die 'already displayed'; +        log::l('HERE: ', join(',', map { $_->[1] } @solutions)); +        $o->ask_from_({  +            title => N("Partitioning"), +            interactive_help_id => 'doPartitionDisks', +                      }, +                      [ +                       { label => N("The DrakX Partitioning wizard found the following solutions:"),  title => $::isInstall }, +                       { val => \$sol, list => \@solutions, format => sub { $_[0][1] }, type => 'list' }, +                      ]); +    }      log::l("partitionWizard calling solution $sol->[1]");      my $ok = eval { $sol->[2]->() };      if (my $err = $@) {          if ($err =~ /wizcancel/) {              $_->destroy foreach $::WizardTable->get_children;          } else { +            log::l("Partitioning failed: $err");              $o->ask_warn('', N("Partitioning failed: %s", formatError($err)));          }      } @@ -291,4 +648,8 @@ sub main {      1;  } +=back + +=cut +  1; diff --git a/perl-install/fs/proc_partitions.pm b/perl-install/fs/proc_partitions.pm index 566f9ee70..ea714ca5b 100644 --- a/perl-install/fs/proc_partitions.pm +++ b/perl-install/fs/proc_partitions.pm @@ -1,4 +1,4 @@ -package fs::proc_partitions; # $Id$ +package fs::proc_partitions;  use common; @@ -6,8 +6,12 @@ use common;  sub read_raw() {      my (undef, undef, @all) = cat_("/proc/partitions");      grep { -	$_->{size} != 1 &&	  # skip main extended partition -	$_->{size} != 0x3fffffff; # skip cdroms (otherwise stops cd-audios) +	$_->{size} != 1 &&	      # skip main extended partition +	$_->{size} != 0x3fffffff &&   # skip cdroms (otherwise stops cd-audios) +	$_->{dev} !~ /mmcblk\d+[^p]/; # only keep partitions like mmcblk0p0 +	                              # not mmcblk0rpmb or mmcblk0boot0 as they +				      # are not in the partition table and +				      # things will break (mga#15759)      } map {   	my %l;   	@l{qw(major minor size dev)} = split;  @@ -16,7 +20,7 @@ sub read_raw() {  }  sub read { -    my ($hds) = @_; +    my ($hds, $o_ignore_fstype) = @_;      my @all = read_raw();      my ($parts, $_disks) = partition { $_->{dev} =~ /\d$/ && $_->{dev} !~ /^(sr|scd)/ } @all; @@ -36,7 +40,7 @@ sub read {  	$part->{size} *= 2;	# from KB to sectors  	$part->{start} = $prev_part ? $prev_part->{start} + $prev_part->{size} : 0;  	require fs::type; -	put_in_hash($part, fs::type::type_subpart_from_magic($part)); +	put_in_hash($part, fs::type::type_subpart_from_magic($part)) if !$o_ignore_fstype;  	$prev_part = $part;  	delete $part->{dev}; # cleanup      } @@ -50,7 +54,7 @@ sub compare {      my @l1 = partition_table::get_normal_parts($hd); -    my @l2 = grep { $_->{rootDevice} eq $hd->{device} } &read([$hd]); +    my @l2 = grep { $_->{rootDevice} eq $hd->{device} } &read([$hd], 1);      #- /proc/partitions includes partition with type "empty" and a non-null size      #- so add them for comparison @@ -61,7 +65,7 @@ sub compare {  	    log::l("not using /proc/partitions because of the presence of solaris extended partition"); #- cf #33866  	} else {  	    die sprintf( -		    "/proc/partitions does not agree with drakx %d != %d:\n%s\n", $len1, $len2, +		    "/proc/partitions does not agree with drakx %d != %d for %s:\n%s\n", $len1, $len2, $hd->{device},  		    "/proc/partitions: " . join(", ", map { "$_->{device} ($_->{rootDevice})" } @l2));  	}      } diff --git a/perl-install/fs/remote.pm b/perl-install/fs/remote.pm index ea22a04af..ea5944a25 100644 --- a/perl-install/fs/remote.pm +++ b/perl-install/fs/remote.pm @@ -1,4 +1,4 @@ -package fs::remote; # $Id$ +package fs::remote;  use strict;  use diagnostics; diff --git a/perl-install/fs/remote/davfs.pm b/perl-install/fs/remote/davfs.pm new file mode 100644 index 000000000..890530cb9 --- /dev/null +++ b/perl-install/fs/remote/davfs.pm @@ -0,0 +1,99 @@ +package fs::remote::davfs; + +use strict; +use diagnostics; + +use common; +use fs::mount_options; + +sub secrets_file() { "$::prefix/etc/davfs2/secrets" } + +sub fstab_entry_to_credentials { +    my ($part) = @_;     + +    my ($options, $unknown) = fs::mount_options::unpack($part); +    my %h = map { $_ => delete $options->{"$_="} } qw(username password); +    foreach (qw(username password)) { +        $h{$_} ||= 'nobody'; +    } +    $h{mntpoint} = $part->{mntpoint} or return; +    fs::mount_options::pack_($part, $options, $unknown), \%h; +} + +sub save_credentials { +    my ($credentials) = @_; +    @$credentials or return; + +    output_with_perm(secrets_file(), 0600,  +		     map { to_double_quoted($_->{mntpoint}, $_->{username}, $_->{password}) . "\n" } @$credentials); +} + +sub mountpoint_credentials_save { +    my ($mntpoint, $mount_opt) = @_; +    my @entries = read_credentials_raw(); +    my $entry = find { $mntpoint eq $_->{mntpoint} } @entries; +    die "mountpoint not found" if !$entry; +    my %h; +    foreach (@$mount_opt) { +        my @var = split(/=/); +        $h{$var[0]} = $var[1]; +    } +    foreach my $key (qw(username password)) { +        $entry->{$key} = $h{$key}; +    } +    save_credentials(\@entries); +} + + +sub read_credentials_raw() { +    from_double_quoted(cat_(secrets_file())); +} + +sub read_credentials { +    my ($mntpoint) = @_; +    find { $mntpoint eq $_->{mntpoint} } read_credentials_raw(); +} + +# Comments are indicated by a '#' character and the rest of the line +# is ignored. Empty lines are ignored too. +# +# Each line consists of two or three items separated by spaces or tabs. +# If an item contains one of the characters space, tab, #, \ or ", this +# character must be escaped by a preceding \. Alternatively, the item +# may be enclosed in double quotes. + +sub from_double_quoted { +    my ($file) = @_; +    my @l; +    my @lines = split("\n",$file); +    foreach (@lines) { +	my ($mnt, $user, $pass, $comment);  +	if (/^\s*(#.*)?$/) { +	    $comment = $1; +	} else { +            if (/^(?:"((?:\\.|[^"])*)"|((?:\\.|[^"\s#])+))\s+(?:"((?:\\.|[^"])*)"|((?:\\.|[^"\s#])+))(?:\s+(?:"((?:\\.|[^"])*)"|((?:\\.|[^"\s#])+)))?(?:\s*|\s*(#.*))?$/) { +	            $mnt = "$1$2"; +		    $mnt =~ s/\\(.)/$1/g; +		    $user = "$3$4"; +	            $user =~ s/\\(.)/$1/g; +		    $pass = "$5$6"; +	            $pass =~ s/\\(.)/$1/g; +		    $comment=$7; +	    } else { +		    die "bad entry $_"; +	    } +        } +        push @l, { 'mntpoint' => $mnt, 'username' => $user, 'password' => $pass, 'comment' => $comment }; +    } +    @l; +} + +sub to_double_quoted { +    my (@l) = @_; +    join(' ', map { +	s/(["\\])/\\$1/g; +	/\s/ ? qq("$_") : $_; +    } @l); +} + +1; diff --git a/perl-install/fs/remote/nfs.pm b/perl-install/fs/remote/nfs.pm index 7acddb730..f7a98cb69 100644 --- a/perl-install/fs/remote/nfs.pm +++ b/perl-install/fs/remote/nfs.pm @@ -1,10 +1,11 @@ -package fs::remote::nfs; # $Id$ +package fs::remote::nfs;  use strict;  use diagnostics;  use common;  use fs::remote; +use network::tools;  use log;  our @ISA = 'fs::remote'; @@ -28,33 +29,36 @@ sub to_dev_raw {  sub check {      my ($_class, $in) = @_; -    $in->do_pkgs->ensure_binary_is_installed('nfs-utils-clients', 'showmount') or return; +    $in->do_pkgs->ensure_files_are_installed([ [ qw(nfs-utils showmount) ] , [ qw(nmap nmap) ] ]);      require services; -    services::start_not_running_service('portmap'); +    services::start_not_running_service('rpcbind');      services::start('nfs-common'); #- TODO: once nfs-common is fixed, it could use start_not_running_service()      1;  }  sub find_servers { -    open(my $F2, "rpcinfo-flushed -b mountd 2 |"); -    open(my $F3, "rpcinfo-flushed -b mountd 3 |"); - -    common::nonblock($F2); -    common::nonblock($F3); -    my $domain = chomp_(`domainname`); -    my ($s, %servers); -    my $quit; -    while (!$quit) { -	$quit = 1; -	sleep 1; -	while ($s = <$F2> || <$F3>) { -	    $quit = 0; -	    my ($ip, $name) = $s =~ /(\S+)\s+(\S+)/ or log::explanations("bad line in rpcinfo output"), next; -	    $name =~ s/\.$//; -	    $name =~ s/\Q.$domain\E$//; -	    $servers{$ip} ||= { ip => $ip, if_($name ne '(unknown)', name => $name) }; +    my @hosts; +    my %servers; +    my @routes = cat_("/proc/net/route"); +    @routes = reverse(@routes) if common::cmp_kernel_versions(c::kernel_version(), "2.6.39") >= 0; +    foreach (@routes) { +	if (/^(\S+)\s+([0-9A-F]+)\s+([0-9A-F]+)\s+[0-9A-F]+\s+\d+\s+\d+\s+(\d+)\s+([0-9A-F]+)/) { +	    my $net = network::tools::host_hex_to_dotted($2); +	    my $gateway = $3; +	    # get the netmask in binary and remove leading zeros +	    my $mask = unpack('B*', pack('h*', $5)); +	    $mask =~ s/^0*//; +	    push @hosts, $net . "/" . length($mask) if $gateway eq '00000000' && $net ne '169.254.0.0';  	} +     } +    # runs the nmap command on the local subnet +    my $cmd = "/usr/bin/nmap -p 111 --open --system-dns -oG - " . (join ' ',@hosts); +    open my $FH, "$cmd |" or die "Could not perform nmap scan - $!"; +    foreach (<$FH>) {  +      my ($ip, $name) = /^H\S+\s(\S+)\s+\((\S*)\).+Port/ or next; +      $servers{$ip} ||= { ip => $ip, name => $name || $ip };      } +    close $FH;      values %servers;  } diff --git a/perl-install/fs/remote/smb.pm b/perl-install/fs/remote/smb.pm index 7757eeb3f..d440fc174 100644 --- a/perl-install/fs/remote/smb.pm +++ b/perl-install/fs/remote/smb.pm @@ -1,4 +1,4 @@ -package fs::remote::smb; # $Id$ +package fs::remote::smb;  use strict;  use diagnostics; @@ -12,7 +12,7 @@ our @ISA = 'fs::remote';  sub to_fstab_entry {      my ($class, $e) = @_; -    my $part = $class->to_fstab_entry_raw($e, 'smbfs'); +    my $part = $class->to_fstab_entry_raw($e, 'cifs');      if ($e->{server}{username}) {  	my ($options, $unknown) = fs::mount_options::unpack($part);  	$options->{"$_="} = $e->{server}{$_} foreach qw(username password domain); @@ -53,10 +53,11 @@ sub smbclient {  }  sub find_servers { -    my (undef, @l) = `nmblookup "*"`; +    my (undef, @l) = `nmblookup "*"; nmblookup -M -- -`;      s/\s.*\n// foreach @l;      require network::network;      my @servers = grep { network::network::is_ip($_) } @l; +    return unless @servers;      my %servers;      $servers{$_}{ip} = $_ foreach @servers;      my ($ip, $browse); @@ -124,7 +125,7 @@ sub fstab_entry_to_credentials {      my ($options, $unknown) = fs::mount_options::unpack($part);      $options->{'username='} && $options->{'password='} or return; -    my %h = map { $_ => delete $options->{"$_="} } qw(username domain password); +    my %h = map { $_ => delete $options->{"$_="} } qw(username password);      $h{file} = $options->{'credentials='} = to_credentials($server_name, $h{username});      fs::mount_options::pack_($part, $options, $unknown), \%h;  } @@ -137,7 +138,7 @@ sub remove_bad_credentials {  sub save_credentials {      my ($credentials) = @_;      my $file = $credentials->{file}; -    output_with_perm("$::prefix$file", 0640, map { "$_ = $credentials->{$_}\n" } qw(username domain password)); +    output_with_perm("$::prefix$file", 0640, map { "$_=$credentials->{$_}\n" } qw(username password));  } diff --git a/perl-install/fs/type.pm b/perl-install/fs/type.pm index e4cf4503b..141d5b5e2 100644 --- a/perl-install/fs/type.pm +++ b/perl-install/fs/type.pm @@ -1,4 +1,4 @@ -package fs::type; # $Id$ +package fs::type;  use diagnostics;  use strict; @@ -6,11 +6,20 @@ use strict;  use common;  use devices; +=head1 SYNOPSYS + +B<fs::type> enables to perform various tests on filesystem types. + +=head1 Functions + +=over + +=cut  our @ISA = qw(Exporter);  our @EXPORT = qw( -   isEmpty isExtended isTrueLocalFS isTrueFS isDos isSwap isOtherAvailableFS isRawLVM isRawRAID isRAID isLVM isMountableRW isNonMountable isPartOfLVM isPartOfRAID isPartOfLoopback isLoopback isMounted isBusy isSpecial isApple isAppleBootstrap isWholedisk isFat_or_NTFS -   maybeFormatted set_isFormatted +   isBlockCheckable isEmpty isExtended isFormatable isTrueLocalFS isTrueFS isDos isSwap isOtherAvailableFS isRawLVM isRawRAID isRawLUKS isRAID isLVM isLUKS isMountableRW isNonMountable isPartOfLVM isPartOfRAID isPartOfLoopback isLoopback isMounted isBusy isSpecial isApple isAppleBootstrap isBIOS_GRUB isESP isFat_or_NTFS isnormal_Fat_or_NTFS isRecovery +   maybeFormatted set_isFormatted defaultFS  ); @@ -22,26 +31,25 @@ my (%type_name2pt_type, %type_name2fs_type, %fs_type2pt_type, %pt_type2fs_type,    0x82 => 'swap',     'Linux swap',    0x83 => 'ext2',     'Linux native',    0x83 => 'ext3',     'Journalised FS: ext3', -  0x83 => 'reiserfs', 'Journalised FS: ReiserFS', -if_(arch() =~ /ppc|i.86|ia64|x86_64/,  -  0x83 => 'xfs',      'Journalised FS: XFS', +  0x83 => 'ext4',     'Journalised FS: ext4', +  0x83 => 'btrfs',    'Journalised FS: Btrfs', +(is_uefi() ? +  (0xef => 'vfat',     'EFI System Partition') : +  ('BIOS_GRUB' => 'BIOS_GRUB',  'BIOS boot or Empty partition')  ), -if_(arch() =~ /ppc|i.86|x86_64/,  +if_(arch() =~ /i.86|x86_64/, +  0x83 => 'xfs',      'Journalised FS: XFS',    0x83 => 'jfs',      'Journalised FS: JFS', -), -if_(arch() =~ /i.86|ia64|x86_64/,    0x0b => 'vfat',     'FAT32',    0x07 => 'ntfs-3g',  'NTFS-3G',    0x07 => 'ntfs',     'NTFS', -), -if_(arch() =~ /ppc/, -  0x401	=> '',         'Apple Bootstrap', -  0x402	=> 'hfs',      'Apple HFS Partition', -  0x41  => '',         'PPC PReP Boot', +  0x07 => 'ntfs3',    'NTFS3', +  0x07 => 'exfat',    'exFAT',  ),  	],          non_fs_type => [ +  0x83 => '',         'Encrypted',    0x8e => '',         'Linux Logical Volume Manager',    0xfd => '',         'Linux RAID',  	], @@ -54,20 +62,7 @@ if_(arch() =~ /ppc/,  	],  	other => [ - if_(arch() =~ /^ia64/, -  0x100 => '',         'Various', -), if_(arch() =~ /^ppc/, -  0x401	=> 'apple',    'Apple Partition', -), if_(arch() =~ /^sparc/, -  0x01 => 'ufs',      'SunOS boot', -  0x02 => 'ufs',      'SunOS root', -  0x03 => '',      'SunOS swap', -  0x04 => 'ufs',      'SunOS usr', -  0x05 => '',      'Whole disk', -  0x06 => 'ufs',      'SunOS stand', -  0x07 => 'ufs',      'SunOS var', -  0x08 => 'ufs',      'SunOS home', -), if_(arch() =~ /^i.86|x86_64/, + if_(arch() =~ /^i.86|x86_64/,    0x01 => 'vfat',     'FAT12',    0x02 => '',         'XENIX root',    0x03 => '',         'XENIX usr', @@ -94,9 +89,7 @@ if_(arch() =~ /ppc/,    0x39 => '',         'Plan 9',    0x3c => '',         'PartitionMagic recovery',    0x40 => '',         'Venix 80286', -if_(arch() !~ /ppc/,    0x41 => '',         'PPC PReP Boot', -),    0x42 => '',         'SFS',    0x4d => '',         'QNX4.x',    0x4e => '',         'QNX4.x 2nd part', @@ -117,10 +110,9 @@ if_(arch() !~ /ppc/,    0x75 => '',         'PC/IX',    0x80 => '',         'Old Minix',    0x81 => '',         'Minix / old Linux', - if_(!$::isInstall, -  0x83 => 'reiser4',  'Journalised FS: Reiser4', -  0x83 => 'ext4dev',  'Journalised FS: ext4', - ), +  0x83 => 'f2fs',     'Journalised FS: F2FS', +  0x83 => 'reiserfs', 'Journalised FS: ReiserFS', +  0x83 => 'nilfs2',   'Journalised FS: NILFS2',    0x84 => '',         'OS/2 hidden C: drive',    0x86 => '',         'NTFS volume set (0x86)',    0x87 => '',         'NTFS volume set (0x87)', @@ -152,7 +144,6 @@ if_(arch() !~ /ppc/,    0xe4 => '',         'SpeedStor (FAT-16)',    0xeb => 'befs',     'BeOS fs',    0xee => '',         'EFI GPT', -  0xef => 'vfat',     'EFI (FAT-12/16/32)',    0xf0 => '',         'Linux/PA-RISC boot',    0xf4 => '',         'SpeedStor (large part.)',    0xf2 => '',         'DOS secondary', @@ -182,11 +173,12 @@ if_(arch() !~ /ppc/,  sub type_names {       my ($expert, $o_hd) = @_;      my @l = @{$type_names{important}}; -    push @l, @{$type_names{non_fs_type}}, sort @{$type_names{other}} if $expert; -    if ($o_hd && !$o_hd->use_pt_type) { -	warn "$_ => $type_name2fs_type{$_}\n" foreach @l; +    push @l, grep { $_ ne 'Encrypted' } @{$type_names{non_fs_type}}; +    push @l, sort @{$type_names{other}} if $expert; +    # not show partition types which have no associated filesystem for LVM LV: +    if ($o_hd && isLVM($o_hd)) {  	@l = grep { $type_name2fs_type{$_} } @l; -	@l = uniq_ { $type_name2fs_type{$_[0]} } @l; +	@l = uniq_ { $type_name2fs_type{$_} } @l;  	(@l, @{$type_names{non_fs_type}});      } else {  	@l; @@ -268,19 +260,20 @@ sub fs_type_from_magic {      }  } -sub call_vol_id { +sub call_blkid {      my ($part) = @_; +    # IMPORTANT: Always use the -p argument with blkid. See r7324 commit msg      my %h = map {  	if_(/(.*?)=(.*)/, $1 => $2); -    } run_program::get_stdout('vol_id', '2>', '/dev/null', devices::make($part->{device})); +    } run_program::get_stdout_raw({ timeout => 30 }, 'blkid', '2>', '/dev/null', '-o', 'udev', '-p', devices::make($part->{device}));      \%h;  }  sub type_subpart_from_magic {       my ($part) = @_; -    my $ids = call_vol_id($part); +    my $ids = call_blkid($part);      my $p;      if ($ids->{ID_FS_USAGE} eq 'raid') { @@ -291,55 +284,118 @@ sub type_subpart_from_magic {  	}->{$ids->{ID_FS_TYPE}};  	$p = type_name2subpart($name) if $name; +    } elsif ($ids->{ID_FS_USAGE} eq 'crypto') { +	$p = type_name2subpart('Encrypted');      } elsif (my $fs_type = $ids->{ID_FS_TYPE}) {  	$fs_type = 'ntfs-3g' if $fs_type eq 'ntfs'; -	$p = fs_type2subpart($fs_type) or log::l("unknown filesystem $fs_type returned by vol_id"); +	$p = fs_type2subpart($fs_type) or log::l("unknown filesystem $fs_type returned by blkid");      }      if ($p) { +	$p->{fs_type} = '' if $part->{pt_type} eq 'BIOS_GRUB' && $p->{fs_type} ne 'iso9660';  	$part->{fs_type_from_magic} = $p->{fs_type};  	$p->{device_LABEL} = $ids->{ID_FS_LABEL} if $ids->{ID_FS_LABEL};  	$p->{device_UUID} = $ids->{ID_FS_UUID} if $ids->{ID_FS_UUID}; +	log::l("blkid gave: $p->{fs_type} $p->{device_UUID} $p->{device_LABEL}");      }      $p;  } -sub true_local_fs_types() { qw(ext3 ext2 ext4dev reiserfs reiser4 xfs jfs) } +# helpers +sub defaultFS() { 'ext4' } +sub true_local_fs_types() { qw(btrfs ext3 ext2 ext4 f2fs reiserfs xfs jfs) } -sub isEmpty { !$_[0]{fs_type} && $_[0]{pt_type} == 0 } -sub isEfi { arch() =~ /ia64/ && $_[0]{pt_type} == 0xef } -sub isWholedisk { arch() =~ /^sparc/ && $_[0]{pt_type} == 5 } -sub isExtended { arch() !~ /^sparc/ && ($_[0]{pt_type} == 5 || $_[0]{pt_type} == 0xf || $_[0]{pt_type} == 0x85) } +sub isEmpty { !$_[0]{fs_type} && !$_[0]{pt_type} } +sub isBIOS_GRUB { $_[0]{pt_type} eq 'BIOS_GRUB' } +sub isESP { $_[0]{pt_type} == 0xef && member($_[0]{fs_type}, qw(fat32 vfat)) } +sub isExtended { $_[0]{pt_type} == 5 || $_[0]{pt_type} == 0xf || $_[0]{pt_type} == 0x85 } +sub isBlockCheckable { !member($_[0]{fs_type}, qw(btrfs hfs ntfs ntfs-3g reiserfs xfs)) }  sub isRawLVM { $_[0]{pt_type} == 0x8e || $_[0]{type_name} eq 'Linux Logical Volume Manager' }  sub isRawRAID { $_[0]{pt_type} == 0xfd || $_[0]{type_name} eq 'Linux RAID' } +sub isRawLUKS { $_[0]{type_name} eq 'Encrypted' }  sub isSwap { $_[0]{fs_type} eq 'swap' } -sub isDos { arch() !~ /^sparc/ && ${{ 1 => 1, 4 => 1, 6 => 1 }}{$_[0]{pt_type}} } -sub isFat_or_NTFS { member($_[0]{fs_type}, 'vfat', 'ntfs', 'ntfs-3g') } +sub isDos { ${{ 1 => 1, 4 => 1, 6 => 1 }}{$_[0]{pt_type}} } +sub isFat_or_NTFS { member($_[0]{fs_type}, qw(vfat ntfs ntfs3 ntfs-3g)) } +sub isnormal_Fat_or_NTFS { grep { isFat_or_NTFS($_) && !isESP($_) && !isRecovery($_) } @_ }  sub isApple { $_[0]{pt_type} == 0x401 && defined $_[0]{isDriver} }  sub isAppleBootstrap { $_[0]{pt_type} == 0x401 && defined $_[0]{isBoot} } +sub isRecovery {  +    isFat_or_NTFS($_[0]) && ($_[0]{type_name} =~ /^Hidden/ || +      $_[0]{pt_type} == 0x12 || # "Compaq diagnostics" +        member($_[0]{device_LABEL} ,  +            # Extracted from /usr/lib/udev/rules.d/80-udisks2.rules +            # Hopefuly we'll ask to udev/udisk2 someday +            # generated by grep Recovery /usr/lib/udev/rules.d/80-udisks2.rules : +            qw(Recovery RECOVERY Lenovo_Recovery HP_RECOVERY Recovery_Partition DellUtility DellRestore IBM_SERVICE SERVICEV001 SERVICEV002 SYSTEM_RESERVED System_Reserved WINRE_DRV DIAGS IntelRST), +            # gathered over the years (Hald, mga#1371, mga#15999): +            qw(PQSERVICE Packard_Bell Push_Button_Reset SYSTEM_DRV)) +    ); +} + +=item isTrueLocalFS($part) + +Like isTrueFS(), to make a distinction between ext3/reiserfs/... and NFS + => allow /home on NFS + +=cut + +sub isTrueFS { isTrueLocalFS($_[0]) || $_[0]{fs_type} eq 'nfs' } + +=item isTrueFS($part) + +Is is a general purpose file system with the right Unix properties + +=cut -sub isTrueFS { isTrueLocalFS($_[0]) || member($_[0]{fs_type}, qw(nfs)) }  sub isTrueLocalFS { member($_[0]{fs_type}, true_local_fs_types()) } -sub isOtherAvailableFS { isEfi($_[0]) || isFat_or_NTFS($_[0]) || member($_[0]{fs_type}, 'ufs', 'hfs', 'iso9660') } #- other OS that linux can access its filesystem +=item isOtherAvailableFS($part) + +Is it another OS that linux can access its filesystem + +=cut + +sub isOtherAvailableFS { isESP($_[0]) || isFat_or_NTFS($_[0]) || member($_[0]{fs_type}, 'ufs', 'hfs', 'iso9660', 'nilfs2', 'exfat') }  sub isMountableRW { (isTrueFS($_[0]) || isOtherAvailableFS($_[0])) && $_[0]{fs_type} ne 'ntfs' } +sub cannotBeMountable {  +    my ($part) = @_; +    isRawRAID($part) || isRawLUKS($part) || isRawLVM($part) || isBIOS_GRUB($part); +} + +=item isFormatable($part) + +Is not a special sg that cannot be mounted/formatted (parts of RAID/LVM, BIOS_GRUB). Basically the reverse of cannotBeMountable(). + +=cut + +sub isFormatable { +    my ($part) = @_; +    !cannotBeMountable($part); +} +  sub isNonMountable {       my ($part) = @_; -    isRawRAID($part) || isRawLVM($part) || $part->{fs_type} eq 'ntfs' && !$part->{isFormatted} && $part->{notFormatted}; +    cannotBeMountable($part) || $part->{fs_type} eq 'ntfs' && !$part->{isFormatted} && $part->{notFormatted};  }  sub isPartOfLVM { defined $_[0]{lvm} }  sub isPartOfRAID { defined $_[0]{raid} }  sub isPartOfLoopback { defined $_[0]{loopback} } -sub isRAID { $_[0]{device} =~ /^md/ } +sub isRAID { $_[0]{device} =~ /^md/ && defined $_[0]{level} }  sub isUBD { $_[0]{device} =~ /^ubd/ } #- should be always true during an $::uml_install  sub isLVM { $_[0]{VG_name} || $_[0]{lv_name} } +sub isLUKS { defined $_[0]{dmcrypt_name} }  sub isLoopback { defined $_[0]{loopback_file} }  sub isMounted { $_[0]{isMounted} } -sub isBusy { isMounted($_[0]) || isPartOfRAID($_[0]) || isPartOfLVM($_[0]) || isPartOfLoopback($_[0]) } +sub isBusy { isMounted($_[0]) || isPartOfRAID($_[0]) || isPartOfLVM($_[0]) || $_[0]{dm_active} || isPartOfLoopback($_[0]) }  sub isSpecial { isRAID($_[0]) || isLVM($_[0]) || isLoopback($_[0]) || isUBD($_[0]) } -#- not for partitions, but for hds: +=item is_dmraid($hd) + +Check that a disk (not a partition) is in a fake/soft RAID + +=cut +  sub is_dmraid { $_[0]{bus} =~ /^dmraid_/ }  sub can_be_this_fs_type { @@ -364,24 +420,37 @@ sub set_isFormatted {      delete $part->{fs_type_from_magic};  } -#- do this before modifying $part->{fs_type} +=item check($fs_type, $_hd, $part) + +Called before before modifying $part->{fs_type} + +=cut +  sub check {      my ($fs_type, $_hd, $part) = @_; -    $fs_type eq "jfs" && $part->{size} < MB(16) and die N("You can not use JFS for partitions smaller than 16MB"); -    $fs_type eq "reiserfs" && $part->{size} < MB(32) and die N("You can not use ReiserFS for partitions smaller than 32MB"); +    $fs_type eq "jfs" && $part->{size} < MB(16) and die N("You cannot use JFS for partitions smaller than 16MB"); +    $fs_type eq "reiserfs" && $part->{size} < MB(32) and die N("You cannot use ReiserFS for partitions smaller than 32MB"); +    $fs_type eq "btrfs" && $part->{size} < MB(256) and die N("You cannot use btrfs for partitions smaller than 256MB");  }  sub guessed_by_mount() {      grep { $_ && !/nodev/ } chomp_(cat_('/etc/filesystems'));  } -sub directories_needed_to_boot() {  +sub directories_needed_to_boot_not_ESP() {      qw(/ /usr /var /boot /tmp);  } +sub directories_needed_to_boot() {  +    directories_needed_to_boot_not_ESP(), '/boot/EFI'; +}  sub carry_root_loopback {      my ($part) = @_;      any { $_->{mntpoint} eq '/' } @{$part->{loopback} || []};  } +=back + +=cut +  1; diff --git a/perl-install/fs/wild_device.pm b/perl-install/fs/wild_device.pm index 0e10f19ab..ff5a32253 100644 --- a/perl-install/fs/wild_device.pm +++ b/perl-install/fs/wild_device.pm @@ -1,8 +1,8 @@ -package fs::wild_device; # $Id$ +package fs::wild_device;  use diagnostics;  use strict; - +use devices;  use common; @@ -11,19 +11,19 @@ sub analyze {      if ($dev =~ m!^/u?dev/(.*)!) {  	'dev', $dev; -    } elsif ($dev !~ m!^/! && (-e "/dev/$dev" || -e "$::prefix/dev/$dev")) { +    } elsif ($dev !~ m!^/! && (-e "/dev/$dev" || -e "/dev/$dev")) {  	'dev', "/dev/$dev";      } elsif ($dev =~ /^LABEL=(.*)/) {  	'label', $1;      } elsif ($dev =~ /^UUID=(.*)/) {  	'uuid', $1; -    } elsif ($dev eq 'none' || $dev eq 'rootfs') { +    } elsif (member($dev, qw(none rootfs))) {  	'virtual'; -    } elsif ($dev =~ m!^(\S+):/\w!) { +    } elsif ($dev =~ m!^(\S+):/(\w|$)!) {  	'nfs';      } elsif ($dev =~ m!^//\w!) {  	'smb'; -    } elsif ($dev =~ m!^http://!) { +    } elsif ($dev =~ m!^https?://!) {  	'dav';      }  } @@ -40,16 +40,16 @@ sub to_subpart {  	    $part->{device_UUID} = $val;  	} elsif ($kind eq 'dev') {  	    my %part = (faked_device => 0); -	    if (my $rdev = (stat "$::prefix$dev")[6]) { +	    if (my $rdev = (stat "$dev")[6]) {  		($part{major}, $part{minor}) = unmakedev($rdev);  	    } -	    my $symlink = readlink("$::prefix$dev"); +	    my $symlink = $dev !~ m!mapper/! ? readlink("$dev") : undef;  	    $dev =~ s!/u?dev/!!;  	    if ($symlink && $symlink !~ m!^/!) {  		my $keep = 1; -		if ($symlink =~ m!/!) { +		if ($symlink =~ m!/! || $dev =~ m!/!) {  		    $symlink = MDK::Common::File::concat_symlink("/dev/" . dirname($dev), $symlink);  		    $symlink =~ s!^/dev/!! or $keep = 0;  		} @@ -67,7 +67,7 @@ sub to_subpart {  	    return \%part;  	}      } else { -	if ($dev =~ m!^/! && -f "$::prefix$dev") { +	if ($dev =~ m!^/! && -f "$dev") {  	    #- it must be a loopback file or directory to bind  	} else {  	    log::l("part_from_wild_device_name: unknown device $dev"); @@ -76,6 +76,12 @@ sub to_subpart {      $part;  } +sub _prefer_device_UUID { +    my ($part) = @_; +    $part->{prefer_device_UUID} ||  +      !$::no_uuid_by_default && devices::should_prefer_UUID($part->{device}); +} +  sub from_part {      my ($prefix, $part) = @_; @@ -83,7 +89,7 @@ sub from_part {  	'LABEL=' . $part->{device_LABEL};      } elsif ($part->{device_alias}) {  	"/dev/$part->{device_alias}"; -    } elsif (!$part->{prefer_device} && ($part->{prefer_device_UUID} || !$::no_uuid_by_default) && $part->{device_UUID}) { +    } elsif (!$part->{prefer_device} && $part->{device_UUID} && _prefer_device_UUID($part)) {  	'UUID=' . $part->{device_UUID};      } else {  	my $faked_device = exists $part->{faked_device} ?  | 
