diff options
Diffstat (limited to 'perl-install/fs')
| -rw-r--r-- | perl-install/fs/format.pm | 94 | ||||
| -rw-r--r-- | perl-install/fs/get.pm | 128 | ||||
| -rw-r--r-- | perl-install/fs/mount_options.pm | 250 | ||||
| -rw-r--r-- | perl-install/fs/type.pm | 366 |
4 files changed, 838 insertions, 0 deletions
diff --git a/perl-install/fs/format.pm b/perl-install/fs/format.pm new file mode 100644 index 000000000..3b04bba56 --- /dev/null +++ b/perl-install/fs/format.pm @@ -0,0 +1,94 @@ +package fs::format; # $Id$ + +use diagnostics; +use strict; + +use run_program; +use common; +use fs::type; +use log; + +my %cmds = ( + ext2 => [ 'e2fsprogs', 'mke2fs', '-F' ], + ext3 => [ 'e2fsprogs', 'mke2fs', '-F', '-j' ], + reiserfs => [ 'reiserfsprogs', 'mkreiserfs', '-ff' ], + xfs => [ 'xfsprogs', 'mkfs.xfs', '-f', '-q' ], + jfs => [ 'jfsprogs', 'mkfs.jfs', '-f' ], + hfs => [ 'hfsutils', 'hformat' ], + dos => [ 'dosfstools', 'mkdosfs' ], + vfat => [ 'dosfstools', 'mkdosfs', '-F', '32' ], + swap => [ 'util-linux', 'mkswap' ], +); + +sub package_needed_for_partition_type { + my ($part) = @_; + my $l = $cmds{$part->{fs_type}} or return; + $l->[0]; +} + +sub check_package_is_installed { + my ($do_pkgs, $fs_type) = @_; + + my ($pkg, $binary) = @{$cmds{$fs_type} || return}; + $do_pkgs->ensure_binary_is_installed($pkg, $binary); +} + +sub part { + my ($raids, $part, $prefix, $wait_message) = @_; + if (isRAID($part)) { + $wait_message->(N("Formatting partition %s", $part->{device})) if $wait_message; + require raid; + raid::format_part($raids, $part); + } elsif (isLoopback($part)) { + $wait_message->(N("Creating and formatting file %s", $part->{loopback_file})) if $wait_message; + loopback::format_part($part, $prefix); + } else { + $wait_message->(N("Formatting partition %s", $part->{device})) if $wait_message; + part_raw($part); + } +} + +sub part_raw { + my ($part) = @_; + + $part->{isFormatted} and return; + + if ($part->{encrypt_key}) { + require fs; + fs::set_loop($part); + } + + my $dev = $part->{real_device} || $part->{device}; + + my @options = if_($part->{toFormatCheck}, "-c"); + log::l("formatting device $dev (type $part->{fs_type})"); + + my $fs_type = $part->{fs_type}; + + if ($fs_type eq 'ext2' || $fs_type eq 'ext3') { + push @options, "-m", "0" if $part->{mntpoint} =~ m|^/home|; + } elsif (isDos($part)) { + $fs_type = 'dos'; + } elsif ($fs_type eq 'hfs') { + push @options, '-l', "Untitled"; + } elsif (isAppleBootstrap($part)) { + push @options, '-l', 'bootstrap'; + } + + my ($_pkg, $cmd, @first_options) = @{$cmds{$fs_type} || die N("I don't know how to format %s in type %s", $part->{device}, $part->{fs_type})}; + + run_program::raw({ timeout => 60 * 60 }, $cmd, @first_options, @options, devices::make($dev)) or die N("%s formatting of %s failed", $fs_type, $dev); + + if ($fs_type eq 'ext3') { + disable_forced_fsck($dev); + } + + set_isFormatted($part, 1); +} + +sub disable_forced_fsck { + my ($dev) = @_; + run_program::run("tune2fs", "-c0", "-i0", devices::make($dev)); +} + +1; diff --git a/perl-install/fs/get.pm b/perl-install/fs/get.pm new file mode 100644 index 000000000..859ddf0ac --- /dev/null +++ b/perl-install/fs/get.pm @@ -0,0 +1,128 @@ +package fs::get; # $Id$ + +use diagnostics; +use strict; + +use partition_table; +use fs::type; +use fs; +use common; +use log; + +sub empty_all_hds() { + { hds => [], lvms => [], raids => [], 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}}; +} +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}}; +} + +sub fstab_and_holes { + my ($all_hds) = @_; + hds_fstab_and_holes(hds($all_hds)), @{$all_hds->{raids}}, @{$all_hds->{loopbacks}}; +} + +sub holes { + my ($all_hds) = @_; + grep { $_->{pt_type} == 0 } fstab_and_holes($all_hds); +} +sub hds_holes { + grep { $_->{pt_type} == 0 } hds_fstab_and_holes(@_); +} +sub free_space { + my ($all_hds) = @_; + sum map { $_->{size} } holes($all_hds); +} +sub hds_free_space { + sum map { $_->{size} } hds_holes(@_); +} + +sub hds { + my ($all_hds) = @_; + (@{$all_hds->{hds}}, @{$all_hds->{lvms}}); +} + +#- get all normal partition including special ones as found on sparc. +sub hds_fstab { + map { partition_table::get_normal_parts($_) } @_; +} + +sub hds_fstab_and_holes { + map { + if (isLVM($_)) { + my @parts = partition_table::get_normal_parts($_); + my $free = $_->{totalsectors} - sum map { $_->{size} } @parts; + my $free_part = { start => 0, size => $free, pt_type => 0, rootDevice => $_->{VG_name} }; + @parts, if_($free >= $_->cylinder_size, $free_part); + } else { + partition_table::get_normal_parts_and_holes($_); + } + } @_; +} + + +sub device2part { + my ($dev, $fstab) = @_; + my $subpart = fs::subpart_from_wild_device_name($dev); + my $part = find { fsedit::is_same_hd($subpart, $_) } @$fstab; + log::l("fs::get::device2part: unknown device <<$dev>>") if !$part; + $part; +} + +sub part2hd { + my ($part, $all_hds) = @_; + my $hd = find { $part->{rootDevice} eq ($_->{device} || $_->{VG_name}) } hds($all_hds); + $hd; +} + +sub file2part { + my ($fstab, $file, $b_keep_simple_symlinks) = @_; + my $part; + + $file = $b_keep_simple_symlinks ? common::expand_symlinks_but_simple("$::prefix$file") : expand_symlinks("$::prefix$file"); + unless ($file =~ s/^$::prefix//) { + my $part = find { loopback::carryRootLoopback($_) } @$fstab or die; + log::l("found $part->{mntpoint}"); + $file =~ s|/initrd/loopfs|$part->{mntpoint}|; + } + foreach (@$fstab) { + my $m = $_->{mntpoint}; + $part = $_ if + $file =~ /^\Q$m/ && + (!$part || length $part->{mntpoint} < length $m); + } + $part or die "file2part: not found $file"; + $file =~ s|$part->{mntpoint}/?|/|; + ($part, $file); +} + +sub mntpoint2part { + my ($mntpoint, $fstab) = @_; + find { $mntpoint eq $_->{mntpoint} } @$fstab; +} +sub has_mntpoint { + my ($mntpoint, $all_hds) = @_; + mntpoint2part($mntpoint, [ really_all_fstab($all_hds) ]); +} +sub root_ { + my ($fstab, $o_boot) = @_; + $o_boot && mntpoint2part("/boot", $fstab) || mntpoint2part("/", $fstab); +} +sub root { &root_ || {} } + +sub up_mount_point { + my ($mntpoint, $fstab) = @_; + while (1) { + $mntpoint = dirname($mntpoint); + $mntpoint ne "." or return; + $_->{mntpoint} eq $mntpoint and return $_ foreach @$fstab; + } +} + +1; diff --git a/perl-install/fs/mount_options.pm b/perl-install/fs/mount_options.pm new file mode 100644 index 000000000..b4890e877 --- /dev/null +++ b/perl-install/fs/mount_options.pm @@ -0,0 +1,250 @@ +package fs::mount_options; # $Id$ + +use diagnostics; +use strict; + +use common; +use fs::type; +use log; + +sub list() { + my %non_defaults = ( + sync => 'async', noatime => 'atime', noauto => 'auto', ro => 'rw', + user => 'nouser', nodev => 'dev', noexec => 'exec', nosuid => 'suid', + ); + my @user_implies = qw(noexec nodev nosuid); + \%non_defaults, \@user_implies; +} + +sub unpack { + my ($part) = @_; + my $packed_options = $part->{options}; + + my ($non_defaults, $user_implies) = list(); + + my @auto_fs = fs::auto_fs(); + my %per_fs = ( + iso9660 => [ qw(unhide) ], + vfat => [ qw(umask=0 umask=0022) ], + ntfs => [ qw(umask=0 umask=0022) ], + nfs => [ qw(rsize=8192 wsize=8192) ], + smbfs => [ qw(username= password=) ], + davfs => [ qw(username= password= uid= gid=) ], + reiserfs => [ 'notail' ], + ); + push @{$per_fs{$_}}, 'usrquota', 'grpquota' foreach 'ext2', 'ext3', 'xfs'; + + while (my ($fs, $l) = each %per_fs) { + $part->{fs_type} eq $fs || $part->{fs_type} eq 'auto' && member($fs, @auto_fs) or next; + $non_defaults->{$_} = 1 foreach @$l; + } + + $non_defaults->{encrypted} = 1 if !$part->{isFormatted} || isSwap($part); + + $non_defaults->{supermount} = 1 if $part->{fs_type} =~ /:/ || member($part->{fs_type}, 'auto', @auto_fs); + + my $defaults = { reverse %$non_defaults }; + my %options = map { $_ => '' } keys %$non_defaults; + my @unknown; + foreach (split(",", $packed_options)) { + if ($_ eq 'user') { + $options{$_} = 1 foreach 'user', @$user_implies; + } elsif (exists $non_defaults->{$_}) { + $options{$_} = 1; + } elsif ($defaults->{$_}) { + $options{$defaults->{$_}} = 0; + } elsif (/(.*?=)(.*)/) { + $options{$1} = $2; + } else { + push @unknown, $_; + } + } + # merge those, for cleaner help + $options{'rsize=8192,wsize=8192'} = delete $options{'rsize=8192'} && delete $options{'wsize=8192'} + if exists $options{'rsize=8192'}; + + my $unknown = join(",", @unknown); + \%options, $unknown; +} + +sub pack_ { + my ($_part, $options, $unknown) = @_; + + my ($non_defaults, $user_implies) = list(); + my @l; + + my @umasks = map { + if (/^umask=/) { + my $v = delete $options->{$_}; + /^umask=(.+)/ ? if_($v, $1) : $v; + } else { () } + } keys %$options; + if (@umasks) { + push @l, 'umask=' . min(@umasks); + } + + if (delete $options->{user}) { + push @l, 'user'; + foreach (@$user_implies) { + if (!delete $options->{$_}) { + # overriding + $options->{$non_defaults->{$_}} = 1; + } + } + } + push @l, map_each { if_($::b, $::a =~ /=$/ ? "$::a$::b" : $::a) } %$options; + push @l, $unknown; + + join(",", uniq(grep { $_ } @l)); +} +sub pack { + my ($part, $options, $unknown) = @_; + $part->{options} = pack_($part, $options, $unknown); + noreturn(); +} + +# update me on each util-linux new release: +sub help() { + ( + + 'grpquota' => '', + + 'noatime' => N("Do not update inode access times on this file system +(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)."), + + 'nodev' => N("Do not interpret character or block special devices on the file system."), + + '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 +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."), + + 'sync' => N("All I/O to the file system should be done synchronously."), + + 'supermount' => '', + + 'user' => N("Allow an ordinary user to mount the file system. The +name of the mounting user is written to mtab so that he can unmount the file +system again. This option implies the options noexec, nosuid, and nodev +(unless overridden by subsequent options, as in the option line +user,exec,dev,suid )."), + + 'usrquota' => '', + + 'umask=0' => N("Give write access to ordinary users"), + + 'umask=0022' => N("Give read-only access to ordinary users"), + ); +} + + +sub rationalize { + my ($part) = @_; + + my ($options, $unknown) = &unpack($part); + + if ($part->{fs_type} ne 'reiserfs') { + $options->{notail} = 0; + } + + &pack($part, $options, $unknown); +} + +sub set_default { + my ($part, %opts) = @_; + #- opts are: useSupermount security iocharset codepage ignore_is_removable + + my ($options, $unknown) = &unpack($part); + + if (!$opts{ignore_is_removable} && $part->{is_removable} && !member($part->{mntpoint}, qw(/ /usr /var /boot))) { + $options->{supermount} = $opts{useSupermount} && !($opts{useSupermount} eq 'magicdev' && $part->{media_type} eq 'cdrom'); + $part->{fs_type} = !$options->{supermount} ? 'auto' : + $part->{media_type} eq 'cdrom' ? 'udf:iso9660' : 'ext2:vfat'; + $options->{sync} = 1 if $part->{media_type} ne 'cdrom'; + } + + if ($part->{media_type} eq 'cdrom') { + $options->{ro} = 1; + } + + if ($part->{media_type} eq 'fd') { + # slow device so don't loose time, write now! + $options->{sync} = 1; + } + + if (isTrueFS($part)) { + #- noatime on laptops (do not wake up the hd) + #- Do not update inode access times on this + #- file system (e.g, for faster access on the + #- news spool to speed up news servers). + $options->{noatime} = detect_devices::isLaptop(); + } + 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') { + add2hash($options, { 'username=' => '%' }) if !$options->{'credentials='}; + } + if (fs::type::can_be_this_fs_type($part, 'vfat')) { + + put_in_hash($options, { + users => 1, noexec => 0, + }) if $part->{is_removable}; + + put_in_hash($options, { + 'umask=0' => $opts{security} < 3, 'umask=0022' => $opts{security} < 4, + 'iocharset=' => $opts{iocharset}, 'codepage=' => $opts{codepage}, + }); + } + 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, + }); + } + if (fs::type::can_be_this_fs_type($part, 'iso9660')) { + put_in_hash($options, { user => 1, noexec => 0, 'iocharset=' => $opts{iocharset} }); + } + if ($part->{fs_type} eq 'reiserfs') { + $options->{notail} = 1; + } + if (isLoopback($part) && !isSwap($part)) { #- no need for loop option for swap files + $options->{loop} = 1; + } + + # rationalize: no need for user + if ($options->{autofs} || $options->{supermount}) { + $options->{users} = $options->{user} = 0; + } + + if ($options->{user} || $options->{users}) { + # have noauto when we have user + $options->{noauto} = 1; + # ensure security (user_implies - noexec as noexec is not a security matter) + $options->{$_} = 1 foreach 'nodev', 'nosuid'; + } + + &pack($part, $options, $unknown); + + rationalize($part); +} + +sub set_all_default { + my ($all_hds, %opts) = @_; + #- opts are: useSupermount security iocharset codepage + + foreach my $part (fs::get::really_all_fstab($all_hds)) { + set_default($part, %opts); + } +} + +1; diff --git a/perl-install/fs/type.pm b/perl-install/fs/type.pm new file mode 100644 index 000000000..2caf1d803 --- /dev/null +++ b/perl-install/fs/type.pm @@ -0,0 +1,366 @@ +package fs::type; # $Id$ + +use diagnostics; +use strict; + +use common; + + +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 +); + + +my (%type_name2pt_type, %type_name2fs_type, %fs_type2pt_type, %pt_type2fs_type, %type_names); + +{ + my @list_types = ( + important => [ + 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', +), +if_(arch() =~ /ppc|i.86/, + 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', +), + ], + + less_important => [ + 0x8e => '', 'Linux Logical Volume Manager', + 0xfd => '', 'Linux RAID', + ], + + special => [ + 0x0 => '', 'Empty', + 0x05 => '', 'Extended', + 0x0f => '', 'W95 Extended (LBA)', + 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|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)', + 0x08 => '', 'AIX', +), + 0x09 => '', 'AIX bootable', + 0x0a => '', 'OS/2 Boot Manager', + 0x0c => 'vfat', 'W95 FAT32 (LBA)', + 0x0e => 'vfat', 'W95 FAT16 (LBA)', + 0x10 => '', 'OPUS', + 0x11 => '', 'Hidden FAT12', + 0x12 => '', 'Compaq diagnostics', + 0x14 => '', 'Hidden FAT16 <32M', + 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)', + 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', + 0x4f => '', 'QNX4.x 3rd part', + 0x50 => '', 'OnTrack DM', + 0x51 => '', 'OnTrack DM6 Aux1', + 0x52 => '', 'CP/M', + 0x53 => '', 'OnTrack DM6 Aux3', + 0x54 => '', 'OnTrackDM6', + 0x55 => '', 'EZ-Drive', + 0x56 => '', 'Golden Bow', + 0x5c => '', 'Priam Edisk', + 0x61 => '', 'SpeedStor', + 0x63 => '', 'GNU HURD or SysV', + 0x64 => '', 'Novell Netware 286', + 0x65 => '', 'Novell Netware 386', + 0x70 => '', 'DiskSecure Multi-Boot', + 0x75 => '', 'PC/IX', + 0x80 => '', 'Old Minix', + 0x81 => '', 'Minix / old Linux', + 0x84 => '', 'OS/2 hidden C: drive', + 0x86 => '', 'NTFS volume set', + 0x87 => '', 'NTFS volume set ', + 0x93 => '', 'Amoeba', + 0x94 => '', 'Amoeba BBT', + 0x9f => '', 'BSD/OS', + 0xa0 => '', 'IBM Thinkpad hibernation', + 0xa5 => '', 'FreeBSD', + 0xa6 => '', 'OpenBSD', + 0xa7 => '', 'NeXTSTEP', + 0xa8 => '', 'Darwin UFS', + 0xa9 => '', 'NetBSD', + 0xab => '', 'Darwin boot', + 0xb7 => '', 'BSDI fs', + 0xb8 => '', 'BSDI swap', + 0xbb => '', 'Boot Wizard hidden', + 0xbe => '', 'Solaris boot', + 0xc1 => '', 'DRDOS/sec (FAT-12)', + 0xc4 => '', 'DRDOS/sec (FAT-16 < 32M)', + 0xc6 => '', 'DRDOS/sec (FAT-16)', + 0xc7 => '', 'Syrinx', + 0xda => '', 'Non-FS data', + 0xdb => '', 'CP/M / CTOS / ...', + 0xde => '', 'Dell Utility', + 0xdf => '', 'BootIt', + 0xe1 => '', 'SpeedStor (FAT-12)', + 0xe3 => '', 'DOS R/O', + 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', + 0xfe => '', 'LANstep', + 0xff => '', 'BBT', + ], + ); + + foreach (group_by2(@list_types)) { + my ($name, $l) = @$_; + for (my $i = 0; defined $l->[$i]; $i += 3) { + my $pt_type = $l->[$i]; + my $fs_type = $l->[$i + 1]; + my $type_name = $l->[$i + 2]; + !exists $type_name2fs_type{$type_name} or internal_error("'$type_name' is not unique"); + $type_name2fs_type{$type_name} = $fs_type; + $type_name2pt_type{$type_name} = $pt_type; + + $fs_type2pt_type{$fs_type} ||= $pt_type; + $pt_type2fs_type{$pt_type} ||= $fs_type; + push @{$type_names{$name}}, $type_name; + } + } +} + + +sub type_names() { + my @l = @{$type_names{important}}; + push @l, @{$type_names{less_important}}, sort @{$type_names{other}} if $::expert; + @l; +} + +sub type_name2subpart { + my ($name) = @_; + exists $type_name2fs_type{$name} && + { fs_type => $type_name2fs_type{$name}, pt_type => $type_name2pt_type{$name} }; +} + +sub part2type_name { + my ($part) = @_; + my @names = keys %type_name2fs_type; + + my $pt_type = defined $part->{pt_type} ? $part->{pt_type} : $part->{fs_type} && $fs_type2pt_type{$part->{fs_type}}; + if (defined $pt_type) { + @names = grep { $pt_type eq $type_name2pt_type{$_} } @names; + } + if (my $fs_type = $part->{fs_type} || $part->{pt_type} && $pt_type2fs_type{$part->{pt_type}}) { + @names = grep { $fs_type eq $type_name2fs_type{$_} } @names; + } + if (@names > 1) { + log::l("ERROR: (part2type_name) multiple match for $part->{pt_type} $part->{fs_type}"); + } + first(@names); +} +sub type_name2pt_type { + local ($_) = @_; + /0x(.*)/ ? hex $1 : $type_name2pt_type{$_} || $_; +} + + +sub pt_type2subpart { + my ($pt_type) = @_; + my $fs_type = $pt_type2fs_type{$pt_type}; + { pt_type => $pt_type, if_($fs_type, fs_type => $fs_type) }; +} +sub fs_type2subpart { + my ($fs_type) = @_; + my $pt_type = $fs_type2pt_type{$fs_type}; + { fs_type => $fs_type, if_($pt_type, pt_type => $pt_type) }; +} +sub set_fs_type { + my ($part, $fs_type) = @_; + put_in_hash($part, fs_type2subpart($fs_type)); +} +sub set_pt_type { + my ($part, $pt_type) = @_; + put_in_hash($part, pt_type2subpart($pt_type)); +} +sub suggest_fs_type { + my ($part, $fs_type) = @_; + set_fs_type($part, $fs_type) if !$part->{pt_type} && !$part->{fs_type}; +} +sub set_type_subpart { + my ($part, $subpart) = @_; + if (exists $subpart->{pt_type} && exists $subpart->{fs_type}) { + $part->{fs_type} = $subpart->{fs_type}; + $part->{pt_type} = $subpart->{pt_type}; + } elsif (exists $subpart->{pt_type}) { + set_pt_type($part, $subpart->{pt_type}); + } elsif (exists $subpart->{fs_type}) { + set_fs_type($part, $subpart->{fs_type}); + } else { + log::l("ERROR: (set_type_subpart) subpart has no type"); + } +} + + +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}) { + $part->{fs_type_from_magic}; + } else { + my $type = type_subpart_from_magic($part); + $type && $type->{fs_type}; + } +} + +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); + } + $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 } +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 isTrueFS { isTrueLocalFS($_[0]) || member($_[0]{fs_type}, qw(nfs)) } +sub isTrueLocalFS { member($_[0]{fs_type}, qw(ext2 reiserfs xfs jfs ext3)) } + +sub isOtherAvailableFS { isEfi($_[0]) || isFat_or_NTFS($_[0]) || isSunOS($_[0]) || $_[0]{fs_type} eq 'hfs' } #- other OS that linux can access its filesystem +sub isMountableRW { (isTrueFS($_[0]) || isOtherAvailableFS($_[0])) && $_[0]{fs_type} ne 'ntfs' } +sub isNonMountable { + my ($part) = @_; + isRawRAID($part) || isRawLVM($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 isUBD { $_[0]{device} =~ /^ubd/ } #- should be always true during an $::uml_install +sub isLVM { $_[0]{VG_name} } +sub isLoopback { defined $_[0]{loopback_file} } +sub isMounted { $_[0]{isMounted} } +sub isBusy { isMounted($_[0]) || isPartOfRAID($_[0]) || isPartOfLVM($_[0]) || isPartOfLoopback($_[0]) } +sub isSpecial { isRAID($_[0]) || isLVM($_[0]) || isLoopback($_[0]) || isUBD($_[0]) } + +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}))); +} + +sub maybeFormatted { + my ($part) = @_; + $part->{isFormatted} || !$part->{notFormatted} && !$part->{bad_fs_type_magic}; +} +sub set_isFormatted { + my ($part, $val) = @_; + $part->{isFormatted} = $val; + $part->{notFormatted} = !$val; + delete $part->{bad_fs_type_magic}; + delete $part->{fs_type_from_magic}; +} + +#- do this before modifying $part->{fs_type} +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"); +} |
