diff options
Diffstat (limited to 'perl-install/fs/type.pm')
| -rw-r--r-- | perl-install/fs/type.pm | 320 | 
1 files changed, 205 insertions, 115 deletions
| diff --git a/perl-install/fs/type.pm b/perl-install/fs/type.pm index 88d3a6fc3..141d5b5e2 100644 --- a/perl-install/fs/type.pm +++ b/perl-install/fs/type.pm @@ -1,15 +1,25 @@ -package fs::type; # $Id$ +package fs::type;  use diagnostics;  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( -   isExtended isTrueLocalFS isTrueFS isDos isSwap isSunOS isOtherAvailableFS isRawLVM isRawRAID isRAID isLVM isMountableRW isNonMountable isPartOfLVM isPartOfRAID isPartOfLoopback isLoopback isMounted isBusy isSpecial isApple isAppleBootstrap isWholedisk isHiddenMacPart 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  ); @@ -21,24 +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/,  +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', -), -if_(arch() =~ /ppc/, -  0x401	=> 'apple',    'Apple Bootstrap', -  0x402	=> 'hfs',      'Apple HFS Partition', -  0x41  => '',         'PPC PReP Boot', +  0x07 => 'ntfs-3g',  'NTFS-3G', +  0x07 => 'ntfs',     'NTFS', +  0x07 => 'ntfs3',    'NTFS3', +  0x07 => 'exfat',    'exFAT',  ),  	], -        less_important => [ +        non_fs_type => [ +  0x83 => '',         'Encrypted',    0x8e => '',         'Linux Logical Volume Manager',    0xfd => '',         'Linux RAID',  	], @@ -50,34 +61,14 @@ if_(arch() =~ /ppc/,    0x85 => '',         'Linux extended',  	], -        backward_compatibility => [ -  0x183 => 'reiserfs', 'reiserfs (deprecated)', -  0x283 => 'xfs',      'xfs (deprecated)', -  0x383 => 'jfs',      'jfs (deprecated)', -  0x483 => 'ext3',     'ext3 (deprecated)', -	], -  	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 => 'ufs',      'SunOS swap', -  0x04 => 'ufs',      'SunOS usr', -  0x05 => 'ufs',      'Whole disk', -  0x06 => 'ufs',      'SunOS stand', -  0x07 => 'ufs',      'SunOS var', -  0x08 => 'ufs',      'SunOS home', -), if_(arch() =~ /^i.86/, + if_(arch() =~ /^i.86|x86_64/,    0x01 => 'vfat',     'FAT12',    0x02 => '',         'XENIX root',    0x03 => '',         'XENIX usr',    0x04 => 'vfat',     'FAT16 <32M',    0x06 => 'vfat',     'FAT16', -  0x07 => (arch() =~ /^ppc/ ? 'hpfs' : 'ntfs'), 'NTFS (or HPFS)', +  0x07 => 'hpfs',     'HPFS',    0x08 => '',         'AIX',  ),    0x09 => '',         'AIX bootable', @@ -91,16 +82,14 @@ if_(arch() =~ /ppc/,    0x16 => '',         'Hidden FAT16',    0x17 => 'ntfs',     'Hidden HPFS/NTFS',    0x18 => '',         'AST SmartSleep', -  0x1b => 'vfat',     'Hidden W95 FAT32', -  0x1c => 'vfat',     'Hidden W95 FAT32 (LBA)', -  0x1e => 'vfat',     'Hidden W95 FAT16 (LBA)', +  0x1b => 'vfat',     'Hidden W95 FAT32',       # \  +  0x1c => 'vfat',     'Hidden W95 FAT32 (LBA)', #  > don't change label, it's used to know if it's not a boot partition in bootloader.pm +  0x1e => 'vfat',     'Hidden W95 FAT16 (LBA)', # /    0x24 => '',         'NEC DOS',    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', @@ -121,9 +110,12 @@ if_(arch() !~ /ppc/,    0x75 => '',         'PC/IX',    0x80 => '',         'Old Minix',    0x81 => '',         'Minix / old Linux', +  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', -  0x87 => '',         'NTFS volume set ', +  0x86 => '',         'NTFS volume set (0x86)', +  0x87 => '',         'NTFS volume set (0x87)',    0x93 => '',         'Amoeba',    0x94 => '',         'Amoeba BBT',    0x9f => '',         'BSD/OS', @@ -138,6 +130,7 @@ if_(arch() !~ /ppc/,    0xb8 => '',         'BSDI swap',    0xbb => '',         'Boot Wizard hidden',    0xbe => '',         'Solaris boot', +  0xbf => '',         'Microsoft XBox OS Partitions',    0xc1 => '',         'DRDOS/sec (FAT-12)',    0xc4 => '',         'DRDOS/sec (FAT-16 < 32M)',    0xc6 => '',         'DRDOS/sec (FAT-16)', @@ -151,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', @@ -178,16 +170,26 @@ if_(arch() !~ /ppc/,  } -sub type_names() {  +sub type_names {  +    my ($expert, $o_hd) = @_;      my @l = @{$type_names{important}}; -    push @l, @{$type_names{less_important}}, sort @{$type_names{other}} if $::expert; -    @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{$_} } @l; +	(@l, @{$type_names{non_fs_type}}); +    } else { +	@l; +    }  }  sub type_name2subpart {      my ($name) = @_;      exists $type_name2fs_type{$name} &&  -      { fs_type => $type_name2fs_type{$name}, pt_type => $type_name2pt_type{$name} }; +      { type_name => $name, +	fs_type => $type_name2fs_type{$name}, pt_type => $type_name2pt_type{$name} };  }  sub part2type_name {  @@ -248,24 +250,6 @@ sub set_type_subpart {      }  } - -my @partitions_signatures = ( -    (map { [ 'Linux Logical Volume Manager', 0x200 * $_ + 0x18, "LVM2" ] } 0 .. 3), -    [ 'Linux Logical Volume Manager', 0, "HM\1\0" ], -    [ 'ext2', 0x438, "\x53\xEF" ], -    [ 'reiserfs', 0x10034, "ReIsErFs" ], -    [ 'reiserfs', 0x10034, "ReIsEr2Fs" ], -    [ 'xfs', 0, 'XFSB', 0x200, 'XAGF', 0x400, 'XAGI' ], -    [ 'jfs', 0x8000, 'JFS1' ], -    [ 'swap', 4086, "SWAP-SPACE" ], -    [ 'swap', 4086, "SWAPSPACE2" ], -    [ 'ntfs', 0x1FE, "\x55\xAA", 0x3, "NTFS" ], -    [ 'FAT32',  0x1FE, "\x55\xAA", 0x52, "FAT32" ], -if_(arch() !~ /^sparc/, -    [ 'FAT16',  0x1FE, "\x55\xAA", 0x36, "FAT" ], -), -); -  sub fs_type_from_magic {      my ($part) = @_;      if (exists $part->{fs_type_from_magic}) { @@ -276,79 +260,157 @@ sub fs_type_from_magic {      }  } +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_raw({ timeout => 30 }, 'blkid', '2>', '/dev/null', '-o', 'udev', '-p', devices::make($part->{device})); + +    \%h; +} +  sub type_subpart_from_magic {       my ($part) = @_; -    my $dev = devices::make($part->{device}); - -    my $check_md = sub { -	my ($F) = @_; -	my $MD_RESERVED_SECTORS = 128; -	my $sector = round_down($part->{size}, $MD_RESERVED_SECTORS) - $MD_RESERVED_SECTORS; #- MD_NEW_SIZE_SECTORS($part->{size}) -	if (c::lseek_sector(fileno $F, $sector, 0)) { -	    my $tmp; -	    my $signature = "\xfc\x4e\x2b\xa9"; -	    sysread($F, $tmp, length $signature); -	    $tmp eq $signature and return "Linux RAID"; -	} -	''; -    }; -    my $t = typeFromMagic($dev,  -			  if_($part->{size}, $check_md), -			  @partitions_signatures) or return; - -    my $p = type_name2subpart($t) || fs_type2subpart($t) || internal_error("unknown name/fs $t"); -    if ($p->{fs_type} eq 'ext2') { -	#- there is no magic to differentiate ext3 and ext2. Using libext2fs -	#- to check if it has a journal -	$p->{fs_type} = 'ext3' if c::is_ext3($dev); +    my $ids = call_blkid($part); + +    my $p; +    if ($ids->{ID_FS_USAGE} eq 'raid') { +	my $name = { +	    linux_raid_member => "Linux RAID", +	    LVM1_member => 'Linux Logical Volume Manager', +	    LVM2_member => 'Linux Logical Volume Manager', +	}->{$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 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}");      } -    $part->{fs_type_from_magic} = $p->{fs_type};      $p;  } - -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 isRawLVM { $_[0]{pt_type} == 0x8e } -sub isRawRAID { $_[0]{pt_type} == 0xfd } +# 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} } +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') } -sub isSunOS { arch() =~ /sparc/ && ${{ 0x1 => 1, 0x2 => 1, 0x4 => 1, 0x6 => 1, 0x7 => 1, 0x8 => 1 }}{$_[0]{pt_type}} } -sub isApple { $_[0]{fs_type} eq 'apple' && defined $_[0]{isDriver} } -sub isAppleBootstrap { $_[0]{fs_type} eq 'apple' && defined $_[0]{isBoot} } -sub isHiddenMacPart { defined $_[0]{isMap} } +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' } -sub isTrueFS { isTrueLocalFS($_[0]) || member($_[0]{fs_type}, qw(nfs)) } -sub isTrueLocalFS { member($_[0]{fs_type}, qw(ext2 reiserfs xfs jfs ext3)) } +=item isTrueFS($part) -sub isOtherAvailableFS { isEfi($_[0]) || isFat_or_NTFS($_[0]) || isSunOS($_[0]) || $_[0]{fs_type} eq 'hfs' } #- other OS that linux can access its filesystem +Is is a general purpose file system with the right Unix properties + +=cut + +sub isTrueLocalFS { member($_[0]{fs_type}, true_local_fs_types()) } + +=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} } +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]) } +=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 {      my ($part, $fs_type) = @_; -    $part->{fs_type} && ($part->{fs_type} eq 'auto' || member($fs_type, split(':', $part->{fs_type}))); +    can_be_one_of_those_fs_types($part, $fs_type); +} +sub can_be_one_of_those_fs_types { +    my ($part, @fs_types) = @_; +    $part->{fs_type} or return; +    $part->{fs_type} eq 'auto' || listlength(intersection(\@fs_types, [ split(':', $part->{fs_type}) ]));  }  sub maybeFormatted {       my ($part) = @_; -    $part->{isFormatted} || !$part->{notFormatted} && !$part->{bad_fs_type_magic}; +    $part->{isFormatted} || !$part->{notFormatted} && (!$part->{bad_fs_type_magic} || $part->{options} =~ /encrypted/);  }  sub set_isFormatted {      my ($part, $val) = @_; @@ -358,9 +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} < 16 << 11 and die N("You can't use JFS for partitions smaller than 16MB"); -    $fs_type eq "reiserfs" && $part->{size} < 32 << 11 and die N("You can't 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_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; | 
