#!/bin/ksh93 # file: /data/httpd/htdocs/intern/ubuntu-part.sh typeset -r VERSION='1.0' FPROG=${.sh.file} PROG=${FPROG##*/} SDIR=${FPROG%/*} unset LANG export LC_CTYPE=C LC_NUMERIC=C LC_MESSAGES=C LC_COLLATE=C LC_TIME=C function showUsage { [[ -n $1 ]] && X='-?' || X='--man' getopts -a ${PROG} "${ print ${USAGE} ; }" OPT $X } typeset -A CODE2GUID GUID2CODE function AddType { typeset K=$1 K="_${K#0x}" CODE2GUID[$K]="$2:$3" GUID2CODE["$2"]="$K" } # extracted from gptfdisk-1.0.1 via: # grep ' AddType' parttypes.cc | sed -e 's,;.*,,' -e 's,root (/),/,' \ # -e 's/[),]//g' -e 's/(/ /' -e 's/^ *//' -e 's,",@,g' -e "s,@,',g" # see also: sfdisk -T AddType 0x0000 '00000000-0000-0000-0000-000000000000' 'Unused entry' 0 AddType 0x0100 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7' 'Microsoft basic data' 0 AddType 0x0400 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7' 'Microsoft basic data' 0 AddType 0x0600 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7' 'Microsoft basic data' 0 AddType 0x0700 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7' 'Microsoft basic data' 1 AddType 0x0b00 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7' 'Microsoft basic data' 0 AddType 0x0c00 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7' 'Microsoft basic data' 0 AddType 0x0c01 'E3C9E316-0B5C-4DB8-817D-F92DF00215AE' 'Microsoft reserved' AddType 0x0e00 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7' 'Microsoft basic data' 0 AddType 0x1100 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7' 'Microsoft basic data' 0 AddType 0x1400 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7' 'Microsoft basic data' 0 AddType 0x1600 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7' 'Microsoft basic data' 0 AddType 0x1700 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7' 'Microsoft basic data' 0 AddType 0x1b00 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7' 'Microsoft basic data' 0 AddType 0x1c00 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7' 'Microsoft basic data' 0 AddType 0x1e00 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7' 'Microsoft basic data' 0 AddType 0x2700 'DE94BBA4-06D1-4D40-A16A-BFD50179D6AC' 'Windows RE' AddType 0x3000 '7412F7D5-A156-4B13-81DC-867174929325' 'ONIE boot' AddType 0x3001 'D4E6E2CD-4469-46F3-B5CB-1BFF57AFC149' 'ONIE config' AddType 0x3900 'C91818F9-8025-47AF-89D2-F030D7000C2C' 'Plan 9' AddType 0x4100 '9E1A2D38-C612-4316-AA26-8B49521E5A8B' 'PowerPC PReP boot' AddType 0x4200 'AF9B60A0-1431-4F62-BC68-3311714A69AD' 'Windows LDM data' AddType 0x4201 '5808C8AA-7E8F-42E0-85D2-E1E90434CFB3' 'Windows LDM metadata' AddType 0x4202 'E75CAF8F-F680-4CEE-AFA3-B001E56EFC2D' 'Windows Storage Spaces' AddType 0x7501 '37AFFC90-EF7D-4E96-91C3-2D7AE055B174' 'IBM GPFS' AddType 0x7f00 'FE3A2A5D-4F32-41A7-B725-ACCC3285A309' 'ChromeOS kernel' AddType 0x7f01 '3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC' 'ChromeOS root' AddType 0x7f02 '2E0A753D-9E48-43B0-8337-B15192CB1B5E' 'ChromeOS reserved' AddType 0x8200 '0657FD6D-A4AB-43C4-84E5-0933C84B4F4F' 'Linux swap' AddType 0x8300 '0FC63DAF-8483-4772-8E79-3D69D8477DE4' 'Linux filesystem' AddType 0x8301 '8DA63339-0007-60C0-C436-083AC8230908' 'Linux reserved' AddType 0x8302 '933AC7E1-2EB4-4F13-B844-0E14E2AEF915' 'Linux /home' AddType 0x8303 '44479540-F297-41B2-9AF7-D131D5F0458A' 'Linux x86 /' AddType 0x8304 '4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709' 'Linux x86-64 /' AddType 0x8305 'B921B045-1DF0-41C3-AF44-4C6F280D3FAE' 'Linux ARM64 /' AddType 0x8306 '3B8F8425-20E0-4F3B-907F-1A25A76F98E8' 'Linux /srv' AddType 0x8307 '69DAD710-2CE4-4E3C-B16C-21A1D49ABED3' 'Linux ARM32 /' AddType 0x8400 'D3BFE2DE-3DAF-11DF-BA40-E3A556D89593' 'Intel Rapid Start' AddType 0x8e00 'E6D6D379-F507-44C2-A23C-238F2A3DF928' 'Linux LVM' AddType 0xa500 '516E7CB4-6ECF-11D6-8FF8-00022D09712B' 'FreeBSD disklabel' AddType 0xa501 '83BD6B9D-7F41-11DC-BE0B-001560B84F0F' 'FreeBSD boot' AddType 0xa502 '516E7CB5-6ECF-11D6-8FF8-00022D09712B' 'FreeBSD swap' AddType 0xa503 '516E7CB6-6ECF-11D6-8FF8-00022D09712B' 'FreeBSD UFS' AddType 0xa504 '516E7CBA-6ECF-11D6-8FF8-00022D09712B' 'FreeBSD ZFS' AddType 0xa505 '516E7CB8-6ECF-11D6-8FF8-00022D09712B' 'FreeBSD Vinum/RAID' AddType 0xa580 '85D5E45A-237C-11E1-B4B3-E89A8F7FC3A7' 'Midnight BSD data' AddType 0xa581 '85D5E45E-237C-11E1-B4B3-E89A8F7FC3A7' 'Midnight BSD boot' AddType 0xa582 '85D5E45B-237C-11E1-B4B3-E89A8F7FC3A7' 'Midnight BSD swap' AddType 0xa583 '0394Ef8B-237E-11E1-B4B3-E89A8F7FC3A7' 'Midnight BSD UFS' AddType 0xa584 '85D5E45D-237C-11E1-B4B3-E89A8F7FC3A7' 'Midnight BSD ZFS' AddType 0xa585 '85D5E45C-237C-11E1-B4B3-E89A8F7FC3A7' 'Midnight BSD Vinum' AddType 0xa600 '824CC7A0-36A8-11E3-890A-952519AD3F61' 'OpenBSD disklabel' AddType 0xa800 '55465300-0000-11AA-AA11-00306543ECAC' 'Apple UFS' AddType 0xa900 '516E7CB4-6ECF-11D6-8FF8-00022D09712B' 'FreeBSD disklabel' 0 AddType 0xa901 '49F48D32-B10E-11DC-B99B-0019D1879648' 'NetBSD swap' AddType 0xa902 '49F48D5A-B10E-11DC-B99B-0019D1879648' 'NetBSD FFS' AddType 0xa903 '49F48D82-B10E-11DC-B99B-0019D1879648' 'NetBSD LFS' AddType 0xa904 '2DB519C4-B10F-11DC-B99B-0019D1879648' 'NetBSD concatenated' AddType 0xa905 '2DB519EC-B10F-11DC-B99B-0019D1879648' 'NetBSD encrypted' AddType 0xa906 '49F48DAA-B10E-11DC-B99B-0019D1879648' 'NetBSD RAID' AddType 0xab00 '426F6F74-0000-11AA-AA11-00306543ECAC' 'Recovery HD' AddType 0xaf00 '48465300-0000-11AA-AA11-00306543ECAC' 'Apple HFS/HFS+' AddType 0xaf01 '52414944-0000-11AA-AA11-00306543ECAC' 'Apple RAID' AddType 0xaf02 '52414944-5F4F-11AA-AA11-00306543ECAC' 'Apple RAID offline' AddType 0xaf03 '4C616265-6C00-11AA-AA11-00306543ECAC' 'Apple label' AddType 0xaf04 '5265636F-7665-11AA-AA11-00306543ECAC' 'AppleTV recovery' AddType 0xaf05 '53746F72-6167-11AA-AA11-00306543ECAC' 'Apple Core Storage' AddType 0xbc00 '0311FC50-01CA-4725-AD77-9ADBB20ACE98' 'Acronis Secure Zone' AddType 0xbe00 '6A82CB45-1DD2-11B2-99A6-080020736631' 'Solaris boot' AddType 0xbf00 '6A85CF4D-1DD2-11B2-99A6-080020736631' 'Solaris root' AddType 0xbf01 '6A898CC3-1DD2-11B2-99A6-080020736631' 'Solaris /usr & Mac ZFS' AddType 0xbf02 '6A87C46F-1DD2-11B2-99A6-080020736631' 'Solaris swap' AddType 0xbf03 '6A8B642B-1DD2-11B2-99A6-080020736631' 'Solaris backup' AddType 0xbf04 '6A8EF2E9-1DD2-11B2-99A6-080020736631' 'Solaris /var' AddType 0xbf05 '6A90BA39-1DD2-11B2-99A6-080020736631' 'Solaris /home' AddType 0xbf06 '6A9283A5-1DD2-11B2-99A6-080020736631' 'Solaris alternate sector' AddType 0xbf07 '6A945A3B-1DD2-11B2-99A6-080020736631' 'Solaris Reserved 1' AddType 0xbf08 '6A9630D1-1DD2-11B2-99A6-080020736631' 'Solaris Reserved 2' AddType 0xbf09 '6A980767-1DD2-11B2-99A6-080020736631' 'Solaris Reserved 3' AddType 0xbf0a '6A96237F-1DD2-11B2-99A6-080020736631' 'Solaris Reserved 4' AddType 0xbf0b '6A8D2AC7-1DD2-11B2-99A6-080020736631' 'Solaris Reserved 5' AddType 0xc001 '75894C1E-3AEB-11D3-B7C1-7B03A0000000' 'HP-UX data' AddType 0xc002 'E2A1E728-32E3-11D6-A682-7B03A0000000' 'HP-UX service' AddType 0xea00 'BC13C2FF-59E6-4262-A352-B275FD6F7172' 'Freedesktop $BOOT' AddType 0xeb00 '42465331-3BA3-10F1-802A-4861696B7521' 'Haiku BFS' AddType 0xed00 'F4019732-066E-4E12-8273-346C5641494F' 'Sony system partition' AddType 0xed01 'BFBFAFE7-A34F-448A-9A5B-6213EB736C22' 'Lenovo system partition' AddType 0xef00 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B' 'EFI System' AddType 0xef01 '024DEE41-33E7-11D3-9D69-0008C781F39F' 'MBR partition scheme' AddType 0xef02 '21686148-6449-6E6F-744E-656564454649' 'BIOS boot partition' AddType 0xf800 '4FBD7E29-9D25-41B8-AFD0-062C0CEFF05D' 'Ceph OSD' AddType 0xf801 '4FBD7E29-9D25-41B8-AFD0-5EC00CEFF05D' 'Ceph dm-crypt OSD' AddType 0xf802 '45B0969E-9B03-4F30-B4C6-B4B80CEFF106' 'Ceph journal' AddType 0xf803 '45B0969E-9B03-4F30-B4C6-5EC00CEFF106' 'Ceph dm-crypt journal' AddType 0xf804 '89C57F98-2FE5-4DC0-89C1-F3AD0CEFF2BE' 'Ceph disk in creation' AddType 0xf805 '89C57F98-2FE5-4DC0-89C1-5EC00CEFF2BE' 'Ceph dm-crypt disk in creation' AddType 0xfb00 'AA31E02A-400F-11DB-9590-000C2911D1B8' 'VMWare VMFS' AddType 0xfb01 '9198EFFC-31C0-11DB-8F78-000C2911D1B8' 'VMWare reserved' AddType 0xfc00 '9D275380-40AD-11DB-BF97-000C2911D1B8' 'VMWare kcore crash protection' AddType 0xfd00 'A19D880F-05FC-4D3B-A006-743F0F84911E' 'Linux RAID' function listGUIDs { typeset K V for K in ${!CODE2GUID[@]} ; do V="${CODE2GUID[$K]}" print "${K:1} ${V%%:*} ${.sh.match:1}" done } typeset -T Part_t=( typeset -ih 'partition number' n=-1 typeset -lih '# of the first logical sector of the partion' start=-1 typeset -lih '# of the last logical sector of the partion (incl.)' end=-1 typeset -h 'partition type (GUID|parted fs-name|sgdisk code)' type= typeset -h 'partition name' name= typeset -h 'partition attrs' attrs= function getSize { integer -li S (( S=_.end - _.start + 1 )) print -- "$S" } typeset -fh 'Get the partition size in logical blocks' getSize function show { typeset T='-- (0000)' if [[ -n ${_.type} ]]; then T="${CODE2GUID[${_.type}]}" [[ -n $T ]] && T="${T#*:} (${_.type:2})" || T="??? (${_.type})" fi print "${_.n} ${_.start}s..${_.end}s (size=${ _.getSize ; }s) $T ${_.name} ${_.attrs:--}" } typeset -fh 'Show the summary info for this partition' show ) typeset -T Disk_t=( typeset -lih 'size in logical sectors' sz=-1 typeset -ih 'logical sector size in byte' lssz=-1 typeset -ih 'physical sector size in byte' pssz=-1 typeset -h 'partition table type' ptt= typeset -h 'device path' devpath= typeset -h 'device alias' devalias= typeset -h 'the device path for the partition containing the zfs' zfs= Part_t -a -h 'partition infos' parts function show { typeset -lui M=${_.sz} (( M=(M * _.lssz) >> 30 )) print "Label: ${_.ptt}\nSize: ${_.sz}s (~${M} GiB)" \ "\nBlock size: ${_.lssz}/${_.pssz} (logical/physical)\n" # we use this because [0] usually contains garbage typeset -lui N for P in "${!_.parts[@]}" ; do X="M" N=${_.parts[P].getSize} (( N*=_.lssz )) (( N=N >> 20 )) (( N > 1023 )) && (( N=N >> 10 )) && X="G" print "${_.parts[P].show} ${N} ${X}iB" done } typeset -fh 'Print disk and partition infos' show function add { typeset -n P=$1 _.parts+=( P ) } # with 512B log. block size (LBA): # 0x0000..0x01FF MBR (e.g. with Grub) # 0x000 440B Bootloader (Stage 1) # 0x1b8 4B Datenträgersignatur (seit Win2K) # 0x1bc 2B Null # 0x1be 64B Partition Table with 4 entries a 16B: # 0 1B bootable (0x80) or not (0x00) # 1 3B 1st sector CHS address (absolut) # 4 1B partition type (0x82 Linux swap, ...) # 5 3B last sector CHS address (absolut) # 8 4B start sector in LBA # 12 4B size in LBA sectors # 0x1fe 2B Boot Signature = 55aa # 0x0200..0x03FF GPT Header # 0x200 8B Signature 'EFI PART' # 0x208 4B Revision = 0000 0100 # 0x20c 4B Header Size (usually 5c00 0000 = 92B) # 0x210 4B Header CRC32 sum # 0x214 4B reserved (zero filled) # 0x218 8B Position of this Header in LBAs (usually 1) # 0x220 8B Position of the Backup-Header in LBAs # 0x228 8B 1st usable LBA for partitions (usually 34) # 0x230 8B last usable LBA for partitions (usually n/512-34) # 0x238 16B Disk GUID aka UUID # 0x248 8B Starting LBA of part table entries = 2 # 0x250 4B Number of part table entries # 0x254 4B Size of a each part table entry (usually 128B) # 0x258 4B part table CRC32 sum # 0x25c 420B reserved, zero filled (sz differs for non-512B LBAs) # 0x0400..0x43FF Partition Table # 0x400 16B Partition type GUID # 0x410 16B Unique partition GUID # 0x420 8B First LBA # 0x428 8B Last LBA (incl.) # 0x430 8B Partition Attribute Flags (bits): # 63-48 Defined/used by the individual part type # 63 MS: No drive letter aka do not automount # 62 MS: Hidden # 61 MS: Shadow copy (of another partition) # 60 MS: Read-only # 47- 3 Reserved for future use # 2 Legacy BIOS bootable # 1 EFI firmware should ignore this entry # 0 platform required: reserve as is # 0x438 72B Partition name (36 UTF-16LE code units) # 0x480 128B next entry # ... # 0x4400..n-0x4201 free space for partions (max. 128 in this case) # n-0x4200..n-0x201 backup aka secondary Partition Table # n-0x0200..n-1 backup aka secondary GPT Header function getRecommendedLayout { typeset -n DISK=$1 typeset -li I N S O SPC LAST SWAP=$2 RESERVED CHUNK_SZ ZFS=$3 typeset X (( RESERVED=8*1024*1024 / _.lssz )) # reserved sectors (8 MiB) (( CHUNK_SZ=128*1024 / _.lssz )) # sectors per md chunk (( ZFS )) && SWAP=0 || (( SWAP*=1024*1024*1024 / _.lssz )) DISK.devpath=${_.devpath} DISK.sz=${_.sz} DISK.lssz=${_.lssz} DISK.pssz=${_.pssz} DISK.ptt='gpt' DISK.zfs= [[ -z ${_.devalias} ]] && \ DISK.devalias=${DISK.devpath} || DISK.devalias=${_.devalias} # At the end of the disk 1 sector for GPT header and at least 16K for # GPT entries are required (GPT backup) -> for 512B sectors == 33 (( LAST=_.sz - 1 - 16 * 1024 / _.lssz - 1 )) # If later a HDD gets inserted, which has not exactly the same size as # this one, we need some space to adjust it. So reserve some space and # align it to the common chunk_sz Part_t R (( S=LAST - RESERVED )) (( N=S / CHUNK_SZ )) (( N*=CHUNK_SZ )) # remaining sectors if aligned (( N != S )) && (( S=N + CHUNK_SZ )) (( S < 0 || LAST <= S )) && return 1 R.n=9 R.start=$S R.end=${LAST} R.type='_bf07' R.name= R.attrs= (( LAST=S-1 )) # At the start there should be enough space for 2 sectors (1xMBR, # 1xGPT header) + at least 16 KiB for GPT entries. However, we start # the 1st partition on sector 256 (128KiB), so that e.g. Grub can put # its 1.5 stage (30K) right after the MBR and use the 1st partition as # bios_grub for stage 2 or it might be used some day as UEFI partition - # therefore size == 256 MB. # Also starting at 128KiB guarantees alignment (even to chunk size). S=${CHUNK_SZ} I=1 if (( BOOT )); then # BIOS GRUB/EFI partition - 256 MiB also assures 4k alignment. (( N=S + 256 * 1024 * 1024 / _.lssz - 1 )) (( S < 0 || N <= S )) && return 1 Part_t P P.n=1 P.start=$S P.end=$N P.type='_ef02' P.name= (( USE_UEFI )) && P.type='_ef00' #|| P.attrs='2' DISK.add P (( S=N + 1 )) (( I++ )) fi # Data unset P ; Part_t P (( N=LAST - SWAP )) (( S < 0 || N <= S )) && return 1 P.n=$I P.start=$S P.end=${N} P.type='_8300' P.name= P.attrs= if (( USE_ZFS )); then P.type='_bf01' P.name='zfs' X=${DISK.devalias##*/} if [[ ${X:0:2} == 'sd' ]]; then DISK.zfs="${DISK.devalias}$I" elif [[ ${X:0:4} == 'nvme' || ${X:0:4} == 'disk' \ || $X =~ ^[pd][0-9] ]] then DISK.zfs="${DISK.devalias}p$I" else DISK.zfs="${DISK.devalias}p$I" print -u2 "Assuming ZFS partition is ${DISK.zfs}" fi fi DISK.add P # Swap if (( SWAP )); then unset P ; Part_t P (( S=N + 1 )) (( N=S + SWAP - 1 )) (( S < 0 || N <= S )) && return 1 P.n=3 P.start=$S P.end=$N P.type='_8200' P.name= DISK.add P fi DISK.add R return 0 } ) FS2CODE=( ['linux-swap(v0)']='_8200' ['linux-swap(v1)']='_8200' ['primary']='_8300' ['logical']='_8300' ['hfs']='_af00' ['hfs+']='_af00' ['hfsx']='_af00' ['ext2']='_8300' ['ext3']='_8300' ['ext4']='_8300' ['xfs']='_8300' ['fat16']='_0600' ['fat32']='_0b00' ['ntfs']='_0700' ) CODE2PATTR=( ['_ef00']='boot' ['_8200']='swap' ['_fd01']='raid' ['_8e00']='lvm' ['_8400']='irst' ['_ef02']='bios_grub' ) # parted variant - sufficient but misses many details, like part type function getDiskInfoParted { typeset -n DISK=$1 integer K=0 typeset -a INFO typeset LINE X X=${ (( $3 )) && cat "$2" || ${PARTED} -m "$2" u s p ; } DISK.devpath="$2" print "$X" | while read LINE ; do if (( K == 1 )); then INFO=( ${LINE//:/ } ) DISK.devpath=${INFO[0]} # real device DISK.sz=${INFO[1]%s} # size in sectors (logical) # 2 # devtype (scsi|ide|md|...) DISK.lssz=${INFO[3]} # byte/s (logical) DISK.pssz=${INFO[4]} # byte/s (physical) DISK.ptt=${INFO[5]} # part table type # 6 # HDD model # 7 # HDD attrs elif (( K > 1 )); then unset P ; Part_t P LINE=${LINE%\;} # trailer aka EOL weg LINE=${LINE%:*} P.attrs=${.sh.match:1} # part attrs like bios_grub LINE=${LINE%:*} P.name=${.sh.match:1} # part name like primary or zfs LINE=${LINE%:*} P.type=${.sh.match:1} # part type, e.g. zfs or linux-swap(v1) LINE=${LINE%:*} LINE=${LINE//s} # skip size, remove trailing s LINE=${LINE%:*} P.end=${.sh.match:1} # last sector of the part (incl.) LINE=${LINE%:*} P.start=${.sh.match:1} # first sector of the part P.n=${LINE} # number of the part X= P.type=${FS2CODE[${P.type}]} [[ -z ${P.type} ]] && P.type='_0000' [[ ${P.attrs} =~ msftdata ]] && P.type='_0100' [[ ${P.attrs} =~ msftres ]] && P.type='_0c01' [[ ${P.attrs} =~ (msftrecv|diag) ]] && P.type='_2700' [[ ${P.attrs} =~ prep ]] && P.type='_4100' [[ ${P.attrs} =~ swap ]] && P.type='_8200' [[ ${P.attrs} =~ irst ]] && P.type='_8400' [[ ${P.attrs} =~ lvm ]] && P.type='_8e00' [[ ${P.attrs} =~ atvrecv ]] && P.type='_af04' [[ ${P.attrs} =~ hp-service ]] && P.type='_c002' [[ ${P.attrs} =~ boot ]] && P.type='_ef00' [[ ${P.attrs} =~ bios_grub ]] && P.type='_ef02' [[ ${P.attrs} =~ raid ]] && P.type='_fd00' [[ ${P.attrs} =~ hidden ]] && X+=",62" [[ ${P.attrs} =~ read_only ]] && X+=",60" [[ ${P.attrs} =~ legacy_boot ]] && X+=",2" P.attrs=${X:1} DISK.add P fi (( K++ )) done } function getDiskInfoFdisk { typeset -n DISK=$1 typeset L X T V integer S=1 I K X=${ (( $3 )) && cat "$2" || ${SFDISK} -l -o Device,Start,End,Attrs,Type-UUID,Name "$2" ; } DISK.devpath="$2" print "$X" | while read -A L ; do unset P ; Part_t P [[ $L == 'Disk' && ${L[7]} == 'sectors' ]] && \ DISK.devpath="${L[1]%:}" && DISK.sz=${L[6]} && continue [[ $L == 'Sector' && ${L[1]} == 'size' ]] && \ DISK.lssz=${L[3]} && DISK.pssz=${L[6]} && continue [[ $L == 'Disklabel' ]] && DISK.ptt=${L[3]} && continue [[ $L == 'Device' ]] && S=0 && continue (( S )) && continue P.n=${L##*[^0-9]} P.start=${L[1]} P.end=${L[2]} I=3 X= for (( I=3; I < ${#L[@]}; I++ )); do if (( ${#L[3]} == 36 )) && [[ ${L[3]:8:1} == '-' ]]; then V= [[ -n $X ]] && for T in $X ; do if [[ $T == 'RequiredPartiton' ]]; then V+=',0' elif [[ $T == 'NoBlockIOProtocol' ]]; then V+=',1' elif [[ $T == 'LegacyBIOSBootable' ]]; then V+=',2' elif [[ ${T:0:5} == 'GUID:' ]]; then V+=",${T:5}" fi done P.attrs="${V:1}" P.type=${GUID2CODE[${L[I]}]} (( I++ )) break fi X+=" ${L[I]}" done X= while (( I < ${#L[@]} )); do X+=" ${L[I]}" (( I++ )) done P.name="${X:1}" DISK.add P done } function getDiskInfoSgdisk { typeset -n DISK=$1 typeset L X typeset -l l integer S=1 I X=${ (( $3 )) && cat "$2" || ${SGDISK} -Pp "$2" ; } DISK.devpath="$2" DISK.ptt= print "$X" | while read -A L ; do unset P ; Part_t P [[ $L == 'Disk' && ${L[3]} == 'sectors,' ]] && \ DISK.devpath="${L[1]%:}" && DISK.sz=${L[2]} && continue [[ $L == 'Logical' ]] && DISK.lssz=${L[3]} && continue [[ $L == 'Number' ]] && S=0 && continue (( S )) && continue P.n=$L P.start=${L[1]} P.end=${L[2]} l=${L[5]} # convert to lower case P.type="_$l" X= for (( I=6 ; I < ${#L[@]} ; I++ )); do X+=" ${L[I]}" done P.name="${X:1}" DISK.add P done if [[ -n ${FDISK} ]]; then ${FDISK} -l ${DISK.devpath} | while read -A L ; do [[ $L == 'Sector' && ${L[1]} == 'size' ]] && DISK.pssz=${L[6]} [[ $L == 'Disklabel' ]] && DISK.ptt=$3 done fi } function getDiskInfo { if (( $4 )); then [[ ! -f $2 ]] && print -u2 "$2 is not a file - skipped" && return 1 elif [[ ! -b $2 ]]; then print -u2 "$2 is not a block device - skipping partition check." return 1 fi typeset -n DISK=$1 typeset X=$2 B if [[ $X =~ p[0-9]+$ ]]; then X="${X%p*}" elif [[ $X =~ /sd[a-z][0-9]$ ]]; then X="${X%%*([0-9])}" fi (( $4 )) || DISK.devalias="$X" getDiskInfo$3 DISK "$X" $4 || return $? [[ -z ${DISK.devalias} ]] && DISK.devalias=${DISK.devpath} return 0 } # SanDisk Optimus Max (SDLLOCDR038T5CA1): 512/4096 log/phys sector size # jel+sandisk@cs.uni-magdeburg.de function compareDisks { typeset -n A=$1 B=$2 [[ -n $3 ]] && typeset -n INFO=$3 || typeset -a INFO integer RES=0 if (( A.sz != B.sz )); then INFO+=( "different size (${A.sz} vs. ${B.sz} sectors)" ) (( RES++ )) fi if (( A.lssz != B.lssz )); then INFO+=( "different logical block size (${A.lssz} vs. ${B.lssz})" ) (( RES++ )) fi if (( A.pssz != B.pssz )); then INFO+=( "different physical block size (${A.lssz} vs. ${B.lssz})" ) (( RES++ )) fi if [[ ${A.ptt} != ${B.ptt} ]]; then INFO+=( "different label aka disk partition table type ('${A.ptt}' vs. '${B.ptt}')" ) (( RES++ )) fi typeset -A IDXA IDXB typeset -a IDXAA IDXBA integer I for I in ${!A.parts[@]} ; do IDXA[$I]=$I IDXAA+=( $I ) done for I in ${!B.parts[@]} ; do IDXB[$I]=$I IDXBA+=( $I ) done if [[ ${#IDXAA[@]} != ${#IDXBA[@]} ]]; then INFO+=( "different number of partitions (${#IDXAA[@]} vs. ${#IDXBA[@]})" ) (( RES++ )) fi for I in ${IDXBA[@]}; do if [[ -z ${IDXA[$I]} ]]; then INFO+=( "missing partition $I" ) (( RES++ )) else if (( A.parts[I].start != B.parts[I].start )); then INFO+=( "partition $I should start at ${B.parts[$I].start}s (current ${A.parts[$I].start})" ) (( RES++ )) fi if (( A.parts[I].end != B.parts[I].end )); then INFO+=( "partition $I should end at ${B.parts[$I].end}s (current ${A.parts[$I].end})" ) (( RES++ )) fi # filesystems are different thing # also it doesn't realy matter, whether logical or primary, anyway: if [[ ${A.parts[I].type} != ${B.parts[I].type} ]]; then INFO+=( "partition $I type should be 0x${B.parts[$I].type:1} (current 0x${A.parts[$I].type:1})" ) (( RES++ )) fi if [[ ${A.parts[$I].attrs} != ${B.parts[$I].attrs} ]]; then if [[ -z ${B.parts[$I].attrs} ]]; then INFO+=( "partition $I should have no attrs set" ) else INFO+=( "partition $I should have the following attrs: ${B.parts[$I].attrs}" ) fi (( RES++ )) fi fi done return $RES } # Generate and store commands in arg2 to stop all Linux MD Raid devices aka # /dev/md on the given raw disk device (arg1), to disable related swap, to # zero out a possible md superblock and finally to remove all its patitions. function getRmCmds { typeset -n D=$1 C=$2 # device path, command array integer I typeset PRE X F=$3 PRE=${D.devpath%/*} X=${.sh.match:1} if [[ $X == 'disk' || $X == 'p0' ]]; then PRE+='/p' else PRE+="/$X" if [[ ${X:0:2} == 'sd' ]]; then : # append plain number elif [[ ${X:0:4} == 'nvme' || ${X:0:4} == 'disk' \ || $X =~ ^[pd][0-9] ]] then PRE+='p' else PRE+='p' # probably fi fi C+=( '# Stop all raid devices (sh/bash/ash/dash/ksh* syntax):' 'for X in /dev/md[0-9]* ; do mdadm --stop $X 2>/dev/null ; done' ' ' '# Destroy data, which might be in the way.' '# But first unlock all mounted zfs and destroy a possibly existing' '# rpool including its snapshots and deduced clones.' '# If there are other pools containing the new boot disks or your' '# current root pool has a different name, then you need to umount' '# and destroy them in a similar way first. NOTE that zfs utils are' '# not POSIXLY correct - if set commands will fail/produce garbage!' 'unset POSIXLY_CORRECT' '/sbin/modprobe zfs' ' ' 'cd /run' 'zfs umount -a' 'zpool destroy rpool 2>/dev/null' ) for I in ${!D.parts[@]}; do [[ ${D.parts[$I].name} =~ swap ]] && C+=( "swapoff ${D.devpath}" ) # make sure, that the kernel/md driver doesn't find a md array # signature - re-partioning may not overwrite the related place on disk C+=( "mdadm --zero-superblock ${PRE}$I 2>/dev/null" ) # actually only needed for MBR driven disks [[ $F == 'p' ]] && C+=( "parted ${D.devpath} rm $I" ) #[[ $F == 's' ]] && C+=( "sgdisk -d ${D.parts[I].n} ${D.devpath}" ) [[ $F == 'f' ]] && C+=( "sfdisk --part-type ${D.devpath} ${D.parts[I].n} ${CODE2GUID['_0000']%%:*}" ) done [[ $F == 's' ]] && C+=( "sgdisk --zap-all ${D.devpath}" ) [[ $F == 'f' ]] && C+=( "printf 'g\\\nw\\\nq\\\n' | fdisk ${D.devpath}" ) C+=( 'partprobe' ) } # Generate and store commands in arg2 to re-partion the given raw disk # device (arg1). function getFmtCmds { typeset -n D=$1 C=$2 integer I OFFSET typeset X F=$3 A C+=( '# repartitioning the disk - all data get lost' ) if [[ $F == 'p' ]]; then C+=( "parted ${D.devpath} mklabel ${D.ptt}" ) for I in ${!D.parts[@]}; do A=${D.parts[$I].type} [[ -n $A ]] && A=${CODE2PATTR[$A]} X="parted -s ${D.devpath} mkpart ${D.parts[$I].name:-primary}" [[ $A == 'swap' ]] && X+=' linux-swap' && A= C+=( "$X ${D.parts[$I].start}s ${D.parts[$I].end}s") [[ -n $A ]] && C+=( "parted -s ${D.devpath} set $I $A on" ) A=( ${D.parts[$I].attrs//,/ } ) for X in "${A[@]}"; do [[ $X == '2' ]] && \ C+=( "parted -s ${D.devpath} set $I legacy_boot on" ) [[ $X == '60' ]] && \ C+=( "parted -s ${D.devpath} set $I read_only on" ) [[ $X == '62' ]] && \ C+=( "parted -s ${D.devpath} set $I hidden on" ) done done C+=( 'partprobe' ' ' "parted ${D.devpath} u s p" ) elif [[ $F == 's' ]]; then # assuming a 'sgdisk --zap-all $dev' has been run A='sgdisk -a 1 ' for I in ${!D.parts[@]}; do X=${D.parts[$I].n} A+='\\'"\n\t\t" A+="-n ${X}:${D.parts[$I].start}:${D.parts[$I].end} " A+="-t ${X}:${D.parts[$I].type:1} " [[ -n ${D.parts[$I].name} ]] && \ A+="-c '${X}:${D.parts[$I].name}' " if [[ -n ${D.parts[$I].attrs} ]]; then for T in ${D.parts[$I].attrs//,/ } ; do A+="-A ${D.parts[$I].n}:set:${T} " done fi done C+=( "$A"'\\'"\n\t\t${D.devpath}" ) C+=( 'partprobe' ' ' "sgdisk -p ${D.devpath}" ) elif [[ $F == 'f' ]]; then # actually we could do it in one row using a temp file, but that's # less transparent to the user OFFSET=0 # we assume, part. 1 the first of all for I in ${!D.parts[@]}; do A="printf '" if (( D.parts[I].n == 1 )) && \ [[ ${D.parts[$I].type:1:2} == 'ef' ]] && \ (( D.parts[I].start < 2048 )) then C+=( '# fdisk does not allow start sector < 2048 - adjusted' ) (( OFFSET=2048 - D.parts[I].start )) (( D.parts[I].start+=OFFSET )) (( D.parts[I].end+=OFFSET )) (( D.parts[I+1].start+=OFFSET )) # if .start > .end it is trash anyway fi A+='n\\n' A+="${D.parts[$I].n}\\\n" A+="${D.parts[$I].start}\\\n" A+="${D.parts[$I].end}\\\nw\\\nq\\\n' | fdisk ${D.devpath}" C+=( "$A >/dev/null" ) if [[ -n ${D.parts[$I].attrs} ]]; then V= for T in ${D.parts[$I].attrs//,/ } ; do if [[ $T == '0' ]]; then V+=',RequiredPartiton' elif [[ $T == '1' ]]; then V+=',NoBlockIOProtocol' elif [[ $T == '2' ]]; then V+=',LegacyBIOSBootable' else V+=",$T" fi done C+=( "sfdisk --part-attrs ${D.devpath} ${D.parts[$I].n} '${V:1}'" ) fi done C+=( 'partprobe' ' ' "fdisk -l ${D.devpath}" ) fi } # Create an rpool from the given Disk (arg1) and store commands into # vname (arg2). function getZfsCmds { typeset -n D=$1 C=$2 typeset X ZBASE='rpool/ROOT/linux' integer S M SWAP=$3 (( S=log2(D.lssz) )) (( S < 9 )) && S=9 (( M=log2(MEMORY) + 11 - 30 )) (( M=pow(2, M) )) X="-o ashift=$S -m none -o altroot=/target -O canmount=on" X+=' \\\n\t\t'"-o cachefile=/boot/zfs/zpool.cache" X+=' \\\n\t\t-o autoexpand=off -o autoreplace=off -o failmode=continue' X+=' \\\n\t\t-o delegation=on -o listsnapshots=off' X+=' \\\n\t\t-O compression=lz4 -O checksum=on -O atime=on -O xattr=sa' X+=' \\\n\t\t-O aclinherit=restricted -O acltype=off -O overlay=off' X+=' \\\n\t\t-O casesensitivity=mixed -O normalization=none' C+=( '# We assume, that "rpool" is the boot disk pool and mount it temp. to' '# /target , so that installation can continue.' 'unset POSIXLY_CORRECT' 'mkdir -p /boot/zfs' "zpool create -f $X "'\\\n\t\t'"rpool ${D.zfs}" 'partprobe' # just in case zpool did stupid things "zfs create -o mountpoint=none ${ZBASE%/*}" "zfs create -o canmount=noauto -o mountpoint=/ ${ZBASE}" # partman-zfs/bootfs rpool/ROOT/linux "zpool set bootfs=${ZBASE} rpool" # set mountpoint to legacy, so that partman fuck automtically mounts # it (it doesn't understand zfs). # "zfs create -o mountpoint=legacy ${ZBASE}/boot" "zfs create -o mountpoint=legacy ${ZBASE}/home" "zfs create -o canmount=noauto -o mountpoint=legacy ${ZBASE}/var" 'zfs create -o canmount=noauto -o mountpoint=/var/share rpool/VARSHARE' "zfs create -b 1M -V ${M}g -o compression=off rpool/dump" # "zfs create -o mountpoint=legacy ${ZBASE}/usr" # "zfs create -p -o canmount=noauto -o mountpoint=/a ${ZBASE}/var" # "zfs set canmount=off ${ZBASE%/*}" # "zfs set mountpoint=legacy ${ZBASE%/*}" # "zfs inherit mountpoint ${ZBASE}/var" # "zfs mount ${ZBASE}" # "zfs mount ${ZBASE}/var" ) (( SWAP )) && C+=( \ "zfs create -b 1M -V ${SWAP}g -o compression=off rpool/swap" ) # if 'zpool create' applied to a wrong partition, this may show the error C+=( ' ' '# check' ) if [[ -n ${SGDISK} ]]; then C+=( "sgdisk -p ${D.devpath}" ) elif [[ -n ${SFDISK} ]]; then C+=( "fdisk -l ${D.devpath}" ) elif [[ -n ${PARTED} ]]; then C+=( "parted ${D.devpath} u s m" ) fi C+=( 'zfs list -r rpool' ) } function init { [[ ${ uname -s ; } == 'SunOS' ]] && return X="======= partman ======\n${ set ; }" X+="\n/proc/mdstat:\n${ cat /proc/mdstat ; }" X+='\n======================' #print "$X" # fix the braindamaged original [ -x /etc/auto-raidcfg ] && cp /etc/auto-raidcfg /bin/auto-raidcfg # this doesn't work because of the exec braindamage # . /usr/share/debconf/confmodule # instead we need to create a separate busybox script, when we need to use # db_* stuff ... } function getProductName { typeset -n PRODUCT=$1 typeset SMBIOS=${ whence dmidecode ; } [[ -z ${SMBIOS} ]] && SMBIOS=${ whence smbios ; } ${SMBIOS} -t 1 2>/dev/null | while read LINE ; do [[ ${LINE:0:13} == 'Product Name:' ]] || continue PRODUCT="${LINE:14}" break done } function getSwap { typeset -n N=$1 print \ '\nTo calculate a proper disk layout the swap space to be used is needed. Usually RAM/4 GB (our default) are sufficient. However, if this is a laptop and you wanna use hibernation, you might need 1.5xGB of RAM of your machine. You may adjust this via CLI option "-s GB".\n' typeset X=4 K V T integer D P=0 # this is alway < 2^n , so no need to -1 (( D=rint(log2(MEMORY)) - 22 )) (( D < 0 )) && D=0 (( D=pow(2, D) )) N=$D while (( N < 0 )) ; do P=1 X=$D read X?"Enter the swap size in GB (default: $D): " [[ $X =~ ^[0-9]+$ ]] && N=$X done (( N < 0 )) && N=$D (( P )) && print } function doMain { typeset D X typeset -l A integer RES=0 SWAP=0 USE_FILES=1 I PARTED=${ whence parted ; } SGDISK=${ whence sgdisk ; } SFDISK=${ whence fdisk ; } if [[ -z ${FILES} ]]; then if [[ -n ${SFDISK} ]]; then FILES='Fdisk' elif [[ -n ${SGDISK} ]]; then FILES='Sgdisk' elif [[ -n ${PARTED} ]]; then FILES='Parted' else print -u2 'ERROR: No suitable partition tool found.' \ 'Make sure fdisk is installed, e.g.\n\tby adding it to your' \ 'your preseed file like this:' \ '\n\t"d-i anna/choose_modules string util-linux-udeb"' return 99 fi USE_FILES=0 elif [[ ${FILES} == 'p' ]]; then print -u2 'Warning: parted is ancient junk. Output contains not all' \ 'required information\n\tto properly create a GPT partition.' FILES='Parted' elif [[ ${FILES} == 's' ]]; then print -u2 'Warning: sgdisk output might not contain all required' \ 'information and\n\t supports GPT labeled disks, only.' FILES='Sgdisk' elif [[ ${FILES} == 'f' ]]; then FILES='Fdisk' else print -u2 "ERROR: Unsupported part output format '${FILES}' - exiting" return 98 fi [[ -z ${FORMAT} ]] && FORMAT='s' if [[ ${FORMAT} == 's' || ${FORMAT} == 'sgdisk' ]]; then FORMAT='s' elif [[ ${FORMAT} == 'f' || ${FORMAT} == 'fdisk' ]]; then FORMAT='f' elif [[ ${FORMAT} == 'p' || ${FORMAT} == 'parted' ]]; then print -u2 '\nWarning: ancient formatter 'parted' should not be used.' \ 'It is unsuitable\n\tfor GPT formatting.\n' FORMAT='p' else print -u2 "ERROR: Unknown disk formatter tool '${FORMAT}' - exiting." return 97 fi # We put it here, since when pre.sh gets executed, neither the full kernel # is expanded yet nor are the related devices available. #/sbin/udevadm settle if (( USE_ZFS == -1 )); then X= [[ ${ uname -s; } == 'SunOS' ]] && X=1 || X=${ /bin/lsmod | grep zfs; } [[ -n $X ]] && USE_ZFS=1 || USE_ZFS=0 fi if (( MEMORY < 1 )); then if [[ -e /proc/meminfo ]]; then while read K V T ; do [[ $K == 'MemTotal:' ]] && MEMORY=$V && break done $X 2>&1 # make sure, we have the chassis links /lib/udev/bayLinks.sh -u >>$X 2>&1 else print -u2 'Warning: /lib/udev/bayLinks.sh not available!\n' \ '\t/dev/chassis/*/HDD* symlinks might not be uptodate.' fi if [[ -z $1 ]]; then print -u2 'Nothing to do - params missing?' showUsage return 0 fi . init typeset -i GB_SWAP=0 (( FIX_SWAP >= 0 )) && GB_SWAP=${FIX_SWAP} || getSwap GB_SWAP typeset SCRIPT I=1 for D in "$@" ; do unset DISK RDISK Disk_t DISK RDISK getDiskInfo DISK "$D" ${FILES} ${USE_FILES} || continue if ! DISK.getRecommendedLayout RDISK ${GB_SWAP} ${USE_ZFS} ; then print -u2 "\nERROR: no recommended layout for ${DISK.devpath} -" \ 'not enough space.' (( ! USE_ZFS )) && print '\tYou may limit space required for swap'\ 'via option "-m GB".\n' continue fi unset INFO; typeset -a INFO SCRIPT='\n' if ! compareDisks DISK RDISK INFO ; then print -u2 \ "Problems found wrt. recommended layout of ${DISK.devpath}:" for X in "${INFO[@]}"; do print -u2 "\t- $X" done print -u2 '\nTo reformat the disk, use e.g. the following commands:' unset INFO; typeset -a INFO getRmCmds DISK INFO ${FORMAT} for X in "${INFO[@]}"; do SCRIPT+="\t$X\n" done SCRIPT+='\n' unset INFO; typeset -a INFO getFmtCmds RDISK INFO ${FORMAT} for X in "${INFO[@]}"; do SCRIPT+="\t$X\n" done if (( USE_ZFS && I )); then SCRIPT+='\n' unset INFO; typeset -a INFO getZfsCmds RDISK INFO ${GB_SWAP} for X in "${INFO[@]}"; do SCRIPT+="\t$X\n" done (( I-- )) fi print -u2 "${SCRIPT}" X="/tmp/format-disk${RES}.sh" print "#!/bin/sh\n${SCRIPT}" >"$X" chmod 755 "$X" A= if (( ! USE_FILES )); then while [[ $A != 'y' && $A != 'n' ]]; do A='y' read -v A?"Should $D be reformatted NOW as shown above: " done if [[ $A == 'y' ]]; then A= while [[ $A != 'y' && $A != 'n' ]]; do A='y' read -v A?"Please confirm: ALL DATA on $D will be LOST: " done if [[ $A == 'y' ]]; then "$X" unset DISK RDISK ; Disk_t DISK RDISK getDiskInfo DISK "$D" ${FILES} ${USE_FILES} DISK.getRecommendedLayout RDISK ${GB_SWAP} ${USE_ZFS} compareDisks DISK RDISK && (( RES-- )) fi fi fi if (( USE_FILES )) || [[ $A != 'y' ]]; then print -u2 "Formatting script saved as '$X'." fi (( RES++ )) fi done return ${RES} } # partman invocation order: # /lib/partman/init.d/ must return 0 (also starts parted_server if needed) # /lib/partman/update.d/ invoked for each new device/part found # /lib/partman/display.d/ 0 = continue, 1-99 restart, 100-254 skip, 255 abort # /lib/partman/check.d/ return reasonable code # /lib/partman/undo.d/ if undo invoked by user. must return 0. # /lib/partman/commit.d/ return 0 or stop; jumps to init.d/ if part continues # /lib/partman/finish.d/ return 0 or 1 (stops parted_server), >1 abort # # see also: /var/lib/partman/devices/ USAGE="[-?${VERSION}"' ] [-copyright?Copyright (c) 2015 Jens Elkner. All rights reserved.] [-license?CDDL 1.0] [+NAME?'"${PROG}"' - re-partitioning script generator.] [+DESCRRIPTION?Usually we use this script as debian installer \bpartman/early_command\b, which means that it gets executed as the first of all partman scripts (see /lib/partman/init.d/01early_command). It generates a single script for each given \afile_or_dev\a, which contains the commands to re-partion it to match the our defaults/recommandations. The user will be asked to executed it, when generated. If not, it gets stored in an appropriate location (for later use/inspection). This way it is used to overcome all this partman limitations/ancient stuff by formatting drives with the proper tools, so that partman sees all what it wants to see and does not any crazy re-formatting by itself and debian installer can continue without intervention to the next task.] [+?However, if the re-partitoning script gets fired, an "undo" option as partman usually provides in interactive installs is not supported (because early command gets invoked before partman reads the current layout).] [h:help?Print this help and exit.] [F:functions?Print a list of all functions available.] [T:trace]:[functionList?A comma separated list of functions of this script to trace (convinience for troubleshooting).] [+?] [f:files]:[type?Mark the given operands (\afile_or_dev\a) as files containing the output of "parted -m \asd_device\a u s p" for \atype\a=\bp\b, "fdisk -l -o Device,Start,End,Attrs,Type-UUID,Name \asd_device\a" for \atype\a=\bf\b - preferred - (requires fdisk from util-linux 2.27.1+) or "sgdisk -Pp \asd_device\a" for \atype\a=\bs\b. This is usually used for offline development/testing of this script.] [l:list-guid?List all known partition GUIDs incl. sgdisk code and exit.] [m:memory]:[num?Assume \anum\a GiB of physical RAM. If not given, /proc/meminfo or prtconf gets consulted to find out the value automatically.] [N:noboot?Do not reserve a 256 MiB Grub/BIOS boot partition (EF02) and for non-ZFS systems also skip generating an entry for a swap partition (for zfs system swap gets reserved as part of the rpool, i.e. rpool/swap volume if needed). This is ok, if the related disks will be used as normal data pool disk. Never use this option for [potential]] boot disks! For ZFS hot spares it is not that important, because these disks get reformatted when needed, anyway.] [s:swap]:[num?Use \anum\a GiB for swap and do not deduce it from available RAM.] [t:tool]:[formatter?The disk partition tool to use. Choices are: \bp\b for \bparted\b (the worst choice since it is actually an MBR oriented tool and is not really usable for GPT formatted disks). \bf\b stands for \bfdisk\b from linux-utils and finally the default/preferred \bs\b for \bsgdisk\b.] [Z:nozfs?Do not use ZFS, i.e. assume that Linux md will be used.] [z:zfs?Force to use ZFS, even if no zfs kernel modules are loaded yet.] [+EXAMPLES]{ [+?'"${PROG}"' /dev/sda /dev/sdb] } [+EXIT STATUS?The script usually exits with:]{ [+0?The script did nothing, move to the next script in \bdisplay.d/\b.] [+1..99?Restart the partitioning, i.e. move again to the first script in \bdisplay.d/\b.] [+100..254?The script succesfuly partitioned the disks, do not execute the following scripts in \bdisplay.d/\b.] [+255?Abort the partitioning.] } \n\n\afile_or_dev\a ... ' integer BOOT=1 USE_ZFS=-1 MEMORY=0 LIST_GUID=0 FIX_SWAP=-1 typeset PARTED= SGDISK= SFDISK= FILES= FORMAT= X="${ print ${USAGE} ; }" while getopts "$X" OPT ; do case "${OPT}" in f) FILES=${OPTARG} ;; N) BOOT=0 ;; h) showUsage; exit 1 ;; T) if [[ ${OPTARG} == 'ALL' ]]; then typeset -ft ${ typeset +f ; } else typeset -ft ${OPTARG//,/ } fi ;; F) typeset +f ; exit 0 ;; t) FORMAT=${OPTARG} ;; Z) USE_ZFS=0 ;; z) USE_ZFS=1 ;; m) MEMORY=${OPTARG} || exit 1 ;; l) LIST_GUID=1 ;; s) [[ ${OPTARG} =~ ^[0-9]+$ ]] && FIX_SWAP=${OPTARG} || \ { print -u2 'Invalid swap size value' && exit 255 ; } ;; *) print -u2 "Unknown option '-${OPT}'."; showUsage 1 ;; esac done X=$((OPTIND-1)) shift $X && OPTIND=1 unset X (( LIST_GUID )) && listGUIDs && exit 0 [[ -z $1 ]] && showUsage 1 && exit 2 doMain "$@"