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/installer

2099 lines
66 KiB
Plaintext
Raw Normal View History

2018-07-18 19:50:37 -05:00
#!/usr/bin/env bash
# vim:ft=sh:fdm=marker:fmr={,}
# Written by Nathaniel Maia for use in Archlabs
# Some ideas and code were taken from other installers
# AIF, ABIF, Calamares.. Credit where credit is due
# This program is free software, provided under the GNU GPL
# dry run performing no action, used to check for syntax errors
# set -n
# no unbound variables
# set -u
# set verbose, print lines as they are read
# set -v
# immutable vaulues {
readonly LIVEUSER="liveuser" # Live user
readonly DIST="Archlabs" # Distributor
readonly VER="1.5.48" # Version
readonly MNT="/mnt/install" # Mountpoint
readonly ANS="/tmp/answer" # Stores answers
readonly OPT="/tmp/opts" # Mount options
readonly ERR="/tmp/errlog" # Error logging
readonly LOG="/tmp/log" # set -x logging
# }
# mutable values and prep {
EFI="/boot/efi" # EFI system partition mountpoint
EFI_PARTITION="NONE"
VG_MB=0
SEPERATE_BOOT=0
MKINIT_HOOKS="shutdown"
# timezones used for manual setup if automatic fails
FULLZONES="$(awk '{print $3}' < /usr/share/zoneinfo/zone.tab |
grep ".*/.*" |
sort -ud)"
ZONES=""
for i in $(awk -F'/' '{print $1}' <<< "$FULLZONES" | uniq); do
ZONES="$ZONES $i -"
done
# list of available countries for reflector
COUNTRIES="$(reflector --list-countries |
awk '{print $1}' |
grep -v '[0-9]')"
COUNTRY=""
for i in $COUNTRIES; do
COUNTRY="$COUNTRY $i -"
done
# parsed locales from /etc/locale.gen
FULL_LOCALES="$(grep -v "# " /etc/locale.gen |
sed 's/#//g; s/ UTF-8//g' |
grep .UTF-8)"
LOCALES=""
for i in $FULL_LOCALES; do
LOCALES="$LOCALES $i -"
done
# parsed console maps from /usr/share/kbd/keymaps
FULL_CONSOLE_MAPS="$(ls -R /usr/share/kbd/keymaps |
grep "map.gz" |
sed 's/\.map\.gz//g' |
sort)"
CONSOLE_MAPS=""
for i in $FULL_CONSOLE_MAPS; do
CONSOLE_MAPS="$CONSOLE_MAPS $i -"
done
# raw set of available keyboard maps and their language
FULL_XORG_MAPS=("us English" "cm English" "gb English" "au English" "gh English" "za English"
"ng English" "ca French" "cd French" "gn French" "tg French" "fr French"
"de German" "at German" "ch German" "gr Greek" "hu Hungarian" "by Belarusian"
"is Icelandic" "cn Chinese" "ua Ukrainian" "cz Czech" "ru Russian" "dk Danish"
"it Italian" "br Portuguese" "pt Portuguese" "in Indian" "se Swedish" "ara Arabic"
"al Albanian" "am Armenian" "be Belgian" "bd Bangla" "ba Bosnian" "az Azerbaijani"
"bg Bulgarian" "dz Berber" "ma Arabic" "mm Burmese" "hr Croatian" "il Hebrew"
"ee Estonian" "ir Persian" "iq Iraqi" "fo Faroese" "fi Finnish" "ge Georgian"
"kg Kyrgyz" "kh Khmer" "kz Kazakh" "la Lao" "latam Spanish" "lt Lithuanian"
"me Montenegrin" "mk Macedonian" "mt Maltese" "mn Mongolian" "no Norwegian" "pl Polish"
"ro Romanian" "rs Serbian" "si Slovenian" "sk Slovak" "es Spanish" "sy Arabic"
"tj Tajik" "lk Sinhala" "th Thai" "tr Turkish" "tw Taiwanese" "uz Uzbek"
"vn Vietnamese" "kr Korean" "ie Irish" "pk Urdu" "mv Dhivehi" "epo Esperanto"
"np Nepali" "et Amharic" "sn Wolof" "ml Bambara" "tz Swahili" "ke Swahili"
"bw Tswana" "ph Filipino" "id Indonesian" "my Malay" "nec_vndr/jp Japanese" "jp Japanese"
"tm Turkmen" "bt Dzongkha" "nl Dutch" "lv Latvian" "md Moldavian" "mao Maori" "af Afghani")
XORG_MAPS=""
for i in "${FULL_XORG_MAPS[@]}"; do
XORG_MAPS="$XORG_MAPS $i"
done
# }
######################################################################
## Utility and Check Functions ##
######################################################################
chroot_cmd() {
arch-chroot $MNT /bin/bash -c "$1"
}
show_devices() {
lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE,MOUNTPOINT |
grep "disk\|part\|lvm\|crypt\|NAME\|TYPE\|SIZE" >/tmp/.devlist
dialog --backtitle "$BT" --title " $_PrepShowDev " --textbox /tmp/.devlist 0 0
}
set_debug() {
local cmd
echo "" >$LOG
set -x
exec 3>| $LOG
BASH_XTRACEFD=3
if hash st &>/dev/null; then
st -e tail -f $LOG &
elif hash termite &>/dev/null; then
termite -e tail -f $LOG &
else
xterm -e tail -f $LOG &
fi
}
cleanup() {
[[ -e $ANS ]] && rm -rf $ANS
[[ -e $OPT ]] && rm -rf $OPT
[[ -e $ERR ]] && rm -rf $ERR
[[ -e $LOG ]] && rm -rf $LOG
return 0
}
select_language() {
dialog --backtitle "$DIST Installer - (x86_64)" --title " Select Language " --menu \
"\nLanguage - sprache - taal - språk - lingua - idioma - nyelv - língua\n" 0 0 10 \
"1" "English (en_**)" \
"2" "Español (es_ES)" \
"3" "Português [Brasil] (pt_BR)" \
"4" "Português (pt_PT)" \
"5" "Français (fr_FR)" \
"6" "Russkiy (ru_RU)" \
"7" "Italiano (it_IT)" \
"8" "Nederlands (nl_NL)" \
"9" "Magyar (hu_HU)" \
"10" "Chinese (zh_CN)" 2> $ANS
# always source the english translation first.
# it acts as a set of fallback values should any other
# translations be missing or lack values
source /installer/english.trans 2>/dev/null
case "$(cat $ANS)" in
1) LOC="en_US.UTF-8" ;;
2) source /installer/spanish.trans 2>/dev/null && LOC="es_ES.UTF-8" ;;
3) source /installer/p_brasil.trans 2>/dev/null && LOC="pt_BR.UTF-8" ;;
4) source /installer/portuguese.trans 2>/dev/null && LOC="pt_PT.UTF-8" ;;
5) source /installer/french.trans 2>/dev/null && LOC="fr_FR.UTF-8" ;;
6) source /installer/russian.trans 2>/dev/null && LOC="ru_RU.UTF-8" ;;
7) source /installer/italian.trans 2>/dev/null && LOC="it_IT.UTF-8" ;;
8) source /installer/dutch.trans 2>/dev/null && LOC="nl_NL.UTF-8" ;;
9) source /installer/hungarian.trans 2>/dev/null && LOC="hu_HU.UTF-8" ;;
10) source /installer/chinese.trans 2>/dev/null && LOC="zh_CN.UTF-8" ;;
*) clear && exit 0
esac
sed -i "s/#en_US.UTF-8/en_US.UTF-8/" /etc/locale.gen
[[ $LOC != "en_US.UTF-8" ]] && sed -i "s/#${LOC}/${LOC}/" /etc/locale.gen
locale-gen &>/dev/null
export LANG="$LOC"
}
identify_system() {
if grep -q 'Apple' /sys/class/dmi/id/sys_vendor; then
modprobe -r -q efivars || true
else
modprobe -q efivarfs
fi
if [[ -d "/sys/firmware/efi/" ]]; then
if grep -q /sys/firmware/efi/efivars <<< "$(mount)"; then
mount -t efivarfs efivarfs /sys/firmware/efi/efivars
fi
SYS="UEFI"
else
SYS="BIOS"
fi
readonly BT="$DIST Installer - $SYS (x86_64) - Version $VER"
}
check_requirements() {
local msg cur_user
cur_user="$(whoami)"
if [[ $cur_user != "root" ]] || ! (ping -c 1 archlabslinux.com &>/dev/null || ping -c 1 bitbucket.org &>/dev/null || ping -c 1 github.com &>/dev/null); then
[[ $cur_user != "root" ]] && msg="$_NotRoot" || msg="$_NoNetwork"
infobox "$_ErrTitle" "$msg\n$_Exit"
clear && exit 1
fi
echo "" > $ERR
return 0
}
check_for_errors() {
# check if last process exited with non zero
if (( $? != 0 )); then # grep -wqi "$1" "$ERR"
# clean escape sequences from the error message
local err
err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
# show the error message if any
[[ $err ]] && msgbox "$_ErrTitle" "$err"
local yes="Manual Fix"
local no="Wipe Install"
if ! yesno "$_ErrTitle" "$_ErrChoice" 0 0 --yes-label "$yes" --no-label "$no"; then
for d in $MNT/?*; do
if ! grep -q "boot" <<< "$d"; then
rm -rf "$d"
fi
done
fi
cleanup
return 1
fi
return 0
}
check_parts_are_mounted() {
grep -q "$MNT" <<< "$(lsblk -o MOUNTPOINT)" && return 0
# partitions aren't mounted
msgbox "$_ErrTitle" "$_ErrNoMount"
return 1
}
check_base_unpacked() {
[[ -e $MNT/etc ]] && return 0
# base isn't unpacked
msgbox "$_ErrTitle" "$_ErrNoBase"
return 1
}
check_part_is_crypt_or_lvm() {
local part="$1"
local fullblock
fullblock="$(lsblk -lno NAME,FSTYPE,TYPE)"
# Identify if $part is "crypt" (LUKS on LVM, or LUKS alone)
if grep -qi "crypt" <<< "$(lsblk -lno TYPE "$part")"; then
LUKS=1
LUKS_NAME="$(sed "s~^/dev/mapper/~~g" <<< "$part")"
local cryptlv
cryptlv="$(grep "lvm" <<< "$fullblock" |
grep -i "crypto_luks" |
awk '{print "/dev/mapper/"$1}' |
uniq)"
for i in $cryptlv; do
if grep -q "$LUKS_NAME" <<< "$(lsblk -lno NAME "$i")"; then
LUKS_DEV="$LUKS_DEV cryptdevice=$i:$LUKS_NAME"
LVM=1
break
fi
done
local crypt
crypt="$(grep "part" <<< "$fullblock" |
grep -i "crypto_luks" |
awk '{print "/dev/"$1}' |
uniq)"
for i in $crypt; do
if grep -q "$LUKS_NAME" <<< "$(lsblk -lno NAME "$i")"; then
LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$i" |
grep 'part' |
grep -i 'crypto_luks' |
awk '{print $1}')"
LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
break
fi
done
elif grep -qi "lvm" <<< "$(lsblk -lno TYPE "$part")"; then
LVM=1
LV_NAME="$(sed "s~^/dev/mapper/~~g" <<< "$part")"
local lvcrypt
lvcrypt="$(grep "crypt" <<< "$fullblock" |
grep -i "lvm2_member" |
awk '{print "/dev/mapper/"$1}' |
uniq)"
for i in $lvcrypt; do
if grep -q "$LV_NAME" <<< "$(lsblk -lno NAME "$i")"; then
LUKS_NAME="$(sed 's~/dev/mapper/~~g' <<< "$i")"
break
fi
done
local crypt
crypt="$(grep "part" <<< "$fullblock" |
grep -i "crypto_luks" |
awk '{print "/dev/"$1}' |
uniq)"
for i in $crypt; do
if grep -q "$LUKS_NAME" <<< "$(lsblk -lno NAME "$i")"; then
LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$i" |
grep 'part' |
grep -i 'crypto_luks' |
awk '{print $1}')"
LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
LUKS=1
break
fi
done
fi
}
######################################################################
## Dialog Functions ##
######################################################################
getpass() {
dialog --backtitle "$BT" --title " $1 " --insecure --passwordbox "$2" ${3:-0} ${4:-0} 2>$ANS || return 1
return 0
} # }}
getinput() {
dialog --backtitle "$BT" --title " $1 " --inputbox "$2" ${4:-0} ${5:-0} "$3" 2>$ANS || return 1
return 0
} # }}}
msgbox() {
if [[ $# -gt 4 ]]; then
dialog --backtitle "$BT" --title " $1 " $5 "$6" --msgbox "$2" ${3:-0} ${4:-0}
else
dialog --backtitle "$BT" --title " $1 " --msgbox "$2" ${3:-0} ${4:-0}
fi
return 0
} # }}
infobox() {
local bt="${BT:-$DIST Installer - (x86_64)}"
dialog --backtitle "$bt" --title " $1 " --infobox "$2" ${3:-0} ${4:-0}
sleep 2
} # }}
yesno() {
# when additional args (--yes-label, --no-label) are passed ensure text ($6, $8) is quoted
if [[ $# -eq 8 ]]; then
dialog --backtitle "$BT" --title " $1 " $5 "$6" $7 "$8" --yesno "$2" $3 $4 && return 0
return 1
fi
dialog --backtitle "$BT" --title " $1 " --yesno "$2" ${3:-0} ${4:-0} && return 0
return 1
} # }}
######################################################################
## System Settings Functions ##
######################################################################
set_keymap() {
KEYMAP=""
console_keymap() {
local map
dialog --backtitle "$BT" --title " $_CMapTitle " --menu "$_CMapBody" 0 0 16 $CONSOLE_MAPS 2>$ANS
map="$(cat $ANS)"
map="${map:-us}"
localectl set-keymap
echo "KEYMAP=$map" >/tmp/vconsole.conf
}
xorg_keymap() {
local map
dialog --backtitle "$BT" --title " $_PrepLayout " --menu "$_XMapBody" 0 0 16 $XORG_MAPS 2>$ANS
map="$(sed 's/_.*//' $ANS)"
map="${map:-us}"
KEYMAP="$map"
setxkbmap "$map" 2>$ERR
check_for_errors || return 1
cat >/tmp/00-keyboard.conf <<EOF
# Use localectl(1) to instruct systemd-localed to update it.
Section "InputClass"
Identifier "system-keyboard"
MatchIsKeyboard "on"
Option "XkbLayout" "$map"
EndSection
EOF
cat >/tmp/keyboard <<EOF
# KEYBOARD CONFIGURATION FILE
# Consult the keyboard(5) manual page.
XKBMODEL=""
XKBLAYOUT="$map"
XKBVARIANT=""
XKBOPTIONS=""
BACKSPACE="guess"
EOF
}
xorg_keymap
if grep -qw "^$KEYMAP$" <<< "$FULL_CONSOLE_MAPS"; then
echo "KEYMAP=${KEYMAP:-us}" >/tmp/vconsole.conf
else
console_keymap
fi
}
set_locale() {
local locale
dialog --backtitle "$BT" --title "$_ConfLocale" \
--menu "$_LocaleBody" 0 0 12 $LOCALES 2>$ANS || return 1
locale="$(cat $ANS)"
infobox "$_ConfLocale" "$_GenLocale $locale\n\n"
sed -i "s/en_US.UTF-8/${locale}/g" $MNT/etc/locale.conf
cp -f $MNT/etc/locale.conf $MNT/etc/default/locale
sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${locale}/${locale}/g" $MNT/etc/locale.gen
chroot_cmd "locale-gen" >/dev/null 2>$ERR
check_for_errors || return 1
set_timezone
}
set_timezone() {
local zone subzone
dialog --backtitle "$BT" --title " $_TimeZTitle " --menu "$_TimeZBody" 0 0 10 $ZONES 2>$ANS || return 1
zone="$(cat $ANS)"
for i in $(grep "$zone/" <<< "$FULLZONES" | awk -F'/' '{print $2}' | sort -ud); do
SUBZONES="$SUBZONES $i -"
done
dialog --backtitle "$BT" --title " $_TimeZTitle " --menu "$_TimeSubZBody" 0 0 10 $SUBZONES 2>$ANS || return 1
subzone="$(cat $ANS)"
if [[ $zone && $subzone ]] && yesno "$_TimeZTitle" "$_TimeZQ $zone/$subzone?\n\n"; then
chroot_cmd "ln -sf /usr/share/zoneinfo/$zone/$subzone /etc/localtime" 2>$ERR
check_for_errors || return 1
else
set_timezone
fi
# step done and continue to set hwclock
TIMEZONE_SET="True"
set_hwclock
}
set_hwclock() {
# try setting the default setting for hwclock
chroot_cmd "hwclock --systohc --utc"
if (( $? != 0 )); then
# when errors occur attempt handling them with a fallback
chroot_cmd "hwclock --systohc --utc --directisa"
# if still failing, alert the user and just continue
if (( $? != 0 )); then
msgbox "$_ErrTitle" "Hwclock setup and fallback attempts failed..\n\nContinuing anyway."
fi
fi
}
set_hostname() {
local hostentry
getinput "$_ConfHost" "$_HostNameBody" "${DIST,,}" 14 60 || return 1
hostentry="$(cat $ANS)"
echo "$hostentry" >$MNT/etc/hostname
cat > $MNT/etc/hosts << EOF
127.0.0.1 localhost
127.0.1.1 $hostentry
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF
}
root_password() {
getpass "$_ConfRoot" "$_RootBody" 10 40 || return 1
PASSWD="$(cat $ANS)"
getpass "$_ConfRoot" "$_RootBody2" 10 40 || return 1
PASSWD2="$(cat $ANS)"
if [[ "$PASSWD" == "$PASSWD2" ]]; then
echo -e "$PASSWD\n$PASSWD" >/tmp/.passwd
chroot_cmd "passwd root" </tmp/.passwd >/dev/null 2>$ERR
check_for_errors || return 1
rm -f /tmp/.passwd
SET_ROOT_PASSWD="True"
return 0
fi
# passwords don't match
msgbox "$_ErrTitle" "${_PassErr}$_TryAgain"
root_password
}
create_user() {
local newuser
getinput "$_UserTitle" "$_UserBody" "" || return 1
newuser="$(cat $ANS)"
# bad name answer
while [[ ${#newuser} -eq 0 || $newuser =~ \ |\' || $newuser =~ [^a-z0-9\ ] ]]; do
getinput "$_UserTitle" "$_UserErrBody" "" 14 40 || { break; return 1; }
newuser="$(cat $ANS)"
done
getpass "$_ConfUser" "$_UserPass $newuser" 10 40 || return 1
PASSWD="$(cat $ANS)"
getpass "$_ConfUser" "$_UserPass2 $newuser" 10 40 || return 1
PASSWD2="$(cat $ANS)"
# passwords don't match
while [[ "$PASSWD" != "$PASSWD2" ]]; do
msgbox "$_ErrTitle" "${_PassErr}$_TryAgain" 8 60
getpass "$_ConfUser" "$_UserPass $newuser" 10 40 || { break; return 1; }
PASSWD="$(cat $ANS)"
getpass "$_ConfUser" "$_UserPass2 $newuser" 10 40 || { break; return 1; }
PASSWD2="$(cat $ANS)"
done
infobox "$_ConfUser" "$_UserSetBody"
echo -e "$PASSWD\n$PASSWD" >/tmp/.passwd
# for first user created, swap the live user account
if [[ -e $MNT/home/$LIVEUSER ]]; then
chroot_cmd "passwd $LIVEUSER" </tmp/.passwd >/dev/null 2>$ERR
check_for_errors || return 1
sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" $MNT/etc/sudoers
local tty_autologin
if [[ -e $MNT/etc/systemd/system/autologin@.service ]]; then
tty_autologin="systemd/system/autologin@.service"
elif [[ -e $MNT/etc/systemd/system/getty@tty1.service.d/override.conf ]]; then
tty_autologin="systemd/system/getty@tty1.service.d/override.conf"
elif [[ -e $MNT/etc/systemd/system/getty@tty1.service.d/autologin.conf ]]; then
tty_autologin="systemd/system/getty@tty1.service.d/autologin.conf"
fi
for f in group gshadow passwd shadow $tty_autologin; do
sed -i "s/${LIVEUSER}/${newuser}/g" "$MNT/etc/$f"
done
chroot_cmd "mv /home/$LIVEUSER /home/$newuser" 2>$ERR
check_for_errors || return 1
chroot_cmd "chown -R $newuser:users /home/$newuser" 2>$ERR
check_for_errors || return 1
chroot_cmd "usermod -aG rfkill,wheel,autologin,network,lp,storage,power,video,audio,lp $newuser" 2>$ERR
else
# create new user account
chroot_cmd "useradd $newuser -m -g users -G rfkill,wheel,autologin,network,lp,storage,power,video,audio,lp -s /bin/zsh" 2>$ERR
check_for_errors || return 1
chroot_cmd "passwd $newuser" < /tmp/.passwd >/dev/null 2>$ERR
check_for_errors || return 1
chroot_cmd "cp -R /etc/skel/ /home/$newuser" 2>$ERR
check_for_errors || return 1
chroot_cmd "chown -R ${newuser}:users /home/$newuser" 2>$ERR
fi
check_for_errors || return 1
[[ -e /tmp/.passwd ]] && rm /tmp/.passwd
# if all the needed steps are not finished, bail early
[[ -z $UNPACKED_BASE || -z $TIMEZONE_SET || -z $SET_ROOT_PASSWD || -z $BOOT_DONE ]] && return 0
local yes="Exit and Reboot"
local no="Go Back"
yesno "$_InstFin" "$_InstFinBody" 0 0 --yes-label "$yes" --no-label "$no" && { unmount_partitions; reboot; } || return 1
}
######################################################################
## System Partitioning Functions ##
######################################################################
confirm_mount() {
local part="$1"
local mntpnt="$2"
# partition failed to mount properly
if ! grep -q "$mntpnt" <<< "$(mount)"; then
infobox "$_MntTitle" "$_MntFail"
return 1
fi
# mount was successful
infobox "$_MntTitle" "$_MntSucc"
# sed s~${part}$' -'~~
# remove mounted partition from dialog list
PARTS="$(sed "s~${part} [0-9]*[G-M]~~; s~${part} [0-9]*\.[0-9]*[G-M]~~" <<< "$PARTS")"
# decrement the number of partitions left, used in while loop
((PART_COUNT--))
}
mount_partition() {
local part="$1"
local mntp="$2"
mkdir -p "${MNT}$mntp"
# get mount options if any
if (( ${#FS_OPTS[@]} > 0 )) && select_mount_opts "$part"; then
mount -o $MNT_OPTS "$part" "${MNT}$mntp" 2>$ERR
else
# generic auto mount
mount "$part" "${MNT}$mntp" 2>$ERR
fi
check_for_errors || return 1
confirm_mount "$part" "${MNT}$mntp" || return 1
check_part_is_crypt_or_lvm "$part"
}
unmount_partitions() {
swapoff -a
for i in $(mount | grep "$MNT" | awk '{print $3}' | sort -r); do
umount -r "$i" &>/dev/null
done
}
find_partitions() {
local str="$1"
# string of partitions as: /TYPE/PART SIZE
PARTS="$(lsblk -lno TYPE,NAME,SIZE |
grep "$str" |
sed 's|^part|/dev/|g; s|^lvm|/dev/mapper/|g; s|^crypt|/dev/mapper/|g' |
awk '{print $1$2 " " $3}' |
sort -u)"
PART_COUNT=0
for i in $PARTS; do
((PART_COUNT++))
done
# due to storing the device size, we need half the number of fields
PART_COUNT=$((PART_COUNT / 2))
local err="NONE"
case $str in
'part\|lvm\|crypt')
([[ $PART_COUNT -eq 0 ]] || [[$SYS == "UEFI" && $PART_COUNT -lt 2 ]]) && err="$_PartErrBody"
;;
'part\|crypt')
(( PART_COUNT == 0 )) && err="$_LvmPartErrBody"
;;
'part\|lvm')
(( PART_COUNT < 2 )) && err="$_LuksPartErrBody"
esac
if [[ $err != "NONE" ]]; then
msgbox "$_ErrTitle" "$err"
select_device && create_partitions "$DEVICE" || return 1
fi
}
create_partitions() {
local choice
local device="$1"
dialog --backtitle "$BT" --title " $_PartTitle " --menu "$_PartBody" 0 0 5 \
"$_PartWipe" "BIOS & UEFI" \
"$_PartAuto" "BIOS & UEFI" \
"gparted" "BIOS & UEFI" \
"cfdisk" "BIOS/MBR" \
"parted" "UEFI/GPT" 2>$ANS
choice="$(cat $ANS)"
[[ -z $choice ]] && return 1 || clear
if [[ $choice != "$_PartWipe" && $choice != "$_PartAuto" ]]; then
$choice "$device"
elif [[ $choice == "$_PartWipe" ]]; then
wipe_device "$device" && create_partitions "$device"
else
auto_partition "$device"
fi
}
auto_partition() {
local device="$1"
if [[ $SYS == "BIOS" ]]; then
_PartBody2="will be destroyed.\n\nAn ext4 partition will be created using all available space."
fi
if yesno "$_PrepParts" "$_PartBody1 $device $_PartBody2 $_PartBody3"; then
current_parts="$(parted -s "$device" print |
awk '/^ / {print $1}' |
sort -r)"
for part in $current_parts; do
parted -s "$device" rm $part 2>$ERR
check_for_errors || { break; return 1; }
done
part_table="$(parted -s "$device" print |
grep -i 'partition table' |
awk '{print $3}')"
if [[ $SYS == "BIOS" && $part_table != "msdos" ]]; then
parted -s "$device" mklabel msdos 2>$ERR
elif [[ $SYS == "UEFI" && $part_table != "gpt" ]]; then
parted -s "$device" mklabel gpt 2>$ERR
fi
check_for_errors || return 1
if [[ $SYS == "BIOS" ]]; then
parted -s "$device" mkpart primary ext4 1MiB 100% 2>$ERR
else
parted -s "$device" mkpart ESP fat32 1MiB 513MiB 2>$ERR
check_for_errors || return 1
parted -s "$device" set 1 boot on 2>$ERR
check_for_errors || return 1
parted -s "$device" mkpart primary ext4 513MiB 100% 2>$ERR
fi
check_for_errors || return 1
lsblk "$device" -o NAME,TYPE,FSTYPE,SIZE >/tmp/.devlist
dialog --backtitle "$BT" --title " $_PrepParts " --textbox /tmp/.devlist 0 0
fi
}
wipe_device() {
local device="$1"
if yesno "$_PartWipe" "$_PartBody1 $device $_PartBody2 $_PartBody3"; then
clear
echo -e "Secure wiping $device this will take a while.."
wipe -Ifre "$device"
else
create_partitions "$device"
fi
}
select_swap() {
local ans msg mem tot swap_part
mem="$(grep MemTotal /proc/meminfo |
awk '{print $2/1024}' |
sed 's/\..*//')"
dialog --backtitle "$BT" --title " $_PrepMount " --menu "$_SelSwpBody" 0 0 7 \
"$_Skip" "-" \
"$_SelSwpFile" "${mem}M" \
$PARTS 2>$ANS || return 0
ans="$(cat $ANS)"
if [[ $ans && $ans != "$_Skip" ]]; then
if [[ $ans == "$_SelSwpFile" ]]; then
msg="Enter size for swapfile below\n\nM = MB, G = GB"
getinput "$_SelSwpFile" "$msg" "${mem}M" 10 40 || return 0
tot="$(cat $ANS)"
# bad answer
while ! [[ ${tot: -1} =~ [MG] ]]; do
msgbox "$_SelSwpFile" "\n$_SelSwpFile $_ErrTitle: M = MB, G = GB\n\n" 7 40
msg="Enter size for swapfile below\n\nM = MB, G = GB"
getinput "$_SelSwpFile" "$msg" "${mem}M" 10 40 || { break; return 0; }
tot="$(cat $ANS)"
done
fallocate -l "$tot" $MNT/swapfile 2>$ERR
check_for_errors || return 1
chmod 600 $MNT/swapfile 2>$ERR
check_for_errors || return 1
mkswap $MNT/swapfile >/dev/null 2>$ERR
check_for_errors || return 1
swapon $MNT/swapfile >/dev/null 2>$ERR
check_for_errors || return 1
else
swap_part="$(cat $ANS)"
if [[ $(lsblk -o FSTYPE "$swap_part" | grep -i "swap") != "swap" ]]; then
if yesno "$_PrepMount" "\nmkswap $swap_part\n$_ContinueYN"; then
mkswap "$swap_part" >/dev/null 2>$ERR
check_for_errors || return 1
else
return 0
fi
fi
swapon "$swap_part" >/dev/null 2>$ERR
check_for_errors || return 1
# sed s~${swap_part}$' -'~~
# remove mounted partition from dialog list
PARTS="$(sed "s~${swap_part} [0-9]*[G-M]~~; s~${swap_part} [0-9]*\.[0-9]*[G-M]~~" <<< "$PARTS")"
((PART_COUNT--))
fi
fi
return 0
}
select_device() {
local msg
if [[ $1 == "bootloader" ]]; then
msg="$_DevSelTitle $_DevSelBoot $ROOT_PARTITION\n"
else
msg="$_DevSelBody"
fi
DEVICE=""
DEVS="$(lsblk -lno NAME,SIZE,TYPE |
grep 'disk' |
awk '{print "/dev/" $1 " " $2}' |
sort -u)"
dialog --backtitle "$BT" --title " $_DevSelTitle " --menu "$msg" 0 0 4 $DEVS 2>$ANS || return 1
[[ $1 == "bootloader" && $(cat $ANS) != "" ]] && BOOT_DEVICE="$(cat $ANS)"
[[ $(cat $ANS) != "" ]] && DEVICE="$(cat $ANS)" || return 1
}
select_filesystem() {
local part="$1"
FS_OPTS=()
dialog --backtitle "$BT" --title " $_FSTitle " --menu "$_FSBody" 0 0 12 \
"$_Skip" "-" \
"ext4" "mkfs.ext4 -q" \
"ext3" "mkfs.ext3 -q" \
"ext2" "mkfs.ext2 -q" \
"vfat" "mkfs.vfat -F32" \
"btrfs" "mkfs.btrfs -f" \
"ntfs" "mkfs.ntfs -q" \
"f2fs" "mkfs.f2fs" \
"jfs" "mkfs.jfs -q" \
"nilfs2" "mkfs.nilfs2 -q" \
"reiserfs" "mkfs.reiserfs -q" \
"xfs" "mkfs.xfs -f" 2>$ANS || return 1
local choice
choice="$(cat $ANS)"
case $choice in
"$_Skip") FS_TYPE="$_Skip" ;;
ext4) FS_TYPE="mkfs.ext4 -q"
FS_OPTS=(dealloc discard noacl noatime nobarrier nodelalloc) ;;
ext3) FS_TYPE="mkfs.ext3 -q" ;;
ext2) FS_TYPE="mkfs.ext2 -q" ;;
vfat) FS_TYPE="mkfs.vfat -F32" ;;
ntfs) FS_TYPE="mkfs.ntfs -q" ;;
btrfs) FS_TYPE="mkfs.btrfs -f"
FS_OPTS=(autodefrag "compress=zlib" "compress=lzo" "compress=no"
"compress-force=zlib" "compress-force=lzo" discard noacl noatime
nodatasum nospace_cache recovery skip_balance space_cache ssd ssd_spread)
modprobe btrfs
;;
f2fs) FS_TYPE="mkfs.f2fs"
FS_OPTS=(data_flush disable_roll_forward disable_ext_identify
discard fastboot flush_merge inline_xattr inline_data inline_dentry
no_heap noacl nobarrier noextent_cache noinline_data norecovery)
modprobe f2fs ;;
jfs) FS_TYPE="mkfs.jfs -q"
FS_OPTS=(discard "errors=continue" "errors=panic" nointegrity) ;;
nilfs2) FS_TYPE="mkfs.nilfs2 -q"
FS_OPTS=(discard nobarrier "errors=continue"
"errors=panic" "order=relaxed" "order=strict" norecovery)
;;
reiserfs) FS_TYPE="mkfs.reiserfs -q"
FS_OPTS=(acl nolog notail replayonly user_xattr) ;;
xfs) FS_TYPE="mkfs.xfs -f"
FS_OPTS=(discard filestreams ikeep largeio
noalign nobarrier norecovery noquota wsync)
;;
*) return 1
esac
if [[ $FS_TYPE != "$_Skip" ]]; then
if yesno "$_FSTitle" "\nFormat $part as $choice?\n\n"; then
infobox "$_FSTitle" "\nFormatting $part as $choice\n\n"
$FS_TYPE $part >/dev/null 2>$ERR
check_for_errors || return 1
else
select_filesystem "$part" || return 1
fi
fi
return 0
}
select_mount_opts() {
echo "" >$OPT
local part="$1"
local list=""
for i in "${FS_OPTS[@]}"; do
list="$list $i - off"
done
local title="$(sed "s/.*\.//g; s/-.*//g" <<< "$FS_TYPE") Mount Options"
dialog --backtitle "$BT" --title " $title " --checklist "$_MntBody" 0 0 7 $list 2>$OPT || return 1
MNT_OPTS="$(cat $OPT | sed 's/ /,/g; $s/,$//')"
if [[ $MNT_OPTS ]]; then
if ! yesno "$title" "${_MntConfBody}$MNT_OPTS" 9 45; then
select_mount_opts
fi
return 0
fi
# no mount options were chosen or cancel was pressed
return 1
}
select_boot_setup() {
# choose mountpoint and bootloader
if [[ $SYS == "UEFI" ]]; then
dialog --backtitle "$BT" --title " $_PrepMount " --menu "$_MntUefiBody" 0 0 2 \
"grub" "/boot/efi" \
"systemd-boot" "/boot" 2>$ANS || return 1
BOOTLOADER="$(cat $ANS)"
BOOTLOADER="${BOOTLOADER:-grub}"
# $EFI only needs to be modified when not using grub
# otherwise the default /boot/efi works
if [[ $BOOTLOADER != "grub" ]]; then
EFI="/boot"
fi
mkdir -p "${MNT}$EFI"
mount "$EFI_PARTITION" "${MNT}$EFI" 2>$ERR
check_for_errors || return 1
confirm_mount "$EFI_PARTITION" "${MNT}$EFI" || return 1
else
dialog --backtitle "$BT" --title " $_InstBiosBtTitle " \
--menu "$_InstBiosBtBody" 0 0 2 \
"grub" "-" \
"syslinux" "-" 2>$ANS || return 1
BOOTLOADER="$(cat $ANS)"
BOOTLOADER="${BOOTLOADER:-grub}"
if [[ $BOOTLOADER == "grub" ]]; then
select_device "bootloader" || return 1
BOOT_DEVICE="$DEVICE"
else
dialog --backtitle "$BT" --title " $_InstSysTitle " --menu "$_InstSysBody" 0 0 2 \
"syslinux-install_update -iam" "[MBR]" \
"syslinux-install_update -i" "[/]" 2>$ANS || return 1
SYSLNUX_CMD="$(cat $ANS)"
SYSLNUX_CMD="${SYSLNUX_CMD:-syslinux-install_update -iam}"
BOOT_DEVICE="$ROOT_PARTITION / (root)"
if grep -q "iam" <<< "$SYSLNUX_CMD"; then
BOOT_DEVICE="$ROOT_PARTITION MBR"
fi
fi
fi
return 0
}
select_efi_partition() {
dialog --backtitle "$BT" --title " $_PrepMount " \
--menu "$_SelUefiBody" 0 0 7 $PARTS 2>$ANS || return 1
EFI_PARTITION="$(cat $ANS)"
BOOT_DEVICE="$EFI_PARTITION"
format_efi_as_vfat() {
infobox "$_FSTitle" "\nFormatting $BOOT_DEVICE as vfat/fat32.\n"
mkfs.vfat -F32 "$EFI_PARTITION" >/dev/null 2>$ERR
check_for_errors || return 1
}
if grep -q 'fat' <<< "$(fsck -N "$EFI_PARTITION")"; then
local yes="Skip Formatting"
local no="Format $EFI_PARTITION"
local msg="$_FormUefiBody $EFI_PARTITION $_FormUefiBody2"
if ! yesno "$_PrepMount" "$msg" 0 0 --yes-label "$yes" --no-label "$no"; then
format_efi_as_vfat || return 1
fi
else
format_efi_as_vfat || return 1
fi
return 0
}
select_install_partitions() {
msgbox "$_PrepMount" "$_WarnMount1 '$_Skip' $_WarnMount2"
lvm_detect
# prepare partition list for menu
unmount_partitions
find_partitions 'part\|lvm\|crypt' || return 1
# select root (/)
dialog --backtitle "$BT" --title "$_PrepMount" \
--menu "$_SelRootBody" 0 0 7 $PARTS 2>$ANS || return 1
ROOT_PARTITION="$(cat $ANS)"
# choose filesystem
select_filesystem "$ROOT_PARTITION" || return 1
# choose mount options and mount the partition
mount_partition "$ROOT_PARTITION" || return 1
select_swap || return 1
if [[ $SYS == "UEFI" ]]; then
select_efi_partition || return 1
fi
select_boot_setup || return 1
# remaining partitions
while (( PART_COUNT > 0 )); do
dialog --backtitle "$BT" --title " $_PrepMount " \
--menu "$_ExtPartBody" 0 0 7 "$_Done" "-" $PARTS 2>$ANS
local part="$(cat $ANS)"
# return to main menu
if [[ $? == 1 || $part == "$_Done" ]]; then
break
return 0
else
select_filesystem "$part" || return 1
local title="$_PrepMount $part"
local examples
[[ $SYS == "UEFI" ]] && examples="/home /var" || examples="/boot /home /var"
# get mountpoint
getinput "$title" "${_ExtPartBody1}$examples\n" "/" || { break; return 1; }
local mntp="$(cat $ANS)"
# bad mountpoint
while [[ ${mntp:0:1} != "/" || ${#mntp} -le 1 || $mntp =~ \ |\' ]]; do
msgbox "$_ErrTitle" "$_ExtErrBody"
getinput "$title" "${_ExtPartBody1}$examples\n" "/" || { break 2; return 1; }
mntp="$(cat $ANS)"
done
# mount it
mount_partition "$part" "$mntp" || return 1
# add needed hooks for certain mountpoints
if [[ $mntp == "/usr" ]]; then
! grep -q "usr" <<< "$MKINIT_HOOKS" && MKINIT_HOOKS="usr $MKINIT_HOOKS"
elif [[ $mntp == "/boot" ]]; then
if grep -q "lvm" <<< "$(lsblk -lno TYPE "$part")"; then
SEPERATE_BOOT=2
else
SEPERATE_BOOT=1
fi
fi
((PART_COUNT--))
fi
done
}
######################################################################
## Encryption (dm_crypt) Functions ##
######################################################################
luks_pass() {
getpass "$_PrepLUKS" "$_LuksPassBody" || return 1
PASSWD="$(cat $ANS)"
getpass "$_PrepLUKS" "$_UserPass2 $LUKS_ROOT_NAME" || return 1
PASSWD2="$(cat $ANS)"
if [[ $PASSWD != "$PASSWD2" ]]; then
msgbox "$_ErrTitle" "${_PassErr}$_TryAgain"
luks_pass
fi
LUKS_PASSWD="$PASSWD"
}
luks_open() {
unmount_partitions
find_partitions 'part\|crypt\|lvm'
dialog --backtitle "$BT" --title " $_LuksOpen " \
--menu "$_LuksMenuBody" 15 50 7 $PARTS 2>$ANS || return 1
LUKS_PART="$(cat $ANS)"
getinput "$_LuksOpen" "$_LuksOpenBody" "cryptroot" || return 1
LUKS_ROOT_NAME="$(cat $ANS)"
if luks_pass; then
infobox "$_LuksOpen" "$_LuksWaitBody $LUKS_ROOT_NAME $_LuksWaitBody2 $LUKS_PART\n"
echo "$LUKS_PASSWD" | cryptsetup open --type luks "$LUKS_PART" "$LUKS_ROOT_NAME" 2>$ERR
check_for_errors || return 1
luks_show
fi
}
luks_setup() {
modprobe -a dm-mod dm_crypt
unmount_partitions
find_partitions 'part\|lvm'
dialog --backtitle "$BT" --title "$_LuksEncrypt" \
--menu "$_LuksEncryptBody" 0 0 7 $PARTS 2>$ANS || return 1
LUKS_PART="$(cat $ANS)"
getinput "$_LuksEncrypt" "$_LuksOpenBody" "cryptroot" || return 1
LUKS_ROOT_NAME="$(cat $ANS)"
luks_pass || return 1
}
luks_default() {
if luks_setup; then
infobox "$_LuksEncrypt" "$_LuksWaitBody $LUKS_ROOT_NAME $_LuksWaitBody2 $LUKS_PART\n"
echo "$LUKS_PASSWD" | cryptsetup -q luksFormat "$LUKS_PART" 2>$ERR
check_for_errors || return 1
echo "$LUKS_PASSWD" | cryptsetup open "$LUKS_PART" "$LUKS_ROOT_NAME" 2>$ERR
check_for_errors || return 1
luks_show
fi
}
luks_key() {
if luks_setup; then
getinput "$_PrepLUKS" "$_LuksCipherKey" "-s 512 -c aes-xts-plain64" || return 1
local msg="$_LuksWaitBody $LUKS_ROOT_NAME $_LuksWaitBody2 $LUKS_PART\n"
infobox "$_LuksEncryptAdv" "$msg"
echo "$LUKS_PASSWD" | cryptsetup -q "$(cat $ANS)" luksFormat "$LUKS_PART" 2>$ERR
check_for_errors || return 1
echo "$LUKS_PASSWD" | cryptsetup open "$LUKS_PART" "$LUKS_ROOT_NAME" 2>$ERR
check_for_errors || return 1
luks_show
fi
}
luks_show() {
echo -e "$_LuksEncryptSucc" >/tmp/.devlist
lsblk -o NAME,TYPE,FSTYPE,SIZE "$LUKS_PART" |
grep "part\|crypt\|NAME\|TYPE\|FSTYPE\|SIZE" >>/tmp/.devlist
dialog --backtitle "$BT" --title " $_LuksEncrypt " --textbox /tmp/.devlist 0 0
}
luks_menu() {
dialog --backtitle "$BT" --title " $_PrepLUKS " \
--menu "${_LuksMenuBody}${_LuksMenuBody2}${_LuksMenuBody3}" 0 0 4 \
"$_LuksOpen" "cryptsetup open --type luks" \
"$_LuksEncrypt" "cryptsetup -q luksFormat" \
"$_LuksEncryptAdv" "cryptsetup -q -s -c luksFormat" \
"$_Back" "-" 2> $ANS || return 0
case "$(cat $ANS)" in
"$_LuksOpen") luks_open ;;
"$_LuksEncrypt") luks_default ;;
"$_LuksEncryptAdv") luks_key ;;
*) return 0
esac
luks_menu
}
luks_keyfile() {
# Only used when choosing grub as bootloader. Without a keyfile, during boot
# the user will be asked to enter password for decryption twice, this is annoying
if [[ ! -e $MNT/crypto_keyfile.bin ]] && yesno "$_LuksKeyFileTitle" "$_LuksKeyFile"; then
infobox "$_LuksKeyFileTitle" "$_LuksKeyFileCreate\n"
local dev
dev="$(lsblk -lno NAME,UUID,TYPE |
grep "part\|crypt\|lvm" |
grep "$LUKS_UUID" |
awk '{print $1}')"
(( LVM == 1 )) && dev="/dev/mapper/$dev" || dev="/dev/$dev"
chroot_cmd "dd bs=512 count=8 if=/dev/urandom of=/crypto_keyfile.bin" &>/dev/null
chroot_cmd "chmod 000 /crypto_keyfile.bin" &>/dev/null
chroot_cmd "echo '$LUKS_PASSWD' | cryptsetup luksAddKey $dev /crypto_keyfile.bin" &>/dev/null
sed -i 's/FILES=()/FILES=(\/crypto_keyfile.bin)/g' $MNT/etc/mkinitcpio.conf &>/dev/null
chroot_cmd "mkinitcpio -p linux" 2>$ERR &>/dev/null
check_for_errors || return 1
fi
return 0
}
######################################################################
## Logical Volume Management Functions ##
######################################################################
lvm_detect() {
LVM_PV="$(pvs -o pv_name --noheading 2>/dev/null)"
LV_VG="$(vgs -o vg_name --noheading 2>/dev/null)"
LV="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
if [[ $LV && $LV_VG && $LVM_PV ]]; then
infobox "$_PrepLVM" "$_LvmDetBody"
modprobe dm-mod 2>$ERR
check_for_errors || return 1
vgscan >/dev/null 2>&1
vgchange -ay >/dev/null 2>&1
fi
}
lvm_show_vg() {
VG_LIST=""
for i in $(lvs --noheadings | awk '{print $2}' | uniq); do
VG_LIST="$VG_LIST $i $(vgdisplay "$i" | grep -i "vg size" | awk '{print $3$4}')"
done
if [[ -z $VG_LIST ]]; then
msgbox "$_ErrTitle" "$_LvmVGErr"
return 1
fi
dialog --backtitle "$BT" --title " $_PrepLVM " --menu "$_LvmSelVGBody" 0 0 5 $VG_LIST 2>$ANS || return 1
return 0
}
check_lv_size() {
local lv="$((${#LV_SIZE} - 1))"
(( ${#LV_SIZE} == 0 || ${LV_SIZE:0:1} == 0 )) && ERR_SIZE=1 || ERR_SIZE=0
if (( ERR_SIZE == 0 )); then
for (( i=0; i<lv; i++ )); do
[[ ${LV_SIZE:$i:1} != [0-9] ]] && { ERR_SIZE=1; break; }
done
if (( ERR_SIZE == 0 )); then
case ${LV_SIZE:$lv:1} in
[mMgG]) ERR_SIZE=0 ;;
*) ERR_SIZE=1
esac
if (( ERR_SIZE == 0 )); then
s=${LV_SIZE:0:$lv}
m=$((s * 1000))
case ${LV_SIZE:$lv:1} in
[Gg]) (( m >= VG_MB )) && ERR_SIZE=1 || VG_MB=$((VG_MB - m)) ;;
[Mm]) (( ${LV_SIZE:0:$lv} >= VG_MB )) && ERR_SIZE=1 || VG_MB=$((VG_MB - s)) ;;
*) ERR_SIZE=1
esac
fi
fi
fi
if (( ERR_SIZE == 1 )); then
msgbox "$_ErrTitle" "$_LvmLvSizeErrBody"
msg="$LV_VG: ${VG_SIZE}$VG_SIZE_TYPE (${LV_VG_MB}MB $_LvmLvSizeBody1).$_LvmLvSizeBody2"
getinput "$_LvmCreateVG (LV:$NUM_LVS)" "$msg" "" || { break; return 1; }
LV_SIZE="$(cat $ANS)"
check_lv_size
fi
return 0
}
lvm_create() {
LV_VG=""
VG_PARTS=""
VG_MB=0
unmount_partitions
find_partitions 'part\|crypt'
PARTS="$(sed 's/M\|G\|T/& off/g' <<< "$PARTS")"
# get volume group name
getinput "$_LvmCreateVG" "$_LvmNameVgBody" "VolGroup" || return 1
LV_VG="$(cat $ANS)"
# bad answer or volume group name already taken
while [[ ${LV_VG:0:1} == "/" || ${#LV_VG} -eq 0 || $LV_VG =~ \ |\' ]] || grep -q "$LV_VG" <<< "$(lsblk)"; do
msgbox "$_ErrTitle" "$_LvmNameVgErr"
getinput "$_LvmCreateVG" "$_LvmNameVgBody" "VolGroup" || { break; return 1; }
LV_VG="$(cat $ANS)"
done
# choose partitions
dialog --backtitle "$BT" --title "$_LvmCreateVG" --checklist "$_LvmPvSelBody" 0 0 7 $PARTS 2>$ANS
[[ $(cat $ANS) != "" ]] && VG_PARTS="$(cat $ANS)" || return 1
# confirm or bail out
yesno "$_LvmCreateVG" "$_LvmPvConfBody1 $LV_VG\n$_LvmPvConfBody2 $VG_PARTS" || return 1
# create it
infobox "$_LvmCreateVG" "$_LvmPvActBody1 $LV_VG.\n"
vgcreate -f "$LV_VG" "$VG_PARTS" >/dev/null 2>$ERR
check_for_errors || return 1
VG_SIZE=$(vgdisplay "$LV_VG" |
grep 'VG Size' |
sed 's/\..*//; s/[^0-9]*//g')
SIZE_TYPE="$(vgdisplay "$LV_VG" |
grep 'VG Size' |
awk '{print $4}')"
# transform vg size to MB if needed
[[ ${SIZE_TYPE:0:1} == "G" ]] && VG_MB=$((VG_SIZE * 1000)) || VG_MB=$VG_SIZE
# finished volume group creation
msgbox "$_LvmCreateVG" "$_LvmPvDoneBody1 '$LV_VG' ($VG_SIZE $SIZE_TYPE) $_LvmPvDoneBody2\n"
# how many logical volumes
local msg="$_LvmLvNumBody1 '$LV_VG'.\n$_LvmLvNumBody2"
dialog --backtitle "$BT" --title " $_LvmCreateVG " --radiolist "$msg" 0 0 9 \
"1" "-" off \
"2" "-" off \
"3" "-" off \
"4" "-" off \
"5" "-" off \
"6" "-" off \
"7" "-" off \
"8" "-" off \
"9" "-" off 2>$ANS
[[ $(cat $ANS) != "" ]] && NUM_LVS=$(cat $ANS) || return 1
# loop selected amount
while (( NUM_LVS > 1 )); do
local ttl=" $_LvmCreateVG (LV:$NUM_LVS) "
getinput "$ttl" "$_LvmLvNameBody1" "volext" || { break; return 1; }
LV_NAME="$(cat $ANS)"
# bad answer
while [[ ${LV_NAME:0:1} == "/" || ${#LV_NAME} -eq 0 || $LV_NAME =~ \ |\' ]] || grep -q "$LV_NAME" <<< "$(lsblk)"; do
msgbox "$_ErrTitle" "$_LvmLvNameErrBody"
getinput "$ttl" "$_LvmLvNameBody1" "volext" || { break 2; return 1; }
LV_NAME="$(cat $ANS)"
done
msg="${LV_VG}: ${VG_SIZE}$SIZE_TYPE (${VG_MB}MB $_LvmLvSizeBody1).$_LvmLvSizeBody2"
getinput "$ttl" "$msg" "" || { break; return 1; }
LV_SIZE="$(cat $ANS)"
check_lv_size || return 1
lvcreate -L "$LV_SIZE" "$LV_VG" -n "$LV_NAME" 2>$ERR
check_for_errors || return 1
msgbox "$ttl" "$_Done LV $LV_NAME ($LV_SIZE) $_LvmPvDoneBody2."
((NUM_LVS--))
done
# last or only
msg="$_LvmLvNameBody1 $_LvmLvNameBody2 (${VG_MB}MB)."
# volume name
getinput "$_LvmCreateVG (LV:$NUM_LVS)" "$msg" "volhome" || return 1
LV_NAME="$(cat $ANS)"
# bad volume name
while [[ ${LV_NAME:0:1} == "/" || ${#LV_NAME} -eq 0 || $LV_NAME =~ \ |\' ]] || grep -q "$LV_NAME" <<< "$(lsblk)"; do
msgbox "$_ErrTitle" "$_LvmLvNameErrBody"
getinput "$_LvmCreateVG (LV:$NUM_LVS)" "$msg" "volhome" || { break; return 1; }
LV_NAME="$(cat $ANS)"
done
# create it
lvcreate -l +100%FREE "$LV_VG" -n "$LV_NAME" 2>$ERR
check_for_errors || return 1
((NUM_LVS--))
LVM=1
yesno "$_LvmCreateVG" "$_LvmCompBody" && show_devices
return 0
}
lvm_del_vg() {
lvm_show_vg
if yesno "$_LvmDelVG" "$_LvmDelQ"; then
vgremove -f "$(cat $ANS)" >/dev/null 2>&1
fi
return 0
}
lvm_del_all() {
LVM_PV="$(pvs -o pv_name --noheading 2>/dev/null)"
LV_VG="$(vgs -o vg_name --noheading 2>/dev/null)"
LV="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
if yesno "$_LvMDelAll" "$_LvmDelQ"; then
for i in $LV; do
lvremove -f "/dev/mapper/$i" >/dev/null 2>&1
done
for i in $LV_VG; do
vgremove -f "$i" >/dev/null 2>&1
done
for i in $LVM_PV; do
pvremove -f "$i" >/dev/null 2>&1
done
LVM=0
fi
return 0
}
lvm_menu() {
lvm_detect
dialog --backtitle "$BT" --title " $_PrepLVM " --menu "$_LvmMenu" 0 0 4 \
"$_LvmCreateVG" "vgcreate -f, lvcreate -L -n" \
"$_LvmDelVG" "vgremove -f" \
"$_LvMDelAll" "lvrmeove, vgremove, pvremove -f" \
"$_Back" "-" 2>$ANS || return 0
case "$(cat $ANS)" in
"$_LvmCreateVG") lvm_create ;;
"$_LvmDelVG") lvm_del_vg ;;
"$_LvMDelAll") lvm_del_all ;;
*) return 0
esac
lvm_menu
}
######################################################################
## Installation Functions ##
######################################################################
install_main() {
unpack_base_system || return 0 # user can choose to bail at this point
update_mirrorlist
update_system
genfstab -U -p $MNT >$MNT/etc/fstab 2>$ERR
check_for_errors || return 1
# remove /mnt/install prefix from /etc/fstab for swapfile
[[ -f $MNT/swapfile ]] && sed -i "s~${MNT}~~" $MNT/etc/fstab
run_mkinitcpio || return 1
setup_bootloader || return 1
configure_menu || edit_config_menu
}
unpack_base_system() {
[[ $UNPACKED_BASE ]] && return 0
if ! yesno "$_InstTitle" "$_BeginInst $ROOT_PARTITION\n$_ContinueYN"; then
return 1
fi
clear
echo -e "\nUnpacking the system\n\n"
rsync -a --info=progress2 /run/archiso/sfs/airootfs/ $MNT/ 2>$ERR
check_for_errors || return 1
rm -rf $MNT/etc/polkit-1/rules.d/49-nopasswd_global.rules
rm -rf $MNT/etc/sudoers.d/g_wheel
rm -rf $MNT/etc/mkinitcpio-archiso.conf
rm -rf $MNT/usr/bin/install-al
rm -rf $MNT/usr/bin/al-installer
rm -rf $MNT/home/$LIVEUSER/.config/keypack
rm -rf $MNT/home/$LIVEUSER/bin/welcome.sh
find $MNT/usr/lib/initcpio -name "archiso*" -type f -exec rm '{}' \;
local openbox="$MNT/home/$LIVEUSER/.config/openbox"
sed -i '/keypack/d; /welcome.sh/d; s/#$HOME/$HOME/g; s|#$HOME/.config/setup &|$HOME/.config/setup &|g' $openbox/autostart
sed -i '/installer/ { N; N; d; }' $openbox/rc.xml
sed -i '/item label="Welcome Screen"/ i\ <separator label="A r c h L a b s"/>' $openbox/menu.xml
sed -i '/item label="Welcome Screen"/ { N; N; N; N; N; N; N; N; N; N; N; d; }' $openbox/menu.xml
sed -i 's/volatile/auto/g' $MNT/etc/systemd/journald.conf
if hash al-hello &>/dev/null; then
if hash st &>/dev/null; then
cmd="st"
elif hash termite &>/dev/null; then
cmd="termite"
else
cmd="xterm"
fi
sed -i "/al-hello/ c sleep 10; ${cmd} -e al-hello &" $openbox/autostart
else
sed -i '/al-hello/d' $openbox/autostart
fi
# vmlinuz, needed for mkinitcpio
cp -f /run/archiso/bootmnt/arch/boot/x86_64/vmlinuz $MNT/boot/vmlinuz-linux
# config files we made during prepare_menu()
cp -f /tmp/keyboard $MNT/etc/default/
cp -f /tmp/vconsole.conf $MNT/etc/
cp -f /tmp/00-keyboard.conf $MNT/etc/X11/xorg.conf.d/
# existing network config
cp -f /etc/resolv.conf $MNT/etc/
cp -rf /etc/NetworkManager/system-connections $MNT/etc/NetworkManager/
UNPACKED_BASE="True"
}
update_system() {
# update system and install needed packages
infobox "$_UpdSysTitle" "$_UpdSysBody\n"
chroot_cmd "pacman -Rs archlabs-installer --noconfirm" &>/dev/null
chroot_cmd "pacman -Syyu --color always --noconfirm" &>/dev/null
chroot_cmd "pacman -S iputils --noconfirm" &>/dev/null
chroot_cmd "pacman -S base-devel git --needed --noconfirm" &>/dev/null
}
update_mirrorlist() {
local yes="Automatic Sort"
local no="Customize Command"
if yesno "$_MirrorTitle" "$_MirrorSetup" 0 0 --yes-label "$yes" --no-label "$no"; then
CMD="reflector --score 100 -l 50 -f 10 --sort rate"
else
dialog --backtitle "$BT" --title "$_MirrorTitle" --menu "$_MirrorCountry" 20 45 10 $COUNTRY 2>$ANS || return 1
COUNTRY="$(cat $ANS)"
CMD="reflector --country $COUNTRY --score 100 --latest 50 --fastest 10 --sort rate"
REF="\n--score n Limit the list to the n servers with the highest score.
\n-l n, --latest n Limit the list to the n most recently synchronized servers.
\n-f n, --fastest n Return the n fastest mirrors that meet the other criteria.
\n--sort {age,rate,country,score,delay}
\n 'age': last server synchronization; 'rate': download rate;
\n 'country': server's location; 'score': MirrorStatus score;
\n 'delay': MirrorStatus delay."
getinput "$_MirrorTitle" "$_MirrorCmd\n$REF\n" "$CMD"
CMD="$(cat $ANS)"
fi
infobox "$_MirrorTitle" "$_MirrorSort"
if ! ${CMD:-reflector --score 100 -l 50 -f 10 --sort rate} --save $MNT/etc/pacman.d/mirrorlist; then
infobox "$_ErrTitle" "\nAn error occurred updating the mirrorlist\n\n"
mirrors
fi
}
create_bootloader_config() {
if [[ $BOOTLOADER == "grub" ]]; then
sed -i "s/GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR=\"${DIST}\"/g" $MNT/etc/default/grub 2>$ERR
check_for_errors || return 1
if (( LUKS == 1 )); then
sed -i 's/#GRUB_ENABLE_CRYPTODISK/GRUB_ENABLE_CRYPTODISK/g' $MNT/etc/default/grub 2>$ERR
check_for_errors || return 1
if [[ $LUKS_DEV ]]; then
sed -i "s~GRUB_CMDLINE_LINUX=.*~GRUB_CMDLINE_LINUX=\"${LUKS_DEV}\"~g" $MNT/etc/default/grub 2>$ERR
check_for_errors || return 1
fi
fi
if [[ $SYS != "UEFI" ]]; then
if (( LVM == 1 && SEPERATE_BOOT == 0 )) || (( SEPERATE_BOOT == 2 )); then
sed -i "s/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g" $MNT/etc/default/grub 2>$ERR
check_for_errors || return 1
fi
fi
elif [[ $BOOTLOADER == "syslinux" ]]; then
local cfgdir="$MNT/boot/syslinux"
[[ ! -d $cfgdir ]] && mkdir -p $cfgdir
# menu would be nice, so try setting that up
if [[ -e /usr/lib/syslinux/bios/vesamenu.c32 && ! -e $cfgdir/vesamenu.c32 ]]; then
cp -f /usr/lib/syslinux/bios/vesamenu.c32 $cfgdir/
if [[ -e /run/archiso/bootmnt/arch/boot/syslinux/splash.png ]]; then
cp -f /run/archiso/bootmnt/arch/boot/syslinux/splash.png $cfgdir/
fi
fi
# if the menu exists we can proceed to setup a default list
if [[ -e $cfgdir/vesamenu.c32 ]]; then
local menu_top="UI vesamenu.c32\nDEFAULT archlabs\nPROMPT 0\n"
menu_top="$menu_top\nMENU TITLE ArchLabs\nMENU BACKGROUND splash.png\nTIMEOUT 50\n"
menu_top="$menu_top\nMENU WIDTH 78\nMENU MARGIN 4\nMENU ROWS 5\nMENU VSHIFT 10"
menu_top="$menu_top\nMENU TIMEOUTROW 13\nMENU TABMSGROW 11\nMENU CMDLINEROW 11"
menu_top="$menu_top\nMENU HELPMSGROW 16\nMENU HELPMSGENDROW 29\n"
menu_top="$menu_top\n# Refer to https://www.syslinux.org/wiki/index.php/Comboot/menu.c32\n"
menu_top="$menu_top\nMENU COLOR border 30;44 #40ffffff #a0000000 std"
menu_top="$menu_top\nMENU COLOR title 1;36;44 #9033ccff #a0000000 std"
menu_top="$menu_top\nMENU COLOR sel 7;37;40 #e0ffffff #20ffffff all"
menu_top="$menu_top\nMENU COLOR unsel 37;44 #50ffffff #a0000000 std"
menu_top="$menu_top\nMENU COLOR help 37;40 #c0ffffff #a0000000 std"
menu_top="$menu_top\nMENU COLOR timeout_msg 37;40 #80ffffff #00000000 std"
menu_top="$menu_top\nMENU COLOR timeout 1;37;40 #c0ffffff #00000000 std"
menu_top="$menu_top\nMENU COLOR msg07 37;40 #90ffffff #a0000000 std"
menu_top="$menu_top\nMENU COLOR tabmsg 31;40 #30ffffff #00000000 std"
else
# no menu, but should display 'boot: ' and automatically boot after 5 seconds
local menu_top="PROMPT 1\nTIMEOUT 50\nDEFAULT archlabs"
fi
cat > $cfgdir/syslinux.cfg << EOF
$(echo -e "$menu_top")
LABEL archlabs
MENU LABEL Archlabs Linux
LINUX ../vmlinuz-linux
APPEND root=$ROOT_PARTITION $([[ $LUKS_DEV ]] && echo -n "$LUKS_DEV ")rw
INITRD ../initramfs-linux.img
LABEL archlabsfallback
MENU LABEL Archlabs Linux Fallback
LINUX ../vmlinuz-linux
APPEND root=$ROOT_PARTITION $([[ $LUKS_DEV ]] && echo -n "$LUKS_DEV ")rw
INITRD ../initramfs-linux-fallback.img
LABEL hdt
MENU LABEL HDT (Hardware Detection Tool)
COM32 hdt.c32
#LABEL windows
#MENU LABEL Windows
#COM32 chain.c32
#APPEND root=/dev/sda2 rw
#LABEL grub2
#MENU LABEL Grub2
#COM32 chain.c32
#APPEND file=../grub/boot.img
LABEL reboot
MENU LABEL Reboot
COM32 reboot.c32
LABEL poweroff
MENU LABEL Poweroff
COM32 poweroff.c32
EOF
else
# remove leftover grub configs from previous installs
find $MNT/boot/efi/EFI -name '[aA][rR][cC][hH][lL]abs*' -type d -exec rm '{}' \;
find $MNT/boot/efi/EFI -name 'grub*' -type d -exec rm '{}' \;
if grep -q "/dev/mapper/" <<< "$ROOT_PARTITION"; then
ROOT_PART_ID="$ROOT_PARTITION"
else
ROOT_PART_ID="PARTUUID=$(blkid -s PARTUUID $ROOT_PARTITION | sed 's/.*=//g; s/"//g')"
fi
cat > $MNT/boot/loader/loader.conf << EOF
default archlabs
timeout 5
editor no
EOF
cat > $MNT/boot/loader/entries/archlabs.conf << EOF
title Archlabs Linux
linux /vmlinuz-linux
initrd /initramfs-linux.img
options root=$ROOT_PART_ID rw
EOF
for i in $(ls $MNT/boot/loader/entries/arch*.conf); do
[[ $LUKS_DEV ]] && sed -i "s~rw~$LUKS_DEV rw~g" "$i"
done
fi
return 0
}
setup_bootloader() {
bootloader_info() {
local msg="$_InstBootloader $BOOTLOADER\n\n$_InstBootDev $BOOT_DEVICE"
if [[ $SYS == "BIOS" ]]; then
infobox "$_InstBiosBtTitle" "$msg\n"
else
infobox "$_InstUefiBtTitle" "$msg\n\nMountpoint: $EFI\n"
fi
}
bios_bootloader_install() {
if [[ $BOOTLOADER == "grub" ]]; then
# must be before running grub-install or it will fail with encrypted devices
create_bootloader_config || return 1
chroot_cmd "grub-install --bootloader-id=$DIST --recheck --force $BOOT_DEVICE" 2>$ERR
check_for_errors || return 1
chroot_cmd "grub-mkconfig -o /boot/grub/grub.cfg" 2>$ERR
check_for_errors || return 1
else
chroot_cmd "pacman -Rs grub --noconfirm" &>/dev/null
chroot_cmd "$SYSLNUX_CMD" 2>$ERR
check_for_errors || return 1
create_bootloader_config
fi
return 0
}
uefi_bootloader_install() {
if [[ $BOOTLOADER == "grub" ]]; then
# must be before running grub-install or it will fail with encrypted devices
create_bootloader_config || return 1
chroot_cmd "grub-install --bootloader-id=$DIST --recheck --force" 2>$ERR
check_for_errors || return 1
local efidir="${MNT}$EFI/EFI"
local fallback="BOOT"
for i in $(find "$efidir" -maxdepth 1 -mindepth 1 -type d); do
if grep -qi "boot" <<< "$(basename $i)"; then
fallback="$(basename $i)"
break
fi
done
mkdir -p $efidir/$fallback
cp -f $efidir/$DIST/grubx64.efi $efidir/$fallback/bootx64.efi
cp -f $efidir/$DIST/grubx64.efi $efidir/$fallback/BOOTX64.EFI
chroot_cmd "grub-mkconfig -o /boot/grub/grub.cfg" 2>$ERR
check_for_errors || return 1
else
# remove old grub entries from previous installs
chroot_cmd "pacman -Rs grub --noconfirm" &>/dev/null
[[ -d $MNT/boot/efi/EFI/Archlabs ]] && rm -rf $MNT/boot/efi/EFI/{Archlabs,BOOT,boot,Boot}
[[ -d $MNT/boot/EFI/Archlabs ]] && rm -rf $MNT/boot/EFI/{Archlabs,BOOT,boot,Boot}
[[ -d $MNT/boot/grub ]] && rm -rf $MNT/boot/grub
[[ -e $MNT/etc/default/grub ]] && rm -rf $MNT/etc/default/grub
# since systemd v232 systemd-boot requires machine id to be setup first
systemd-machine-id-setup --root="$MNT" 2>$ERR
check_for_errors || return 1
chroot_cmd "bootctl --path=/boot install" 2>$ERR
check_for_errors || return 1
create_bootloader_config
fi
return 0
}
chroot_cmd "export PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/bin/core_perl"
# save repetition of basically the same command
bootloader_info
if [[ $SYS != "UEFI" ]]; then
bios_bootloader_install || return 1
else
if grep -q "/sys/firmware/efi/efivars" <<< "$(mount)"; then
mount -t efivarfs efivarfs /sys/firmware/efi/efivars &>/dev/null
chroot_cmd "mount -t efivarfs efivarfs /sys/firmware/efi/efivars" &>/dev/null
fi
uefi_bootloader_install || return 1
fi
BOOT_DONE="True"
[[ $BOOTLOADER == "grub" && $LUKS -eq 1 && $LUKS_PASSWD && $LUKS_UUID ]] && luks_keyfile
return 0
}
run_mkinitcpio() {
local conf="$MNT/etc/mkinitcpio.conf"
local addition
# amend HOOKS in /etc/mkinitcpio.conf
if (( LVM == 1 && LUKS == 0 )); then
sed -i 's/block filesystems/block lvm2 filesystems/g' $conf 2>$ERR &>/dev/null
addition="lvm2"
elif (( LVM == 1 && LUKS == 1 )); then
sed -i 's/block filesystems/block encrypt lvm2 filesystems/g' $conf 2>$ERR &>/dev/null
addition="encrypt lvm2"
elif (( LVM == 0 && LUKS == 1 )); then
sed -i 's/block filesystems/block encrypt filesystems/g' $conf 2>$ERR &>/dev/null
addition="encrypt"
fi
check_for_errors || return 1
sed -i "s/keyboard fsck/keyboard ${MKINIT_HOOKS} fsck/g" $conf 2>$ERR &>/dev/null
check_for_errors || return 1
addition="$addition $MKINIT_HOOKS"
infobox "$_RunMkinit" "$_RunMkinitBody\n\nAdded HOOKS: $addition\n"
chroot_cmd "mkinitcpio -p linux" 2>$ERR &>/dev/null
check_for_errors || return 1
}
######################################################################
## Menu Interfaces ##
######################################################################
main_menu() {
# automatically jump to prepare_menu() on first run
if [[ $FIRST_RUN_PREP != "True" ]]; then
# if prepare_menu() returns non zero begin the install
if ! prepare_menu; then
check_parts_are_mounted && install_main && MAIN_HIGHLIGHT=3
fi
FIRST_RUN_PREP="True"
fi
if [[ $CURRENT_MENU != "main" ]]; then
MAIN_HIGHLIGHT=1
CURRENT_MENU="main"
elif (( MAIN_HIGHLIGHT < 5 )); then
((MAIN_HIGHLIGHT++)) # highlight the next choice
fi
dialog --backtitle "$BT" --title " $_MainTitle " \
--default-item $MAIN_HIGHLIGHT --menu "$_MainBody" 0 0 5 \
"1" "$_PrepTitle" \
"2" "$_InstTitle" \
"3" "$_ConfTitle" \
"4" "$_EditTitle" \
"5" "$_Done" 2>$ANS
MAIN_HIGHLIGHT=$(cat $ANS)
if [[ -n $MAIN_HIGHLIGHT ]]; then
# make sure everything has been set before installing or configuring install
if (( MAIN_HIGHLIGHT == 2 )) && ! check_parts_are_mounted; then
return 1
elif (( MAIN_HIGHLIGHT >= 3 && MAIN_HIGHLIGHT <= 4 )); then
if ! (check_parts_are_mounted && check_base_unpacked); then
return 1
fi
fi
fi
case $MAIN_HIGHLIGHT in
1) prepare_menu ;;
2) install_main ;;
3) configure_menu ;;
4) edit_config_menu ;;
*)
local yes="Exit Installer"
local no="Go Back"
if yesno "Close Installer" "$_CloseInstBody" 0 0 --yes-label "$yes" --no-label "$no"; then
unmount_partitions
cleanup
clear
exit 0
fi
esac
return 0
}
prepare_menu() {
if [[ $CURRENT_MENU != "prep" ]]; then
SUB_HIGHLIGHT=1
CURRENT_MENU="prep"
elif (( SUB_HIGHLIGHT < 7 )); then
((SUB_HIGHLIGHT++)) # increment the highlighted item
# return non zero to main_menu()
# only when we reach the end of the menu and have done required steps
if [[ $SUB_HIGHLIGHT -eq 7 && -n $ROOT_PARTITION ]]; then
([[ $SYS == "UEFI" && -n $EFI_PARTITION ]] || [[ $SYS != "UEFI" ]]) && return 1
fi
fi
dialog --backtitle "$BT" --title " $_PrepTitle " \
--default-item $SUB_HIGHLIGHT --menu "$_PrepBody" 0 0 7 \
"1" "$_PrepLayout" \
"2" "$_PrepShowDev" \
"3" "$_PrepParts" \
"4" "$_PrepLUKS" \
"5" "$_PrepLVM" \
"6" "$_PrepMount" \
"7" "$_Back" 2>$ANS
SUB_HIGHLIGHT=$(cat $ANS)
case $SUB_HIGHLIGHT in
1) set_keymap ;;
2) show_devices ;;
3) unmount_partitions && select_device && create_partitions "$DEVICE" ;;
4) luks_menu ;;
5) lvm_menu ;;
6) select_install_partitions ;;
*) return 0
esac
# recurse back until explicitly chosen to leave
prepare_menu
}
configure_menu() {
chroot_cmd "export PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/core_perl"
# run through each step automatically on first run
if [[ $FIRST_RUN_CONFIG != "True" ]]; then
SUB_HIGHLIGHT=1
CURRENT_MENU="config"
FIRST_RUN_CONFIG="True"
set_hostname && set_locale && root_password
# if create_user returns non zero, pass return code back to install_main()
# this will return us to the edit_config_menu()
create_user || return 1
# returning from another menu after first run
elif [[ $CURRENT_MENU != "config" ]]; then
SUB_HIGHLIGHT=1
CURRENT_MENU="config"
# highlight next option
elif (( SUB_HIGHLIGHT < 5 )); then
((SUB_HIGHLIGHT++))
fi
dialog --backtitle "$BT" --title " $_ConfTitle " \
--default-item $SUB_HIGHLIGHT --menu "$_ConfBody" 0 0 5 \
"1" "$_ConfHost" \
"2" "$_ConfLocale" \
"3" "$_ConfRoot" \
"4" "$_ConfUser" \
"5" "$_Back" 2>$ANS
SUB_HIGHLIGHT=$(cat $ANS)
case $SUB_HIGHLIGHT in
1) set_hostname ;;
2) set_locale ;;
3) root_password ;;
4) create_user ;;
*) return 0
esac
# recurse back until we explicitly choose to exit
configure_menu
}
edit_config_menu() {
if [[ $CURRENT_MENU != "edit" ]]; then
SUB_HIGHLIGHT=1
CURRENT_MENU="edit"
elif (( SUB_HIGHLIGHT < 11 )); then
((SUB_HIGHLIGHT++))
fi
dialog --backtitle "$BT" --title " $_EditTitle " \
--default-item $SUB_HIGHLIGHT --menu "$_EditBody" 0 0 11 \
"1" "keymap configs" \
"2" "locale configs" \
"3" "/etc/hostname" \
"4" "/etc/hosts" \
"5" "/etc/sudoers" \
"6" "/etc/mkinitcpio.conf" \
"7" "/etc/fstab" \
"8" "/etc/crypttab" \
"9" "bootloader configs" \
"10" "/etc/pacman.conf" \
"11" "$_Back" 2>$ANS
SUB_HIGHLIGHT="$(cat $ANS)"
local file=""
local xorg_conf="etc/X11/xorg.conf.d/00-keyboard.conf"
case $SUB_HIGHLIGHT in
1) [[ -e $MNT/$xorg_conf ]] && file="$MNT/$xorg_conf"
[[ -e $MNT/etc/vconsole.conf ]] && file="$file $MNT/etc/vconsole.conf"
[[ -e $MNT/etc/default/keyboard ]] && file="$file $MNT/etc/default/keyboard" ;;
2) [[ -e $MNT/etc/locale.conf ]] && file="$MNT/etc/locale.conf"
[[ -e $MNT/etc/default/locale ]] && file="$file $MNT/etc/default/locale" ;;
3) [[ -e $MNT/etc/hostname ]] && file="$MNT/etc/hostname" ;;
4) [[ -e $MNT/etc/hosts ]] && file="$MNT/etc/hosts" ;;
5) [[ -e $MNT/etc/sudoers ]] && file="$MNT/etc/sudoers" ;;
6) [[ -e $MNT/etc/mkinitcpio.conf ]] && file="$MNT/etc/mkinitcpio.conf" ;;
7) [[ -e $MNT/etc/fstab ]] && file="$MNT/etc/fstab" ;;
8) [[ -e $MNT/etc/crypttab ]] && file="$MNT/etc/crypttab" ;;
9)
if [[ $BOOTLOADER == "systemd-boot" && -e $MNT/boot/loader/entries/archlabs.conf ]]; then
file="$MNT/boot/loader/entries/archlabs.conf"
elif [[ $BOOTLOADER == "syslinux" && -e $MNT/boot/syslinux/syslinux.cfg ]]; then
file="$MNT/boot/syslinux/syslinux.cfg"
elif [[ $BOOTLOADER == "grub" && -e $MNT/etc/default/grub ]]; then
file="$MNT/etc/default/grub"
fi
;;
10) [[ -e $MNT/etc/pacman.conf ]] && file="$MNT/etc/pacman.conf" ;;
*) return 0
esac
if [[ $file != "" ]]; then
if [[ $DISPLAY ]] && hash geany &>/dev/null; then
geany -i $file
else
vim -O $file
fi
else
msgbox "$_ErrTitle" "$_NoFileErr"
fi
# recurse back after each file edit finishes
edit_config_menu
}
for arg in $@; do
[[ $arg == "--debug" || $arg == "-d" ]] && set_debug
done
select_language
check_requirements
identify_system
# welcome message
msgbox "$_WelTitle $DIST Installer" "$_WelBody"
FIRST_RUN_PREP="False"
FIRST_RUN_CONFIG="False"
CURRENT_MENU="main"
MAIN_HIGHLIGHT=0
SUB_HIGHLIGHT=0
while true; do
main_menu
done