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

2367 lines
85 KiB
Bash
Executable File

#!/usr/bin/bash
# vim:ft=sh:fdm=marker:fmr={,}
# This program is free software, provided under the GNU GPL
# Written by Nathaniel Maia for use in Archlabs
# Some ideas and code were taken from other installers
# AIF, ABIF, Calamares, Arch Wiki.. Credit where credit is due
# set -n
# set -u
# set -v
# immutable variables {
readonly DIST="Archlabs" # Linux distributor
readonly VER="1.6.35" # Installer version
readonly LIVE="liveuser" # Live session user
readonly TRN="/usr/share/archlabs-installer" # Translation path
readonly MNT="/mnt/install" # Install mountpoint
readonly ERR="/tmp/errlog" # Built-in error log
# create a regex string of all usb devices on the system
for dev in $(lsblk -lno NAME,TRAN | awk '/usb/ {print $1}'); do USB_DEVS="${dev}$([[ $USB_DEVS ]] && echo -n "|$USB_DEVS")"; done
# determine which device was used for booting to ignore later during partition select
readonly IGNORE_DEV="$(lsblk -lno NAME,TYPE,TRAN,MOUNTPOINT | awk "/$USB_DEVS/"' && /\/run\/archiso\/bootmnt/ {sub(/[1-9]/, ""); print $1}')"
readonly SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE,TRAN | awk '/disk/ && !'"/$IGNORE_DEV/"' {print "/dev/" $1 " " $2}')"
readonly LOCALES="$(awk '/\.UTF-8/ {gsub(/# .*|#/, ""); if($1) print $1 " -"}' /etc/locale.gen)"
readonly SYS_MEM=$(grep 'MemTotal' /proc/meminfo | awk '{print int($2 / 1024)}')
readonly DEV_COUNT="$(wc -l <<< "$SYS_DEVS")"
readonly KBD="$(find /usr/share/kbd/keymaps -name '*.map.gz')"
readonly CONSOLE_MAPS="$(awk '{gsub(/\.map\.gz|.*\//, ""); print $1 " -"}' <<< "$KBD" | sort -r)"
# create associative array for SUBZONES[zone], value is: 'sub-zone country_code'
declare -Ag SUBZONES
for zone in America Australia Asia Atlantic Africa Europe Indian Pacific Arctic Antarctica; do
SUBZONES[$zone]="$(awk "/$zone\// {gsub(/$zone\//, \"\"); print \$3 \" \"\$1}" /usr/share/zoneinfo/zone.tab)"
done
readonly SUBZONES # make it read only
for t in st termite xterm; do
hash $t >/dev/null 2>&1 && { readonly TERM_CMD="$t"; break; }
done
# static string of keymap codes and respective language
readonly KEYMAPS="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
es Spanish latam Spanish br Portuguese pt Portuguese ma Arabic sy Arabic ara Arabic
ua Ukrainian cz Czech ru Russian sk Slovak nl Dutch it Italian hu Hungarian cn Chinese
tw Taiwanese vn Vietnamese kr Korean jp Japanese th Thai la Lao pl Polish se Swedish
is Icelandic fi Finnish dk Danish be Belgian in Indian al Albanian am Armenian bd Bangla
ba Bosnian bg Bulgarian dz Berber mm Burmese hr Croatian gr Greek il Hebrew ir Persian iq Iraqi
af Afghani fo Faroese ge Georgian ee Estonian kg Kyrgyz kz Kazakh lt Lithuanian mt Maltese
mn Mongolian no Norwegian ro Romanian rs Serbian si Slovenian tj Tajik lk Sinhala tr Turkish
uz Uzbek 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 tm Turkmen bt Dzongkha
lv Latvian md Moldavian mao Maori by Belarusian me Montenegrin mk Macedonian kh Khmer
az Azerbaijani"
declare -Agr BOOT_MNTS=(
[UEFI-grub]="/boot/efi" [UEFI-systemd-boot]="/boot"
[BIOS-grub]="/boot" [BIOS-syslinux]="/boot"
)
# static list of bootloaders & boot partition mountpoints stored as the system type (BIOS or UEFI)
declare -Agr BOOTLOADERS=(
[UEFI]="grub ${BOOT_MNTS[UEFI-grub]} systemd-boot ${BOOT_MNTS[UEFI-systemd-boot]}"
[BIOS]="grub ${BOOT_MNTS[BIOS-grub]} syslinux ${BOOT_MNTS[BIOS-syslinux]}"
)
# static mkfs commands for each filesystem offered
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"
)
# static filesystem mount options
declare -Agr FS_OPTS=(
[vfat]="" [ntfs]="" [ext2]="" [ext3]=""
[ext4]="dealloc - off discard - 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"
)
# }
luks_variable_init() {
declare -g LUKS=0
declare -g LVM=0
declare -g VOL_GROUP_MB=0
declare -g LUKS_NAME="cryptroot"
declare -g LUKS_PART=""
declare -g LUKS_PASS=""
declare -g LUKS_UUID=""
declare -g LUKS_DEV=""
declare -g MKINIT_HOOKS="shutdown"
declare -g SEPERATE_BOOT=0
}
initialize_variables() {
# Modified during runtime and are all globally accessible
# This is called once when the script is started, and again if/when an error occurs
# Some of may never be used, depending on the system and choices made
declare -g ROOT_PART=""
declare -g BOOT_DEVICE=""
declare -g BOOT_PART=""
declare -g BOOTLOADER=""
declare -g EXTRA_MNT=""
declare -g SWAP_FILE="none"
declare -g SWAP_SIZE="${SYS_MEM}M"
declare -g NEWUSER=""
declare -g USER_PASS=""
declare -g ROOT_PASS=""
declare -g LOGIN_WM=""
declare -g LOGIN_TYPE=""
declare -g INSTALL_WMS=""
declare -g WM_PACKAGES=""
declare -g EXTRA_PACKAGES=""
declare -g REMOVE_PKGS=""
declare -g CURRENT_MENU="main"
declare -g MENU_HIGHLIGHT=0
declare -g EDITOR_CHOICE=""
declare -g MIRROR_CMD="reflector --score 100 -l 50 -f 10 --sort rate"
# boolean checks
declare -g AUTOLOGIN=false
declare -g FIRST_PREP=false
declare -g FIRST_CONFIG=false
declare -g UNPACKED_BASE=false
declare -g SET_ROOT_PASSWD=false
declare -g TIMEZONE_SET=false
declare -g DONE_UPDATE=false
declare -g BOOT_DONE=false
declare -g FULL_DONE=false
declare -g CONFIRM_DONE=false
declare -g GRUB_UEFI_FALLBACK=false
# Commands used to install each bootloader.
# NOTE: syslinux and grub in particular can/will change during runtime
declare -Ag BOOT_CMDS=(
[syslinux]="syslinux-install_update -iam"
[grub]="grub-install --bootloader-id=$DIST --recheck --force"
[systemd-boot]="bootctl --path=/boot install"
)
# files able to be reviewed when finishing install
# item index [9] can change depending on which bootloader is selected
declare -Ag EDIT_FILES=(
[2]="/etc/X11/xorg.conf.d/00-keyboard.conf /etc/vconsole.conf /etc/default/keyboard"
[3]="/etc/locale.conf /etc/default/locale"
[4]="/etc/hostname /etc/hosts"
[5]="/etc/sudoers"
[6]="/etc/mkinitcpio.conf"
[7]="/etc/fstab"
[8]="/etc/crypttab"
[9]="/etc/default/grub"
[10]="/etc/pacman.conf"
)
}
######################################################################
## Utility and Check Functions ##
######################################################################
chroot_cmd() {
arch-chroot $MNT /bin/bash -c "$1"
}
show_devices() {
tput civis
if [[ $IGNORE_DEV != "" ]]; then
lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE,MOUNTPOINT |
awk "!/$IGNORE_DEV/"' && /disk|part|lvm|crypt|NAME/ {print $0}' > /tmp/.devlist
else
lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE,MOUNTPOINT |
awk '/disk|part|lvm|crypt|NAME/ {print $0}' > /tmp/.devlist
fi
dialog --cr-wrap --backtitle "$BT" --title " $_PrepShowDev " --textbox /tmp/.devlist 0 0
}
set_debug() {
set -x
exec 3>| /tmp/debug-log
BASH_XTRACEFD=3
if [[ $DISPLAY ]]; then
if [[ $TERM_CMD == 'st' ]]; then
$TERM_CMD -e tail -f /tmp/debug-log &
else
$TERM_CMD -e "tail -f /tmp/debug-log" &
fi
fi
}
select_language() {
tput civis
local lang
lang=$(dialog --cr-wrap --stdout --backtitle "$DIST Installer - (x86_64)" \
--title " Select Language " --menu \
"\nLanguage - sprache - taal - språk - lingua - idioma - nyelv - língua\n" 0 0 0 \
"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)")
source $TRN/english.trans 2>/dev/null
FONT="ter-i16n"
case $lang in
1) LOC="en_US.UTF-8" ;;
2) source $TRN/spanish.trans 2>/dev/null && LOC="es_ES.UTF-8" ;;
3) source $TRN/p_brasil.trans 2>/dev/null && LOC="pt_BR.UTF-8" ;;
4) source $TRN/portuguese.trans 2>/dev/null && LOC="pt_PT.UTF-8" ;;
5) source $TRN/french.trans 2>/dev/null && LOC="fr_FR.UTF-8" ;;
6) source $TRN/russian.trans 2>/dev/null && LOC="ru_RU.UTF-8" FONT="LatKaCyrHeb-14" ;;
7) source $TRN/italian.trans 2>/dev/null && LOC="it_IT.UTF-8" ;;
8) source $TRN/dutch.trans 2>/dev/null && LOC="nl_NL.UTF-8" ;;
9) source $TRN/hungarian.trans 2>/dev/null && LOC="hu_HU.UTF-8" FONT="lat2-16" ;;
10) source $TRN/chinese.trans 2>/dev/null && LOC="zh_CN.UTF-8" ;;
*) clear; tput cnorm
pgrep -f "$TERM_CMD -e tail" && pkill -f "$TERM_CMD -e tail"
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 2>&1
setfont $FONT >/dev/null 2>&1
export LANG="$LOC"
}
identify_system() {
if grep -qi 'apple' /sys/class/dmi/id/sys_vendor; then
modprobe -r -q efivars || true
else
modprobe -q efivarfs
fi
if [[ -d /sys/firmware/efi ]]; then
SYS="UEFI"
[[ $(mount) =~ /sys/firmware/efi/efivars ]] && mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
else
SYS="BIOS"
fi
readonly BT="$DIST Installer - $SYS (x86_64) - Version $VER"
}
check_requirements() {
declare -g HAS_NETWORK=false
if [[ $(whoami) != "root" ]]; then
infobox "$_ErrTitle" "$_NotRoot\n$_Exit"; clear; tput cnorm
pgrep -f "$TERM_CMD -e tail" && pkill -f "$TERM_CMD -e tail"
exit 1
elif ! (ping -c 1 archlabslinux.com || ping -c 1 google.com || ping -c 1 bitbucket.org || ping -c 1 github.com || ping -c 1 sourceforge.net) >/dev/null 2>&1; then
if [[ $(systemctl is-active NetworkManager) == "active" ]] && hash nmtui >/dev/null 2>&1;then
tput civis; nmtui
fi
if (ping -c 1 archlabslinux.com || ping -c 1 google.com || ping -c 1 bitbucket.org || ping -c 1 github.com || ping -c 1 sourceforge.net) >/dev/null 2>&1; then
HAS_NETWORK=true
else
infobox "$_ErrTitle" "$_NoNetwork\nYou may experience issues without one...\n"
fi
else
HAS_NETWORK=true
fi
return 0
}
check_for_errors() {
# if the last process exited normally then we can bail
(( $? == 0 )) && return 0
local command="$1"
local msg="\nThe command exited abnormally: $command"
# get error message from logfile and attempt to format slightly better for humans
# strip any non-printable characters, escape sequences, and other known messy text
local err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
if [[ $err != "" ]]; then
msgbox "$_ErrTitle" "$msg\n\nWith the following error message:\n\n$err"
fi
if yesno "$_ErrTitle" "$msg\n$_ErrChoice" "Wipe Install" "Manual Fix" "no"; then
for d in $MNT/?*; do
if ! grep -q "boot" <<< "$d"; then
rm -rf "$d" 2>/dev/null
fi
done
unmount_partitions
[[ -e $ERR ]] && rm -rf $ERR
initialize_variables
luks_variable_init
fi
return 1
}
check_parts_are_mounted() {
[[ $(lsblk -o MOUNTPOINT) =~ "$MNT" ]] && return 0
msgbox "$_ErrTitle" "$_ErrNoMount"
return 1
}
check_base_unpacked() {
[[ -e $MNT/etc ]] && return 0
msgbox "$_ErrTitle" "$_ErrNoBase"
return 1
}
getinput() {
local answer
answer="$(dialog --cr-wrap --max-input 63 --stdout --backtitle "$BT" --title " $1 " --inputbox "$2" 0 0 "$3")"
[[ $? != 0 || $answer == "" ]] && return 1
echo "$answer"
}
msgbox() {
tput civis
dialog --cr-wrap --backtitle "$BT" --title " $1 " --msgbox "$2\n" 0 0
}
infobox() {
local bt="${BT:-$DIST Installer - (x86_64)}"
tput civis
dialog --cr-wrap --backtitle "$bt" --title " $1 " --infobox "$2\n" 0 0
sleep 2
}
yesno() {
tput civis
if [[ $# -eq 5 && $5 == "no" ]]; then
# option for default no using custom labels
dialog --cr-wrap --backtitle "$BT" --defaultno --title " $1 " \
--yes-label "$3" --no-label "$4" --yesno "$2\n" 0 0
elif [[ $# -eq 4 ]]; then
# option for custom labels with standard default yes
dialog --cr-wrap --backtitle "$BT" --title " $1 " --yes-label "$3" \
--no-label "$4" --yesno "$2\n" 0 0
else
# basic yes no without custom labels and default yes
dialog --cr-wrap --backtitle "$BT" --title " $1 " --yesno "$2\n" 0 0
fi
}
wrap_up() {
if yesno "$_CloseInst" "$1" "$2" "$3"; then
unmount_partitions
[[ -e $ERR ]] && rm -rf $ERR
pgrep -f "$TERM_CMD -e tail" && pkill -f "$TERM_CMD -e tail"
tput cnorm
clear
[[ $4 == "reboot" ]] && reboot
exit 0
fi
}
######################################################################
## System Settings Functions ##
######################################################################
set_keymap() {
local map
tput civis
map="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_PrepLayout " \
--menu "$_XMapBody" 20 70 12 $KEYMAPS)"
[[ $? != 0 || $map == "" ]] && 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
# when a matching console map is not available open a selection dialog
if ! [[ $CONSOLE_MAPS =~ "$map -" ]]; then
tput civis
map="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_CMapTitle " \
--menu "$_CMapBody" 20 70 12 $CONSOLE_MAPS)"
[[ $? != 0 || $map == "" ]] && return 1
fi
setxkbmap $XKBMAP >/dev/null 2>&1
echo -e "KEYMAP=$map\nFONT=$FONT" >/tmp/vconsole.conf
return 0
}
set_locale() {
local locale
tput civis
locale="$(dialog --cr-wrap --stdout --no-cancel --backtitle "$BT" \
--title "$_ConfLocale" --menu "$_LocaleBody" 25 70 12 $LOCALES)"
[[ $? != 0 || $locale == "" ]] && return 1
infobox "$_ConfLocale" "$_GenLocale $locale\n"
sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${locale}/${locale}/g" $MNT/etc/locale.gen
sed -i "s/en_US.UTF-8/${locale}/g" $MNT/etc/locale.conf
cp -f $MNT/etc/locale.conf $MNT/etc/default/locale
chroot_cmd "locale-gen" >/dev/null 2>$ERR
check_for_errors 'locale-gen' || return 1
set_timezone
}
set_timezone() {
tput civis
local zone
zone="$(dialog --cr-wrap --stdout --no-cancel --backtitle "$BT" \
--title " $_TimeZTitle " --menu "$_TimeZBody" 20 70 10 America - Australia - \
Asia - Atlantic - Africa - Europe - Indian - Pacific - Arctic - Antarctica -)"
local subzone
subzone="$(dialog --cr-wrap --stdout --no-cancel --backtitle "$BT" \
--title " $_TimeZTitle " --menu "$_TimeSubZBody" 20 70 12 ${SUBZONES[$zone]})"
if yesno "$_TimeZTitle" "$_TimeZQ $zone/$subzone?\n"; then
chroot_cmd "ln -sf /usr/share/zoneinfo/$zone/$subzone /etc/localtime" 2>$ERR
check_for_errors "ln -sf /usr/share/zoneinfo/$zone/$subzone /etc/localtime" || return 1
else
set_timezone || return 1
fi
TIMEZONE_SET=true
set_hwclock
}
set_hwclock() {
chroot_cmd "hwclock --systohc --utc"
if [[ $? != 0 ]]; then
chroot_cmd "hwclock --systohc --utc --directisa"
[[ $? != 0 ]] && infobox "$_ErrTitle" "\nHwclock setup attempts failed.\n\nContinuing anyway.\n"
fi
return 0
}
set_hostname() {
tput cnorm
local hostname
hostname="$(getinput "$_ConfHost" "$_HostNameBody" "${DIST,,}")"
[[ $? != 0 || $hostname == "" ]] && return 1
echo "$hostname" > $MNT/etc/hostname
cat > $MNT/etc/hosts << EOF
127.0.0.1 localhost
127.0.1.1 $hostname
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF
}
user_input_values() {
local user="$1"
tput cnorm
local values
if [[ $SET_ROOT_PASSWD != true ]]; then
values="$(dialog --stdout --no-cancel --separator '~' --ok-label "Submit" --backtitle "$BT" \
--title " $_UserTitle " --insecure --mixedform "$_UserBody" 27 75 10 \
"$_Username" 1 1 "$user" 1 $((${#_Username} + 2)) 71 0 0 \
"$_Password" 2 1 "" 2 $((${#_Password} + 2)) 71 0 1 \
"$_Password2" 3 1 "" 3 $((${#_Password2} + 2)) 71 0 1 \
"$_RootBody" 6 1 "" 6 $((${#_RootBody} + 1)) 71 0 2 \
"$_Password" 8 1 "" 8 $((${#_Password} + 2)) 71 0 1 \
"$_Password2" 9 1 "" 9 $((${#_Password2} + 2)) 71 0 1)"
else
values="$(dialog --stdout --no-cancel --separator '~' --ok-label "Submit" --backtitle "$BT" \
--title " $_UserTitle " --insecure --mixedform "$_UserBody" 20 75 4 \
"$_Username" 1 1 "$user" 1 $((${#_Username} + 2)) 71 0 0 \
"$_Password" 2 1 "" 2 $((${#_Password} + 2)) 71 0 1 \
"$_Password2" 3 1 "" 3 $((${#_Password2} + 2)) 71 0 1)"
fi
[[ $? != 0 || $values == "" ]] && return 1
user="$(awk -F'~' '{print $1}' <<< "$values")"
local pass pass2
pass="$(awk -F'~' '{print $2}' <<< "$values")"
pass2="$(awk -F'~' '{print $3}' <<< "$values")"
# if the root password has not yet been set
local rpass rpass2
if [[ $SET_ROOT_PASSWD != true ]]; then
rpass="$(awk -F'~' '{print $5}' <<< "$values")"
rpass2="$(awk -F'~' '{print $6}' <<< "$values")"
# when both passwords match but are empty
# resort to using the user passwords instead
if [[ $rpass == "" && $rpass2 == "" ]]; then
rpass="$pass"
rpass2="$pass2"
fi
fi
# make sure we dont have anything wrong and that the passwords match
if [[ ${#user} -eq 0 || $user =~ \ |\' || $user =~ [^a-z0-9\ ] || $pass == "" || "$pass" != "$pass2" || "$rpass" != "$rpass2" ]]; then
tput civis
# passwords don't match
if [[ $pass == "" || "$pass" != "$pass2" || "$rpass" != "$rpass2" ]]; then
if [[ "$rpass" != "$rpass2" ]]; then
msgbox "$_ErrTitle" "$_RootPassErr\n$_TryAgain"
else
msgbox "$_ErrTitle" "$_UserPassErr\n$_TryAgain"
fi
else
# bad username
msgbox "$_UserErrTitle" "$_UserErrBody"
user=""
fi
# recursively loop back unless the user chooses cancel, then bail
user_input_values "$user" || return 1
else
NEWUSER="$user"
USER_PASS="$pass"
[[ $SET_ROOT_PASSWD != true ]] && ROOT_PASS="$rpass"
fi
return 0
}
create_user() {
if [[ $AUTOLOGIN == true && $LOGIN_TYPE == 'lightdm' ]]; then
local groups="rfkill,wheel,autologin,nopasswdlogin,network,lp,storage,power,video,audio,lp"
else
local groups="rfkill,wheel,autologin,network,lp,storage,power,video,audio,lp"
fi
NEWUSER=""
user_input_values "$NEWUSER" || return 1
if [[ $SET_ROOT_PASSWD != true ]]; then
infobox "$_ConfRoot" "\nSetting root password\n"
chroot_cmd "echo 'root:$ROOT_PASS' | chpasswd" 2>$ERR
check_for_errors "chpasswd root" || return 1
SET_ROOT_PASSWD=true
fi
infobox "$_ConfUser" "$_UserSetBody"
if [[ -e $MNT/home/$LIVE ]]; then
# for first user created, swap the live user account
swap_livuser
chroot_cmd "mv -f /home/$LIVE /home/$NEWUSER" 2>$ERR
check_for_errors "mv -f /home/$LIVE /home/$NEWUSER" || return 1
chroot_cmd "usermod -aG $groups $NEWUSER" 2>$ERR
check_for_errors "usermod -aG $groups $NEWUSER" || return 1
else
# create new user account
chroot_cmd "useradd $NEWUSER -m -g users -G $groups -s /bin/zsh" 2>$ERR
check_for_errors "useradd $NEWUSER -m -g users -G $groups -s /bin/zsh" || return 1
chroot_cmd "cp -rf /etc/skel/ /home/$NEWUSER" 2>$ERR
check_for_errors "cp -rf /etc/skel/ /home/$NEWUSER" || return 1
fi
chroot_cmd "echo '$NEWUSER:$USER_PASS' | chpasswd" 2>$ERR
check_for_errors "chpasswd $NEWUSER" || return 1
chroot_cmd "chown -Rf $NEWUSER:users /home/$NEWUSER" 2>$ERR
check_for_errors "chown -Rf $NEWUSER:users /home/$NEWUSER" || return 1
if [[ $AUTOLOGIN == true && $LOGIN_TYPE == 'lightdm' ]]; then
sed -i "/#autologin-user=/ c autologin-user=${NEWUSER}" $MNT/etc/lightdm/lightdm.conf
fi
fix_home_files
if [[ $UNPACKED_BASE == true && $TIMEZONE_SET == true ]]; then
[[ $SET_ROOT_PASSWD == true && $BOOT_DONE == true ]] && FULL_DONE=true
fi
return 0
}
swap_livuser() {
# edit the required files in /etc/ to swap the liveuser account name
sed -i "s/${LIVE}/${NEWUSER}/g" $MNT/etc/{group,gshadow,passwd,shadow}
if [[ $AUTOLOGIN != true || $LOGIN_TYPE == 'lightdm' ]]; then
rm -rf $MNT/etc/systemd/system/getty@tty1.service.d >/dev/null 2>&1
elif [[ $AUTOLOGIN == true && $LOGIN_TYPE != 'lightdm' ]]; then
sed -i "s/${LIVE}/${NEWUSER}/g" $MNT/etc/systemd/system/getty@tty1.service.d/autologin.conf
fi
return 0
}
fix_home_files() {
local user_home="$MNT/home/$NEWUSER"
sed -i "s/${LIVE}/${NEWUSER}/g" $user_home/.config/{openbox/autostart,gtk-3.0/bookmarks} \
$user_home/.mozilla/firefox/{archlabs.default/prefs.js,archlabs.default/sessionstore.js}
if [[ $AUTOLOGIN == true ]]; then
if [[ $LOGIN_TYPE == 'lightdm' ]]; then
rm -rf $user_home/.{zprofile,xinitrc}
else
sed -i "s/:-openbox/:-${LOGIN_WM}/g" $user_home/.xinitrc
sed -i '/archlabs-installer/d' $user_home/.zprofile
echo '[[ -z $DISPLAY && $XDG_VTNR -eq 1 ]] && exec startx -- vt1 &>/dev/null' >> $user_home/.zprofile
fi
else
rm -rf $user_home/.zprofile
sed -i "s/:-openbox/:-${LOGIN_WM}/g" $user_home/.xinitrc
fi
return 0
}
choose_window_manager() {
LOGIN_WM=""
LOGIN_TYPE=""
WM_PACKAGES=""
INSTALL_WMS="$(dialog --cr-wrap --stdout --backtitle "$BT" --no-cancel \
--title " $_WMChoice " --checklist "$_WMChoiceBody\n" 0 0 0 \
"openbox" "A lightweight, powerful, and highly configurable stacking window manager" off \
"bspwm" "A tiling window manager that represents windows as the leaves of a binary tree" off \
"i3-gaps" "A fork of i3 window manager with more features including gaps" off \
"gnome" "A desktop environment that aims to be simple and easy to use" off \
"xfce4" "A lightweight and modular desktop environment based on GTK+ 2 and 3" off)"
INSTALL_WMS="${INSTALL_WMS:-openbox}"
WM_NUM=$(awk '{print NF}' <<< "$INSTALL_WMS")
for wm in $INSTALL_WMS; do
WM_LOGIN_CHOICES="${WM_LOGIN_CHOICES}$wm - "
case $wm in
openbox) WM_PACKAGES="$WM_PACKAGES $wm obconf archlabs-ob-autostart archlabs-obkey archlabs-kickshaw" ;;
bspwm) WM_PACKAGES="$WM_PACKAGES $wm sxhkd lxappearance" ;;
i3-gaps) WM_PACKAGES="$WM_PACKAGES $wm i3status perl-anyevent-i3 lxappearance" ;;
gnome) WM_PACKAGES="$WM_PACKAGES $wm gnome-extra" ;;
xfce4) WM_PACKAGES="$WM_PACKAGES $wm xfce4-goodies xfce4-pulseaudio-plugin" ;;
esac
done
if yesno "$_WMLogin" "$_LoginTypeBody\n" "xinit" "lightdm"; then
LOGIN_TYPE="xinit"
else
LOGIN_TYPE="lightdm"
fi
if yesno "$_WMLogin" "$_AutoLoginBody\n"; then
AUTOLOGIN=true
else
AUTOLOGIN=false
fi
if [[ $WM_NUM -eq 1 ]]; then
LOGIN_WM="$INSTALL_WMS"
else
LOGIN_WM="$(dialog --cr-wrap --stdout --no-cancel --backtitle "$BT" \
--title " $_WMLogin " --menu "$_WMLoginBody" 0 0 0 $WM_LOGIN_CHOICES)"
[[ $LOGIN_WM == "" ]] && LOGIN_WM="$(awk '{print $1}' <<< "$INSTALL_WMS")"
fi
case $LOGIN_WM in
i3-gaps) LOGIN_WM='i3' ;;
gnome) LOGIN_WM='gnome-session' ;;
openbox) LOGIN_WM='openbox-session' ;;
xfce4) LOGIN_WM='startxfce4' ;;
esac
return 0
}
######################################################################
## System Partitioning Functions ##
######################################################################
decrease_part_count() {
# remove a partition from the dialog list and decrement the number partitions left
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
}
wipe_device() {
local device="$1"
if yesno "$_PartWipe" "$_PartBody1 $device $_PartWipeBody2"; then
tput civis
wipe -Ifre "$device" | dialog --cr-wrap --backtitle "$BT" --title " $_PartWipe " \
--progressbox "\nSecure wiping $device\n" 18 70
else
create_partitions "$device"
fi
}
mount_partition() {
local part="$1"
local mount="$2"
local fs="$(lsblk -lno FSTYPE $part)"
mkdir -p "${MNT}$mount"
if [[ ${FS_OPTS[$fs]} != "" && $part != "$BOOT_PART" ]] && select_mount_opts "$part" "$fs"; then
mount -o $MNT_OPTS "$part" "${MNT}$mount" 2>$ERR
check_for_errors "mount -o $MNT_OPTS $part ${MNT}$mount" || return 1
else
mount "$part" "${MNT}$mount" 2>$ERR
check_for_errors "mount $part ${MNT}$mount" || return 1
fi
confirm_mount "$part" "${MNT}$mount" || return 1
check_part_is_crypt_or_lvm "$part"
return 0
}
unmount_partitions() {
swapoff -a
for i in $(mount | grep "$MNT" | awk '{print $3}' | sort -r); do
umount -r "$i" >/dev/null 2>&1
done
}
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
# partition failed to mount properly
if ! grep -q "$mount" <<< "$(mount)"; then
infobox "$_MntTitle" "$_MntFail\n$msg\n"
return 1
fi
# mount was successful
infobox "$_MntTitle" "$_MntSucc\n$msg\n"
decrease_part_count "$part"
return 0
}
find_partitions() {
local str="$1"
local err='NONE'
# 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 an error was found with the partition setup and there aren't enough partitions
# show the appropriate error message for the given $str types were using
if [[ $err != 'NONE' ]]; then
msgbox "$_ErrTitle" "$err"
if select_device 'root'; then
create_partitions "$DEVICE"
else
return 1
fi
fi
return 0
}
auto_partition() {
local device="$1"
# confirm or bail
yesno "$_PrepParts" "$_PartBody1 $device $_PartBody2" || return 0
infobox "$_PrepParts" "\nAuto partitioning device: $device\n"
swapoff -a # make sure swap is disabled
# partition number of each partition on the device in reverse order
local dev_info="$(parted -s $device print)"
for i in $(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r); do
parted -s $device rm $i 2>$ERR
check_for_errors "parted -s $device rm $i" || { break; return 1; }
done
# make sure we have the correct device table for the system type, gpt or msdos
local table="$(awk '/Table:/ {print $3}' <<< "$dev_info")"
if [[ $SYS == BIOS ]]; then
local newtable="msdos"
else
local newtable="gpt"
fi
# if the current device table isn't correct run mklabel
if [[ $table != "$newtable" ]]; then
parted -s $device mklabel $newtable 2>$ERR
check_for_errors "parted -s $device mklabel $newtable" || return 1
fi
local part_num=1
BOOT_PART="${device}$part_num"
if [[ $SYS == "BIOS" ]]; then
parted -s $device mkpart primary ext4 1MiB 513MiB 2>$ERR
check_for_errors "parted -s $device mkpart primary ext4 1MiB 513MiB" || { BOOT_PART=""; return 1; }
mkfs.ext4 -q $BOOT_PART >/dev/null 2>$ERR
check_for_errors "mkfs.ext4 -q $BOOT_PART" || { BOOT_PART=""; return 1; }
else
parted -s $device mkpart ESP fat32 1MiB 513MiB 2>$ERR
check_for_errors "parted -s $device mkpart ESP fat32 1MiB 513MiB" || { BOOT_PART=""; return 1; }
mkfs.vfat -F32 $BOOT_PART >/dev/null 2>$ERR
check_for_errors "mkfs.vfat -F32 $BOOT_PART" || { BOOT_PART=""; return 1; }
parted -s $device set 1 esp on 2>$ERR
check_for_errors "parted -s $device set 1 esp on" || { BOOT_PART=""; return 1; }
fi
parted -s $device set 1 boot on 2>$ERR
check_for_errors "parted -s $device set 1 boot on" || return 1
BOOT_DEVICE="$device" # only grub on BIOS systems uses this
ROOT_PART="${device}$((part_num + 1))"
parted -s $device mkpart primary ext4 514MiB 100% 2>$ERR
check_for_errors "parted -s $device mkpart primary ext4 514MiB 100%" || return 1
mkfs.ext4 -q $ROOT_PART >/dev/null 2>$ERR
check_for_errors "mkfs.ext4 -q $ROOT_PART" || { ROOT_PART=""; return 1; }
tput civis
sleep 0.5
echo -e "\nAuto partitioning complete.\n" > /tmp/.devlist
lsblk $device -o NAME,MODEL,TYPE,FSTYPE,SIZE >> /tmp/.devlist
dialog --cr-wrap --backtitle "$BT" --title " $_PrepParts " --textbox /tmp/.devlist 0 0
return 0
}
create_partitions() {
local device="$1"
local choice
tput civis
if hash gparted >/dev/null 2>&1 && [[ $DISPLAY ]]; then
choice="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_PartTitle " \
--menu "$_PartBody" 0 0 0 "$_PartAuto" "BIOS & UEFI" \
"gparted" "BIOS & UEFI" "cfdisk" "BIOS & UEFI" "parted" "BIOS & UEFI" "$_PartWipe" "BIOS & UEFI")"
else
choice="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_PartTitle " \
--menu "$_PartBody" 0 0 0 "$_PartAuto" "BIOS & UEFI" \
"cfdisk" "BIOS & UEFI" "parted" "BIOS & UEFI" "$_PartWipe" "BIOS & UEFI")"
fi
[[ $? != 0 || $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 || { initialize_variables; return 1; }
fi
}
get_swap_size() {
tput cnorm
SWAP_SIZE="$(getinput "$_SelSwpSetup" "$_SelSwpSize" "$SWAP_SIZE")"
[[ $? != 0 || $SWAP_SIZE == "" ]] && return 1
# size is incorrect
if ! [[ ${SWAP_SIZE:0:1} =~ [1-9] && ${SWAP_SIZE: -1} =~ (M|G) ]]; then
msgbox "$_SelSwpSetup Error" "\n$_SelSwpErr $SWAP_SIZE\n"
SWAP_SIZE="${SYS_MEM}M"
get_swap_size || return 1
fi
return 0
}
select_swap() {
# Ask user to select partition or create swapfile
SWAP="$(dialog --backtitle "$BT" --cr-wrap --stdout --title " $_SelSwpSetup " \
--menu "$_SelSwpBody" 0 0 0 "$_SelSwpNone" "-" "$_SelSwpFile" "-" $PARTS)"
[[ $? != 0 || $SWAP == "$_SelSwpNone" ]] && return 0
if [[ $SWAP == "$_SelSwpFile" ]]; then
get_swap_size || return 1
fallocate -l $SWAP_SIZE $MNT/swapfile 2>$ERR
check_for_errors "fallocate -l $size $MNT/swapfile" || return 1
chmod 600 $MNT/swapfile 2>$ERR
check_for_errors "chmod 600 $MNT/swapfile" || return 1
mkswap $MNT/swapfile >/dev/null 2>$ERR
check_for_errors "mkswap $MNT/swapfile" || return 1
swapon $MNT/swapfile >/dev/null 2>$ERR
check_for_errors "swapon $MNT/swapfile" || return 1
SWAP_FILE="/swapfile"
else
# Warn user if creating a new swap on the chosen partition
if ! grep -qi "swap" <<< "$(lsblk -o FSTYPE $SWAP)"; then
yesno "$_PrepMount" "\nmkswap $SWAP\n" || return 0
mkswap $SWAP >/dev/null 2>$ERR
check_for_errors "mkswap $SWAP" || return 1
fi
swapon $SWAP >/dev/null 2>$ERR
check_for_error "swapon $SWAP" || return 1
decrease_part_count "$SWAP"
SWAP_FILE="$SWAP"
fi
return 0
}
select_device() {
local msg=""
[[ $1 == 'boot' ]] && msg="$_DevSelTitle for bootloader\n"
if (( DEV_COUNT == 1 )); then
DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
infobox "$_DevSelTitle" "\nOnly one device available$([[ $1 == 'boot' ]] && echo -n " for bootloader"): $DEVICE\n"
elif (( DEV_COUNT > 1 )); then
tput civis
DEVICE="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_DevSelTitle " \
--menu "${msg}$_DevSelBody" 0 0 0 $SYS_DEVS)"
[[ $? != 0 || $DEVICE == "" ]] && return 1
else
msgbox "$_ErrTitle" "\nNo available devices for installation to use.\n\nExiting.."
pgrep -f "$TERM_CMD -e tail" && pkill -f "$TERM_CMD -e tail"
tput cnorm
clear
exit 1
fi
# if the device selected was for grub, set the BOOT_DEVICE
# this is needed because grub uses the base device for BIOS, not the partition
[[ $msg != "" ]] && BOOT_DEVICE="$DEVICE"
return 0
}
select_mount_opts() {
local part="$1"
local fs="$2"
local title="${fs^} Mount Options"
tput civis
MNT_OPTS="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $title " \
--checklist "$_MntBody" 0 0 0 ${FS_OPTS[$fs]} | sed 's/ /,/g; $s/,$//')"
[[ $? != 0 || $MNT_OPTS == "" ]] && return 1
if ! yesno "$title" "$_MntConfBody $MNT_OPTS\n"; then
select_mount_opts "$part" "$fs" || return 1
fi
return 0
}
select_filesystem() {
local part="$1"
local cur_fs
cur_fs="$(lsblk -lno FSTYPE $part)"
tput civis
local choice
choice="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_FSTitle: $part" \
--menu "\nPartition: ${part}$([[ $cur_fs != "" ]] && echo -n "\nCurrent: ${cur_fs}")\n$_FSBody" 0 0 0 \
$([[ $cur_fs != "" ]] && echo -n "$_Skip -") \
"ext4" "${FS_CMDS[ext4]}" "ext3" "${FS_CMDS[ext3]}" \
"ext2" "${FS_CMDS[ext2]}" "vfat" "${FS_CMDS[vfat]}" \
"ntfs" "${FS_CMDS[ntfs]}" "f2fs" "${FS_CMDS[f2fs]}" \
"jfs" "${FS_CMDS[jfs]}" "nilfs2" "${FS_CMDS[nilfs2]}" \
"reiserfs" "${FS_CMDS[reiserfs]}" "xfs" "${FS_CMDS[xfs]}")"
[[ $choice == "$_Skip" ]] && return 0
[[ $choice == "" ]] && return 1
if yesno "$_FSTitle" "\nFormat $part as $choice?\n"; then
infobox "$_FSTitle" "\nFormatting: $part\n\nCommand: ${FS_CMDS[$choice]}\n"
${FS_CMDS[$choice]} $part >/dev/null 2>$ERR
check_for_errors "${FS_CMDS[$choice]} $part" || return 1
else
select_filesystem "$part" || return 1
fi
return 0
}
select_boot_setup() {
# choose bootloader and by extension mountpoint (if needed)
tput civis
BOOTLOADER="$(dialog --cr-wrap --stdout --backtitle "$BT" \
--title " $_PrepMount " --menu "$_MntBootBody" 0 0 0 ${BOOTLOADERS[$SYS]})"
[[ $? != 0 || $BOOTLOADER == "" ]] && return 1
if [[ $SYS == 'BIOS' ]]; then
if [[ $BOOTLOADER == "grub" && $BOOT_DEVICE == "" ]]; then
# grub BIOS needs an install device eg. /dev/sda
select_device 'boot' || return 1
BOOT_DEVICE="$DEVICE"
else
local cmd
cmd="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_InstSysTitle " \
--menu "$_InstSysBody\nDefault: ${BOOT_CMDS[syslinux]}" 0 0 0 \
"syslinux-install_update -iam" "[MBR]" \
"syslinux-install_update -i" "[/]")"
[[ $? != 0 || $cmd == "" ]] && return 1
BOOT_CMDS[syslinux]="$cmd"
EDIT_FILES[9]="/boot/syslinux/syslinux.cfg"
fi
else
if [[ $BOOTLOADER == 'systemd-boot' ]]; then
EDIT_FILES[9]="/boot/loader/entries/archlabs.conf"
else
EDIT_FILES[9]="/etc/default/grub"
if yesno "$_PrepMount" "$_SetBootDefault"; then
GRUB_UEFI_FALLBACK=true
fi
fi
fi
# if BOOT_PART was set, mount the partition to the correct mountpoint
if [[ $BOOT_PART != "" ]]; then
mount_partition "$BOOT_PART" "${BOOT_MNTS[$SYS-$BOOTLOADER]}" || return 1
SEPERATE_BOOT=1
fi
return 0
}
select_efi_partition() {
format_efi_as_vfat() {
infobox "$_FSTitle" "\nFormatting $1 as vfat/fat32.\n"
mkfs.vfat -F32 "$1" >/dev/null 2>$ERR
check_for_errors "mkfs.vfat -F32 $1" || return 1
}
if (( COUNT == 1 )); then
BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
infobox "$_PrepMount" "\nOnly one partition available for EFI: $BOOT_PART\n"
else
tput civis
BOOT_PART="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_PrepMount " \
--menu "$_SelUefiBody" 0 0 0 $PARTS)"
[[ $? != 0 || $BOOT_PART == "" ]] && return 1
fi
if grep -q 'fat' <<< "$(fsck -N "$BOOT_PART")"; then
local msg="$_FormUefiBody $BOOT_PART $_FormUefiBody2"
if yesno "$_PrepMount" "$msg" "Format $BOOT_PART" "Skip Formatting" "no"; then
format_efi_as_vfat "$BOOT_PART" || return 1
fi
else
format_efi_as_vfat "$BOOT_PART" || return 1
fi
return 0
}
select_bios_boot_partition() {
format_as_ext4() {
infobox "$_FSTitle" "\nFormatting $1 as ext4.\n"
mkfs.ext4 -q "$1" >/dev/null 2>$ERR
check_for_errors "mkfs.ext4 -q $1" || return 1
}
tput civis
BOOT_PART="$(dialog --cr-wrap --stdout --backtitle "$BT" --title "$_PrepMount" \
--menu "$_SelBiosBody" 0 0 0 "$_Skip" "-" $PARTS)"
if [[ $? != 0 || $BOOT_PART == "$_Skip" || $BOOT_PART == "" ]]; then
BOOT_PART=""
else
if grep -q 'ext[34]' <<< "$(fsck -N "$BOOT_PART")"; then
local msg="$_FormBiosBody $BOOT_PART $_FormUefiBody2"
if yesno "$_PrepMount" "$msg" "Format $BOOT_PART" "Skip Formatting" "no"; then
format_as_ext4 "$BOOT_PART" || return 1
fi
else
format_as_ext4 "$BOOT_PART" || return 1
fi
# set BOOT_DEVICE for BIOS grub by removing digit from the end
BOOT_DEVICE="${BOOT_PART%[1-9]}"
PART_NUM="${BOOT_PART#$BOOT_DEVICE}"
parted -s $BOOT_DEVICE set $PART_NUM boot on 2>$ERR
check_for_errors "parted -s $BOOT_DEVICE set $PART_NUM boot on" || return 1
fi
return 0
}
select_root_partition() {
if (( LUKS == 1 && LVM == 0 )); then
ROOT_PART="/dev/mapper/$LUKS_NAME"
decrease_part_count "$LUKS_PART"
elif (( LUKS == 1 && LVM == 1 )); then
decrease_part_count "$LUKS_PART"
decrease_part_count "/dev/mapper/$LUKS_NAME"
ROOT_PART=""
fi
if [[ $COUNT -eq 1 && $ROOT_PART == "" ]]; then
ROOT_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
infobox "$_PrepMount" "\nOnly one partition available for root (/): $ROOT_PART\n"
elif [[ $ROOT_PART == "" || $LVM -eq 1 ]]; then
tput civis
ROOT_PART="$(dialog --cr-wrap --stdout --backtitle "$BT" --title "$_PrepMount" \
--menu "$_SelRootBody" 0 0 0 $PARTS)"
[[ $? != 0 || $ROOT_PART == "" ]] && return 1
else
infobox "$_PrepMount" "\nUsing $([[ $LUKS -eq 1 ]] && echo -n "encrypted ")root partition: $ROOT_PART\n"
fi
select_filesystem "$ROOT_PART" || { ROOT_PART=""; return 1; }
mount_partition "$ROOT_PART" "" || { ROOT_PART=""; return 1; }
return 0
}
select_mountpoint() {
tput cnorm
EXTRA_MNT="$(getinput "$_PrepMount $part" "$_ExtPartBody1 /home /var\n" "/")"
[[ $? != 0 || $EXTRA_MNT == "" ]] && return 1
# bad mountpoint
if [[ ${EXTRA_MNT:0:1} != "/" || ${#EXTRA_MNT} -le 1 || $EXTRA_MNT =~ \ |\' ]]; then
msgbox "$_ErrTitle" "$_ExtErrBody"
select_mountpoint || return 1
fi
return 0
}
select_extra_partitions() {
while (( COUNT > 0 )); do
tput civis
local part
part="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_PrepMount " \
--menu "$_ExtPartBody" 0 0 0 "$_Done" "-" $PARTS)"
# cancel or done, exit normally
[[ $? != 0 || $part == "$_Done" || $part == "" ]] && break
# choose what filesystem and get mountpoint
select_filesystem "$part" || { break; return 1; }
select_mountpoint || { break; return 1; }
# mount it
mount_partition "$part" "$EXTRA_MNT" || { break; return 1; }
# if the mountpoint was /usr add 'usr' to MKINIT_HOOKS
[[ $EXTRA_MNT == "/usr" && $MKINIT_HOOKS != *usr* ]] && MKINIT_HOOKS="usr $MKINIT_HOOKS"
done
return 0
}
select_install_partitions() {
msgbox "$_PrepMount" "$_WarnMount"
lvm_detect
# prepare partition list PARTS for dialog
unmount_partitions
find_partitions 'part|lvm|crypt' || return 1
# remove boot partition from dialog list if we auto partitioned one
[[ $BOOT_PART != "" ]] && decrease_part_count "$BOOT_PART"
select_root_partition || return 1
if [[ $BOOT_PART == "" ]]; then
if [[ $SYS == "UEFI" ]]; then
select_efi_partition || { BOOT_PART=""; return 1; }
elif (( COUNT > 0 )); then
select_bios_boot_partition || { BOOT_PART=""; return 1; }
fi
else
infobox "$_PrepMount" "\nUsing boot partition: $BOOT_PART\n"
fi
select_boot_setup || { BOOTLOADER=""; return 1; }
select_swap || return 1
select_extra_partitions || return 1
return 0
}
check_part_is_crypt_or_lvm() {
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=1
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=1
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=1
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=1
break
fi
done
fi
}
######################################################################
## Encryption (dm_crypt) Functions ##
######################################################################
luks_open() {
LUKS_PART=""
modprobe -a dm-mod dm_crypt
unmount_partitions
find_partitions 'part|crypt|lvm'
tput civis
if (( COUNT == 1 )); then
LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
infobox "$_LuksOpen" "\nOnly one partition available: $LUKS_PART\n"
else
tput civis
LUKS_PART="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_LuksOpen " \
--menu "$_LuksMenuBody" 0 0 0 $PARTS)"
[[ $? != 0 || $LUKS_PART == "" ]] && return 1
fi
# get password and name for encryption
luks_input_values "$_LuksOpen" "$LUKS_NAME" || return 1
infobox "$_LuksOpen" "$_LuksWaitBody $LUKS_NAME $_LuksWaitBody2 $LUKS_PART\n"
echo "$LUKS_PASS" | cryptsetup open --type luks "$LUKS_PART" "$LUKS_NAME" 2>$ERR
check_for_errors "cryptsetup open --type luks $LUKS_PART $LUKS_NAME" || return 1
LUKS=1
luks_show
return 0
}
luks_input_values() {
local title="$1"
local name="$2"
LUKS_PASS=""
tput cnorm
local values
values="$(dialog --stdout --separator '~' --ok-label "Submit" --backtitle "$BT" \
--title " $title " --insecure --mixedform "$_LuksOpenBody" 16 75 4 \
"$_Name" 1 1 "$name" 1 $((${#_Name} + 2)) 71 0 0 \
"$_Password" 2 1 "" 2 $((${#_Password} + 2)) 71 0 1 \
"$_Password2" 3 1 "" 3 $((${#_Password2} + 2)) 71 0 1)"
[[ $? != 0 || $values == "" ]] && return 1
name="$(awk -F'~' '{print $1}' <<< "$values")"
local pass pass2
pass="$(awk -F'~' '{print $2}' <<< "$values")"
pass2="$(awk -F'~' '{print $3}' <<< "$values")"
if [[ $pass == "" || "$pass" != "$pass2" ]]; then
msgbox "$_ErrTitle" "$_PassErr\n$_TryAgain"
luks_input_values "$title" "$name" || return 1
fi
LUKS_PASS="$pass"
LUKS_NAME="$name"
return 0
}
luks_setup() {
LUKS_PART=""
modprobe -a dm-mod dm_crypt
unmount_partitions
if [[ $ROOT_PART == "" || $LVM -eq 1 ]]; then
find_partitions 'part|lvm'
[[ $BOOT_PART != "" ]] && decrease_part_count "$BOOT_PART"
if (( COUNT == 1 )); then
LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
infobox "$_LuksEncrypt" "\nOnly one partition available: $LUKS_PART\n"
else
tput civis
LUKS_PART="$(dialog --cr-wrap --stdout --backtitle "$BT" \
--title "$_LuksEncrypt" --menu "$_LuksEncryptBody" 0 0 0 $PARTS)"
[[ $? != 0 || $LUKS_PART == "" ]] && return 1
fi
else
infobox "$_PrepMount" "\nUsing root partition created in auto partitioning: $ROOT_PART\n"
LUKS_PART="$ROOT_PART"
fi
# get password and name for encryption
luks_input_values "$_LuksEncrypt" "$LUKS_NAME" || return 1
return 0
}
luks_default() {
luks_setup || return 1
local msg="$_LuksWaitBody $LUKS_NAME $_LuksWaitBody2 $LUKS_PART\n"
infobox "$_LuksEncrypt" "$msg"
echo "$LUKS_PASS" | cryptsetup -q luksFormat "$LUKS_PART" 2>$ERR
check_for_errors "cryptsetup -q luksFormat $LUKS_PART" || return 1
echo "$LUKS_PASS" | cryptsetup open "$LUKS_PART" "$LUKS_NAME" 2>$ERR
check_for_errors "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
LUKS=1
luks_show
return 0
}
luks_cipher_key() {
if luks_setup; then
tput cnorm
local cipher
cipher="$(getinput "$_PrepLUKS" "$_LuksCipherKey" "-s 512 -c aes-xts-plain64")"
[[ $? != 0 || $cipher == "" ]] && return 1
infobox "$_LuksEncryptAdv" "$_LuksWaitBody $LUKS_NAME $_LuksWaitBody2 $LUKS_PART\n"
echo "$LUKS_PASS" | cryptsetup -q $cipher luksFormat $LUKS_PART 2>$ERR
check_for_errors "cryptsetup -q $cipher luksFormat $LUKS_PART" || return 1
echo "$LUKS_PASS" | cryptsetup open $LUKS_PART "$LUKS_NAME" 2>$ERR
check_for_errors "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
luks_show
return 0
fi
return 1
}
luks_show() {
tput civis
sleep 0.5
echo -e "$_LuksEncryptSucc" > /tmp/.devlist
lsblk -o NAME,TYPE,FSTYPE,SIZE $LUKS_PART >> /tmp/.devlist
dialog --cr-wrap --backtitle "$BT" --title " $_LuksEncrypt " --textbox /tmp/.devlist 0 0
}
luks_menu() {
tput civis
local choice
choice="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_PrepLUKS " \
--menu "${_LuksMenuBody}${_LuksMenuBody2}${_LuksMenuBody3}" 0 0 0 \
"$_LuksEncrypt" "cryptsetup -q luksFormat" \
"$_LuksOpen" "cryptsetup open --type luks" \
"$_LuksEncryptAdv" "cryptsetup -q -s -c luksFormat" \
"$_Back" "-")"
case $choice in
"$_LuksEncrypt") luks_default && return 0 ;;
"$_LuksOpen") luks_open && return 0 ;;
"$_LuksEncryptAdv") luks_cipher_key && return 0 ;;
*) 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"
local dev
dev="$(lsblk -lno NAME,UUID,TYPE | awk "/$LUKS_UUID/"' && /part|crypt|lvm/ {print $1}')"
dev="/dev/$dev"
local keycmd
keycmd="dd bs=512 count=8 if=/dev/urandom of=/crypto_keyfile.bin && chmod 000 /crypto_keyfile.bin &&
echo '$LUKS_PASS' | cryptsetup luksAddKey $dev /crypto_keyfile.bin"
chroot_cmd "$keycmd" 2>$ERR
check_for_errors "$keycmd" || return 1
sed -i 's/FILES=()/FILES=(\/crypto_keyfile.bin)/g' $MNT/etc/mkinitcpio.conf 2>$ERR
check_for_errors 'sed -i "s/FILES=()/FILES=(/crypto_keyfile.bin)/g"' || return 1
chroot_cmd "mkinitcpio -p linux" 2>$ERR >/dev/null 2>&1
check_for_errors "mkinitcpio -p linux" || return 1
fi
return 0
}
######################################################################
## Logical Volume Management Functions ##
######################################################################
lvm_detect() {
PHYSICAL_VOLUMES="$(pvs -o pv_name --noheading 2>/dev/null)"
VOLUME_GROUP="$(vgs -o vg_name --noheading 2>/dev/null)"
VOLUMES="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
if [[ $VOLUMES && $VOLUME_GROUP && $PHYSICAL_VOLUMES ]]; then
infobox "$_PrepLVM" "$_LvmDetBody"
modprobe dm-mod 2>$ERR
check_for_errors 'modprobe dm-mod' || return 1
vgscan >/dev/null 2>&1
vgchange -ay >/dev/null 2>&1
fi
}
lvm_show_vg() {
DEL_VG=""
VOL_GROUP_LIST=""
for i in $(lvs --noheadings | awk '{print $2}' | uniq); do
VOL_GROUP_LIST="$VOL_GROUP_LIST $i $(vgdisplay "$i" | awk '/VG Size/ {print $3$4}')"
done
if [[ $VOL_GROUP_LIST == "" ]]; then
msgbox "$_ErrTitle" "$_LvmVGErr"
return 1
fi
tput civis
DEL_VG="$(dialog --cr-wrap --stdout --backtitle "$BT" \
--title " $_PrepLVM " --menu "$_LvmSelVGBody" 18 70 10 $VOL_GROUP_LIST)"
[[ $? != 0 || $DEL_VG == "" ]] && return 1
}
get_lv_size() {
tput cnorm
local ttl=" $_LvmCreateVG (LV:$VOL_COUNT) "
local msg="${VOLUME_GROUP}: ${VOL_GROUP_SIZE}$VOL_GROUP_SIZE_TYPE (${VOL_GROUP_MB}MB $_LvmLvSizeBody1).$_LvmLvSizeBody2"
VOLUME_SIZE="$(getinput "$ttl" "$msg" "")"
[[ $? != 0 || $VOLUME_SIZE == "" ]] && return 1
ERR_SIZE=0
# if the size is empty or 0
(( ${#VOLUME_SIZE} == 0 || ${VOLUME_SIZE:0:1} == 0 )) && ERR_SIZE=1
if (( ERR_SIZE == 0 )); then
# number of characters in VOLUME_SIZE minus the last, which should be a letter
local lv="$((${#VOLUME_SIZE} - 1))"
# loop each character (except the last) in VOLUME_SIZE and ensure they are numbers
for (( i=0; i<lv; i++ )); do
[[ ${VOLUME_SIZE:$i:1} != [0-9] ]] && { ERR_SIZE=1; break; }
done
if (( ERR_SIZE == 0 )); then
# ensure the last character is either m/M or g/G
case ${VOLUME_SIZE:$lv:1} in
[mMgG]) ERR_SIZE=0 ;;
*) ERR_SIZE=1
esac
if (( ERR_SIZE == 0 )); then
s=${VOLUME_SIZE:0:$lv}
m=$((s * 1000))
# check whether the value is greater than or equal to the LV remaining Size.
# if not, convert into MB for VG space remaining.
case ${VOLUME_SIZE:$lv:1} in
[Gg])
if (( m >= VOL_GROUP_MB )); then
ERR_SIZE=1
else
VOL_GROUP_MB=$((VOL_GROUP_MB - m))
fi ;;
[Mm])
if (( ${VOLUME_SIZE:0:$lv} >= VOL_GROUP_MB )); then
ERR_SIZE=1
else
VOL_GROUP_MB=$((VOL_GROUP_MB - s))
fi ;;
*) ERR_SIZE=1
esac
fi
fi
fi
if (( ERR_SIZE == 1 )); then
msgbox "$_ErrTitle" "$_LvmLvSizeErrBody"
get_lv_size || return 1
fi
return 0
}
lvm_volume_name() {
local msg="$1"
local default="volmain"
(( VOL_COUNT > 1 )) && default="volextra"
tput cnorm
local name
name="$(getinput "$_LvmCreateVG (LV:$VOL_COUNT)" "$msg" "$default")"
[[ $? != 0 || $name == "" ]] && return 1
# bad volume name answer or name already in use
if [[ ${name:0:1} == "/" || ${#name} -eq 0 || $name =~ \ |\' ]] || grep -q "$name" <<< "$(lsblk)"; then
msgbox "$_ErrTitle" "$_LvmLvNameErrBody"
lvm_volume_name "$msg" || return 1
fi
VOLUME_NAME="$name"
return 0
}
lvm_group_name() {
tput cnorm
local group
group="$(getinput "$_LvmCreateVG" "$_LvmNameVgBody" "VolGroup")"
[[ $? != 0 || $group == "" ]] && return 1
# bad answer or group name already taken
if [[ ${group:0:1} == "/" || ${#group} -eq 0 || $group =~ \ |\' ]] || grep -q "$group" <<< "$(lsblk)"; then
msgbox "$_ErrTitle" "$_LvmNameVgErr"
lvm_group_name || return 1
fi
VOLUME_GROUP="$group"
return 0
}
lvm_extra_lvs() {
while (( VOL_COUNT > 1 )); do
# get the name and size
lvm_volume_name "$_LvmLvNameBody1" || { break; return 1; }
get_lv_size || { break; return 1; }
# create it
lvcreate -L "$VOLUME_SIZE" "$VOLUME_GROUP" -n "$VOLUME_NAME" 2>$ERR
check_for_errors "lvcreate -L $VOLUME_SIZE $VOLUME_GROUP -n $VOLUME_NAME" || { break; return 1; }
msgbox "$_LvmCreateVG (LV:$VOL_COUNT)" "$_Done LV $VOLUME_NAME ($VOLUME_SIZE) $_LvmPvDoneBody2."
((VOL_COUNT--)) # decrement the number of volumes chosen to end the loop
done
return 0
}
lvm_volume_count() {
VOL_COUNT=$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_LvmCreateVG " \
--radiolist "$_LvmLvNumBody1 $VOLUME_GROUP\n$_LvmLvNumBody2" 0 0 0 \
"1" "-" off "2" "-" off "3" "-" off "4" "-" off "5" "-" off "6" "-" off "7" "-" off "8" "-" off "9" "-" off)
[[ $? != 0 || $VOL_COUNT == "" ]] && return 1
return 0
}
lvm_create() {
VOLUME_GROUP=""
VOL_GROUP_PARTS=""
VOL_GROUP_MB=0
unmount_partitions
if [[ $LUKS -eq 1 && $LUKS_NAME != "" ]]; then
VOL_GROUP_PARTS="/dev/mapper/$LUKS_NAME"
infobox "$_LvmCreateVG" "\nUsing encrypted partition created earlier: $VOL_GROUP_PARTS\n"
else
find_partitions 'part|crypt'
tput civis
PARTS="$(awk 'NF > 0 {print $0 " off"}' <<< "$PARTS")"
# choose partitions
VOL_GROUP_PARTS="$(dialog --cr-wrap --stdout --backtitle "$BT" \
--title "$_LvmCreateVG" --checklist "$_LvmPvSelBody" 0 0 0 $PARTS)"
[[ $? != 0 || $VOL_GROUP_PARTS == "" ]] && return 1
fi
# get volume group name then confirm or bail out
lvm_group_name || return 1
yesno "$_LvmCreateVG" "$_LvmPvConfBody1 $VOLUME_GROUP\n\n$_LvmPvConfBody2 $VOL_GROUP_PARTS\n" || return 1
# create it
infobox "$_LvmCreateVG" "$_LvmPvActBody1 $VOLUME_GROUP\n"
vgcreate -f "$VOLUME_GROUP" "$VOL_GROUP_PARTS" >/dev/null 2>$ERR
check_for_errors "vgcreate -f $VOLUME_GROUP $VOL_GROUP_PARTS" || return 1
# get volume size and size type (MB, GB, etc..)
VOL_GROUP_SIZE=$(vgdisplay "$VOLUME_GROUP" | awk '/VG Size/ {gsub(/\..*|[^0-9]*/, ""); print}')
VOL_GROUP_SIZE_TYPE="$(vgdisplay "$VOLUME_GROUP" | awk '/VG Size/ {print $4}')"
# transform size to MB if needed
if [[ ${VOL_GROUP_SIZE_TYPE:0:1} == "G" ]]; then
VOL_GROUP_MB=$((VOL_GROUP_SIZE * 1000))
else
VOL_GROUP_MB=$VOL_GROUP_SIZE
fi
# finished volume group creation
msgbox "$_LvmCreateVG" "$_LvmPvDoneBody1 $VOLUME_GROUP ($VOL_GROUP_SIZE $VOL_GROUP_SIZE_TYPE) $_LvmPvDoneBody2\n"
tput civis
# how many logical volumes
lvm_volume_count || return 1
# if we chose more than one logical volume create all but the last
lvm_extra_lvs || return 1
# last or only logical volume
lvm_volume_name "$_LvmLvNameBody1 $_LvmLvNameBody2 (${VOL_GROUP_MB}MB)" || return 1
# create it
lvcreate -l +100%FREE "$VOLUME_GROUP" -n "$VOLUME_NAME" 2>$ERR
check_for_errors "lvcreate -l +100%FREE $VOLUME_GROUP -n $VOLUME_NAME" || return 1
LVM=1
# offer the user to see the device tree
yesno "$_LvmCreateVG" "$_LvmCompBody" && show_devices
return 0
}
lvm_del_vg() {
if lvm_show_vg; then
yesno "$_LvmDelVG" "$_LvmDelQ" && vgremove -f "$DEL_VG" >/dev/null 2>&1
fi
return 0
}
lvm_del_all() {
PHYSICAL_VOLUMES="$(pvs -o pv_name --noheading 2>/dev/null)"
VOLUME_GROUP="$(vgs -o vg_name --noheading 2>/dev/null)"
VOLUMES="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
if yesno "$_LvMDelAll" "$_LvmDelQ"; then
for i in $VOLUMES; do
lvremove -f "/dev/mapper/$i" >/dev/null 2>&1
done
for i in $VOLUME_GROUP; do
vgremove -f "$i" >/dev/null 2>&1
done
for i in $PHYSICAL_VOLUMES; do
pvremove -f "$i" >/dev/null 2>&1
done
LVM=0
fi
return 0
}
lvm_menu() {
lvm_detect
tput civis
local choice
choice="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_PrepLVM " \
--menu "$_LvmMenu" 0 0 0 \
"$_LvmCreateVG" "vgcreate -f, lvcreate -L -n" \
"$_LvmDelVG" "vgremove -f" \
"$_LvMDelAll" "lvrmeove, vgremove, pvremove -f" \
"$_Back" "-")"
case $choice in
"$_LvmCreateVG") lvm_create && return 0 ;;
"$_LvmDelVG") lvm_del_vg ;;
"$_LvMDelAll") lvm_del_all ;;
*) return 0
esac
lvm_menu
}
######################################################################
## Installation Functions ##
######################################################################
install_main() {
if [[ $UNPACKED_BASE != true ]]; then
# whether to use a custom mirror sorting command later
update_mirrorlist_cmd || MIRROR_CMD="reflector --score 100 -l 50 -f 10 --sort rate"
choose_window_manager || return 1
select_extra_packages
# user can choose to bail at this point
unpack_base_system || { initialize_variables; return 1; }
fi
genfstab -U $MNT > $MNT/etc/fstab 2>$ERR
check_for_errors "genfstab -U $MNT > $MNT/etc/fstab" || return 1
if [[ -f $MNT/swapfile ]]; then
sed -i "s~${MNT}~~" $MNT/etc/fstab 2>$ERR
check_for_errors "sed -i s~${MNT}~~ $MNT/etc/fstab" || return 1
fi
run_mkinitcpio || return 1
setup_bootloader || return 1
if [[ $HAS_NETWORK == true && $DONE_UPDATE != true ]]; then
update_mirrorlist
update_system
DONE_UPDATE=true
else
chroot_cmd "pacman -Rs archlabs-installer --noconfirm" >/dev/null 2>&1
if ! grep -qi "hypervisor" <<< "$(dmesg)" && pacman -Qsq virtualbox-guest &>/dev/null; then
chroot_cmd "pacman -Rns $(pacman -Qsq virtualbox-guest) --noconfirm" >/dev/null 2>&1
[[ -e $MNT/etc/xdg/autostart/vboxclient.desktop ]] && rm -f $MNT/etc/xdg/autostart/vboxclient.desktop
fi
fi
# these also only should need to be run once, when done jump to the config edit menu
if [[ $FULL_DONE != true ]]; then
configure_menu
if edit_config_menu; then
[[ $FULL_DONE == true ]] && return 0
fi
fi
}
unpack_base_system() {
# continue or bail
local msg="Boot Partition: ${BOOT_PART:-none}\nBootloader: $BOOTLOADER\nSwapfile: $SWAP_FILE"
yesno "$_InstTitle" "$_BeginInst $ROOT_PART\n$msg\n\n$_ContinueYN" || return 1
# create a loading bar while copying files using find, < <(), and a loop
# using awk, sed, or other means doesn't seem to work well (or at all).
local files=($(find /run/archiso/sfs/airootfs/ -maxdepth 1 -mindepth 1))
local total=${#files[@]}
local increment=0
tput civis
dialog --cr-wrap --backtitle "$BT" --title " $_InstTitle " \
--gauge "\nUnpacking the system\n" 7 70 < <(
for f in "${files[@]}"; do
current_percent=$((100 * (++increment) / total))
base="${f#/run/archiso/sfs/airootfs/}"
cat <<EOF
XXX
$current_percent
Unpacking /$base ...
XXX
EOF
if [[ $base == 'sbin' ]]; then
mkdir -p $MNT/usr/bin
ln -sfr $MNT/usr/bin $MNT/$base
elif [[ $base == 'bin' ]]; then
mkdir -p $MNT/usr/bin
ln -sfr $MNT/usr/bin $MNT/$base
elif [[ $base == 'lib' ]]; then
mkdir -p $MNT/usr/lib
ln -sfr $MNT/usr/lib $MNT/$base
elif [[ $base == 'lib64' ]]; then
mkdir -p $MNT/usr/lib
ln -sfr $MNT/usr/lib $MNT/$base
else
rsync -aq /run/archiso/sfs/airootfs/$base/ $MNT/$base
fi
done
)
find $MNT/usr/lib/initcpio -name 'archiso*' -type f -exec rm '{}' \;
rm -rf $MNT/etc/{mkinitcpio-archiso.conf,sudoers.d/g_wheel,polkit-1/rules.d/49-nopasswd_global.rules}
# rm -rf $MNT/usr/bin/{install-al,al-installer}
sed -i 's/volatile/auto/g' $MNT/etc/systemd/journald.conf
sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" $MNT/etc/sudoers
cp -rf /etc/NetworkManager/system-connections $MNT/etc/NetworkManager/
cp -f /run/archiso/bootmnt/arch/boot/x86_64/vmlinuz $MNT/boot/vmlinuz-linux
cp -f /tmp/00-keyboard.conf $MNT/etc/X11/xorg.conf.d/
cp -f /tmp/keyboard $MNT/etc/default/
cp -f /tmp/vconsole.conf $MNT/etc/
cp -f /etc/resolv.conf $MNT/etc/
grep -qi "hypervisor" <<< "$(dmesg)" && rm -rf $MNT/etc/X11/xorg.conf.d
UNPACKED_BASE=true
return 0
}
install_packages() {
tput civis
local pkgs="$WM_PACKAGES"
[[ $LOGIN_TYPE == 'lightdm' ]] && pkgs="$pkgs lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings accountsservice"
[[ $EXTRA_PACKAGES != "" ]] && pkgs="$pkgs $EXTRA_PACKAGES"
if [[ $INSTALL_WMS == 'gnome' ]]; then
REMOVE_PKGS="$(pacman -Qssq 'xfce4*' 2>/dev/null)"
fi
local pkgcmd="pacman -S $pkgs --needed --noconfirm"
[[ $REMOVE_PKGS != "" ]] && pkgcmd="pacman -Rns $REMOVE_PKGS --noconfirm ; $pkgcmd"
chroot_cmd "$pkgcmd" 2>/dev/null | dialog --cr-wrap --backtitle "$BT" --title " Install Packages " \
--progressbox "\nInstalling packages chosen during install setup.\n\n$pkgs" 30 90
[[ $LOGIN_TYPE == 'lightdm' ]] && setup_lightdm
return 0
}
select_extra_packages() {
if yesno "$_ExtraPackages" "$_ChooseExtraPackages"; then
EXTRA_PACKAGES="$(dialog --cr-wrap --stdout --backtitle "$BT" \
--title " $_WMChoice " --checklist "$_WMChoiceBody\n" 0 0 20 \
"firefox" "A popular open-source graphical web browser from Mozilla" off \
"chromium" "an open-source graphical web browser based on the Blink rendering engine" off \
"opera" "Fast and secure, free of charge web browser from Opera Software" off \
"qutebrowser" "A keyboard-focused vim-like web browser based on Python and PyQt5" off \
"atom" "An open-source text editor developed by GitHub that is licensed under the MIT License" off \
"geany" "A fast and lightweight IDE" off \
"emacs" "An extensible, customizable, self-documenting real-time display editor" off \
"neovim" "A fork of Vim aiming to improve user experience, plugins, and GUIs." off \
"mousepad" "A simple text editor" off \
"urxvt" "A unicode enabled rxvt-clone terminal emulator" off \
"tilix" "A tiling terminal emulator for Linux using GTK+ 3" off \
"terminator" "Terminal emulator that supports tabs and grids" off \
"tilda" "A Gtk based drop down terminal for Linux and Unix" off \
"xfce4-terminal" "A terminal emulator primarily for the XFCE desktop" off \
"termite" "A minimal VTE-based terminal emulator" off \
"pcmanfm" "A fast and lightweight file manager" off \
"gnome-disk-utility" "Disk Management Utility" off \
"gnome-system-monitor" "View current processes and monitor system state" off \
"steam steam-native-runtime" "A popular game distribution platform by Valve" off \
"vlc qt4" "a free and open source cross-platform multimedia player" off \
"audacious" "A free and advanced audio player based on GTK+" off \
"nicotine+" "A graphical client for Soulseek" off \
"lollypop" "A new music playing application" off \
"rhythmbox" "Music playback and management application" off \
"deadbeef" "A GTK+ audio player for GNU/Linux" off \
"clementine" "A modern music player and library organizer" off \
"thunderbird" "Standalone mail and news reader from mozilla" off \
"geary" "A lightweight email client for the GNOME desktop" off \
"evolution" "Manage your email, contacts and schedule" off \
"mutt" "Small but very powerful text-based mail client" off \
"deluge" "A BitTorrent client written in python" off \
"transmission-gtk" "Free BitTorrent client GTK+ GUI" off \
"qbittorrent" "An advanced BitTorrent client" off \
"hexchat" "A popular and easy to use graphical IRC client" off \
"pidgin" "Multi-protocol instant messaging client" off \
"weechat" "Fast, light and extensible IRC client" off \
"irssi" "Modular text mode IRC client" off \
"libreoffice-fresh" "Full featured office suite" off \
"abiword" "Fully-featured word processor" off \
"calligra" "A set of applications for productivity" off \
"evince" "Document viewer" off \
"zathura" "Minimalistic document viewer" off \
"qpdfview" "A tabbed PDF viewer" off \
"mupdf" "Lightweight PDF and XPS viewer" off \
"gimp" "GNU Image Manipulation Program" off \
"inkscape" "Professional vector graphics editor" off \
"krita" "Edit and paint images" off \
"simplescreenrecorder" "A feature-rich screen recorder" off \
"obs-studio" "Free opensource streaming/recording software" off \
"guvcview" "Capture video from camera devices" off \
"gpick" "Advanced color picker using GTK+ toolkit" off \
"gcolor2" "A simple GTK+2 color selector" off \
"plank" "Stupidly simple dock" off \
"docky" "The finest dock no money can buy" off \
"cairo-dock" "Light, eye-candy filled dock and desklets" off \
"ttf-hack" "A hand groomed and optically balanced typeface based on Bitstream Vera Mono." off \
"ttf-anonymous-pro" "A family of four fixed-width fonts designed especially with coding in mind" off \
"ttf-font-awesome" "Iconic font designed for Bootstrap" off \
"ttf-fira-code" "Monospaced font with programming ligatures" off \
"noto-fonts-cjk" "Google Noto CJK fonts (Chinese, Japanese, Korean)" off)"
fi
return 0
}
setup_lightdm() {
chroot_cmd 'systemctl enable lightdm.service && systemctl set-default graphical.target' >/dev/null 2>&1
local cfg="$MNT/etc/lightdm/lightdm-gtk-greeter.conf"
sed -i '/#background=/ c background=/usr/share/backgrounds/archlabs/archlabs.jpg' $cfg
sed -i '/#theme-name=/ c theme-name=ArchLabs-dARK' $cfg
sed -i '/#icon-theme-name=/ c icon-theme-name=ArchLabs-Light' $cfg
sed -i '/#position=/ c position=34%,end 66%,end' $cfg
sed -i '/#font-name=/ c font-name=DejaVu Sans Mono 11' $cfg
sed -i '/\[greeter]/ a default-user-image=/usr/share/icons/ArchLabs-Dark/64x64/places/distributor-logo-archlabs.png' $cfg
sed -i '/\[greeter]/ a active-monitor=0' $cfg
if [[ $AUTOLOGIN == true ]]; then
chroot_cmd 'groupadd -r nopasswdlogin' >/dev/null 2>&1
sed -i '/#%PAM-1.0/ a auth sufficient pam_succeed_if.so user ingroup nopasswdlogin' $MNT/etc/pam.d/lightdm
sed -i "/#autologin-session=/ c autologin-session=${LOGIN_WM}" $MNT/etc/lightdm/lightdm.conf
fi
}
update_system() {
local pkgcmd
pkgcmd="pacman -Syyu --noconfirm; pacman -S iputils --noconfirm; pacman -S base-devel git --needed --noconfirm"
if ! grep -qi "hypervisor" <<< "$(dmesg)" && pacman -Qsq virtualbox-guest &>/dev/null; then
pkgcmd="pacman -Rs archlabs-installer $(pacman -Qsq virtualbox-guest) --noconfirm; $pkgcmd"
else
pkgcmd="pacman -Rs archlabs-installer --noconfirm; $pkgcmd"
fi
tput civis
chroot_cmd "$pkgcmd" 2>/dev/null | dialog --cr-wrap --backtitle "$BT" \
--title " $_UpdSysTitle " --progressbox "$_UpdSysBody\n" 30 90
install_packages
return 0
}
update_mirrorlist_cmd() {
if ! yesno "$_MirrorTitle" "$_MirrorSetup" "Automatic Sort" "Customize Sort"; then
infobox "$_MirrorTitle" "\nGathering mirror countries..\n"
local countries
countries="$(reflector --list-countries | awk 'NF > 1 {print $1 " -"}')"
if [[ $countries != "" ]]; then
tput civis
local country
country="$(dialog --cr-wrap --stdout --no-cancel --backtitle "$BT" \
--title "$_MirrorTitle" --menu "$_MirrorCountry" 22 70 10 $countries)"
MIRROR_CMD="reflector --country $country --score 80 --latest 40 --fastest 10 --sort rate"
fi
local ref=" --score n Limit the list to the n servers with the highest score.
-l n, --latest n Limit the list to the n most recently synchronized servers.
-f n, --fastest n Return the n fastest mirrors that meet the other criteria.
--sort {age,rate,country,score,delay}
'age': last server synchronization; 'rate': download rate;
'country': server's location; 'score': MirrorStatus score;
'delay': MirrorStatus delay."
tput cnorm
MIRROR_CMD="$(dialog --cr-wrap --no-cancel --stdout --backtitle "$BT" \
--title " $_MirrorTitle " --inputbox "$_MirrorCmd\n\n$ref\n" 0 0 "$cmd")"
fi
return 0
}
update_mirrorlist() {
infobox "$_MirrorTitle" "$_MirrorSort"
if ! $MIRROR_CMD --save $MNT/etc/pacman.d/mirrorlist; then
infobox "$_ErrTitle" "\nAn error occurred while updating the mirrorlist.\n\nFalling back to automatic sorting...\n"
reflector --score 100 -l 50 -f 10 --sort rate --save $MNT/etc/pacman.d/mirrorlist
fi
return 0
}
bootloader_config() {
ROOT_PART_ID="$ROOT_PART"
if ! grep -q "/dev/mapper/" <<< "$ROOT_PART"; then
ROOT_PART_ID="UUID=$(blkid -s PARTUUID $ROOT_PART | sed 's/.*=//g; s/"//g')"
[[ $BOOTLOADER == "systemd-boot" ]] && ROOT_PART_ID="PART$ROOT_PART_ID"
fi
if [[ $BOOTLOADER == "grub" ]]; then
local cfg="$MNT/etc/default/grub"
sed -i "s/GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR=\"${DIST}\"/g; s/GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"\"/g" $cfg
if (( LUKS == 1 )); then
sed -i "s~#GRUB_ENABLE_CRYPTODISK~GRUB_ENABLE_CRYPTODISK~g; s~GRUB_CMDLINE_LINUX=.*~GRUB_CMDLINE_LINUX=\"${LUKS_DEV}\"~g" $cfg
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" $cfg
fi
fi
elif [[ $BOOTLOADER == "syslinux" ]]; then
local cfgdir="$MNT/boot/syslinux"
mkdir -p $cfgdir
cp -f /usr/lib/syslinux/bios/vesamenu.c32 $cfgdir/
cp -f /run/archiso/bootmnt/arch/boot/syslinux/splash.png $cfgdir/
cat > $cfgdir/syslinux.cfg << EOF
UI vesamenu.c32
DEFAULT archlabs
PROMPT 0
MENU TITLE $DIST Syslinux Boot Menu
MENU BACKGROUND splash.png
TIMEOUT 50
MENU WIDTH 78
MENU MARGIN 4
MENU ROWS 5
MENU VSHIFT 10
MENU TIMEOUTROW 13
MENU TABMSGROW 11
MENU CMDLINEROW 11
MENU HELPMSGROW 16
MENU HELPMSGENDROW 29
# Refer to https://www.syslinux.org/wiki/index.php/Comboot/menu.c32
MENU COLOR border 30;44 #40ffffff #a0000000 std
MENU COLOR title 1;36;44 #9033ccff #a0000000 std
MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
MENU COLOR unsel 37;44 #50ffffff #a0000000 std
MENU COLOR help 37;40 #c0ffffff #a0000000 std
MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
MENU COLOR msg07 37;40 #90ffffff #a0000000 std
MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
LABEL archlabs
MENU LABEL $DIST Linux
LINUX ../vmlinuz-linux
APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && echo -n "$LUKS_DEV ")rw
INITRD ../initramfs-linux.img
LABEL archlabsfallback
MENU LABEL $DIST Linux Fallback
LINUX ../vmlinuz-linux
APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && echo -n "$LUKS_DEV ")rw
INITRD ../initramfs-linux-fallback.img
LABEL hdt
MENU LABEL HDT (Hardware Detection Tool)
COM32 hdt.c32
LABEL reboot
MENU LABEL Reboot
COM32 reboot.c32
LABEL poweroff
MENU LABEL Poweroff
COM32 poweroff.c32
EOF
else
# systemd-boot requires this before running bootctl
systemd-machine-id-setup --root="$MNT" >/dev/null 2>&1
mkdir -p $MNT/boot/loader/entries
cat > $MNT/boot/loader/loader.conf << EOF
default archlabs
timeout 5
editor no
EOF
cat > $MNT/boot/loader/entries/${DIST,,}.conf << EOF
title $DIST Linux
linux /vmlinuz-linux
initrd /initramfs-linux.img
options root=$ROOT_PART_ID rw
EOF
for file in $MNT/boot/loader/entries/arch*?.conf; do
(( LUKS == 1 )) && sed -i "s~rw~$LUKS_DEV rw~g" "$file"
done
fi
return 0
}
grub_uefi_fallback() {
# some UEFI firmware is finicky and requires a specific folder in
# /boot/efi/EFI/ and named 'boot', 'Boot', or 'BOOT'
local fb="boot"
local esp="${MNT}${BOOT_MNTS[$SYS-$BOOTLOADER]}/EFI/"
for i in $(find "$esp" -maxdepth 1 -mindepth 1 -type d 2>/dev/null); do
if grep -qi "boot" <<< "$(basename $i)"; then
fb="$(basename $i)"
break
fi
done
# copy grub's efi stub binary to that directory as $stub
mkdir -p ${esp}$fb
cp -f ${esp}$DIST/grubx64.efi ${esp}$fb/bootx64.efi
return 0
}
setup_bootloader() {
chroot_cmd "export PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/bin/core_perl"
local msg="$_InstBootloader $BOOTLOADER\n"
[[ $BOOT_PART != "" ]] && msg="$msg\n$_InstBootDev $BOOT_PART\n"
infobox "$_InstBootTitle" "$msg\nMountpoint: ${BOOT_MNTS[$SYS-$BOOTLOADER]}\n"
if [[ $SYS == "UEFI" ]]; then
# ensure efivarfs is mounted in host and in chroot
local eficmd="mount -o remount,rw -t efivarfs efivarfs /sys/firmware/efi/efivars"
$eficmd >/dev/null 2>&1
BOOT_CMDS[$BOOTLOADER]="$eficmd ; ${BOOT_CMDS[$BOOTLOADER]}"
# remove old EFI boot entries from previous installs
find $MNT/boot/efi/EFI/ -maxdepth 1 -mindepth 1 -name '[aA][rR][cC][hH][lL]abs*' \
-type d -exec rm -rf '{}' \; >/dev/null 2>&1
if [[ $GRUB_UEFI_FALLBACK == true ]]; then
find $MNT/boot/efi/EFI/ -maxdepth 1 -mindepth 1 -name '[Bb][oO][oO][tT]' \
-type d -exec rm -rf '{}' \; >/dev/null 2>&1
fi
fi
# grub is finicky and requires special treatment
if [[ $BOOTLOADER == "grub" ]]; then
# needed for os-prober module to work properly in the chroot
local udevcmd="mkdir -p /run/udev && mount --rbind /run/udev /run/udev"
$udevcmd >/dev/null 2>&1
BOOT_CMDS[grub]="$udevcmd ; ${BOOT_CMDS[grub]}"
# BIOS uses the base device name, eg. /dev/sda.. so add it to the end of BOOT_CMDS[grub]
[[ $SYS == "BIOS" ]] && BOOT_CMDS[grub]="${BOOT_CMDS[grub]} $BOOT_DEVICE"
# add grub-mkconfig last
BOOT_CMDS[grub]="${BOOT_CMDS[grub]} && grub-mkconfig -o /boot/grub/grub.cfg"
else
# for other bootloaders remove grub and it's configs
rm -rf $MNT/etc/default/grub
find $MNT/boot/ -name 'grub*' -exec rm -rf '{}' \; >/dev/null 2>&1
BOOT_CMDS[$BOOTLOADER]="pacman -Rs grub --noconfirm && ${BOOT_CMDS[$BOOTLOADER]}"
fi
# create the bootloader configs and run the setup commands, BOOT_CMDS[$BOOTLOADER]
bootloader_config
chroot_cmd "${BOOT_CMDS[$BOOTLOADER]}" 2>$ERR >/dev/null 2>&1
check_for_errors "${BOOT_CMDS[$BOOTLOADER]}" || return 1
# copy grub efi stub to generic catch all
[[ $GRUB_UEFI_FALLBACK == true ]] && grub_uefi_fallback
BOOT_DONE=true
# offer to setup a keyfile for LUKS.. Only when choosing grub and system is UEFI
if [[ $LUKS -eq 1 && $SYS == 'UEFI' && $BOOTLOADER == 'grub' && $LUKS_PASS && $LUKS_UUID ]]; then
luks_keyfile || return 1
fi
return 0
}
run_mkinitcpio() {
local conf="$MNT/etc/mkinitcpio.conf"
# new HOOKS needed in /etc/mkinitcpio.conf if we used LUKS and/or LVM
local add
(( LVM == 1 )) && add="lvm2"
(( LUKS == 1 )) && add="encrypt$([[ $add != "" ]] && echo -n " $add")"
if [[ ! -e $MNT/boot/vmlinuz-linux ]]; then
cp -f /run/archiso/bootmnt/arch/boot/x86_64/vmlinuz $MNT/boot/vmlinuz-linux
fi
sed -i "s/block filesystems/block ${add} filesystems ${MKINIT_HOOKS}/g" $conf 2>$ERR
check_for_errors "sed -i 's/block filesystems/block ${add} filesystems ${MKINIT_HOOKS}/g' $conf" || return 1
tput civis
chroot_cmd "mkinitcpio -p linux" 2>$ERR | dialog --cr-wrap --backtitle "$BT" \
--title " $_RunMkinit " --progressbox "$_RunMkinitBody\nHOOKS: $MKINIT_HOOKS $add\n" 30 90
check_for_errors "mkinitcpio -p linux" || return 1
return 0
}
######################################################################
## Menu Dialogs ##
######################################################################
main_menu() {
if [[ $FIRST_PREP != true ]]; then
FIRST_PREP=true
prepare_menu
fi
if [[ $CURRENT_MENU != "main" ]]; then
MENU_HIGHLIGHT=1
CURRENT_MENU="main"
elif (( MENU_HIGHLIGHT < 5 )); then
((MENU_HIGHLIGHT++))
fi
tput civis
MENU_HIGHLIGHT=$(dialog --cr-wrap --stdout --backtitle "$BT" \
--title " $_MainTitle " --default-item $MENU_HIGHLIGHT --menu "$_MainBody" 0 0 0 \
"1" "$_PrepTitle" "2" "$_InstTitle" "3" "$_ConfTitle" "4" "$_EditTitle" "5" "$_Done")
if [[ -n $MENU_HIGHLIGHT ]]; then
# if trying to unpack the system make sure the partitions are mounted
if (( MENU_HIGHLIGHT == 2 )) && ! check_parts_are_mounted; then
return 1
elif (( MENU_HIGHLIGHT == 3 || MENU_HIGHLIGHT == 4 )); then
# when trying to use config_menu() or edit config files make sure
# the system is unpacked and the partitions are mounted
if ! (check_parts_are_mounted && check_base_unpacked); then
return 1
fi
fi
fi
case $MENU_HIGHLIGHT in
1) prepare_menu ;;
2) install_main ;;
3) configure_menu ;;
4) edit_config_menu ;;
*) wrap_up "$_CloseInstBody" 'Exit' 'Back' 'exit'
esac
}
prepare_menu() {
if [[ $ROOT_PART != "" && $BOOTLOADER != "" ]]; then
if check_parts_are_mounted; then
# this is where all the action happens, the rest is mostly automated
# the user will likely reboot after and never get back here, but if we do
# returning goes to the main menu
install_main && return 0
fi
fi
if [[ $CURRENT_MENU != "prep" ]]; then
MENU_HIGHLIGHT=1
CURRENT_MENU="prep"
elif (( MENU_HIGHLIGHT < 7 )); then
((MENU_HIGHLIGHT++))
fi
tput civis
MENU_HIGHLIGHT=$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_PrepTitle " \
--default-item $MENU_HIGHLIGHT --menu "$_PrepBody" 0 0 0 \
"1" "$_PrepLayout" "2" "$_PrepShowDev" "3" "$_PrepParts" "4" "$_PrepLUKS" \
"5" "$_PrepLVM" "6" "$_PrepMount" "7" "$_Back")
case $MENU_HIGHLIGHT in
1) set_keymap ;;
2) show_devices ;;
3) unmount_partitions && select_device 'root' && create_partitions "$DEVICE" ;;
4) luks_menu ;;
5) lvm_menu ;;
6) select_install_partitions ;;
*) return 0
esac
prepare_menu
}
configure_menu() {
chroot_cmd "export PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/core_perl"
if [[ $FIRST_CONFIG != true ]]; then
FIRST_CONFIG=true
set_hostname && set_locale && create_user
[[ $FULL_DONE == true ]] && return 0
elif [[ $CURRENT_MENU != "config" ]]; then
MENU_HIGHLIGHT=1
CURRENT_MENU="config"
elif (( MENU_HIGHLIGHT < 4 )); then
((MENU_HIGHLIGHT++))
fi
tput civis
MENU_HIGHLIGHT=$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_ConfTitle " \
--default-item $MENU_HIGHLIGHT --menu "$_ConfBody" 0 0 0 \
"1" "$_ConfHost" "2" "$_ConfLocale" "3" "$_ConfUser" "4" "$_Back")
case $MENU_HIGHLIGHT in
1) set_hostname ;;
2) set_locale ;;
3) create_user ;;
*) return 0
esac
configure_menu
}
edit_config_menu() {
if [[ $CURRENT_MENU != "edit" ]]; then
MENU_HIGHLIGHT=1
CURRENT_MENU="edit"
elif (( MENU_HIGHLIGHT < 10 )); then
((MENU_HIGHLIGHT++))
fi
local msg
[[ $FULL_DONE == true ]] && msg="${_Final}$_EditBody" || msg="$_EditBody"
tput civis
MENU_HIGHLIGHT=$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_EditTitle " \
--default-item $MENU_HIGHLIGHT --menu "$msg" 0 0 0 \
"1" "$_Done" "2" "keymaps" "3" "locale" "4" "hostname" "5" "sudoers" \
"6" "mkinitcpio.conf" "7" "fstab" "8" "crypttab" "9" "$BOOTLOADER" "10" "pacman.conf")
if [[ $MENU_HIGHLIGHT == "" || $MENU_HIGHLIGHT == 1 ]]; then
if [[ $FULL_DONE == true && $CONFIRM_DONE != true ]]; then
CONFIRM_DONE=true
wrap_up "$_InstFinBody" 'Exit & Reboot' 'Go Back' 'reboot'
fi
return 0
fi
local existing_files=""
for f in $(echo "${EDIT_FILES[$MENU_HIGHLIGHT]}"); do
[[ -e ${MNT}$f ]] && existing_files="$existing_files ${MNT}$f"
done
if [[ $existing_files != "" ]]; then
if [[ $EDITOR_CHOICE == "" && $DISPLAY ]] && hash geany >/dev/null 2>&1; then
if yesno "$_EditTitle" "\nOpen file(s) in Geany or Vim?\n" "Geany" "Vim"; then
EDITOR_CHOICE="geany -i"
geany -i $existing_files
else
EDITOR_CHOICE="vim -O"
vim -O $existing_files
fi
elif [[ $EDITOR_CHOICE ]]; then
$EDITOR_CHOICE $existing_files
else
vim -O $existing_files
fi
else
msgbox "$_ErrTitle" "$_NoFileErr"
fi
edit_config_menu
}
for arg in "$@"; do
[[ $arg == "--debug" || $arg == "-d" ]] && set_debug
done
initialize_variables
luks_variable_init
select_language
check_requirements
identify_system
# welcome message
msgbox "$_WelTitle $DIST Installer" "$_WelBody"
while true; do
main_menu
done