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

2164 lines
74 KiB
Plaintext
Raw Normal View History

2018-07-18 19:50:37 -05:00
#!/usr/bin/env bash
# vim:ft=sh:fdm=marker:fmr={,}
# This program is free software, provided under the GNU GPL
2018-07-18 19:52:06 -05:00
# 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
2018-07-18 19:50:37 -05:00
# set -n
# set -u
# set -v
2018-07-18 19:52:06 -05:00
# immutable variables {
# essentially constants, these won't ever change during runtime
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# export TERM='xterm-256color'
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
readonly DIST="Archlabs" # Linux distributor
readonly VER="1.6.7" # Installer version
readonly LIVE="liveuser" # Live session user name
readonly TRN="/installer" # Translation path
readonly MNT="/mnt/install" # Install mountpoint
readonly ERR="/tmp/errlog" # Built-in error log
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
readonly KBD="$(find /usr/share/kbd/keymaps -name '*.map.gz')"
readonly SYS_MEM=$(grep 'MemTotal' /proc/meminfo | awk '{print int($2 / 1024)}')
readonly SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE,TRAN | awk '/disk/ && !/usb/ {print "/dev/" $1 " " $2}')"
readonly DEV_COUNT="$(wc -l <<< "$SYS_DEVS")"
readonly LOCALES="$(awk '/\.UTF-8/ {gsub(/# .*|#/, ""); if($1) print $1 " -"}' /etc/locale.gen)"
readonly CONSOLE_MAPS="$(awk '{gsub(/\.map\.gz|.*\//, ""); print $1 " -"}' <<< "$KBD" | sort -r)"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# static string of zones to avoid loops and subprocess calls
readonly ZONES="America - Australia - Asia - Atlantic - Africa - Europe - Indian - Pacific - Arctic - Antarctica -"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# create associative array for subzones, value is: 'subzone country_code'
declare -Ag SUBZONES
for zone in $(sed 's/ -//g' <<< "$ZONES"); do
SUBZONES[$zone]="$(awk "/$zone\// {gsub(/$zone\//, \"\"); print \$3 \" \"\$1}" /usr/share/zoneinfo/zone.tab)"
2018-07-18 19:50:37 -05:00
done
2018-07-18 19:52:06 -05:00
readonly SUBZONES # make it read only
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
for t in st termite xterm; do
hash $t >/dev/null 2>&1 && { readonly TERM_CMD="$t"; break; }
2018-07-18 19:50:37 -05:00
done
2018-07-18 19:52:06 -05:00
# 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=(
[BIOS-grub]="/boot"
[UEFI-grub]="/boot/efi"
[BIOS-syslinux]="/boot"
[UEFI-systemd-boot]="/boot"
)
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=(
[btrfs]="mkfs.btrfs -f" [ext2]="mkfs.ext2 -q" [ext3]="mkfs.ext3 -q"
[ext4]="mkfs.ext4 -q" [f2fs]="mkfs.f2fs" [jfs]="mkfs.jfs -q"
[xfs]="mkfs.xfs -f" [ntfs]="mkfs.ntfs -q" [reiserfs]="mkfs.reiserfs -q"
[vfat]="mkfs.vfat -F32" [nilfs2]="mkfs.nilfs2 -q"
)
# 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"
[btrfs]="autodefrag - off compress=zlib - off compress=lzo - off compress=no - off
compress-force=zlib - off compress-force=lzo - off discard - off noacl - off noatime - off
nodatasum - off nospace_cache - off recovery - off skip_balance - off space_cache - off
ssd - off ssd_spread - 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"
)
2018-07-18 19:50:37 -05:00
# }
2018-07-18 19:52:06 -05:00
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 CURRENT_MENU="main"
declare -g MENU_HIGHLIGHT=0
declare -g MKINIT_HOOKS="shutdown"
declare -g SEPERATE_BOOT=0
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=""
# boolean checks
declare -g HAS_NETWORK=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 BOOT_DONE=false
declare -g FULL_DONE=false
declare -g CONFIRM_DONE=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 [8] can change depending on which bootloader is selected
declare -Ag EDIT_FILES=(
[1]="/etc/X11/xorg.conf.d/00-keyboard.conf /etc/vconsole.conf /etc/default/keyboard"
[2]="/etc/locale.conf /etc/default/locale"
[3]="/etc/hostname /etc/hosts"
[4]="/etc/sudoers"
[5]="/etc/mkinitcpio.conf"
[6]="/etc/fstab"
[7]="/etc/crypttab"
[8]="/etc/default/grub"
[9]="/etc/pacman.conf"
)
}
2018-07-18 19:50:37 -05:00
######################################################################
## Utility and Check Functions ##
######################################################################
chroot_cmd() {
arch-chroot $MNT /bin/bash -c "$1"
}
show_devices() {
2018-07-18 19:52:06 -05:00
tput civis
lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE,MOUNTPOINT | grep "disk\|part\|lvm\|crypt\|NAME" > /tmp/.devlist
dialog --cr-wrap --backtitle "$BT" --title " $_PrepShowDev " --textbox /tmp/.devlist 0 0
2018-07-18 19:50:37 -05:00
}
set_debug() {
set -x
2018-07-18 19:52:06 -05:00
exec 3>| /tmp/debug-log
2018-07-18 19:50:37 -05:00
BASH_XTRACEFD=3
2018-07-18 19:52:06 -05:00
[[ $DISPLAY ]] && { $TERM_CMD -e tail -f /tmp/debug-log & }
2018-07-18 19:50:37 -05:00
}
select_language() {
2018-07-18 19:52:06 -05:00
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
case $lang in
2018-07-18 19:50:37 -05:00
1) LOC="en_US.UTF-8" ;;
2018-07-18 19:52:06 -05:00
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" ;;
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" ;;
10) source $TRN/chinese.trans 2>/dev/null && LOC="zh_CN.UTF-8" ;;
*) clear; tput cnorm; exit 0
2018-07-18 19:50:37 -05:00
esac
sed -i "s/#en_US.UTF-8/en_US.UTF-8/" /etc/locale.gen
2018-07-18 19:52:06 -05:00
2018-07-18 19:50:37 -05:00
[[ $LOC != "en_US.UTF-8" ]] && sed -i "s/#${LOC}/${LOC}/" /etc/locale.gen
2018-07-18 19:52:06 -05:00
locale-gen >/dev/null 2>&1
2018-07-18 19:50:37 -05:00
export LANG="$LOC"
}
identify_system() {
2018-07-18 19:52:06 -05:00
if grep -qi 'apple' /sys/class/dmi/id/sys_vendor; then
2018-07-18 19:50:37 -05:00
modprobe -r -q efivars || true
else
modprobe -q efivarfs
fi
2018-07-18 19:52:06 -05:00
if [[ -d /sys/firmware/efi ]]; then
2018-07-18 19:50:37 -05:00
SYS="UEFI"
2018-07-18 19:52:06 -05:00
[[ $(mount) =~ /sys/firmware/efi/efivars ]] && mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
2018-07-18 19:50:37 -05:00
else
SYS="BIOS"
fi
readonly BT="$DIST Installer - $SYS (x86_64) - Version $VER"
}
check_requirements() {
2018-07-18 19:52:06 -05:00
# I use some bashisms such as associative arrays, string manipulation, [[]], etc..
# these require a more up to date version of bash
[[ ${BASH_VERSION:0:1} -lt 4 ]] && { clear; echo "[ERROR]: Requires bash version >= 4.0"; tput cnorm; exit 1; }
# check for each command used in the script to ensure no problems
local miss=""
for cmd in awk sed grep uniq sort find ping rsync dialog arch-chroot reflector chpasswd parted mkfs lsblk; do
! hash $cmd >/dev/null 2>&1 && miss="${miss}$cmd "
done
[[ $miss != "" ]] && { clear; echo "[ERROR]: Missing dependencies: $miss"; tput cnorm; exit 1; }
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
if [[ $(whoami) != "root" ]]; then
infobox "$_ErrTitle" "$_NotRoot\n$_Exit" ; clear; tput cnorm; 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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
if [[ $(systemctl is-active NetworkManager) == "active" ]] && hash nmtui >/dev/null 2>&1;then
tput civis
nmtui
fi
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
fi
return 0
}
check_for_errors() {
2018-07-18 19:52:06 -05:00
# if the last process exited normally then we can bail
(( $? == 0 )) && return 0
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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"
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
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
fi
return 1
2018-07-18 19:50:37 -05:00
}
check_parts_are_mounted() {
2018-07-18 19:52:06 -05:00
[[ $(lsblk -o MOUNTPOINT) =~ "$MNT" ]] && return 0
2018-07-18 19:50:37 -05:00
msgbox "$_ErrTitle" "$_ErrNoMount"
return 1
}
check_base_unpacked() {
[[ -e $MNT/etc ]] && return 0
2018-07-18 19:52:06 -05:00
msgbox "$_ErrTitle" "$_ErrNoBase"
2018-07-18 19:50:37 -05:00
return 1
}
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
}
######################################################################
## Dialog Functions ##
######################################################################
getinput() {
2018-07-18 19:52:06 -05:00
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"
}
2018-07-18 19:50:37 -05:00
msgbox() {
2018-07-18 19:52:06 -05:00
tput civis
dialog --cr-wrap --backtitle "$BT" --title " $1 " --msgbox "$2\n" 0 0
}
2018-07-18 19:50:37 -05:00
infobox() {
local bt="${BT:-$DIST Installer - (x86_64)}"
2018-07-18 19:52:06 -05:00
tput civis
dialog --cr-wrap --backtitle "$bt" --title " $1 " --infobox "$2\n" 0 0
2018-07-18 19:50:37 -05:00
sleep 2
2018-07-18 19:52:06 -05:00
}
2018-07-18 19:50:37 -05:00
yesno() {
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
}
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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
}
2018-07-18 19:50:37 -05:00
######################################################################
## System Settings Functions ##
######################################################################
set_keymap() {
2018-07-18 19:52:06 -05:00
local map
tput civis
map="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_PrepLayout " \
--menu "$_XMapBody" 20 70 12 $KEYMAPS)"
[[ $? != 0 || $map == "" ]] && return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
cat >/tmp/00-keyboard.conf <<EOF
2018-07-18 19:50:37 -05:00
# Use localectl(1) to instruct systemd-localed to update it.
Section "InputClass"
2018-07-18 19:52:06 -05:00
Identifier "system-keyboard"
2018-07-18 19:50:37 -05:00
MatchIsKeyboard "on"
2018-07-18 19:52:06 -05:00
Option "XkbLayout" "$map"
2018-07-18 19:50:37 -05:00
EndSection
EOF
2018-07-18 19:52:06 -05:00
cat >/tmp/keyboard <<EOF
2018-07-18 19:50:37 -05:00
# KEYBOARD CONFIGURATION FILE
# Consult the keyboard(5) manual page.
XKBMODEL=""
XKBLAYOUT="$map"
XKBVARIANT=""
XKBOPTIONS=""
BACKSPACE="guess"
EOF
2018-07-18 19:52:06 -05:00
# 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
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
echo "KEYMAP=$map" > /tmp/vconsole.conf
return 0
2018-07-18 19:50:37 -05:00
}
set_locale() {
local locale
2018-07-18 19:52:06 -05:00
tput civis
locale="$(dialog --cr-wrap --stdout --backtitle "$BT" --title "$_ConfLocale" \
--menu "$_LocaleBody" 25 70 12 $LOCALES)"
[[ $? != 0 || $locale == "" ]] && return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
infobox "$_ConfLocale" "$_GenLocale $locale\n"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${locale}/${locale}/g" $MNT/etc/locale.gen
2018-07-18 19:50:37 -05:00
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
2018-07-18 19:52:06 -05:00
check_for_errors 'locale-gen' || return 1
2018-07-18 19:50:37 -05:00
set_timezone
}
set_timezone() {
local zone subzone
2018-07-18 19:52:06 -05:00
tput civis
zone="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_TimeZTitle " \
--menu "$_TimeZBody" 20 70 10 $ZONES)"
[[ $? != 0 || $zone == "" ]] && return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
subzone="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_TimeZTitle " \
--menu "$_TimeSubZBody" 20 70 12 ${SUBZONES[$zone]})"
[[ $? != 0 || $subzone == "" ]] && return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
if yesno "$_TimeZTitle" "$_TimeZQ $zone/$subzone?\n"; then
2018-07-18 19:50:37 -05:00
chroot_cmd "ln -sf /usr/share/zoneinfo/$zone/$subzone /etc/localtime" 2>$ERR
2018-07-18 19:52:06 -05:00
check_for_errors "ln -sf /usr/share/zoneinfo/$zone/$subzone /etc/localtime" || return 1
2018-07-18 19:50:37 -05:00
else
2018-07-18 19:52:06 -05:00
set_timezone || return 1
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
TIMEZONE_SET=true
2018-07-18 19:50:37 -05:00
set_hwclock
}
set_hwclock() {
chroot_cmd "hwclock --systohc --utc"
if (( $? != 0 )); then
chroot_cmd "hwclock --systohc --utc --directisa"
2018-07-18 19:52:06 -05:00
(( $? != 0 )) && infobox "$_ErrTitle" "\nHwclock setup attempts failed.\n\nContinuing anyway.\n"
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
return 0
2018-07-18 19:50:37 -05:00
}
set_hostname() {
2018-07-18 19:52:06 -05:00
tput cnorm
local hostname
hostname="$(getinput "$_ConfHost" "$_HostNameBody" "${DIST,,}")"
[[ $? != 0 || $hostname == "" ]] && return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
echo "$hostname" > $MNT/etc/hostname
2018-07-18 19:50:37 -05:00
cat > $MNT/etc/hosts << EOF
127.0.0.1 localhost
2018-07-18 19:52:06 -05:00
127.0.1.1 $hostname
2018-07-18 19:50:37 -05:00
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF
}
2018-07-18 19:52:06 -05:00
user_input_values() {
local user="$1"
tput cnorm
local values
if [[ $SET_ROOT_PASSWD != true ]]; then
values="$(dialog --stdout --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 --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")"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
local pass pass2
pass="$(awk -F'~' '{print $2}' <<< "$values")"
pass2="$(awk -F'~' '{print $3}' <<< "$values")"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# 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
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
# 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
2018-07-18 19:50:37 -05:00
}
create_user() {
2018-07-18 19:52:06 -05:00
local groups="rfkill,wheel,autologin,network,lp,storage,power,video,audio,lp"
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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
infobox "$_ConfUser" "$_UserSetBody"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
if [[ -e $MNT/home/$LIVE ]]; then
# for first user created, swap the live user account
swap_livuser
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
chroot_cmd "mv -f /home/$LIVE /home/$NEWUSER" 2>$ERR
check_for_errors "mv -f /home/$LIVE /home/$NEWUSER" || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
chroot_cmd "cp -rf /etc/skel/ /home/$NEWUSER" 2>$ERR
check_for_errors "cp -rf /etc/skel/ /home/$NEWUSER" || return 1
fi
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
chroot_cmd "echo '$NEWUSER:$USER_PASS' | chpasswd" 2>$ERR
check_for_errors "chpasswd $NEWUSER" || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
chroot_cmd "chown -Rf $NEWUSER:users /home/$NEWUSER" 2>$ERR
check_for_errors "chown -Rf $NEWUSER:users /home/$NEWUSER" || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
fix_home_files
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
if [[ $UNPACKED_BASE == true && $TIMEZONE_SET == true ]]; then
[[ $SET_ROOT_PASSWD == true && $BOOT_DONE == true ]] && FULL_DONE=true
fi
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
return 0
}
swap_livuser() {
local openbx="$MNT/home/$LIVE/.config/openbox"
# due to changes in systemd and arch the recommended file override location has changed
# check for each location used in recent versions
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"
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
# edit all the required files in /etc/ and swap the liveuser
sed -i "s/${LIVE}/${NEWUSER}/g" $MNT/etc/{group,gshadow,passwd,shadow,$tty_autologin}
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# remove welcome script and installer/welcome menu entries
# also removes the setting to make the installer open maximized
rm -f $MNT/home/$LIVE/bin/welcome.sh
sed -i '/welcome.sh/d' $openbx/autostart
sed -i '/installer/ { N; N; d; }' $openbx/rc.xml
sed -i '/item label="Welcome Screen"/ i\ <separator label="A r c h L a b s"/>' $openbx/menu.xml
sed -i '/item label="Welcome Screen"/ { N; N; N; N; N; N; N; N; N; N; N; d; }' $openbx/menu.xml
}
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
fix_home_files() {
local user_home="$MNT/home/$NEWUSER"
local files=(".config/polybar/config"
".config/polybar/sessions/i3-sessionfile"
".config/polybar/sessions/bspwm-sessionfile"
".config/polybar/sessions/openbox-sessionfile"
".config/openbox/autostart" ".config/gtk-3.0/bookmarks"
".mozilla/firefox/archlabs.default/prefs.js"
".mozilla/firefox/archlabs.default/sessionstore.js")
for file in "${files[@]}"; do
sed -i "s/${LIVE}/${NEWUSER}/g" $user_home/$file
done
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
rm -f $user_home/.config/keypack
sed -i '/keypack/d' $user_home/.config/openbox/autostart
if hash al-hello >/dev/null 2>&1; then
echo "sleep 10; $TERM_CMD -e al-hello &" >> $user_home/.config/openbox/autostart
fi
2018-07-18 19:50:37 -05:00
}
######################################################################
## System Partitioning Functions ##
######################################################################
2018-07-18 19:52:06 -05:00
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"
2018-07-18 19:50:37 -05:00
fi
}
mount_partition() {
local part="$1"
2018-07-18 19:52:06 -05:00
local mount="$2"
local fs="$(lsblk -lno FSTYPE $part)"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
mkdir -p "${MNT}$mount"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
else
2018-07-18 19:52:06 -05:00
mount "$part" "${MNT}$mount" 2>$ERR
check_for_errors "mount $part ${MNT}$mount" || return 1
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
confirm_mount "$part" "${MNT}$mount" || return 1
2018-07-18 19:50:37 -05:00
check_part_is_crypt_or_lvm "$part"
2018-07-18 19:52:06 -05:00
return 0
2018-07-18 19:50:37 -05:00
}
unmount_partitions() {
swapoff -a
2018-07-18 19:52:06 -05:00
2018-07-18 19:50:37 -05:00
for i in $(mount | grep "$MNT" | awk '{print $3}' | sort -r); do
2018-07-18 19:52:06 -05:00
umount -r "$i" >/dev/null 2>&1
2018-07-18 19:50:37 -05:00
done
}
2018-07-18 19:52:06 -05:00
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
}
2018-07-18 19:50:37 -05:00
find_partitions() {
local str="$1"
2018-07-18 19:52:06 -05:00
local err='NONE'
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# create a regex string of all usb devices on the system
# ignore these devices entirely during partition list creation below
local usb=""
for d in $(lsblk -lno NAME,TRAN | awk '/usb/ {print $1}'); do
usb="${d}$([[ $usb ]] && echo -n "|$usb")"
2018-07-18 19:50:37 -05:00
done
2018-07-18 19:52:06 -05:00
# string of partitions as: /TYPE/PART SIZE
# only list partitions of $str types and ignores $usb devices, this also
# substitutes: 'lvm' -> '/dev/mapper/' and 'part' -> '/dev/'
PARTS="$(lsblk -lno TYPE,NAME,SIZE | awk "/$str/"' && !'"/$usb/"' {sub(/^part/, "/dev/"); sub(/^lvm|^crypt/, "/dev/mapper/"); print $1$2 " " $3}')"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# number of partitions total
COUNT=$(wc -l <<< "$PARTS")
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# ensure we have enough partitions for the system and action type
2018-07-18 19:50:37 -05:00
case $str in
2018-07-18 19:52:06 -05:00
'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" ;;
2018-07-18 19:50:37 -05:00
esac
2018-07-18 19:52:06 -05:00
# 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
2018-07-18 19:50:37 -05:00
msgbox "$_ErrTitle" "$err"
2018-07-18 19:52:06 -05:00
if select_device 'root'; then
create_partitions "$DEVICE"
else
return 1
fi
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
return 0
2018-07-18 19:50:37 -05:00
}
2018-07-18 19:52:06 -05:00
auto_partition() {
2018-07-18 19:50:37 -05:00
local device="$1"
2018-07-18 19:52:06 -05:00
# confirm or bail
yesno "$_PrepParts" "$_PartBody1 $device $_PartBody2" || return 0
infobox "$_PrepParts" "\nAuto partitioning device: $device\n"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
swapoff -a # make sure swap is disabled
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
local dev_info="$(parted -s $device print)"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# partition number of each partition on the device NOTE: MUST be in reverse order
for part in $(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r); do
parted -s "$device" rm $part 2>$ERR
check_for_errors "parted -s $device rm $part" || { break; return 1; }
done
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# 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"
2018-07-18 19:50:37 -05:00
else
2018-07-18 19:52:06 -05:00
local newtable="gpt"
fi
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# 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
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
local part_num=1
BOOT_PART="${device}$part_num"
2018-07-18 19:50:37 -05:00
if [[ $SYS == "BIOS" ]]; then
2018-07-18 19:52:06 -05:00
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; }
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
parted -s $device set 1 boot on 2>$ERR
check_for_errors "parted -s $device set 1 boot on" || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
BOOT_DEVICE="$device" # only grub on BIOS systems uses this
ROOT_PART="${device}$((part_num + 1))"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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; }
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
tput civis
sleep 0.5
echo -e "\nAuto partitioning complete.\n" > /tmp/.devlist
lsblk $device -o NAME,TYPE,FSTYPE,SIZE | grep "disk\|part\|lvm\|crypt\|NAME" >> /tmp/.devlist
dialog --cr-wrap --backtitle "$BT" --title " $_PrepParts " --textbox /tmp/.devlist 0 0
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
return 0
}
create_partitions() {
local device="$1"
local choice
tput civis
choice="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_PartTitle " \
--menu "$_PartBody" 0 0 0 "$_PartAuto" "BIOS & UEFI" \
"gparted" "BIOS & UEFI" "parted" "BIOS & UEFI" "$_PartWipe" "BIOS & UEFI")"
[[ $? != 0 || $choice == "" ]] && return 1 || clear
if [[ $choice != "$_PartWipe" && $choice != "$_PartAuto" ]]; then
if [[ $choice == "gparted" ]] && ! [[ $DISPLAY ]]; then
parted "$device"
2018-07-18 19:50:37 -05:00
else
2018-07-18 19:52:06 -05:00
$choice "$device"
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
elif [[ $choice == "$_PartWipe" ]]; then
wipe_device "$device" && create_partitions "$device"
else
auto_partition "$device" || { ROOT_PART=""; BOOT_PART=""; BOOT_DEVICE=""; return 1; }
2018-07-18 19:50:37 -05:00
fi
}
2018-07-18 19:52:06 -05:00
get_swap_size() {
tput cnorm
SWAP_SIZE="$(getinput "$_SelSwpSetup" "$_SelSwpSize" "$SWAP_SIZE")"
[[ $? != 0 || $SWAP_SIZE == "" ]] && return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# 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
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
return 0
2018-07-18 19:50:37 -05:00
}
select_swap() {
2018-07-18 19:52:06 -05:00
if yesno "$_SelSwpSetup" "$_SwapSetup\n" && get_swap_size; then
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
fallocate -l $SWAP_SIZE $MNT/swapfile 2>$ERR
check_for_errors "fallocate -l $size $MNT/swapfile" || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
chmod 600 $MNT/swapfile 2>$ERR
check_for_errors "chmod 600 $MNT/swapfile" || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
mkswap $MNT/swapfile >/dev/null 2>$ERR
check_for_errors "mkswap $MNT/swapfile" || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
swapon $MNT/swapfile >/dev/null 2>$ERR
check_for_errors "swapon $MNT/swapfile" || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
SWAP_FILE="/swapfile"
fi
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
return 0
}
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
select_device() {
local msg=""
[[ $1 == 'boot' ]] && msg="$_DevSelTitle for bootloader\n"
if (( DEV_COUNT == 1 )); then
DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
infobox "$_PrepMount" "\nOnly one device available: $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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# 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"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
return 0
}
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
select_mount_opts() {
local part="$1"
local fs="$2"
local title="${fs^} Mount Options"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
if ! yesno "$title" "$_MntConfBody $MNT_OPTS\n"; then
select_mount_opts "$part" "$fs" || return 1
2018-07-18 19:50:37 -05:00
fi
return 0
}
2018-07-18 19:52:06 -05:00
select_filesystem() {
local part="$1"
local cur_fs="$(lsblk -lno FSTYPE $part)"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
tput civis
local choice
if [[ $cur_fs != "" ]]; then
choice="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_FSTitle: $part" \
--menu "\nPartition: $part\nCurrent: ${cur_fs}$_FSBody" 0 0 0 \
"$_Skip" "-" "ext4" "${FS_CMDS[ext4]}" "ext3" "${FS_CMDS[ext3]}" \
"ext2" "${FS_CMDS[ext2]}" "vfat" "${FS_CMDS[vfat]}" \
"btrfs" "${FS_CMDS[btrfs]}" "ntfs" "${FS_CMDS[ntfs]}" \
"f2fs" "${FS_CMDS[f2fs]}" "jfs" "${FS_CMDS[jfs]}" \
"nilfs2" "${FS_CMDS[nilfs2]}" "reiserfs" "${FS_CMDS[reiserfs]}" \
"xfs" "${FS_CMDS[xfs]}")"
[[ $? != 0 || $choice == "$_Skip" || $choice == "" ]] && return 0
2018-07-18 19:50:37 -05:00
else
2018-07-18 19:52:06 -05:00
choice="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_FSTitle: $part" \
--menu "\nPartition: $part\n$_FSBody" 0 0 0 \
"ext4" "${FS_CMDS[ext4]}" "ext3" "${FS_CMDS[ext3]}" \
"ext2" "${FS_CMDS[ext2]}" "vfat" "${FS_CMDS[vfat]}" \
"btrfs" "${FS_CMDS[btrfs]}" "ntfs" "${FS_CMDS[ntfs]}" \
"f2fs" "${FS_CMDS[f2fs]}" "jfs" "${FS_CMDS[jfs]}" \
"nilfs2" "${FS_CMDS[nilfs2]}" "reiserfs" "${FS_CMDS[reiserfs]}" \
"xfs" "${FS_CMDS[xfs]}")"
[[ $? != 0 || $choice == "" ]] && return 1
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
return 0
2018-07-18 19:50:37 -05:00
}
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
elif [[ $BOOTLOADER == "syslinux" ]]; then
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" "[/]")"
case $cmd in
"syslinux-install_update -iam"|"syslinux-install_update -i")
BOOT_CMDS[syslinux]="$cmd"
EDIT_FILES[8]="/boot/syslinux/syslinux.cfg" ;;
*) return 1
esac
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
elif [[ $BOOTLOADER == "systemd-boot" ]]; then
EDIT_FILES[8]="/boot/loader/entries/archlabs.conf"
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
2018-07-18 19:50:37 -05:00
fi
return 0
}
2018-07-18 19:52:06 -05:00
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
}
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
if (( COUNT == 1 )); then
BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
infobox "$_PrepMount" "\nOnly one partition available: $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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
if grep -q 'fat' <<< "$(fsck -N "$BOOT_PART")"; then
local msg="$_FormUefiBody $BOOT_PART $_FormUefiBody2"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
return 0
}
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
select_bios_boot_partition() {
if (( COUNT == 1 )); then
BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
infobox "$_PrepMount" "\nOnly one partition available: $BOOT_PART\n"
else
tput civis
BOOT_PART="$(dialog --cr-wrap --stdout --backtitle "$BT" --title "$_PrepMount" \
--menu "$_SelBiosBody" 0 0 0 "$_Skip" "-" $PARTS)"
fi
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
if [[ $? != 0 || $BOOT_PART == "$_Skip" || $BOOT_PART == "" ]]; then
2018-07-18 19:50:37 -05:00
return 0
2018-07-18 19:52:06 -05:00
else
decrease_part_count "$BOOT_PART"
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
# set BOOT_DEVICE for BIOS grub by removing any digits from the end of our boot partition
BOOT_DEVICE="${boot%[1-9]}"
return 0
2018-07-18 19:50:37 -05:00
}
2018-07-18 19:52:06 -05:00
select_root_partition() {
if (( LUKS == 1 && LVM == 0 )); then
ROOT_PART="/dev/mapper/$LUKS_NAME"
decrease_part_count "$LUKS_PART"
fi
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
if (( COUNT == 1 )); then
ROOT_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
infobox "$_PrepMount" "\nOnly one partition available: $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
2018-07-18 19:50:37 -05:00
else
2018-07-18 19:52:06 -05:00
infobox "$_PrepMount" "\nUsing $([[ $LUKS -eq 1 ]] && echo -n "encrypted ")root partition: $ROOT_PART\n"
fi
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
select_filesystem "$ROOT_PART" || { ROOT_PART=""; return 1; }
mount_partition "$ROOT_PART" || { ROOT_PART=""; return 1; }
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
return 0
}
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
select_mountpoint() {
tput cnorm
EXTRA_MNT="$(getinput "$_PrepMount $part" "$_ExtPartBody1/home /var\n" "/")"
[[ $? != 0 || $EXTRA_MNT == "" ]] && return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# bad mountpoint
if [[ ${EXTRA_MNT:0:1} != "/" || ${#EXTRA_MNT} -le 1 || $EXTRA_MNT =~ \ |\' ]]; then
msgbox "$_ErrTitle" "$_ExtErrBody"
select_mountpoint || return 1
2018-07-18 19:50:37 -05:00
fi
return 0
}
2018-07-18 19:52:06 -05:00
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)"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# return cancel or done
[[ $part == "$_Done" || $part == "" ]] && break
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# choose what filesystem and get mountpoint
select_filesystem "$part" || { break; return 1; }
select_mountpoint || { break; return 1; }
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# mount it
mount_partition "$part" "$EXTRA_MNT" || { break; return 1; }
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# if the mountpoint was /usr and MKINIT_HOOKS doesn't contain 'usr' then add it
if [[ $EXTRA_MNT == "/usr" && $MKINIT_HOOKS != *usr* ]]; then
MKINIT_HOOKS="usr $MKINIT_HOOKS"
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
done
2018-07-18 19:50:37 -05:00
return 0
}
select_install_partitions() {
2018-07-18 19:52:06 -05:00
msgbox "$_PrepMount" "$_WarnMount"
2018-07-18 19:50:37 -05:00
lvm_detect
2018-07-18 19:52:06 -05:00
# prepare partition list PARTS for dialog
2018-07-18 19:50:37 -05:00
unmount_partitions
2018-07-18 19:52:06 -05:00
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"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
select_root_partition || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
if [[ $BOOT_PART == "" ]]; then
if [[ $SYS == "UEFI" ]]; then
select_efi_partition || { BOOT_PART=""; return 1; }
else
select_bios_boot_partition || { BOOT_PART=""; BOOT_DEVICE=""; return 1; }
fi
else
infobox "$_PrepMount" "\nUsing boot partition: $BOOT_PART\n"
fi
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
select_boot_setup || { BOOTLOADER=""; return 1; }
2018-07-18 19:50:37 -05:00
select_swap || return 1
2018-07-18 19:52:06 -05:00
select_extra_partitions || { BOOTLOADER=""; return 1; }
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
return 0
}
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
check_part_is_crypt_or_lvm() {
local part="$1"
local devs="$(lsblk -lno NAME,FSTYPE,TYPE)"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# 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/}"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
done
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
}
######################################################################
## Encryption (dm_crypt) Functions ##
######################################################################
luks_open() {
2018-07-18 19:52:06 -05:00
LUKS_PART=""
modprobe -a dm-mod dm_crypt
2018-07-18 19:50:37 -05:00
unmount_partitions
2018-07-18 19:52:06 -05:00
find_partitions 'part|crypt|lvm'
tput civis
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# get password and name for encryption
luks_input_values "$_LuksOpen" "$LUKS_NAME" || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
LUKS=1
luks_show
return 0
}
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
LUKS_PASS="$pass"
LUKS_NAME="$name"
return 0
2018-07-18 19:50:37 -05:00
}
luks_setup() {
2018-07-18 19:52:06 -05:00
LUKS_PART=""
2018-07-18 19:50:37 -05:00
modprobe -a dm-mod dm_crypt
unmount_partitions
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# get password and name for encryption
luks_input_values "$_LuksEncrypt" "$LUKS_NAME" || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
return 0
2018-07-18 19:50:37 -05:00
}
luks_default() {
2018-07-18 19:52:06 -05:00
luks_setup || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
local msg="$_LuksWaitBody $LUKS_NAME $_LuksWaitBody2 $LUKS_PART\n"
infobox "$_LuksEncrypt" "$msg"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
}
2018-07-18 19:52:06 -05:00
luks_cipher_key() {
2018-07-18 19:50:37 -05:00
if luks_setup; then
2018-07-18 19:52:06 -05:00
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"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
echo "$LUKS_PASS" | cryptsetup -q $cipher luksFormat $LUKS_PART 2>$ERR
check_for_errors "cryptsetup -q $cipher luksFormat $LUKS_PART" || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
echo "$LUKS_PASS" | cryptsetup open $LUKS_PART "$LUKS_NAME" 2>$ERR
check_for_errors "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2018-07-18 19:50:37 -05:00
luks_show
2018-07-18 19:52:06 -05:00
return 0
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
return 1
2018-07-18 19:50:37 -05:00
}
luks_show() {
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
}
luks_menu() {
2018-07-18 19:52:06 -05:00
tput civis
local choice
choice="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_PrepLUKS " \
--menu "${_LuksMenuBody}${_LuksMenuBody2}${_LuksMenuBody3}" 0 0 0 \
2018-07-18 19:50:37 -05:00
"$_LuksEncrypt" "cryptsetup -q luksFormat" \
2018-07-18 19:52:06 -05:00
"$_LuksOpen" "cryptsetup open --type luks" \
2018-07-18 19:50:37 -05:00
"$_LuksEncryptAdv" "cryptsetup -q -s -c luksFormat" \
2018-07-18 19:52:06 -05:00
"$_Back" "-")"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
case $choice in
"$_LuksEncrypt") luks_default && return 0 ;;
"$_LuksOpen") luks_open && return 0 ;;
"$_LuksEncryptAdv") luks_cipher_key && return 0 ;;
2018-07-18 19:50:37 -05:00
*) return 0
esac
2018-07-18 19:52:06 -05:00
2018-07-18 19:50:37 -05:00
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
2018-07-18 19:52:06 -05:00
infobox "$_LuksKeyFileTitle" "$_LuksKeyFileCreate"
2018-07-18 19:50:37 -05:00
local dev
2018-07-18 19:52:06 -05:00
dev="$(lsblk -lno NAME,UUID,TYPE | awk "/$LUKS_UUID/"' && /part|crypt|lvm/ {print $1}')"
2018-07-18 19:50:37 -05:00
(( LVM == 1 )) && dev="/dev/mapper/$dev" || dev="/dev/$dev"
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
chroot_cmd "mkinitcpio -p linux" 2>$ERR >/dev/null 2>&1
check_for_errors "mkinitcpio -p linux" || return 1
2018-07-18 19:50:37 -05:00
fi
return 0
}
######################################################################
## Logical Volume Management Functions ##
######################################################################
lvm_detect() {
2018-07-18 19:52:06 -05:00
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)"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
if [[ $VOLUMES && $VOLUME_GROUP && $PHYSICAL_VOLUMES ]]; then
2018-07-18 19:50:37 -05:00
infobox "$_PrepLVM" "$_LvmDetBody"
modprobe dm-mod 2>$ERR
2018-07-18 19:52:06 -05:00
check_for_errors 'modprobe dm-mod' || return 1
2018-07-18 19:50:37 -05:00
vgscan >/dev/null 2>&1
vgchange -ay >/dev/null 2>&1
fi
}
lvm_show_vg() {
2018-07-18 19:52:06 -05:00
VOL_GROUP_LIST=""
2018-07-18 19:50:37 -05:00
for i in $(lvs --noheadings | awk '{print $2}' | uniq); do
2018-07-18 19:52:06 -05:00
VOL_GROUP_LIST="$VOL_GROUP_LIST $i $(vgdisplay "$i" | awk '/VG Size/ {print $3$4}')"
2018-07-18 19:50:37 -05:00
done
2018-07-18 19:52:06 -05:00
if [[ -z $VOL_GROUP_LIST ]]; then
msgbox "$_ErrTitle" "$_LvmVGErr"
2018-07-18 19:50:37 -05:00
return 1
fi
2018-07-18 19:52:06 -05:00
tput civis
choice="$(dialog --cr-wrap --stdout --backtitle "$BT" \
--title " $_PrepLVM " --menu "$_LvmSelVGBody" 18 70 10 $VOL_GROUP_LIST)"
[[ $? != 0 || $choice == "" ]] && return 1
echo -n "$choice"
2018-07-18 19:50:37 -05:00
}
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
ERR_SIZE=0
# if the size is empty or 0
(( ${#VOLUME_SIZE} == 0 || ${VOLUME_SIZE:0:1} == 0 )) && ERR_SIZE=1
2018-07-18 19:50:37 -05:00
if (( ERR_SIZE == 0 )); then
2018-07-18 19:52:06 -05:00
# number of characters in VOLUME_SIZE minus the last, which should be a letter
local lv="$((${#VOLUME_SIZE} - 1))"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# loop each character (except the last) in VOLUME_SIZE and ensure they are numbers
2018-07-18 19:50:37 -05:00
for (( i=0; i<lv; i++ )); do
2018-07-18 19:52:06 -05:00
[[ ${VOLUME_SIZE:$i:1} != [0-9] ]] && { ERR_SIZE=1; break; }
2018-07-18 19:50:37 -05:00
done
if (( ERR_SIZE == 0 )); then
2018-07-18 19:52:06 -05:00
# ensure the last character is either m/M or g/G
case ${VOLUME_SIZE:$lv:1} in
2018-07-18 19:50:37 -05:00
[mMgG]) ERR_SIZE=0 ;;
*) ERR_SIZE=1
esac
if (( ERR_SIZE == 0 )); then
2018-07-18 19:52:06 -05:00
s=${VOLUME_SIZE:0:$lv}
2018-07-18 19:50:37 -05:00
m=$((s * 1000))
2018-07-18 19:52:06 -05:00
# 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 ;;
2018-07-18 19:50:37 -05:00
*) ERR_SIZE=1
esac
fi
fi
fi
if (( ERR_SIZE == 1 )); then
msgbox "$_ErrTitle" "$_LvmLvSizeErrBody"
2018-07-18 19:52:06 -05:00
get_lv_size || return 1
2018-07-18 19:50:37 -05:00
fi
return 0
}
2018-07-18 19:52:06 -05:00
lvm_volume_name() {
local msg="$1"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
local default="volmain"
(( VOL_COUNT > 1 )) && default="volextra"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
tput cnorm
local name
name="$(getinput "$_LvmCreateVG (LV:$VOL_COUNT)" "$msg" "$default")"
[[ $? != 0 || $name == "" ]] && return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# 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
2018-07-18 19:50:37 -05:00
msgbox "$_ErrTitle" "$_LvmNameVgErr"
2018-07-18 19:52:06 -05:00
lvm_group_name || return 1
fi
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
VOLUME_GROUP="$group"
return 0
}
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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; }
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# 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."
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
((VOL_COUNT--)) # decrement the number of volumes chosen to end the loop
done
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
return 0
}
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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
}
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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"
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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# get volume group name then confirm or bail out
lvm_group_name || return 1
yesno "$_LvmCreateVG" "$_LvmPvConfBody1 $VOLUME_GROUP\n$_LvmPvConfBody2 $VOL_GROUP_PARTS" || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# 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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# 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}')"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# 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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# finished volume group creation
msgbox "$_LvmCreateVG" "$_LvmPvDoneBody1 '$VOLUME_GROUP' ($VOL_GROUP_SIZE $VOL_GROUP_SIZE_TYPE) $_LvmPvDoneBody2\n"
tput civis
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# how many logical volumes
lvm_volume_count || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# if we chose more than one logical volume create all but the last
lvm_extra_lvs || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# last or only logical volume
lvm_volume_name "$_LvmLvNameBody1 $_LvmLvNameBody2 (${VOL_GROUP_MB}MB)." || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# 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
2018-07-18 19:50:37 -05:00
LVM=1
2018-07-18 19:52:06 -05:00
# offer the user to see the device tree
yesno "$_LvmCreateVG" "$_LvmCompBody" && show_devices
2018-07-18 19:50:37 -05:00
return 0
}
lvm_del_vg() {
2018-07-18 19:52:06 -05:00
local choice
choice="$(lvm_show_vg)"
yesno "$_LvmDelVG" "$_LvmDelQ" && vgremove -f "$choice" >/dev/null 2>&1
2018-07-18 19:50:37 -05:00
return 0
}
lvm_del_all() {
2018-07-18 19:52:06 -05:00
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)"
2018-07-18 19:50:37 -05:00
if yesno "$_LvMDelAll" "$_LvmDelQ"; then
2018-07-18 19:52:06 -05:00
for i in $VOLUMES; do
2018-07-18 19:50:37 -05:00
lvremove -f "/dev/mapper/$i" >/dev/null 2>&1
done
2018-07-18 19:52:06 -05:00
for i in $VOLUME_GROUP; do
2018-07-18 19:50:37 -05:00
vgremove -f "$i" >/dev/null 2>&1
done
2018-07-18 19:52:06 -05:00
for i in $PHYSICAL_VOLUMES; do
2018-07-18 19:50:37 -05:00
pvremove -f "$i" >/dev/null 2>&1
done
LVM=0
fi
return 0
}
lvm_menu() {
lvm_detect
2018-07-18 19:52:06 -05:00
tput civis
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
local choice
choice="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_PrepLVM " \
--menu "$_LvmMenu" 0 0 0 \
2018-07-18 19:50:37 -05:00
"$_LvmCreateVG" "vgcreate -f, lvcreate -L -n" \
"$_LvmDelVG" "vgremove -f" \
"$_LvMDelAll" "lvrmeove, vgremove, pvremove -f" \
2018-07-18 19:52:06 -05:00
"$_Back" "-")"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
case $choice in
"$_LvmCreateVG") lvm_create && return 0 ;;
2018-07-18 19:50:37 -05:00
"$_LvmDelVG") lvm_del_vg ;;
"$_LvMDelAll") lvm_del_all ;;
*) return 0
esac
lvm_menu
}
######################################################################
## Installation Functions ##
######################################################################
install_main() {
2018-07-18 19:52:06 -05:00
if [[ $UNPACKED_BASE != true ]]; then
unpack_base_system || return 0 # user can choose to bail at this point
UNPACKED_BASE=true
fi
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
genfstab -U $MNT > $MNT/etc/fstab 2>$ERR
check_for_errors "genfstab -U $MNT > $MNT/etc/fstab" || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
run_mkinitcpio || return 1
setup_bootloader || return 1
2018-07-18 19:52:06 -05:00
if [[ $HAS_NETWORK == true && $DONE_UPDATE != true ]]; then
update_mirrorlist && update_system
DONE_UPDATE=true
else
if pacman -Qsq archlabs-installer >/dev/null 2>&1; then
chroot_cmd "pacman -Rs archlabs-installer --noconfirm" >/dev/null 2>&1
elif [[ -d $MNT/installer ]]; then
rm -rf $MNT/installer
fi
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
# 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
2018-07-18 19:50:37 -05:00
fi
fi
2018-07-18 19:52:06 -05:00
}
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
unpack_base_system() {
# continue or bail
local msg="Boot Device: ${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
)
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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/
2018-07-18 19:50:37 -05:00
cp -f /tmp/keyboard $MNT/etc/default/
cp -f /tmp/vconsole.conf $MNT/etc/
cp -f /etc/resolv.conf $MNT/etc/
2018-07-18 19:52:06 -05:00
grep -qi "hypervisor" <<< "$(dmesg)" && rm -rf $MNT/etc/X11/xorg.conf.d
return 0
2018-07-18 19:50:37 -05:00
}
update_system() {
2018-07-18 19:52:06 -05:00
local pkgcmd
local upd="pacman -Syyu --noconfirm"
local net="pacman -S iputils --noconfirm"
local dev="pacman -S base-devel git --needed --noconfirm"
tput civis
if pacman -Qsq archlabs-installer >/dev/null 2>&1; then
pkgcmd="pacman -Rs archlabs-installer --noconfirm ; $upd ; $net ; $dev"
else
pkgcmd="$upd ; $net ; $dev"
fi
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
chroot_cmd "$pkgcmd" 2>/dev/null | dialog --cr-wrap --backtitle "$BT" \
--title " $_UpdSysTitle " --progressbox "$_UpdSysBody\n" 30 90
2018-07-18 19:50:37 -05:00
}
update_mirrorlist() {
2018-07-18 19:52:06 -05:00
local cmd="reflector --score 100 -l 50 -f 10 --sort rate"
if ! yesno "$_MirrorTitle" "$_MirrorSetup" "Automatic Sort" "Customize Sort"; then
local countries
countries="$(reflector --list-countries | awk 'NF > 1 {print $1 " -"}')"
if [[ $countries != "" ]]; then
local country
tput civis
country="$(dialog --cr-wrap --stdout --backtitle "$BT" --title "$_MirrorTitle" \
--menu "$_MirrorCountry" 22 70 10 $countries)"
[[ $? != 0 || $country == "" ]] && return 1
cmd="reflector --country $country --score 80 --latest 40 --fastest 10 --sort rate"
fi
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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
cmd="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_MirrorTitle " \
--inputbox "$_MirrorCmd\n\n$ref\n" 0 0 "$cmd")"
[[ $? != 0 || $cmd == "" ]] && return 1
2018-07-18 19:50:37 -05:00
fi
infobox "$_MirrorTitle" "$_MirrorSort"
2018-07-18 19:52:06 -05:00
if ! $cmd --save $MNT/etc/pacman.d/mirrorlist; then
infobox "$_ErrTitle" "\nAn error occurred updating the mirrorlist\n"
update_mirrorlist || return 1
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
return 0
2018-07-18 19:50:37 -05:00
}
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
if [[ $BOOTLOADER == "grub" ]]; then
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
if (( LUKS == 1 )); then
2018-07-18 19:52:06 -05:00
sed -i "s~#GRUB_ENABLE_CRYPTODISK~GRUB_ENABLE_CRYPTODISK~g; s~GRUB_CMDLINE_LINUX=.*~GRUB_CMDLINE_LINUX=\"${LUKS_DEV}\"~g" $cfg
2018-07-18 19:50:37 -05:00
fi
if [[ $SYS != "UEFI" ]]; then
if (( LVM == 1 && SEPERATE_BOOT == 0 )) || (( SEPERATE_BOOT == 2 )); then
2018-07-18 19:52:06 -05:00
sed -i "s/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g" $cfg
2018-07-18 19:50:37 -05:00
fi
fi
elif [[ $BOOTLOADER == "syslinux" ]]; then
local cfgdir="$MNT/boot/syslinux"
2018-07-18 19:52:06 -05:00
mkdir -p $cfgdir
cp -f /usr/lib/syslinux/bios/vesamenu.c32 $cfgdir/
cp -f /run/archiso/bootmnt/arch/boot/syslinux/splash.png $cfgdir/
2018-07-18 19:50:37 -05:00
cat > $cfgdir/syslinux.cfg << EOF
2018-07-18 19:52:06 -05:00
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
2018-07-18 19:50:37 -05:00
LABEL archlabs
2018-07-18 19:52:06 -05:00
MENU LABEL $DIST Linux
2018-07-18 19:50:37 -05:00
LINUX ../vmlinuz-linux
2018-07-18 19:52:06 -05:00
APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && echo -n "$LUKS_DEV ")rw
2018-07-18 19:50:37 -05:00
INITRD ../initramfs-linux.img
LABEL archlabsfallback
2018-07-18 19:52:06 -05:00
MENU LABEL $DIST Linux Fallback
2018-07-18 19:50:37 -05:00
LINUX ../vmlinuz-linux
2018-07-18 19:52:06 -05:00
APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && echo -n "$LUKS_DEV ")rw
2018-07-18 19:50:37 -05:00
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
2018-07-18 19:52:06 -05:00
# systemd-boot requires this before running bootctl
systemd-machine-id-setup --root="$MNT" >/dev/null 2>&1
mkdir -p $MNT/boot/loader/entries
2018-07-18 19:50:37 -05:00
cat > $MNT/boot/loader/loader.conf << EOF
default archlabs
timeout 5
editor no
EOF
2018-07-18 19:52:06 -05:00
cat > $MNT/boot/loader/entries/${DIST,,}.conf << EOF
title $DIST Linux
2018-07-18 19:50:37 -05:00
linux /vmlinuz-linux
initrd /initramfs-linux.img
options root=$ROOT_PART_ID rw
EOF
2018-07-18 19:52:06 -05:00
for file in $MNT/boot/loader/entries/arch*?.conf; do
(( LUKS == 1 )) && sed -i "s~rw~$LUKS_DEV rw~g" "$file"
2018-07-18 19:50:37 -05:00
done
fi
return 0
}
2018-07-18 19:52:06 -05:00
grub_uefi_fallback() {
# some UEFI firmware is finicky and requires special treatment this loops
# /boot/efi/EFI or /boot/efi/EFI and finds a directory named 'boot' 'Boot' 'BOOT'
# once/if found we copy grub's efi stub binary to that directory as bootx64.efi
local esp="${MNT}${BOOT_MNTS[$SYS-$BOOTLOADER]}"
local fb="boot"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
for i in $(find "$esp/EFI" -maxdepth 1 -mindepth 1 -type d 2>/dev/null); do
if grep -qi "boot" <<< "$(basename $i)"; then
fb="$(basename $i)"
break
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
done
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
mkdir -p $esp/EFI/$fb
cp -f $esp/EFI/$DIST/grubx64.efi $esp/EFI/$fb/grubx64.efi
cp -f $esp/EFI/$DIST/grubx64.efi $esp/EFI/$fb/bootx64.efi
}
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
setup_bootloader() {
chroot_cmd "export PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/bin/core_perl"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
local msg="$_InstBootloader $BOOTLOADER\n"
[[ $BOOT_PART != "" ]] && msg="$msg\n$_InstBootDev $BOOT_PART\n"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
infobox "$_InstBootTitle" "$msg\nMountpoint: ${BOOT_MNTS[$SYS-$BOOTLOADER]}\n"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
if [[ $SYS == "UEFI" ]] && grep -q "/sys/firmware/efi/efivars" <<< "$(mount)"; then
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]}"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# remove old EFI boot entries from previous installs
find $MNT/boot/efi/EFI/ -name '[aA][rR][cC][hH][lL]abs*' \
-type d -exec rm -rf '{}' \; 2>/dev/null
find $MNT/boot/efi/EFI/ -name '[Bb][oO][oO][tT]' \
-type d -exec rm -rf '{}' \; 2>/dev/null
fi
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# 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
# chroot_cmd "$udevcmd" >/dev/null 2>&1
BOOT_CMDS[grub]="$udevcmd ; ${BOOT_CMDS[grub]}"
# BIOS uses the base device name, eg. /dev/sda
[[ $SYS == "BIOS" ]] && BOOT_CMDS[grub]="${BOOT_CMDS[grub]} $BOOT_DEVICE"
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
# add grub-mkconfig last
BOOT_CMDS[grub]="${BOOT_CMDS[grub]} && grub-mkconfig -o /boot/grub/grub.cfg"
2018-07-18 19:50:37 -05:00
else
2018-07-18 19:52:06 -05:00
# for other bootloaders remove grub and 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]}"
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
# create bootloader config first, grub and systemd-boot require this
bootloader_config
# install the selected bootloader using the array command
chroot_cmd "${BOOT_CMDS[$BOOTLOADER]}" 2>$ERR >/dev/null 2>&1
check_for_errors "${BOOT_CMDS[$BOOTLOADER]}" || return 1
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
[[ $SYS == "UEFI" && $BOOTLOADER == "grub" ]] && grub_uefi_fallback
BOOT_DONE=true
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
if [[ $LUKS -eq 1 && $SYS != "BIOS" && $BOOTLOADER == "grub" ]]; then
[[ $LUKS_PASS && $LUKS_UUID ]] && luks_keyfile
fi
2018-07-18 19:50:37 -05:00
return 0
}
run_mkinitcpio() {
local conf="$MNT/etc/mkinitcpio.conf"
2018-07-18 19:52:06 -05:00
# 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
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
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\nAdded HOOKS: $MKINIT_HOOKS $add\n" 30 90
check_for_errors "mkinitcpio -p linux" || return 1
return 0
2018-07-18 19:50:37 -05:00
}
######################################################################
2018-07-18 19:52:06 -05:00
## Menu Dialogs ##
2018-07-18 19:50:37 -05:00
######################################################################
main_menu() {
2018-07-18 19:52:06 -05:00
if [[ $FIRST_PREP != true ]]; then
FIRST_PREP=true
prepare_menu
2018-07-18 19:50:37 -05:00
fi
if [[ $CURRENT_MENU != "main" ]]; then
2018-07-18 19:52:06 -05:00
MENU_HIGHLIGHT=1
2018-07-18 19:50:37 -05:00
CURRENT_MENU="main"
2018-07-18 19:52:06 -05:00
elif (( MENU_HIGHLIGHT < 5 )); then
((MENU_HIGHLIGHT++))
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
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")
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
if [[ -n $MENU_HIGHLIGHT ]]; then
if (( MENU_HIGHLIGHT == 2 )) && ! check_parts_are_mounted; then
2018-07-18 19:50:37 -05:00
return 1
2018-07-18 19:52:06 -05:00
elif (( MENU_HIGHLIGHT == 3 || MENU_HIGHLIGHT == 4 )); then
2018-07-18 19:50:37 -05:00
if ! (check_parts_are_mounted && check_base_unpacked); then
return 1
fi
fi
fi
2018-07-18 19:52:06 -05:00
case $MENU_HIGHLIGHT in
2018-07-18 19:50:37 -05:00
1) prepare_menu ;;
2) install_main ;;
3) configure_menu ;;
4) edit_config_menu ;;
2018-07-18 19:52:06 -05:00
*) wrap_up "$_CloseInstBody" 'Exit' 'Back' 'exit'
2018-07-18 19:50:37 -05:00
esac
}
prepare_menu() {
2018-07-18 19:52:06 -05:00
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 but if we return, then return to main menu
install_main && return 0
2018-07-18 19:50:37 -05:00
fi
fi
2018-07-18 19:52:06 -05:00
if [[ $CURRENT_MENU != "prep" ]]; then
MENU_HIGHLIGHT=1
CURRENT_MENU="prep"
elif (( MENU_HIGHLIGHT < 7 )); then
((MENU_HIGHLIGHT++))
fi
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
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")
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
case $MENU_HIGHLIGHT in
2018-07-18 19:50:37 -05:00
1) set_keymap ;;
2) show_devices ;;
2018-07-18 19:52:06 -05:00
3) unmount_partitions && select_device 'root' && create_partitions "$DEVICE" ;;
2018-07-18 19:50:37 -05:00
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"
2018-07-18 19:52:06 -05:00
if [[ $FIRST_CONFIG != true ]]; then
FIRST_CONFIG=true
set_hostname && set_locale && create_user
[[ $FULL_DONE == true ]] && return 0
2018-07-18 19:50:37 -05:00
elif [[ $CURRENT_MENU != "config" ]]; then
2018-07-18 19:52:06 -05:00
MENU_HIGHLIGHT=1
2018-07-18 19:50:37 -05:00
CURRENT_MENU="config"
2018-07-18 19:52:06 -05:00
elif (( MENU_HIGHLIGHT < 4 )); then
((MENU_HIGHLIGHT++))
2018-07-18 19:50:37 -05:00
fi
2018-07-18 19:52:06 -05:00
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")
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
case $MENU_HIGHLIGHT in
2018-07-18 19:50:37 -05:00
1) set_hostname ;;
2) set_locale ;;
2018-07-18 19:52:06 -05:00
3) create_user ;;
2018-07-18 19:50:37 -05:00
*) return 0
esac
configure_menu
}
edit_config_menu() {
if [[ $CURRENT_MENU != "edit" ]]; then
2018-07-18 19:52:06 -05:00
MENU_HIGHLIGHT=1
2018-07-18 19:50:37 -05:00
CURRENT_MENU="edit"
2018-07-18 19:52:06 -05:00
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" "keymaps" "2" "locale" "3" "hostname" "4" "sudoers" "5" "mkinitcpio.conf" \
"6" "fstab" "7" "crypttab" "8" "$BOOTLOADER" "9" "pacman.conf" "10" "$_Done")
if [[ $MENU_HIGHLIGHT == "" || $MENU_HIGHLIGHT == 10 ]]; 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
2018-07-18 19:50:37 -05:00
2018-07-18 19:52:06 -05:00
if [[ $existing_files != "" ]]; then
if [[ $DISPLAY ]] && hash geany >/dev/null 2>&1; then
if yesno "$_EditTitle" "\nOpen file(s) in Geany or Vim?\n" "Geany" "Vim"; then
geany -i $existing_files
else
vim -O $existing_files
fi
2018-07-18 19:50:37 -05:00
else
2018-07-18 19:52:06 -05:00
vim -O $existing_files
2018-07-18 19:50:37 -05:00
fi
else
msgbox "$_ErrTitle" "$_NoFileErr"
fi
edit_config_menu
}
2018-07-18 19:52:06 -05:00
for arg in "$@"; do
2018-07-18 19:50:37 -05:00
[[ $arg == "--debug" || $arg == "-d" ]] && set_debug
done
2018-07-18 19:52:06 -05:00
initialize_variables
2018-07-18 19:50:37 -05:00
select_language
check_requirements
identify_system
# welcome message
msgbox "$_WelTitle $DIST Installer" "$_WelBody"
while true; do
main_menu
done