#!/usr/bin/perl # $Id: setup_harddisks,v 1.41 2005/04/08 10:08:54 lange Exp $ #********************************************************************* # # setup_harddisks -- create partitions and filesystems on harddisk # # This script is part of FAI (Fully Automatic Installation) # Copyright (c) 1999, 2000 by ScALE Workgroup, Universitaet zu Koeln # Copyright (c) 2000-2005 by Thomas Lange, Uni Koeln # #********************************************************************* # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, # MA 02111-1307, USA. #********************************************************************* # # This program first read the configfiles, partitions and formats the harddisks, # produces fstab and FAI-variables-file. It uses sfdisk, mke2fs, mkswap # # Parameters: # [-X] no test, your harddisks will be formated # default: only test, no real formating # [-f] default: parse classes # [-c] default: $FAI/disk_config/ # [-d] default: no DOS alignment # #--------------------------------------------------- # Last changes: 31.3.2005 by Thomas Lange add sub mapdisk{} # Last changes: 8.11.2004 by Thomas Lange add $devdisklist when calling sfdisk # Last changes: 3.2.2004 by Thomas Lange typos # Last changes: 14.07.2003 by Thomas Lange add xfs filesystem support # Last changes: 23.01.2003 by Thomas Lange print info data to stdout # Last changes: 03.12.2002 by Thomas Lange remove ida, cciss stuff. Just match everything # Last changes: 27.11.2002 by Thomas Lange allow more that 3 primary partitions # Last changes: 14.05.2002 by Thomas Lange use strict # Last changes: 04.05.2002 by Thomas Lange use strict # Last changes: 29.04.2002 by Thomas Lange add swaplist # Last changes: 12.01.2002 by Thomas Lange # /dev/ida/ patch 12.01.2002 by Marc Martinez # Last changes: 9.11.2001 by Thomas Lange # reiserfs patch 8.11.2001 by Diane Trout # Last changes: 25.10.2001 by Thomas Lange # Last changes: 09.07.2001 by Thomas Lange # Last changes: 04.07.2001 by Thomas Lange # Last changes: 06.05.2001 by Thomas Lange # Last changes: 09.03.2001 by Thomas Lange # Last changes: 05.12.2000 by Thomas Lange # Last changes: 03.05.2000 by Thomas Lange # Last changes: 03.04.2000 by Mattias Gaertner #--------------------------------------------------- # # config-file format: # lines beginning with # are comments # # "disk_config |first|end" # The disk_config command starts the parsing. # It has to be the first command. # is the harddisk to format in short form like "hda" or "sdc". # if first is used, the first of $ENV{disklist} is used # "end" = end parsing here # Example: "disk_config hdb" # Example: "disk_config first" # # Defining one partition: # "primary|logical mountpoint|swap|- |preserve [fstab-options][;extraordinary options]" # "primary|logical": # "primary": this are the bootable partitions like the # root directory "/" or the DOS "C:" disk. # "logical": this are all other partitions like a linux # "/var" or a swap partition or a DOS disk. # # "mountpoint|swap|-": # "mountpoint": # This is the mount-point for fstab. # For example "/","/var","/usr". There must not # be a space in the mountpoint. # "swap": # swap-partitions # "-": # do not mount this partition. # # "|preserve": # "": # The size of the partition in megabyte # Examples: # "30" = 30 mb # "10-100" = 10 to 100 mb # "20-" = minimum of 20 mb # "-500" = 1 to 500 mb # The megabytes will be rounded up to cylinders. # "preserve": # This is the alternative for the size attribute. # is the partition number. For example # preserve3 for the third partition. If the # was hda then this results in hda3. # The partition will be left unchanged. This # is useful if you have partitions that do not # need re-installation or if you want to have # other operation systems on the device together # with Linux. Extended Partitions can not be preserved. # The bootable flag will not be preserved. # Preserved partitions are mounted readonly during # installation. # # "fstab-options": # These options are copied to the fstab-file. The # default is "default" # # After the semicolon there could be extra options like: # -i : Bytes per inodes # (only ext2/3 filesystem) # -m % : reserved blocks percentage for superuser # (only ext2/3 filesystem) # -j : format in ext3 # -c : check for bad blocks # format : Always format this partition even if preserve # lazyformat : Do not format if partition has not moved # (useful for testing the installation) # boot : make this partition the boot-partition (the # linux root filesystem is the default) # ext2 : Extended 2 filesystem (this is the default) # swap : swap partition # dosfat16 : DOS 16bit FAT file system # winfat32 : Win95 FAT32 file system # writable : mounts a preserved partition writable # xfs : xfs # reiser : reiserfs # -h : set reiserfs hash # -v : set reiserfs version # use strict; # getopts variables: our ($opt_X, $opt_f, $opt_c, $opt_d); my $test; $| = 1; # flush always #**************************************************** # Variables #**************************************************** my $Version = "version 0.35fai"; my $megabyte = 1024 * 1024; # guess # $gigabyte = 1024 * $megabyte; my $sectorsize = 512; # used programs my $sfdisk_options = "-q $ENV{sfdisk}"; # be quiet my $mke2fs_options = "-q"; # be quiet my $mkreiserfs_options = ""; my $mkxfs_options = "-f"; my $mkswap_options = ""; # FAI input variables my $ClassPath = "$ENV{FAI}/disk_config";# this directory contains the classes my $ConfigFileName = ""; # alternative classfile, only for tests my $DOS_Alignment = ""; # align partitions for tracks # FAI output variables my $BootPartition = ""; # the boot partition like "hda1" my $BOOT_DEVICE = ""; # the root device like "hda" or "sdb" my $FAIOutputFile = $ENV{diskvar}; # write output variables to this file # old partition tables my %DiskUnits = (); # unit size of each disk in sectors my %DiskSize = (); # size of every disk in units my %SectorsAlignment = (); # tracksize in sectors my %PartOldBoot = (); # partition was bootable. "yes"=yes my %PartOldStart = (); # old startunit of partition my %PartOldEnd = (); # old endunit of partition my %PartOldStartSec = (); # old startsector of partition my %PartOldEndSec = (); # old endsector of partition my %PartOldID = (); # old ID of partition my %OldNotAligned = (); # "yes" if old partition boundaries are not DOS aligned # mountpoints ("/" or "swap" or "no" or "extended") my $NofSwapPart = 0; # number of swap partitions my $NofNotMoPart = 0; # number of not mountet partitions my %DiskMountpoints = (); # mountpoints of every disk. separated by spaces my %MountpointPart = (); # partition of every mountpoint. e.g. "hda2" my %PartMountpoint = (); # mountpoint of every partition. my @swaplist; # list of all swpa devices # size of partition/mountpoint my %MPMinSize = (); # minimum size of mountpoint in units my %MPMaxSize = (); # maximum size of mountpoint in units my %MPPreserve = (); # preserve partition: "yes"=yes my %MPPrimary = (); # primary partition: "yes"=yes my %MPStart = (); # start of partition in units my %MPSize = (); # size of partition in units my %MPID = (); # id of partition # options my %MPfstaboptions = (); # fstab options for every mountpoint my %MPOptions = (); # extra options for every mountpoint # sfdisk partition tables my %sfdiskTables = (); # partition tables for sfdisk my $verbose = 0; $verbose = $ENV{verbose} if $ENV{verbose}; # Parse command line use Getopt::Std; &getopts('Xf:c:d') || die " USAGE: [-X] no test, your harddisks will be formated default: only test, no real formating [-f] default: parse classes [-c] default: \$FAI/disk_config/ [-d] default: no DOS alignment "; print "setup_harddisks $Version\n"; if (defined $opt_X){ $test = 2; } else { print "TEST ONLY - no real formating\n\n"; $test = 1; } $ConfigFileName = $opt_f if $opt_f;# alternative config file $ClassPath = $opt_c if $opt_c;# search classes here $DOS_Alignment = "yes" if $opt_d; # track alignment # main part &GetAllDisks; &ParseAllConfigFiles; &BuildNewPartTables; &PartitionPersfdisk; &FormatDisks; &WriteFSTab; &WriteFAIVariables; exit 0; #**************************************************** #**************************************************** # get a partition pathname #**************************************************** sub PartName { my ($disk, $partno) = @_; my $ppath; for ($disk) { /^[a-z]+$/ and $ppath = "${disk}${partno}"; /\d$/ and $ppath = "${disk}p${partno}"; } return $ppath; } #**************************************************** # Read all partition tables of this machine #**************************************************** sub GetAllDisks{ my $line=""; my $disk=""; my $device=""; my $rest; my $result; my $divi; my $devdisklist=""; foreach my $device(split(/\s/,$ENV{disklist})){ $devdisklist = "$devdisklist /dev/$device"; } print "Probing disks: $devdisklist\n"; print "Disks found:"; $result = `sh -c "LC_ALL=C sfdisk -g -q $devdisklist"`; foreach my $line(split(/\n/,$result)){ if($line =~ m'^/dev/(.+?):\s+(\d+)\s+cylinders,\s+(\d+)\s+heads,\s+(\d+)\s+sectors'i){ $disk = $1; $DiskUnits{$disk} = $3 * $4;# heads * sectors = cylinder size in sectors $DiskSize{$disk} = $2; # cylinders ($DOS_Alignment eq "yes") ? ($SectorsAlignment{$disk} = $4) : ($SectorsAlignment{$disk} = 1); print " $disk"; } } $result = `sh -c "LC_ALL=C sfdisk -d -q $devdisklist"`; foreach my $line(split(/\n/,$result)){ # if($line =~ m'# partition table of /dev/(cciss/c\dd\d|ida/c\dd\d|rd/c\dd\d|[a-z]+)'i){ # now just match all devices if($line =~ m'# partition table of /dev/(\S+)$'i){ $disk = $1; } if($line =~ m#^/dev/(.+?)\s*:\s+start=\s*(\d+),\s+size=\s*(\d+),\s+Id=\s*([a-z0-9]+)\b(.*)$#i){ $device = $1; # Sectors $PartOldStartSec{$device} = $2; $PartOldEndSec{$device} = $2 + $3 - 1; # DiskUnits $PartOldStart{$device} = int ($2 / $DiskUnits{$disk}); $PartOldEnd{$device} = int (($2 + $3 - 1) / $DiskUnits{$disk}); $divi = $2 / $SectorsAlignment{$disk}; ($divi != int ($divi)) && ($OldNotAligned{$device} = "yes"); $divi = $3 / $SectorsAlignment{$disk}; ($divi != int ($divi)) && ($OldNotAligned{$device} = "yes"); $PartOldID{$device} = $4; $rest = $5; $PartOldBoot{$device} = ($rest =~ /bootable/) ? "yes" : ""; } } print "\n\n"; } #**************************************************** # parse config file or all class files #**************************************************** sub ParseAllConfigFiles{ my $ConfigFileExists = 0; # no config file parsed yet if ($ConfigFileName){ # Read config filename &ParseConfigFile($ConfigFileName); $ConfigFileExists = 1; } else { # Read classes foreach my $classfile (reverse split(/\s+/,$ENV{"classes"})){ my $filename = "$ClassPath/$classfile"; if (($classfile) && (-r $filename)) { &ParseConfigFile($filename); $ConfigFileExists = 1; } ($ConfigFileExists) && last; } } ($ConfigFileExists == 0) && die "ERROR: no config file for setup_harddisk found. Please check you classes and files in disk_config.\n"; } #**************************************************** # map "disk_config first" to real disk device #**************************************************** sub mapdisk { my ($disk) = @_; my @dlist = split /\s+/,$ENV{disklist}; if ($disk eq "disk1") { print "Mapping disk name disk1 to $dlist[0]\n"; $disk = $dlist[0]; } if ($disk eq "disk2") { print "Mapping disk name disk2 to $dlist[1]\n"; $disk = $dlist[1]; } return $disk; } #**************************************************** # parse config-file #**************************************************** sub ParseConfigFile{ my $size=""; my $mountpoint=""; my $device =""; my $fstaboptions=""; my $options=""; my $disk=""; my $command = ""; my $LogPartNo; my $PrimPartNo; my $NoMoreLogicals; my $LastPresPart; my $extmp; my $Min; my $Max; my $filename = shift; open (FILE,"$filename") || die "config file not found: $filename\n"; (print "Using config file: $filename\n"); $disk = ""; my $a = 1, my $paras ="", my $number=0; while (my $line = ){ chomp($line); $a++; next if( $line =~ /^#|^\s*$/ ); # disk_config - command if ($line =~ /^disk_config(.*)/i){ $paras = $1; if ($paras =~ / end/i){ $disk = ""; } else { # if($paras =~ m# (/dev/)?(cciss/c\dd\d|ida/c\dd\d|rd/c\dd\d|[a-z]+)#i){ # now match all devives if($paras =~ m# (/dev/)?(\S+)#i){ $disk = mapdisk($2); ($DiskMountpoints{$disk}) && die "ERROR: there are more than one configuration of disk $disk.\n"; ($DiskSize{$disk}) || die "ERROR: could not read device /dev/$disk\n"; ($test != 1) || (print "config: $disk\n"); $DiskMountpoints{$disk} = ""; $MPPrimary{"extended$disk"} = ""; $LogPartNo = 4; $PrimPartNo = 0; $NoMoreLogicals = 0; $LastPresPart = ""; $extmp = "extended$disk"; } else { die "SYNTAX ERROR: in config file line $a, unknown disk_config parameter $paras\n$line\n"; } } } if ($disk){ # primary|partition - command if($line =~ /^\s*(primary|logical)\s+(.*)$/i){ $command = $1; # split variables $paras = $2; $options = ""; if($paras =~ /(.*?)\s*;\s*(.*)$/){ $paras = $1; $options = $2; } $size=""; $mountpoint =""; $fstaboptions = ""; ($mountpoint,$size,$fstaboptions)=split(/\s+/,$paras); # mountpoint ($mountpoint =~ m#^/.*|^swap$|^-$#i) || die "SYNTAX ERROR in config file line $a, mountpoint: $mountpoint\n$line\n"; ($MountpointPart{$mountpoint}) && die "SYNTAX ERROR in config file line $a. Mountpoint $mountpoint redefined.\n$line\n"; if($mountpoint eq "/"){ ($BootPartition) || ($BOOT_DEVICE = $disk); } if($mountpoint eq "-"){ $NofNotMoPart++; $mountpoint = "no$NofNotMoPart"; } if($mountpoint eq "swap"){ $NofSwapPart++; $mountpoint = "swap$NofSwapPart"; ($options !~ /\bswap\b/i) && ($options .= " swap"); ($fstaboptions) || ($fstaboptions = "sw"); } if($mountpoint =~ m#^/#){ ($fstaboptions) || ($fstaboptions = "defaults"); } if ($command eq "primary") { ($MPPrimary{$extmp} eq "yes") && ($NoMoreLogicals = 1); $MPPrimary{$mountpoint} = "yes"; $PrimPartNo++; # ($PrimPartNo == 3) && ($disk =~ /^sd/) && ($PrimPartNo++); ($PrimPartNo >4 ) && die "ERROR: Too much primary partitions (max 4).". " All logicals together need one primary too.\n"; $MountpointPart{$mountpoint} = PartName($disk,$PrimPartNo); if($options =~ /\bboot\b/i){ ($BootPartition) && die "ERROR: only one partition can be bootable at a time."; $BootPartition = $MountpointPart{$mountpoint}; $BOOT_DEVICE = $disk; } } else { ($NoMoreLogicals != 0) && die "ERROR: the logical partitions must be together.\n"; $MPPrimary{$mountpoint} = ""; $LogPartNo++; $MountpointPart{$mountpoint} = PartName($disk,$LogPartNo); if (!$MPPrimary{$extmp}){ $MPPreserve{$extmp} = ""; $MPPrimary{$extmp} = "yes"; $MPMinSize{$extmp} = 0; $MPMaxSize{$extmp} = 0; $MPID{$extmp} = 5; $PrimPartNo++; ($PrimPartNo == 3) && ($disk =~ /^sd/) && ($PrimPartNo++); ($PrimPartNo >4 ) && die "ERROR: too much primary partitions (max 4).". " All logicals together need one primary too.\n"; $MountpointPart{$extmp} = PartName($disk,$PrimPartNo); $DiskMountpoints{$disk} .= " $extmp"; } # ($options =~ /\bboot\b/i) && die "ERROR: line $a, only primary partitions can be bootable.\n"; } $DiskMountpoints{$disk} .= " $mountpoint"; # size ($size =~ /^preserve\d+$|^\d+\-?\d*$|^-\d+$/i) || die "SYNTAX ERROR in config file line $a, size: $size\n$line\n"; if($size =~ /^preserve(\d+)$/i){ my $number = $1; $device = PartName($disk,$number); ($OldNotAligned{$device} eq "yes") && die "ERROR: unable to preserve partition /dev/$device. Partition is not DOS aligned."; ($command eq "primary") && ($number != $PrimPartNo) && die "NUMERATION ERROR in line $a, the number of the partition can not be preserved:\n$line\n"; ($command eq "logical") && ($number != $LogPartNo) && die "NUMERATION ERROR in line $a, the number of the partition can not be preserved:\n$line\n"; if ($PartOldEnd{$device}){ (($PartOldID{$device} == 5) || ($PartOldID{$device} == 85)) && die "ERROR in config file line $a.". " Extended partitions can not be preserved. /dev/$device\n$line\n"; $MPPreserve{$mountpoint}="yes"; $MPMinSize{$mountpoint} = $PartOldEnd{$device}-$PartOldStart{$device}+1; $MPMaxSize{$mountpoint} = $MPMinSize{$mountpoint}; # Max=Min $MPStart{$mountpoint} = $PartOldStart{$device}; $MPSize{$mountpoint} = $MPMinSize{$mountpoint}; $MPID{$mountpoint} = $PartOldID{$device}; } else { die "ERROR: cannot preserve partition $device. partition not found.$PartOldEnd{$device}\n"; } if ($LastPresPart) { ($PartOldStart{$device} < $PartOldStart{$LastPresPart}) && die "ERROR: misordered partitions: cannot preserve partitions $LastPresPart and $device\n". " in this order because of their positions on disk."; } $LastPresPart = $device; ($MPMinSize{$mountpoint} < 1) && die "ERROR: unable to preserve partitions of size 0.\n$line\n "; } else { # If not preserve we must know the filesystemtype ($options !~ /\b(ext2|ext3|auto|swap|dosfat16|winfat32|reiser|xfs)\b/i ) && ($options .= " auto"); } if($size =~ /^(\d*)(\-?)(\d*)$/){ $Min = $1; $Min||= 1; $Max = $3; $MPMinSize{$mountpoint} = int (($Min * $megabyte - 1) / ($DiskUnits{$disk} * $sectorsize)) + 1; if ($2 eq "-"){ if($Max =~ /\d+/){ $MPMaxSize{$mountpoint} = int (($Max * $megabyte - 1) / ($DiskUnits{$disk} * $sectorsize)) + 1; } else { $MPMaxSize{$mountpoint} = $DiskSize{$disk}; } } else { $MPMaxSize{$mountpoint} = $MPMinSize{$mountpoint}; # Max=Min } ($MPMinSize{$mountpoint} > $DiskSize{$disk}) && die "ERROR in config file line $a: Minsize larger than disk.\n$line\n"; ($MPMinSize{$mountpoint} > $MPMaxSize{$mountpoint}) && die "SYNTAX ERROR in config file line $a, MIN-MAX-size: $MPMinSize{$mountpoint}-$MPMaxSize{$mountpoint}\n$line\n"; ($MPMinSize{$mountpoint} < 1) && die "SYNTAX ERROR in config file line $a. Minsize must be greater than 1.\n$line\n"; $MPPreserve{$mountpoint} = ""; } # fstaboptions $MPfstaboptions{$mountpoint} = $fstaboptions; # extra options ($options =~ /\b(ext[23]|auto)\b/i) && ($MPID{$mountpoint} = 83); # Linux native ($options =~ /\bswap\b/i) && ($MPID{$mountpoint} = 82); # Linux swap ($options =~ /\bdosfat16\b/i) && ($MPID{$mountpoint} = 6); # DOS FAT 16bit (>=32MB, will be changed later) ($options =~ /\bwinfat32\b/i) && ($MPID{$mountpoint} = "b"); # Win 95 FAT 32 $MPOptions{$mountpoint} = $options; if($test == 1){ print "$mountpoint,$MPMinSize{$mountpoint}-$MPMaxSize{$mountpoint},"; print "$fstaboptions,$options"; ($MPPreserve{$mountpoint} eq "yes") && (print " Preserve: $MountpointPart{$mountpoint}"); print "\n"; } } } } close(FILE); } #**************************************************** # Build all partition tables #**************************************************** sub BuildNewPartTables{ my ($disk, $mountpoint, $part, $PrimaryMP, $LogicalMP); ($test != 1) || (print "\nBuilding partition tables:\n"); # Build PartMountpoint array foreach $disk(keys %DiskMountpoints) { $DiskMountpoints{$disk} =~ s/\s(\s)/$1/g; $DiskMountpoints{$disk} =~ s/^\s//; $DiskMountpoints{$disk} =~ s/\s$//; foreach $mountpoint(split(/\s/,$DiskMountpoints{$disk})) { $PartMountpoint{$MountpointPart{$mountpoint}} = $mountpoint; } } foreach $disk(keys %DiskMountpoints) { &SetPartitionPositions($disk); # change units to sectors foreach $mountpoint(split(/\s/,$DiskMountpoints{$disk})) { if($MPPreserve{$mountpoint} eq "yes"){ $MPStart{$mountpoint} = $PartOldStartSec{$MountpointPart{$mountpoint}}; $MPSize{$mountpoint} = $PartOldEndSec{$MountpointPart{$mountpoint}} - $MPStart{$mountpoint} + 1; } else { $MPStart{$mountpoint} *= $DiskUnits{$disk}; $MPSize{$mountpoint} *= $DiskUnits{$disk}; # align first partition for mbr if($MPStart{$mountpoint} == 0){ $MPStart{$mountpoint} += $SectorsAlignment{$disk}; $MPSize{$mountpoint} -= $SectorsAlignment{$disk}; } } } # align all logical partitions foreach $mountpoint(split(/\s/,$DiskMountpoints{$disk})) { next if ($MPPrimary{$mountpoint} eq "yes"); if ($MountpointPart{$mountpoint} eq "${disk}5") { # partition with number 5 is first logical partition and start of extended partition $MPStart{"extended$disk"} = $MPStart{$mountpoint}; ($MPPreserve{$mountpoint} eq "yes") && ($MPStart{"extended$disk"} -= $SectorsAlignment{$disk}); } if ($MPPreserve{$mountpoint} ne "yes") { $MPStart{$mountpoint} += $SectorsAlignment{$disk}; $MPSize{$mountpoint} -= $SectorsAlignment{$disk}; } } &CalculateExtPartSize($disk); # sort mountpoints of partition number $PrimaryMP = ""; $LogicalMP = ""; foreach $mountpoint(split(/\s/,$DiskMountpoints{$disk})) { ($MPPrimary{$mountpoint} eq "yes") ? ($PrimaryMP .= " $mountpoint") : ($LogicalMP .= " $mountpoint"); } $DiskMountpoints{$disk} = "$PrimaryMP$LogicalMP"; $DiskMountpoints{$disk} =~ s/^\s//; # print partition table ($test != 1) || (PrintPartitionTable($disk)); } if (!$BootPartition){ $BootPartition = $MountpointPart{"/"}; } } #**************************************************** # set position for every partition #**************************************************** sub SetPartitionPositions{ my $disk = shift; my $mountpoint; my $DynGroup =""; my $StartPos; my $EndPos; # Build groups of unpreserved partitions between # preserved partitions $StartPos = 0; foreach $mountpoint(split(/\s/,$DiskMountpoints{$disk})) { if ($MPPreserve{$mountpoint} eq "yes") { $EndPos = $PartOldStart{$MountpointPart{$mountpoint}} - 1; &SetGroupPos($DynGroup,$StartPos,$EndPos); $DynGroup = ""; $StartPos = $PartOldEnd{$MountpointPart{$mountpoint}} + 1; } else { $DynGroup .= " $mountpoint"; } } $EndPos = $DiskSize{$disk} - 1; &SetGroupPos($DynGroup,$StartPos,$EndPos); foreach $mountpoint(split(/\s/,$DiskMountpoints{$disk})) { ($MPOptions{$mountpoint} =~ /\bdosfat16\b/i) && (($MPSize{$mountpoint} * $DiskUnits{$disk} * $sectorsize) < 32 * $megabyte) && ($MPID{$mountpoint} = 4); # DOS 16-bit FAT <32MB } } #**************************************************** # set position for a group of unpreserved partitions # between start and end #**************************************************** sub SetGroupPos{ my ($PartGroup,$Start,$End) = @_; $PartGroup =~ s/^ //; ($PartGroup) || return; my $totalsize = $End - $Start + 1; ($totalsize <= 0) && return; my $mountpoint; my $mintotal = 0; my $maxmintotal = 0; my $rest = 0; my $EndUnit = 0; # compute total of MinSizes and difference to MaxSizes foreach $mountpoint (split(/\s/,$PartGroup)) { $mintotal += $MPMinSize{$mountpoint}; $maxmintotal += ($MPMaxSize{$mountpoint} - $MPMinSize{$mountpoint}); $MPSize{$mountpoint} = $MPMinSize{$mountpoint}; } # Test if partitions fit ($mintotal > $totalsize) && die "ERROR: Mountpoints $PartGroup do not fit.\n"; # Maximize partitions $rest = $totalsize - $mintotal; ($rest > $maxmintotal) && ($rest = $maxmintotal); if ($rest > 0) { foreach $mountpoint (split(/\s/,$PartGroup)) { $MPSize{$mountpoint} += int ((($MPMaxSize{$mountpoint} - $MPMinSize{$mountpoint}) * $rest) / $maxmintotal); } } # compute rest $rest = $totalsize; foreach $mountpoint (split(/\s/,$PartGroup)) { $rest -= $MPSize{$mountpoint}; } # Minimize rest foreach $mountpoint (split(/\s/,$PartGroup)) { if (($rest >0) && ($MPSize{$mountpoint} < $MPMaxSize{$mountpoint})){ $MPSize{$mountpoint}++; $rest--; } } # Set start for every partition foreach $mountpoint (split(/\s/,$PartGroup)) { $MPStart{$mountpoint} = $Start; $Start += $MPSize{$mountpoint}; $EndUnit = $MPStart{$mountpoint} + $MPSize{$mountpoint} - 1; } } #**************************************************** # calculate extended partition size #**************************************************** sub CalculateExtPartSize{ my ($disk) = @_; my $extmp = "extended$disk"; my $mountpoint; my $ExtEnd; my $NewEnd; ($MPPrimary{$extmp}) || return; $ExtEnd = $MPStart{$extmp}; foreach $mountpoint(split(/\s/,$DiskMountpoints{$disk})) { next if ($MPPrimary{$mountpoint} eq "yes"); $NewEnd = $MPStart{$mountpoint} + $MPSize{$mountpoint} - 1; ($NewEnd > $ExtEnd) && ($ExtEnd = $NewEnd); } $MPSize{$extmp} = ($ExtEnd - $MPStart{$extmp} + 1); } #**************************************************** # Print partition "number - mountpoint" table #**************************************************** sub PrintPartitionTable{ my ($disk) = @_; my $part; my $mountpoint; my $mountpointname; my $end; foreach $part (sort %MountpointPart) { next if($part !~ /^$disk/); $mountpoint = $PartMountpoint{$part}; if ($mountpoint =~ /^no(.*)/){ $mountpointname = "no mountpoint ($1)"; } else { $mountpointname = $mountpoint; } $end = $MPStart{$mountpoint} + $MPSize{$mountpoint} - 1; print <<"EOM"; /dev/$part $mountpointname start=$MPStart{$mountpoint} size=$MPSize{$mountpoint} end=$end id=$MPID{$mountpoint} EOM } } #**************************************************** # build all partition tables for sfdisk #**************************************************** sub PartitionPersfdisk{ my ($disk, $mountpoint, $line, $part, $PrimaryNo); my ($command, $result, $filename, $number); print "Creating partition table: "; foreach $disk(keys %DiskMountpoints) { $sfdiskTables{$disk} = "# partition table of device: /dev/$disk\nunit: sectors\n\n"; $PrimaryNo = 1; foreach $mountpoint(split(/\s/,$DiskMountpoints{$disk})) { $part = $MountpointPart{$mountpoint}; $part =~ /(\d+)$/; ($1 < 5) && ($PrimaryNo++); if ( ($1 == 5) && ($PrimaryNo < 5) ){ for my $number($PrimaryNo..4) { $sfdiskTables{$disk} .= BuildsfdiskDumpLine(PartName($disk,$number),0,0,0)."\n"; } } $line = BuildsfdiskDumpLine($MountpointPart{$mountpoint},$MPStart{$mountpoint},$MPSize{$mountpoint},$MPID{$mountpoint}); ($part eq $BootPartition) && ($line .= ", bootable"); $sfdiskTables{$disk} .= "$line\n"; } # print $sfdiskTables{$disk}; $filename = "$ENV{LOGDIR}/partition." . (($disk=~ m#/#) ? join('_', split('/', $disk)) : $disk); if(($test != 1) && ($filename)){ open(FILE, ">$filename") || die "unable to write temporary file $filename\n"; print FILE $sfdiskTables{$disk}; close(FILE); } $command = "LC_ALL=C sfdisk $sfdisk_options /dev/$disk < $filename"; if($test != 1){ print "$command\n"; $result = `sh -c "$command"`; (($? >> 8) == 0) || (die "\nSFDISK ERROR:\n $result\n"); } } } #**************************************************** # build a sfdisk dump line #**************************************************** sub BuildsfdiskDumpLine{ sprintf "/dev/%-5s: start=%10s, size=%10s, Id=%3s",@_; } #**************************************************** # Format all disks #**************************************************** sub FormatDisks{ my ($disk, $device, $mountpoint, $mountpointname, $command, $result); print "Creating file systems:\n"; foreach $disk(keys %DiskMountpoints) { foreach $mountpoint (split(/\s/,$DiskMountpoints{$disk})) { $device = $MountpointPart{$mountpoint}; if ($mountpoint =~ /^no/){ $mountpointname = "no mountpoint"; } else { $mountpointname = $mountpoint; } # preserved partition if ( ($MPPreserve{$mountpoint} eq "yes") && ($MPOptions{$mountpoint} !~ /\bformat\b/i)){ print "Preserve partition $device"; if ($mountpoint =~ /^no$1/){ print " with no mountpoint\n"; } else { print " with mountpoint $mountpoint\n"; } next; } # lazy format if ( ( $MPOptions{$mountpoint} =~ /\blazyformat\b/i ) && ($MPStart{$mountpoint} == $PartOldStartSec{$device}) && (($MPStart{$mountpoint} + $MPSize{$mountpoint} - 1) == $PartOldEndSec{$device}) ){ print "Lazy format: $device"; if ($mountpoint =~ /^no$1/){ print " with no mountpoint"; } else { print " with mountpoint $mountpoint"; } print " was neither moved nor formated.\n"; next; } # swap if ($mountpoint =~ /^swap/i) { # print "Make swap partition:\n"; $command = "mkswap $mkswap_options"; ($MPOptions{$mountpoint} =~ /(\-c)\b/i) && ($command .= " $1"); push @swaplist, "/dev/$device"; $command .= " /dev/$device"; print " $command\n"; if($test != 1){ $result = `$command`; (($? >> 8) == 0) || (die "\nMKSWAP ERROR:\n $result\n"); } next; } # Linux Reiser file system if ($MPOptions{$mountpoint} =~ /\breiser\b/i) { # print "Make Reiser Filesystem:\n"; $command = "echo y | mkreiserfs $mkreiserfs_options"; ($MPOptions{$mountpoint} =~ /(\-h\s*\w+)\b/) && ($command .= " $1"); ($MPOptions{$mountpoint} =~ /(\-v\s*\d+)\b/) && ($command .= " $1"); $command .= " /dev/$device"; print " $command\n"; if ($test != 1){ $result = `$command`; (($? >> 8) == 0) || die "\nMKREISERFS ERROR:\n $result\n"; } next; } # Linux XFS file system if ($MPOptions{$mountpoint} =~ /\bxfs\b/i) { # print "Make XFS Filesystem:\n"; $command = "mkfs.xfs $mkxfs_options"; $command .= " /dev/$device"; print " $command\n"; if ($test != 1){ $result = `$command`; (($? >> 8) == 0) || die "\nMKFS.XFS ERROR:\n $result\n"; } next; } # Linux Extended 2 file system if ($MPOptions{$mountpoint} =~ /\b(ext[23]|auto)\b/i) { # print "Make Extended 2/3 Filesystem:\n"; $command = "mke2fs $mke2fs_options"; ($MPOptions{$mountpoint} =~ /(\-c)\b/i) && ($command .= " $1"); ($MPOptions{$mountpoint} =~ /(\-i\s*\d+)\b/) && ($command .= " $1"); ($MPOptions{$mountpoint} =~ /(\-m\s*\d+)\b/) && ($command .= " $1"); ($MPOptions{$mountpoint} =~ /(\-j)\b/) && ($command .= " $1"); $command .= " /dev/$device"; print " $command\n"; if ($test != 1){ $result = `$command`; (($? >> 8) == 0) || die "\nMKE2FS ERROR:\n $result\n"; } next; } # DOS 16bit FAT / Win95 FAT 32 if ($MPOptions{$mountpoint} =~ /\b(dosfat16|winfat32)\b/i) { print "Clear first sector for DOS/Windows\n"; $command = "dd if=/dev/zero of=/dev/$MountpointPart{$mountpoint} bs=512 count=1"; print " $command\n"; if ($test != 1){ $result = `$command`; (($? >> 8) == 0) || die "\nDD ERROR:\n $result\n"; } next; } } } } #**************************************************** # Build fstab and write it to /etc/fstab #**************************************************** sub WriteFSTab{ my ($FileSystemTab, $device, $type, $filename); $FileSystemTab = << "EOM"; # /etc/fstab: static file system information. # # EOM # 1. / $type = "ext2"; ($MPOptions{'/'} =~ /\b(reiser)\b/i) && ($type = "reiserfs"); ($MPOptions{'/'} =~ /\b(xfs)\b/i) && ($type = "xfs"); ($MPOptions{'/'} =~ /\b(ext3)\b/i) && ($type = "ext3"); ($MPOptions{'/'} =~ /\b(ext2)\b/i) && ($type = "ext2"); $FileSystemTab .= BuildfstabLine("/dev/$MountpointPart{'/'}","/",$type,$MPfstaboptions{'/'},0,1); # 2. swap partitions foreach my $mountpoint (%PartMountpoint){ next if( $mountpoint !~ /^swap/i); $FileSystemTab .= BuildfstabLine("/dev/$MountpointPart{$mountpoint}", "none","swap",$MPfstaboptions{$mountpoint},0,0); } # 3. /proc $FileSystemTab .= BuildfstabLine("none","/proc","proc","defaults",0,0); # 4. sorted others foreach my $mountpoint (sort %PartMountpoint){ next if ( ($mountpoint !~ m#^/#) || ($mountpoint eq "/")); $device = $MountpointPart{$mountpoint}; $type = "ext2"; ($MPOptions{$mountpoint} =~ /\b(dosfat16|winfat32)\b/i) && ($type = "vfat"); ($MPOptions{$mountpoint} =~ /\b(reiser)\b/i) && ($type = "reiserfs"); ($MPOptions{$mountpoint} =~ /\b(xfs)\b/i) && ($type = "xfs"); ($MPOptions{$mountpoint} =~ /\b(ext3)\b/i) && ($type = "ext3"); ($MPOptions{$mountpoint} =~ /\b(ext2)\b/i) && ($type = "ext2"); $FileSystemTab .= BuildfstabLine("/dev/$device",$mountpoint,$type,$MPfstaboptions{$mountpoint},0,2); } # write it $filename = "$ENV{LOGDIR}/fstab"; # print $FileSystemTab; print "Write fstab to $filename\n" if $verbose; if($test != 1){ open(FILE, ">$filename") || die "unable to write fstab $filename\n"; print FILE $FileSystemTab; close(FILE); } } #**************************************************** # Build fstab line #**************************************************** sub BuildfstabLine{ sprintf "%-10s %-15s %-6s %-8s %-4s %-4s\n",@_; } #**************************************************** # Write all FAI variables of this program to file #**************************************************** sub WriteFAIVariables{ my $swaps; print "Write FAI variables to file $FAIOutputFile\n" if $verbose; return if ($test == 1); $swaps = join ' ',@swaplist; open(FILE, ">$FAIOutputFile") || die "Unable to write file $FAIOutputFile\n"; print FILE << "EOM"; BOOT_DEVICE=/dev/$BOOT_DEVICE ROOT_PARTITION=/dev/$MountpointPart{'/'} BOOT_PARTITION=/dev/$BootPartition SWAPLIST="$swaps" EOM close(FILE); }