This repository has been archived on 2024-09-01. You can view files and clone it, but cannot push or open issues or pull requests.
al-installer/src/lib/part.sh
2019-03-16 21:21:48 -07:00

341 lines
11 KiB
Bash

#!/usr/bin/bash
# vim:ft=sh:fdm=marker:fmr={,}
# archlabs installer library script file
# this file is not meant to be run directly
# sourcing this file in a non bash shell is not advised
# shellcheck disable=2154,2155,2153,2046,2034
declare -Agr FS_CMDS=(
[ext2]="mkfs.ext2 -q" [ext3]="mkfs.ext3 -q" [ext4]="mkfs.ext4 -q"
[f2fs]="mkfs.f2fs" [jfs]="mkfs.jfs -q" [xfs]="mkfs.xfs -f" [nilfs2]="mkfs.nilfs2 -q"
[ntfs]="mkfs.ntfs -q" [reiserfs]="mkfs.reiserfs -q" [vfat]="mkfs.vfat -F32"
)
declare -Agr FS_OPTS=([vfat]="" [ntfs]="" [ext2]="" [ext3]=""
[ext4]="discard - off dealloc - off nofail - off noacl - off relatime - off noatime - off nobarrier - off nodelalloc - off"
[jfs]="discard - off errors=continue - off errors=panic - off nointegrity - off"
[reiserfs]="acl - off nolog - off notail - off replayonly - off user_xattr - off"
[xfs]="discard - off filestreams - off ikeep - off largeio - off noalign - off nobarrier - off norecovery - off noquota - off wsync - off"
[nilfs2]="discard - off nobarrier - off errors=continue - off errors=panic - off order=relaxed - off order=strict - off norecovery - off"
[f2fs]="data_flush - off disable_roll_forward - off disable_ext_identify - off discard - off fastboot - off flush_merge - off inline_xattr - off inline_data - off inline_dentry - off no_heap - off noacl - off nobarrier - off noextent_cache - off noinline_data - off norecovery - off"
)
format()
{
infobox "$_FSTitle" "\nFormatting: $1\n\nCommand: ${FS_CMDS[$2]}\n" 0
${FS_CMDS[$2]} $1 >/dev/null 2>$ERR
echeck "${FS_CMDS[$2]} $1"
}
partition()
{
local device
if [[ $# -eq 0 ]]; then
select_device 'root' || return 1
device="$DEVICE"
else
device="$1"
fi
tput civis
local choice
if ! choice="$(menubox "$_PartTitle" "$_PartBody" 0 0 0 "$_PartShowTree" "-" "$_PartAuto" "-" \
$({ [[ $DISPLAY ]] && hash gparted >/dev/null 2>&1; } && printf "gparted -") \
"cfdisk" "-" "parted" "-" "$_PartWipe" "-")"; then
return 1
fi
tput civis
if [[ $choice != "$_PartWipe" && $choice != "$_PartAuto" && $choice != "$_PartShowTree" ]]; then
clear; tput cnorm; $choice $device
elif [[ $choice == "$_PartShowTree" ]]; then
msgbox "$_PrepShowDev" "\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE,MOUNTPOINT "$device")\n"
partition $device
elif [[ $choice == "$_PartWipe" ]]; then
yesno "$_PartWipe" "$_PartBody1 $device $_PartWipeBody2" && wipe -Ifrev $device
partition $device
else
# if auto_partition fails we need to empty the partition variables
auto_partition $device || { ROOT_PART=""; BOOT_PART=""; BOOT_DEVICE=""; return 1; }
fi
}
decr_count()
{
# remove a partition from the dialog list and decrement the number partitions left
(( $# == 1 )) || return 1
local p="$1"
PARTS="$(sed "s~${p} [0-9]*[G-M]~~; s~${p} [0-9]*\.[0-9]*[G-M]~~" <<< "$PARTS")"
(( COUNT > 0 )) && (( COUNT-- ))
return 0
}
enable_swap()
{
if [[ $1 == "$MNT/swapfile" && $SWAP_SIZE ]]; then
fallocate -l $SWAP_SIZE $1 2>$ERR
echeck "fallocate -l $SWAP_SIZE $1"
chmod 600 $1 2>$ERR
echeck "chmod 600 $1"
fi
mkswap $1 >/dev/null 2>$ERR
echeck "mkswap $1"
swapon $1 >/dev/null 2>$ERR
echeck "swapon $1"
return 0
}
device_tree()
{
tput civis
local msg
if [[ $IGNORE_DEV != "" ]]; then
msg="$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE,MOUNTPOINT |
awk "!/$IGNORE_DEV/"' && /disk|part|lvm|crypt|NAME/ {print $0}')"
else
msg="$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE,MOUNTPOINT |
awk '/disk|part|lvm|crypt|NAME/ {print $0}')"
fi
msgbox "$_PrepShowDev" "$msg"
}
select_device()
{
local dev
local msg
if [[ $1 == 'boot' ]]; then
msg="$_DevSelTitle for bootloader\n"
else
umount_dir $MNT
fi
if [[ $DEV_COUNT -eq 1 && $SYS_DEVS ]]; then
DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
msg="\nOnly one device available$([[ $1 == 'boot' ]] && printf " for bootloader"):"
infobox "$_DevSelTitle" "$msg $DEVICE\n" 1
elif (( DEV_COUNT > 1 )); then
tput civis
if ! DEVICE="$(menubox "$_DevSelTitle " "${msg}$_DevSelBody" 0 0 0 $SYS_DEVS)"; then
return 1
fi
elif [[ $DEV_COUNT -lt 1 && $1 != 'boot' ]]; then
msgbox "$_ErrTitle" "\nNo available devices to use.\n$_Exit"; die 1
fi
# if the device selected was for bootloader, set the BOOT_DEVICE
[[ $1 == 'boot' ]] && BOOT_DEVICE="$DEVICE"
return 0
}
confirm_mount()
{
local part="$1"
local mount="$2"
if [[ $mount == "$MNT" ]]; then
local msg="Partition: $part\nMountpoint: / (root)"
else
local msg="Partition: $part\nMountpoint: ${mount#$MNT}"
fi
if [[ $(mount) == *"$mount"* ]]; then
infobox "$_MntTitle" "$_MntSucc\n$msg\n" 1; decr_count "$part"
else
infobox "$_MntTitle" "$_MntFail\n$msg\n" 1; return 1
fi
return 0
}
check_cryptlvm()
{
local dev=""
local part="$1"
local devs="$(lsblk -lno NAME,FSTYPE,TYPE)"
# Identify if $part is "crypt" (LUKS on LVM, or LUKS alone)
if [[ $(lsblk -lno TYPE "$part") =~ 'crypt' ]]; then
LUKS=' encrypted'
LUKS_NAME="${part#/dev/mapper/}"
for dev in $(awk '/lvm/ && /crypto_LUKS/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
if grep -q "$LUKS_NAME" <<< "$(lsblk -lno NAME "$dev")"; then
LUKS_DEV="$LUKS_DEV cryptdevice=$dev:$LUKS_NAME"
LVM=' logical volume'
break
fi
done
for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
if grep -q "$LUKS_NAME" <<< "$(lsblk -lno NAME "$dev")"; then
LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
break
fi
done
elif [[ $(lsblk -lno TYPE "$part") =~ 'lvm' ]]; then
LVM=' logical volume'
VOLUME_NAME="${part#/dev/mapper/}"
for dev in $(awk '/crypt/ && /lvm2_member/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
if grep -q "$VOLUME_NAME" <<< "$(lsblk -lno NAME "$dev")"; then
LUKS_NAME="$(sed 's~/dev/mapper/~~g' <<< "$dev")"
break
fi
done
for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
if grep -q "$LUKS_NAME" <<< "$(lsblk -lno NAME "$dev")"; then
LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
LUKS=' encrypted'
break
fi
done
fi
}
auto_partition()
{
local device="$1"
local size
size=$(lsblk -lno SIZE $device | awk 'NR == 1 {
if ($1 ~ "G") {
sub(/G/, ""); print ($1 * 1000 - 512) / 1000"G"
} else {
sub(/M/, ""); print ($1 - 512)"M"
}
}')
if [[ $SYS == 'BIOS' ]]; then
local msg="$(sed 's|vfat/fat32|ext4|' <<< "$_PartBody2")"
local table="msdos"
local fs="ext4"
else
local msg="$_PartBody2"
local table="gpt"
local fs="fat32";
fi
# confirm or bail
yesno "$_PrepParts" "$_PartBody1 $device $msg ($size)$_PartBody3" || return 0
infobox "$_PrepParts" "\nRemoving existing partitions on $device and setting partition table to $table\n" 1
swapoff -a # in case the device was previously used for swap
local dev_info
dev_info="$(parted -s $device print)"
# walk the partitions on the device in reverse order and delete them
while read -r i; do
parted -s $device rm $i >/dev/null 2>&1
done <<< "$(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r)"
if [[ $(awk '/Table:/ {print $3}' <<< "$dev_info") != "$table" ]]; then
parted -s $device mklabel $table >/dev/null 2>&1
fi
infobox "$_PrepParts" "\nCreating a 512M $fs boot partition.\n" 1
if [[ $SYS == "BIOS" ]]; then
parted -s $device mkpart primary $fs 1MiB 513MiB >/dev/null 2>&1
else
parted -s $device mkpart ESP $fs 1MiB 513MiB >/dev/null 2>&1
fi
sleep 0.1
BOOT_DEVICE="$device"
BOOT_PART=$(lsblk -lno NAME,TYPE $device | awk 'NR == 2 {print "/dev/"$1}')
if [[ $SYS == "BIOS" ]]; then
mkfs.ext4 -q $BOOT_PART >/dev/null 2>&1
else
mkfs.vfat -F32 $BOOT_PART >/dev/null 2>&1
fi
infobox "$_PrepParts" "\nCreating a $size ext4 root partition.\n" 0
parted -s $device mkpart primary ext4 513MiB 100% >/dev/null 2>&1
sleep 0.1
ROOT_PART=$(lsblk -lno NAME,TYPE $device | awk 'NR == 3 {print "/dev/"$1}')
mkfs.ext4 -q $ROOT_PART >/dev/null 2>&1
tput civis; sleep 0.5
msgbox "$_PrepParts" "\nAuto partitioning complete.\n\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE $device)"
}
mount_partition()
{
local part="$1"
local mountp="${MNT}$2"
local fs="$(lsblk -lno FSTYPE $part)"
mkdir -p "$mountp"
if [[ ${FS_OPTS[$fs]} != "" && $part != "$BOOT_PART" ]] && select_mount_opts "$part" "$fs"; then
mount -o $MNT_OPTS $part "$mountp" 2>$ERR
echeck "mount -o $MNT_OPTS $part $mountp"
else
mount $part "$mountp" 2>$ERR
echeck "mount $part $mountp"
fi
confirm_mount $part "$mountp" || return 1
check_cryptlvm "$part"
return 0
}
mount_boot_part()
{
if ! mount_partition "$BOOT_PART" "${BMNTS[$SYS-$BOOTLDR]}"; then
src /usr/share/archlabs/installer/lib/boot.sh
return 1
else
SEPERATE_BOOT=true
fi
}
find_partitions()
{
local str="$1"
local err=''
# string of partitions as /TYPE/PART SIZE
if [[ $IGNORE_DEV != "" ]]; then
PARTS="$(lsblk -lno TYPE,NAME,SIZE |
awk "/$str/"' && !'"/$IGNORE_DEV/"' {
sub(/^part/, "/dev/");
sub(/^lvm|^crypt/, "/dev/mapper/")
print $1$2 " " $3
}')"
else
PARTS="$(lsblk -lno TYPE,NAME,SIZE |
awk "/$str/"' {
sub(/^part/, "/dev/")
sub(/^lvm|^crypt/, "/dev/mapper/")
print $1$2 " " $3
}')"
fi
# number of partitions total
COUNT=$(wc -l <<< "$PARTS")
# ensure we have enough partitions for the system and action type
case $str in
'part|lvm|crypt') [[ $COUNT -eq 0 || ($SYS == 'UEFI' && $COUNT -lt 2) ]] && err="$_PartErrBody" ;;
'part|crypt') (( COUNT == 0 )) && err="$_LvmPartErrBody" ;;
'part|lvm') (( COUNT < 2 )) && err="$_LuksPartErrBody" ;;
esac
# if there aren't enough partitions show the error message
if [[ $err ]]; then
msgbox "$_ErrTitle" "$err"
return 1
fi
return 0
}