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/archlabs-installer
2019-03-16 21:21:48 -07:00

2728 lines
86 KiB
Bash
Executable File

#!/usr/bin/bash
# vim:fdm=marker:fmr={,}
# shellcheck disable=2154
# This program is free software, provided under the GNU GPL
# Written by Nathaniel Maia for use in Archlabs
# Some ideas and code has been taken from other installers
# AIF, Cnichi, Calamares, The Arch Wiki.. Credit where credit is due
VER="1.8.21" # version
DIST="ArchLabs" # distributor
MNT="/mnt" # mountpoint
main()
{
if [[ $CURRENT_MENU != "main" && $SAVED ]]; then
CURRENT_MENU="main"
SELECTED=$((SAVED + 1))
unset SAVED
elif [[ $CURRENT_MENU != "main" ]]; then
SELECTED=1
CURRENT_MENU="main"
elif (( SELECTED < 11 )); then
((SELECTED++))
fi
tput civis
SELECTED=$(dialog --cr-wrap --stdout --backtitle "$BT" \
--title " $_PrepTitle " --default-item $SELECTED \
--cancel-label 'Exit' --menu "$_PrepBody" 0 0 0 \
"1" "$_PrepShowDev" \
"2" "$_PrepParts" \
"3" "$_PrepLUKS" \
"4" "$_PrepLVM" \
"5" "$_PrepMount" \
"6" "$_PrepUser" \
"7" "$_PrepConfig" \
"8" "$_PrepWM" \
"9" "$_PrepPkg" \
"10" "$_PrepShow" \
"11" "$_PrepInstall")
if [[ $WARN != true && $SELECTED =~ (2|5) ]]; then
WARN=true
msgbox "$_PrepTitle" "$_WarnMount"
fi
case $SELECTED in
1) device_tree ;;
2) partition || SELECTED=$((SELECTED - 1)) ;;
3) luks_menu || SELECTED=$((SELECTED - 1)) ;;
4) lvm_menu || SELECTED=$((SELECTED - 1)) ;;
5) mnt_menu || SELECTED=$((SELECTED - 1)) ;;
6) prechecks 0 && { mkuser || SELECTED=$((SELECTED - 1)); } ;;
7) prechecks 1 && { cfg_menu || SELECTED=$((SELECTED - 1)); } ;;
8) prechecks 2 && { select_wm_or_de || SELECTED=$((SELECTED - 1)); } ;;
9) prechecks 2 && { select_packages || SELECTED=$((SELECTED - 1)); } ;;
10) prechecks 2 && show_cfg ;;
11) prechecks 2 && install ;;
*) yesno "$_CloseInst" "$_CloseInstBody" "Exit" "Back" && die
esac
}
###############################################################################
# dialog menus
show_cfg()
{
local cmd="${BCMDS[$BOOTLDR]}"
local mnt="${BMNTS[$SYS-$BOOTLDR]}"
local pkgs="${PACKAGES# }"
pkgs="${pkgs# }"
msgbox "$_PrepTitle" "
---------- PARTITION CONFIGURATION ------------
Root: ${ROOT_PART:-None}
Boot: ${BOOT_PART:-${BOOT_DEVICE:-None}}
Swap: ${SWAP_PART:-None}
Size: ${SWAP_SIZE:-None}
LVM: ${LVM:-None}
LUKS: ${LUKS:-None}
Extra Mounts: ${EXTRA_MNTS:-${EXTRA_MNT:-None}}
Mkinit Hooks: ${HOOKS:-None}
---------- BOOTLOADER CONFIGURATION -----------
Bootloader: ${BOOTLDR:-None}
Mountpoint: ${mnt:-None}
Command: ${cmd:-None}
------------ SYSTEM CONFIGURATION -------------
Locale: ${LOCALE:-None}
Keymap: ${KEYMAP:-None}
Hostname: ${HOSTNAME:-None}
Timezone: ${ZONE:-None}/${SUBZONE:-None}
------------ USER CONFIGURATION --------------
User: ${NEWUSER:-None}
Shell: ${MYSHELL:-None}
Session: ${LOGIN_WM:-None}
Autologin: ${AUTOLOGIN:-None}
Login Method: ${LOGIN_TYPE:-None}
------------ PACKAGES AND MIRRORS -------------
Kernel: ${KERNEL:-None}
Sessions: ${INSTALL_WMS:-None}
Mirrors: ${MIRROR_CMD:-None}
Packages: $(print4 "${pkgs:-None}")
"
}
cfg_menu()
{
tput civis
if ! MYSHELL="$(menubox "$_ShellTitle" "$_ShellBody" '/usr/bin/zsh' '-' '/bin/bash' '-' '/usr/bin/mksh' '-')"; then
return 1
fi
tput cnorm
if ! HOSTNAME="$(getinput "$_ConfHost" "$_HostNameBody" "${DIST,,}")"; then
return 1
fi
tput civis
if ! LOCALE="$(dialog --cr-wrap --no-cancel --stdout --backtitle "$BT" \
--title " $_ConfLocale " --menu "$_LocaleBody" 0 0 $((LINES - 20)) $LOCALES)"; then
return 1
fi
select_timezone || return 1
if ! KERNEL="$(menubox "$_KernelTitle" "$_KernelBody" 'linux' '-' 'linux-lts' '-')"; then
return 1
fi
select_mirrorcmd || return 1
CONFIG_DONE=true
return 0
}
mkuser()
{
tput cnorm
local values
if ! values="$(dialog --stdout --no-cancel --separator '~' \
--ok-label "Submit" --backtitle "$BT" --title " $_UserTitle " \
--insecure --mixedform "$_UserBody" 0 0 0 \
"$_Username" 1 1 "" 1 $((${#_Username} + 2)) $COLUMNS 0 0 \
"$_Password" 2 1 "" 2 $((${#_Password} + 2)) $COLUMNS 0 1 \
"$_Password2" 3 1 "" 3 $((${#_Password2} + 2)) $COLUMNS 0 1 \
"$_RootBody" 6 1 "" 6 $((${#_RootBody} + 1)) $COLUMNS 0 2 \
"$_Password" 8 1 "" 8 $((${#_Password} + 2)) $COLUMNS 0 1 \
"$_Password2" 9 1 "" 9 $((${#_Password2} + 2)) $COLUMNS 0 1)"; then
return 1
fi
local user pass pass2 rpass rpass2
user="$(awk -F'~' '{print $1}' <<< "$values")"
pass="$(awk -F'~' '{print $2}' <<< "$values")"
pass2="$(awk -F'~' '{print $3}' <<< "$values")"
rpass="$(awk -F'~' '{print $5}' <<< "$values")"
rpass2="$(awk -F'~' '{print $6}' <<< "$values")"
# both root passwords are empty, so use the user passwords instead
[[ $rpass == "" && $rpass2 == "" ]] && { rpass="$pass"; rpass2="$pass2"; }
# make sure a username was entered and that the passwords match
if [[ ${#user} -eq 0 || $user =~ \ |\' || $user =~ [^a-z0-9] ]]; then
msgbox "$_UserErrTitle" "$_UserErrBody"
mkuser || return 1
elif [[ $pass == "" ]]; then
msgbox "$_ErrTitle" "$_UserPassEmpty\n$_TryAgain"
mkuser || return 1
elif [[ "$rpass" != "$rpass2" ]]; then
msgbox "$_ErrTitle" "$_RootPassErr\n$_TryAgain"
mkuser || return 1
elif [[ "$pass" != "$pass2" ]]; then
msgbox "$_ErrTitle" "$_UserPassErr\n$_TryAgain"
mkuser || return 1
fi
NEWUSER="$user"
USER_PASS="$pass"
ROOT_PASS="$rpass"
return 0
}
select_keymap()
{
tput civis
if ! KEYMAP="$(dialog --cr-wrap --no-cancel --stdout --backtitle "$BT" \
--title " $_PrepLayout " --menu "$_XMapBody" 0 0 $((LINES - 20)) \
'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' 'ro' 'Romanian' \
'no' 'Norwegian' 'rs' 'Serbian' 'si' 'Slovenian' 'tj' 'Tajik' 'lk' 'Sinhala' \
'tr' 'Turkish' 'uz' 'Uzbek' 'ie' 'Irish' 'pk' 'Urdu' 'mv' 'Dhivehi' \
'np' 'Nepali' 'et' 'Amharic' 'sn' 'Wolof' 'ml' 'Bambara' 'tz' 'Swahili' \
'ke' 'Swahili' 'bw' 'Tswana' 'ph' 'Filipino' 'my' 'Malay' 'tm' 'Turkmen' \
'id' 'Indonesian' 'bt' 'Dzongkha' 'lv' 'Latvian' 'md' 'Moldavian' 'mao' 'Maori' \
'by' 'Belarusian' 'az' 'Azerbaijani' 'mk' 'Macedonian' 'kh' 'Khmer' 'epo' 'Esperanto' \
'me' 'Montenegrin')"; then
return 1
fi
# when a matching console map is not available open a selection dialog
if [[ $CMAPS == *"$KEYMAP"* ]]; then
CMAP="$KEYMAP"
else
if ! CMAP="$(dialog --cr-wrap --no-cancel --stdout --backtitle "$BT" \
--title " $_CMapTitle " --menu "$_CMapBody" 0 0 $((LINES - 17)) $CMAPS)"; then
return 1
fi
fi
if [[ $DISPLAY && $TERM != 'linux' ]]; then
setxkbmap $KEYMAP >/dev/null 2>&1
else
loadkeys $CMAP >/dev/null 2>&1
fi
return 0
}
select_timezone()
{
# create associative array for SUBZONES[zone]
local f="/usr/share/zoneinfo/zone.tab"
declare -A SUBZONES
for i in America Australia Asia Atlantic Africa Europe Indian Pacific Arctic Antarctica; do
SUBZONES[$i]="$(awk '/'"$i"'\// {gsub(/'"$i"'\//, ""); print $3, $1}' $f | sort)"
done
tput civis
if ! ZONE="$(menubox "$_TimeZTitle" "$_TimeZBody" \
'America' '-' 'Australia' '-' 'Asia' '-' 'Atlantic' '-' 'Africa' '-' \
'Europe' '-' 'Indian' '-' 'Pacific' '-' 'Arctic' '-' 'Antarctica' '-')"; then
return 1
fi
if ! SUBZONE="$(dialog --cr-wrap --no-cancel --stdout --backtitle "$BT" \
--title " $_TimeZTitle " --menu "$_TimeSubZBody" 0 0 $((LINES - 17)) ${SUBZONES[$ZONE]})"; then
return 1
fi
yesno "$_TimeZTitle" "$_TimeZQ $ZONE/$SUBZONE?\n" || select_timezone
}
select_wm_or_de()
{
LOGIN_CHOICES=""
tput civis
if ! INSTALL_WMS="$(dialog --cr-wrap --no-cancel --stdout --backtitle "$BT" \
--title " $_WMChoice " --checklist "$_WMChoiceBody\n" 0 0 0 \
"i3-gaps" "A fork of i3wm with more features including gaps" off \
"dwm" "A fork of dwm, with more layouts and features" off \
"openbox" "A lightweight, powerful, and highly configurable stacking wm" off \
"bspwm" "A tiling wm that represents windows as the leaves of a binary tree" off \
"gnome" "A desktop environment that aims to be simple and easy to use" off \
"cinnamon" "A desktop environment combining traditional desktop with modern effects" off \
"plasma" "A kde software project currently comprising a full desktop environment" off \
"xfce4" "A lightweight and modular desktop environment based on gtk+2/3" off)"; then
return 1
fi
WM_NUM=$(awk '{print NF}' <<< "$INSTALL_WMS")
WM_PACKAGES="${INSTALL_WMS/dwm/}" # remove dwm from package list
WM_PACKAGES="${WM_PACKAGES// / }" # remove double spaces
WM_PACKAGES="${WM_PACKAGES# }" # remove leading space
# packages needed for the selected WMs/DEs
for wm in $INSTALL_WMS; do
LOGIN_CHOICES+="$wm - "
[[ ${WM_EXT[$wm]} && $WM_PACKAGES != *"${WM_EXT[$wm]}"* ]] && WM_PACKAGES+=" ${WM_EXT[$wm]}"
done
# choose how to log in
select_login || return 1
# choose which WM/DE to start at login, only for xinit
if [[ $LOGIN_TYPE == 'xinit' ]]; then
if [[ $WM_NUM -eq 1 ]]; then
LOGIN_WM="${WM_SESSIONS[$INSTALL_WMS]}"
else
LOGIN_WM="$(menubox "$_WMLogin" "$_WMLoginBody" $LOGIN_CHOICES)" || return 1
LOGIN_WM="${WM_SESSIONS[$LOGIN_WM]}"
fi
yesno "$_WMLogin" "$_AutoLoginBody\n" && AUTOLOGIN=true || AUTOLOGIN=false
else
AUTOLOGIN=false
fi
# add packages to the main package list
[[ $PACKAGES ]] && PACKAGES+=" ${WM_PACKAGES# }" || PACKAGES="${WM_PACKAGES# }"
}
select_login()
{
if ! LOGIN_TYPE="$(menubox "$_WMLogin" "$_LoginTypeBody" \
"xinit" "Console login without a display manager" \
"lightdm" "Lightweight display manager with a gtk greeter")"; then
return 1
fi
if [[ $LOGIN_TYPE == 'lightdm' ]]; then
WM_PACKAGES+=" lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings accountsservice"
EDIT_FILES[login]="/etc/lightdm/lightdm.conf /etc/lightdm/lightdm-gtk-greeter.conf"
else
PACKAGES="${PACKAGES// lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings accountsservice/}"
WM_PACKAGES="${WM_PACKAGES// lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings accountsservice/}"
EDIT_FILES[login]="/home/$NEWUSER/.xinitrc /home/$NEWUSER/.xprofile"
fi
}
select_packages()
{
if [[ $CURRENT_MENU != "packages" ]]; then
SAVED=$SELECTED
SELECTED=1
CURRENT_MENU="packages"
elif (( SELECTED < 9 )); then
((SELECTED++)) # increment the highlighted menu item
fi
tput civis
SELECTED=$(dialog --cr-wrap --no-cancel --stdout \
--backtitle "$BT" --title " $_Packages " \
--default-item $SELECTED --menu "$_PackageMenu" 0 0 0 \
1 "Browsers" \
2 "Editors" \
3 "Terminals" \
4 "Multimedia" \
5 "Chat/Mail" \
6 "Professional" \
7 "System" \
8 "Miscellaneous" \
9 "$_Done")
if [[ $SELECTED -lt 9 ]]; then
case $SELECTED in
1) PACKAGES+=" $(select_browsers)" ;;
2) PACKAGES+=" $(select_editors)" ;;
3) PACKAGES+=" $(select_terminals)" ;;
4) PACKAGES+=" $(select_multimedia)" ;;
5) PACKAGES+=" $(select_mailchat)" ;;
6) PACKAGES+=" $(select_prof)" ;;
7) PACKAGES+=" $(select_managment)" ;;
8) PACKAGES+=" $(select_extra)" ;;
esac
select_packages
fi
# add any extras for each package
for pkg in $PACKAGES; do
[[ ${PKG_EXT[$pkg]} && $PACKAGES != *"${PKG_EXT[$pkg]}"* ]] && PACKAGES+=" ${PKG_EXT[$pkg]}"
done
# add mksh to package list if it was chosen as the login shell
[[ $MYSHELL == *mksh ]] && PACKAGES+=" mksh"
# remove leading space
PACKAGES="${PACKAGES# }"
return 0
}
select_mirrorcmd()
{
local c
local key="5f29642060ab983b31fdf4c2935d8c56"
if hash reflector >/dev/null 2>&1; then
MIRROR_CMD="reflector --score 100 -l 50 -f 5 --sort rate --verbose"
yesno "$_MirrorTitle" "$_MirrorSetup" "Automatic" "Custom" && return 0
c="$(json 'country_name' "$(json 'ip' "check&?access_key=${key}&fields=ip")?access_key=${key}&fields=country_name")"
MIRROR_CMD="reflector --country $c --fastest 5 --sort rate --verbose"
tput cnorm
MIRROR_CMD="$(dialog --cr-wrap --no-cancel --stdout --backtitle "$BT" \
--title " $_MirrorTitle " --inputbox "$_MirrorCmd\n
--score n Limit the list to the n servers with the highest score.
--latest n Limit the list to the n most recently synchronized servers.
--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 location;
'score': MirrorStatus score;
'delay': MirrorStatus delay.\n" 0 0 "$MIRROR_CMD")"
else
c="$(json 'country_code' "$(json 'ip' "check&?access_key=${key}&fields=ip")?access_key=${key}&fields=country_code")"
local w="https://www.archlinux.org/mirrorlist"
if [[ $c ]]; then
if [[ $c =~ (CA|US) ]]; then
MIRROR_CMD="curl -s '$w/?country=US&country=CA&use_mirror_status=on'"
else
MIRROR_CMD="curl -s '$w/?country=${c}&use_mirror_status=on'"
fi
else
MIRROR_CMD="curl -s '$w/?country=US&country=CA&country=NZ&country=GB&country=AU&use_mirror_status=on'"
fi
fi
return 0
}
edit_configs()
{
[[ $DEBUG == true ]] && str="View log & reboot" || str="Exit & reboot"
tput civis
local choice
choice=$(dialog --cr-wrap --no-cancel --stdout --backtitle "$BT" \
--title " $_EditTitle " --menu "$_EditBody" 0 0 0 "$str" "-" \
"keyboard" "${EDIT_FILES[keyboard]}" \
"console" "${EDIT_FILES[console]}" \
"locale" "${EDIT_FILES[locale]}" \
"hostname" "${EDIT_FILES[hostname]}" \
"sudoers" "${EDIT_FILES[sudoers]}" \
"mkinitcpio" "${EDIT_FILES[mkinitcpio]}" \
"fstab" "${EDIT_FILES[fstab]}" \
"crypttab" "${EDIT_FILES[crypttab]}" \
"bootloader" "${EDIT_FILES[bootloader]}" \
"pacman" "${EDIT_FILES[pacman]}" \
"login" "${EDIT_FILES[login]}")
if [[ ! $choice || $choice == "$str" ]]; then
[[ $DEBUG == true && -r $DBG ]] && vim $DBG
# when die() is passed 127 it will call: systemctl -i reboot
die 127
else
local exists=""
for f in $(printf "%s" "${EDIT_FILES[$choice]}"); do
[[ -e ${MNT}$f ]] && exists+=" ${MNT}$f"
done
if [[ $exists ]]; then
vim -O $exists
else
msgbox "$_ErrTitle" "$_NoFileErr"
fi
fi
edit_configs
}
###############################################################################
# package menus
select_browsers()
{
local pkgs=""
pkgs="$(checkbox "$_Packages" "$_PackageBody" \
"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 \
"epiphany" "A GNOME web browser based on the WebKit rendering engine" off \
"qutebrowser" "A keyboard-focused vim-like web browser based on Python and PyQt5" off)"
printf "%s" "$pkgs"
}
select_editors()
{
local pkgs=""
pkgs="$(checkbox "$_Packages" "$_PackageBody" \
"neovim" "A fork of Vim aiming to improve user experience, plugins, and GUIs." 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 \
"mousepad" "A simple text editor" off)"
printf "%s" "$pkgs"
}
select_terminals()
{
local pkgs=""
pkgs="$(checkbox "$_Packages" "$_PackageBody" \
"termite" "A minimal VTE-based terminal emulator" off \
"rxvt-unicode" "A unicode enabled rxvt-clone terminal emulator" off \
"xterm" "The standard terminal emulator for the X window system" off \
"alacritty" "A cross-platform, GPU-accelerated terminal emulator" off \
"terminator" "Terminal emulator that supports tabs and grids" off \
"sakura" "A terminal emulator based on GTK and VTE" off \
"tilix" "A tiling terminal emulator for Linux using GTK+ 3" off \
"tilda" "A Gtk based drop down terminal for Linux and Unix" off \
"xfce4-terminal" "A terminal emulator based in the Xfce Desktop Environment" off)"
printf "%s" "$pkgs"
}
select_multimedia()
{
local pkgs=""
pkgs="$(checkbox "$_Packages" "$_PackageBody" \
"vlc" "A free and open source cross-platform multimedia player" off \
"mpv" "A media player based on mplayer" off \
"mpd" "A flexible, powerful, server-side application for playing music" off \
"ncmpcpp" "An mpd client and almost exact clone of ncmpc with some new features" off \
"cmus" "A small, fast and powerful console music player for Unix-like operating systems" 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)"
printf "%s" "$pkgs"
}
select_mailchat()
{
local pkgs=""
pkgs="$(checkbox "$_Packages" "$_PackageBody" \
"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 \
"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)"
printf "%s" "$pkgs"
}
select_prof()
{
local pkgs=""
pkgs="$(checkbox "$_Packages" "$_PackageBody" \
"libreoffice-fresh" "Full featured office suite" off \
"abiword" "Fully-featured word processor" off \
"calligra" "A set of applications for productivity" off \
"gimp" "GNU Image Manipulation Program" off \
"inkscape" "Professional vector graphics editor" off \
"krita" "Edit and paint images" off \
"obs-studio" "Free opensource streaming/recording software" off \
"openshot" "An open-source, non-linear video editor for Linux based on MLT framework" off \
"kdenlive" "A non-linear video editor for Linux using the MLT video framework" off \
"audacity" "A program that lets you manipulate digital audio waveforms" off \
"guvcview" "Capture video from camera devices" off \
"simplescreenrecorder" "A feature-rich screen recorder" off)"
printf "%s" "$pkgs"
}
select_managment()
{
local pkgs=""
pkgs="$(checkbox "$_Packages" "$_PackageBody" \
"thunar" "A modern file manager for the Xfce Desktop Environment" off \
"pcmanfm" "A fast and lightweight file manager based in Lxde" off \
"gparted" "A GUI frontend for creating and manipulating partition tables" off \
"gnome-disk-utility" "Disk Management Utility" off \
"gnome-system-monitor" "View current processes and monitor system state" off \
"qt5ct" "GUI for managing Qt based application themes, icons, and fonts" off \
"file-roller" "Create and modify archives" off \
"xarchiver" "A GTK+ frontend to various command line archivers" 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" "Google Noto fonts" off \
"noto-fonts-cjk" "Google Noto CJK fonts (Chinese, Japanese, Korean)" off)"
printf "%s" "$pkgs"
}
select_extra()
{
local pkgs=""
pkgs="$(checkbox "$_Packages" "$_PackageBody" \
"steam" "A popular game distribution platform by Valve" off \
"deluge" "A BitTorrent client written in python" off \
"transmission-gtk" "Free BitTorrent client GTK+ GUI" off \
"qbittorrent" "An advanced BitTorrent client" off \
"evince" "A document viewer" off \
"zathura" "Minimalistic document viewer" off \
"qpdfview" "A tabbed PDF viewer" off \
"mupdf" "Lightweight PDF and XPS viewer" off \
"gpicview" "Lightweight image viewer" off \
"gpick" "Advanced color picker using GTK+ toolkit" off \
"gcolor2" "A simple GTK+2 color selector" off \
"plank" "An elegant, simple, and clean dock" off \
"docky" "Full fledged dock for opening applications and managing windows" off \
"cairo-dock" "Light eye-candy fully themable animated dock" off)"
printf "%s" "$pkgs"
}
###############################################################################
# partition menus
format()
{
infobox "$_FSTitle" "\nRunning: ${FS_CMDS[$2]} $1\n" 0
${FS_CMDS[$2]} $1 >/dev/null 2>$ERR
errshow "${FS_CMDS[$2]} $1"
}
partition()
{
local device
if [[ $# -eq 0 ]]; then
select_device 'root' || return 1
device="$DEVICE"
else
device="$1"
fi
tput civis
local choice
if [[ $DISPLAY ]] && hash gparted >/dev/null 2>&1; then
if ! choice="$(menubox "$_PartTitle" "$_PartBody" \
"$_PartShowTree" "-" \
"$_PartAuto" "-" \
"gparted -" \
"cfdisk" "-" \
"parted" "-" \
"$_PartWipe" "-" \
"$_Done" "-")"; then
return 1
fi
else
if ! choice="$(menubox "$_PartTitle" "$_PartBody" \
"$_PartShowTree" "-" \
"$_PartAuto" "-" \
"cfdisk" "-" \
"parted" "-" \
"$_PartWipe" "-" \
"$_Done" "-")"; then
return 1
fi
fi
tput civis
if [[ $choice == "$_Done" || $choice == "" ]]; then
return 0
elif [[ $choice != "$_PartWipe" && $choice != "$_PartAuto" && $choice != "$_PartShowTree" ]]; then
clear; tput cnorm; $choice $device
elif [[ $choice == "$_PartShowTree" ]]; then
msgbox "$_PrepShowDev" "\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE,MOUNTPOINT "$device")\n"
partition $device
elif [[ $choice == "$_PartWipe" ]]; then
yesno "$_PartWipe" "$_PartBody1 $device $_PartWipeBody2" && wipe -Ifrev $device
partition $device
else
# if auto_partition fails we need to empty the partition variables
auto_partition $device || return 1
fi
}
decr_count()
{
# remove a partition from the dialog list and decrement the number partitions left
(( $# == 1 )) || return 1
local p="$1"
PARTS="$(sed "s~${p} [0-9]*[G-M]~~; s~${p} [0-9]*\.[0-9]*[G-M]~~" <<< "$PARTS")"
(( COUNT > 0 )) && (( COUNT-- ))
return 0
}
enable_swap()
{
if [[ $1 == "$MNT/swapfile" && $SWAP_SIZE ]]; then
fallocate -l $SWAP_SIZE $1 2>$ERR
errshow "fallocate -l $SWAP_SIZE $1"
chmod 600 $1 2>$ERR
errshow "chmod 600 $1"
fi
mkswap $1 >/dev/null 2>$ERR
errshow "mkswap $1"
swapon $1 >/dev/null 2>$ERR
errshow "swapon $1"
return 0
}
device_tree()
{
tput civis
local msg
if [[ $IGNORE_DEV != "" ]]; then
msg="$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE,MOUNTPOINT |
awk "!/$IGNORE_DEV/"' && /disk|part|lvm|crypt|NAME/')"
else
msg="$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE,MOUNTPOINT |
awk '/disk|part|lvm|crypt|NAME/')"
fi
msgbox "$_PrepShowDev" "$msg"
}
select_device()
{
local dev
local msg
if [[ $1 == 'boot' ]]; then
msg="$_DevSelTitle for bootloader\n"
else
umount_dir $MNT
fi
if [[ $DEV_COUNT -eq 1 && $SYS_DEVS ]]; then
# auto select without mention (it's annoying)
DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
elif (( DEV_COUNT > 1 )); then
tput civis
if ! DEVICE="$(menubox "$_DevSelTitle " "${msg}$_DevSelBody" $SYS_DEVS)"; then
return 1
fi
elif [[ $DEV_COUNT -lt 1 && $1 != 'boot' ]]; then
msgbox "$_ErrTitle" "\nNo available devices to use.\n$_Exit"; die 1
fi
# if the device selected was for bootloader, set the BOOT_DEVICE
[[ $1 == 'boot' ]] && BOOT_DEVICE="$DEVICE"
return 0
}
confirm_mount()
{
local part="$1"
local mount="$2"
[[ $mount == "$MNT" ]] && local m="/ (root)" || local m="${mount#$MNT}"
if [[ $(mount) == *"$mount"* ]]; then
infobox "$_MntTitle" "$_MntSucc\nPartition: $part\nMountpoint: $m\n" 1
decr_count "$part"
else
infobox "$_MntTitle" "$_MntFail\n$msg\n" 1
return 1
fi
return 0
}
check_cryptlvm()
{
local dev=""
local part="$1"
local devs
devs="$(lsblk -lno NAME,FSTYPE,TYPE)"
# Identify if $part is "crypt" (LUKS on LVM, or LUKS alone)
if [[ $(lsblk -lno TYPE "$part") =~ 'crypt' ]]; then
LUKS='encrypted'
LUKS_NAME="${part#/dev/mapper/}"
for dev in $(awk '/lvm/ && /crypto_LUKS/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
if grep -q "$LUKS_NAME" <<< "$(lsblk -lno NAME "$dev")"; then
LUKS_DEV="$LUKS_DEV cryptdevice=$dev:$LUKS_NAME"
LVM='logical volume'
break
fi
done
for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
if grep -q "$LUKS_NAME" <<< "$(lsblk -lno NAME "$dev")"; then
LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
break
fi
done
elif [[ $(lsblk -lno TYPE "$part") =~ 'lvm' ]]; then
LVM='logical volume'
VOLUME_NAME="${part#/dev/mapper/}"
for dev in $(awk '/crypt/ && /lvm2_member/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
if grep -q "$VOLUME_NAME" <<< "$(lsblk -lno NAME "$dev")"; then
LUKS_NAME="$(sed 's~/dev/mapper/~~g' <<< "$dev")"
break
fi
done
for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
if grep -q "$LUKS_NAME" <<< "$(lsblk -lno NAME "$dev")"; then
LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
LUKS='encrypted'
break
fi
done
fi
}
auto_partition()
{
local device="$1"
local size
size=$(lsblk -lno SIZE $device | awk 'NR == 1 {
if ($1 ~ "G") {
sub(/G/, ""); print ($1 * 1000 - 512) / 1000"G"
} else {
sub(/M/, ""); print ($1 - 512)"M"
}
}')
if [[ $SYS == 'BIOS' ]]; then
local msg
msg="$(sed 's|vfat/fat32|ext4|' <<< "$_PartBody2")"
local table="msdos"
local fs="ext4"
else
local msg="$_PartBody2"
local table="gpt"
local fs="fat32";
fi
# confirm or bail
yesno "$_PrepParts" "$_PartBody1 $device $msg ($size)$_PartBody3" || return 0
infobox "$_PrepParts" "\nRemoving partitions on $device and setting table to $table\n" 2
swapoff -a # in case the device was previously used for swap
local dev_info
dev_info="$(parted -s $device print)"
# walk the partitions on the device in reverse order and delete them
while read -r i; do
parted -s $device rm $i >/dev/null 2>&1
done <<< "$(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r)"
if [[ $(awk '/Table:/ {print $3}' <<< "$dev_info") != "$table" ]]; then
parted -s $device mklabel $table >/dev/null 2>&1
fi
infobox "$_PrepParts" "\nCreating a 512M $fs boot partition.\n" 2
if [[ $SYS == "BIOS" ]]; then
parted -s $device mkpart primary $fs 1MiB 513MiB >/dev/null 2>&1
else
parted -s $device mkpart ESP $fs 1MiB 513MiB >/dev/null 2>&1
fi
sleep 0.1
BOOT_DEVICE="$device"
AUTO_BOOT_PART=$(lsblk -lno NAME,TYPE $device | awk 'NR == 2 {print "/dev/"$1}')
if [[ $SYS == "BIOS" ]]; then
mkfs.ext4 -q $AUTO_BOOT_PART >/dev/null 2>&1
else
mkfs.vfat -F32 $AUTO_BOOT_PART >/dev/null 2>&1
fi
infobox "$_PrepParts" "\nCreating a $size ext4 root partition.\n" 0
parted -s $device mkpart primary ext4 513MiB 100% >/dev/null 2>&1
sleep 0.1
local rp
rp="$(lsblk -lno NAME,TYPE $device | awk 'NR == 3 {print "/dev/"$1}')"
mkfs.ext4 -q $rp >/dev/null 2>&1
tput civis
sleep 0.5
msgbox "$_PrepParts" "\nAuto partitioning complete.\n\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE $device)"
}
mount_partition()
{
local part="$1"
local mountp="${MNT}$2"
local fs
fs="$(lsblk -lno FSTYPE $part)"
mkdir -p "$mountp"
if [[ $fs && ${FS_OPTS[$fs]} && $part != "$BOOT_PART" ]] && select_mount_opts "$part" "$fs"; then
mount -o $MNT_OPTS "$part" "$mountp" 2>$ERR
errshow "mount -o $MNT_OPTS $part $mountp"
else
mount "$part" "$mountp" 2>$ERR
errshow "mount $part $mountp"
fi
confirm_mount $part "$mountp" || return 1
check_cryptlvm "$part"
return 0
}
find_partitions()
{
local str="$1"
local err=''
# string of partitions as /TYPE/PART SIZE
if [[ $IGNORE_DEV != "" ]]; then
PARTS="$(lsblk -lno TYPE,NAME,SIZE |
awk "/$str/"' && !'"/$IGNORE_DEV/"' {
sub(/^part/, "/dev/");
sub(/^lvm|^crypt/, "/dev/mapper/")
print $1$2 " " $3
}')"
else
PARTS="$(lsblk -lno TYPE,NAME,SIZE |
awk "/$str/"' {
sub(/^part/, "/dev/")
sub(/^lvm|^crypt/, "/dev/mapper/")
print $1$2 " " $3
}')"
fi
# number of partitions total
COUNT=$(wc -l <<< "$PARTS")
# ensure we have enough partitions for the system and action type
case $str in
'part|lvm|crypt') [[ $COUNT -eq 0 || ($SYS == 'UEFI' && $COUNT -lt 2) ]] && err="$_PartErrBody" ;;
'part|crypt') (( COUNT == 0 )) && err="$_LvmPartErrBody" ;;
'part|lvm') (( COUNT < 2 )) && err="$_LuksPartErrBody" ;;
esac
# if there aren't enough partitions show the error message
if [[ $err ]]; then
msgbox "$_ErrTitle" "$err"
return 1
fi
return 0
}
setup_boot_device()
{
infobox "$_PrepMount" "\nSetting device flags for: $BOOT_PART\n" 1
if [[ $BOOT_PART = /dev/nvme* ]]; then
BOOT_DEVICE="${BOOT_PART%p[1-9]}"
else
BOOT_DEVICE="${BOOT_PART%[1-9]}"
fi
BOOT_PART_NUM="${BOOT_PART: -1}"
if [[ $SYS == 'UEFI' ]]; then
parted -s $BOOT_DEVICE set $BOOT_PART_NUM esp on >/dev/null 2>&1
else
parted -s $BOOT_DEVICE set $BOOT_PART_NUM boot on >/dev/null 2>&1
fi
return 0
}
###############################################################################
# mounting menus
mnt_menu()
{
# prepare partition list PARTS for dialog
lvm_detect
umount_dir $MNT
find_partitions 'part|lvm|crypt' || return 1
select_root_partition || return 1
if [[ $SYS == "UEFI" ]]; then
select_efi_partition || { BOOT_PART=""; return 1; }
elif (( COUNT > 0 )); then
select_boot_partition || { BOOT_PART=""; return 1; }
fi
setup_boot || return 1
select_swap || return 1
select_extra_partitions || return 1
return 0
}
select_swap()
{
# Ask user to select partition or create swapfile
tput civis
if ! SWAP_PART="$(menubox "$_SelSwpSetup" "$_SelSwpBody" "$_SelSwpNone" "-" "$_SelSwpFile" "$SYS_MEM" $PARTS)" || [[ $SWAP_PART == "$_SelSwpNone" ]]
then
SWAP_PART=""
return 0
fi
if [[ $SWAP_PART == "$_SelSwpFile" ]]; then
tput cnorm
local i=0
while ! [[ ${SWAP_SIZE:0:1} =~ [1-9] && ${SWAP_SIZE: -1} =~ (M|G) ]]; do
(( i > 0 )) && msgbox "$_SelSwpSetup Error" "\n$_SelSwpErr $SWAP_SIZE\n"
if ! SWAP_SIZE="$(getinput "$_SelSwpSetup" "$_SelSwpSize" "$SYS_MEM")"; then
SWAP_PART=""
SWAP_SIZE=""
break
return 0
fi
((i++))
done
enable_swap "$MNT/swapfile"
SWAP_PART="/swapfile"
else
enable_swap "$SWAP_PART"
decr_count "$SWAP_PART"
SWAP_SIZE="$(lsblk -lno SIZE $SWAP_PART)"
fi
return 0
}
select_mountpoint()
{
tput cnorm
if ! EXTRA_MNT="$(getinput "$_PrepMount $part" "$_ExtPartBody1 /home /var\n" "/" nolimit)"; then
return 1
fi
# bad mountpoint
if [[ ${EXTRA_MNT:0:1} != "/" || ${#EXTRA_MNT} -le 1 || $EXTRA_MNT =~ \ |\' || $EXTRA_MNTS == *"$EXTRA_MNT"* ]]; then
msgbox "$_ErrTitle" "$_ExtErrBody"
select_mountpoint || return 1
fi
return 0
}
select_mount_opts()
{
local part="$1"
local fs="$2"
local title="${fs^} Mount Options"
local opts="${FS_OPTS[$fs]}"
# check for ssd
ssd "$part" >/dev/null 2>&1 && opts=$(sed 's/discard - off/discard - on/' <<< "$opts")
tput civis
if ! MNT_OPTS="$(dialog --cr-wrap --no-cancel --stdout --backtitle "$BT" --title " $title " --checklist "$_MntBody" 0 0 0 $opts)" || [[ $MNT_OPTS == "" ]]
then
return 1
fi
MNT_OPTS="$(sed 's/ /,/g; $s/,$//' <<< "$MNT_OPTS" )"
yesno "$title" "$_MntConfBody $MNT_OPTS\n" || { select_mount_opts "$part" "$fs" || return 1; }
return 0
}
select_filesystem()
{
local part="$1"
local fs cur_fs
cur_fs="$(lsblk -lno FSTYPE $part 2>/dev/null)"
local msg="\nSelect which filesystem you want to use for $part\n\nPartition Name: "
tput civis
if [[ $cur_fs && $part != "$ROOT_PART" ]]; then
fs="$(menubox "$_FSTitle: $part" \
"${msg}${part}\nExisting Filesystem: ${cur_fs}$_FSBody" \
"$_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]}")"
[[ $fs == "$_Skip" ]] && return 0
else
fs="$(menubox "$_FSTitle: $part" "${msg}${part}$_FSBody" \
"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]}")"
fi
[[ $fs ]] || return 1
if yesno "$_FSTitle" "\nFormat $part as $fs?\n" "Format" "Go Back"; then
format $part $fs
else
select_filesystem $part || return 1
fi
return 0
}
select_efi_partition()
{
tput civis
if (( COUNT == 1 )); then
BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
infobox "$_PrepMount" "$_OnlyOne for EFI: $BOOT_PART\n" 1
elif ! BOOT_PART="$(menubox "$_PrepMount" "$_SelUefiBody" $PARTS)"; then
return 1
fi
if grep -q 'fat' <<< "$(fsck -N "$BOOT_PART")"; then
local msg="$_FormUefiBody $BOOT_PART $_FormUefiBody2"
if [[ $AUTO_BOOT_PART != "$BOOT_PART" ]] && yesno "$_PrepMount" "$msg" "Format $BOOT_PART" "Do Not Format" "no"; then
format "$BOOT_PART" "vfat"
sleep 1
fi
else
format "$BOOT_PART" "vfat"
sleep 1
fi
return 0
}
select_boot_partition()
{
tput civis
if ! BOOT_PART="$(menubox "$_PrepMount" "$_SelBiosBody" "$_Skip" "-" $PARTS)" || [[ $BOOT_PART == "$_Skip" ]]; then
BOOT_PART=""
else
if grep -q 'ext[34]' <<< "$(fsck -N "$BOOT_PART")"; then
local msg="$_FormBiosBody $BOOT_PART $_FormBiosBody2"
if [[ $AUTO_BOOT_PART != "$BOOT_PART" ]] && yesno "$_PrepMount" "$msg" "Format $BOOT_PART" "Skip Formatting" "no"; then
format "$BOOT_PART" "ext4"
sleep 1
fi
else
format "$BOOT_PART" "ext4"
sleep 1
fi
fi
return 0
}
select_root_partition()
{
tput civis
if [[ $COUNT -eq 1 ]]; then
ROOT_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
infobox "$_PrepMount" "$_OnlyOne for root (/): $ROOT_PART\n" 1
elif ! ROOT_PART="$(menubox "$_PrepMount" "$_SelRootBody" $PARTS)"; then
return 1
fi
select_filesystem "$ROOT_PART" || { ROOT_PART=""; return 1; }
mount_partition "$ROOT_PART" || { ROOT_PART=""; return 1; }
return 0
}
select_extra_partitions()
{
while (( COUNT > 0 )); do
tput civis
local part
if ! part="$(menubox "$_PrepMount " "$_ExtPartBody" "$_Done" "-" $PARTS)" || [[ $part == "$_Done" ]]; then
break
elif ! select_filesystem "$part"; then
break
return 1
elif ! select_mountpoint; then
break
return 1
elif ! mount_partition "$part" "$EXTRA_MNT"; then
break
return 1
fi
EXTRA_MNTS="$EXTRA_MNTS $part: $EXTRA_MNT"
[[ $EXTRA_MNT == "/usr" && $HOOKS != *usr* ]] && HOOKS="usr $HOOKS"
done
return 0
}
###############################################################################
# installation
install()
{
clear
tput cnorm
install_base
printf "Generating system /etc/fstab\n"
genfstab -U $MNT >$MNT/etc/fstab 2>$ERR
echeck "genfstab -U $MNT >$MNT/etc/fstab"
[[ -f $MNT/swapfile ]] && sed -i "s~${MNT}~~" $MNT/etc/fstab
mirrorlist_sort
package_operations
run_mkinitcpio
install_bootloader
chrun "hwclock --systohc --utc" || chrun "hwclock --systohc --utc --directisa"
create_user
login_manager
chrun "chown -Rf $NEWUSER:users /home/$NEWUSER"
edit_configs
}
install_base()
{
if [[ -e /run/archiso/sfs/airootfs/etc/skel ]]; then
rsync -ahv /run/archiso/sfs/airootfs/ $MNT/ 2>$ERR
echeck "rsync -ahv /run/archiso/sfs/airootfs/ $MNT/"
else
mirrorlist_sort
pacstrap $MNT base $KERNEL $UCODE $(grep -hv '^#' /usr/share/archlabs/installer/packages.txt) 2>$ERR
echeck "pacstrap $MNT base $KERNEL $UCODE $(grep -hv '^#' /usr/share/archlabs/installer/packages.txt)"
fi
printf "Removing archiso remains\n"
rm -rf $MNT/etc/mkinitcpio-archiso.conf
find $MNT/usr/lib/initcpio -name 'archiso*' -type f -exec rm -rf '{}' \;
sed -i 's/volatile/auto/g' $MNT/etc/systemd/journald.conf
if [[ $VM ]]; then
printf "Removing xorg configs in /etc/X11/xorg.conf.d/ to avoid conflict in VMs\n"
rm -rfv $MNT/etc/X11/xorg.conf.d/*?.conf
sleep 1
elif [[ $(lspci | grep ' VGA ' | grep 'Intel') != "" ]]; then
printf "Creating intel GPU 'TearFree' config in /etc/X11/xorg.conf.d/20-intel.conf\n"
cat > $MNT/etc/X11/xorg.conf.d/20-intel.conf <<EOF
Section "Device"
Identifier "Intel Graphics"
Driver "intel"
Option "TearFree" "true"
EndSection
EOF
fi
if [[ -e /run/archiso/sfs/airootfs ]]; then
printf "Copying vmlinuz and ucode to /boot\n"
[[ $KERNEL != 'linux-lts' ]] && cp -vf $RUN/x86_64/vmlinuz $MNT/boot/vmlinuz-linux
[[ $UCODE && ! $VM ]] && cp -vf $RUN/${UCODE/-/_}.img $MNT/boot/${UCODE}.img
fi
printf "Copying network settings to /etc\n"
cp -fv /etc/resolv.conf $MNT/etc/
if [[ -e /etc/NetworkManager/system-connections ]]; then
cp -rvf /etc/NetworkManager/system-connections $MNT/etc/NetworkManager/
fi
printf "Setting locale to $LOCALE\n"
cat > $MNT/etc/locale.conf << EOF
LANG=$LOCALE
EOF
cat > $MNT/etc/default/locale << EOF
LANG=$LOCALE
EOF
sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${LOCALE}/${LOCALE}/g" $MNT/etc/locale.gen
chrun "locale-gen" 2>/dev/null
printf "Setting timezone: $ZONE/$SUBZONE\n"
chrun "ln -svf /usr/share/zoneinfo/$ZONE/$SUBZONE /etc/localtime" 2>/dev/null
if [[ $BROADCOM_WL == true ]]; then
printf "Blacklisting modules for broadcom wireless: bmca\n"
echo 'blacklist bcma' >> $MNT/etc/modprobe.d/blacklist.conf
rm -f $MNT/etc/modprobe/
fi
printf "Creating keyboard configurations for keymap: $KEYMAP\n"
cat > $MNT/etc/X11/xorg.conf.d/00-keyboard.conf <<EOF
# Use localectl(1) to instruct systemd-localed to update it.
Section "InputClass"
Identifier "system-keyboard"
MatchIsKeyboard "on"
Option "XkbLayout" "$KEYMAP"
EndSection
EOF
cat > $MNT/etc/default/keyboard <<EOF
# KEYBOARD CONFIGURATION FILE
# Consult the keyboard(5) manual page.
XKBMODEL=""
XKBLAYOUT="$KEYMAP"
XKBVARIANT=""
XKBOPTIONS=""
BACKSPACE="guess"
EOF
cat > $MNT/etc/vconsole.conf <<EOF
KEYMAP=$CMAP
FONT=$FONT
EOF
printf "Setting system hostname: $HOSTNAME\n"
cat > $MNT/etc/hostname << EOF
$HOSTNAME
EOF
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
}
create_user()
{
printf "Creating user $NEWUSER, setting passwords, and setting shell\n"
# set root password, shell if needed
chrun "chpasswd <<< 'root:$ROOT_PASS'"
if [[ $MYSHELL != *zsh ]]; then
chrun "usermod -s $MYSHELL root"
if [[ $MYSHELL == "/usr/bin/mksh" ]]; then
cp -fv $MNT/etc/skel/.mkshrc /root/.mkshrc
fi
fi
# Create the user, set password, and make sure the ownership of ~/ is correct
local groups='audio,autologin,floppy,log,network,rfkill,scanner,storage,optical,power,wheel'
chrun "groupadd -r autologin"
chrun "useradd -m -u 1000 -g users -G $groups -s $MYSHELL $NEWUSER" 2>$ERR
echeck "useradd -m -u 1000 -g users -G $groups -s $MYSHELL $NEWUSER"
chrun "chpasswd <<< '$NEWUSER:$USER_PASS'"
# for neovim set up ~/.config/nvim
if [[ $PACKAGES =~ neovim ]]; then
mkdir -p $MNT/home/$NEWUSER/.config/nvim
cp -fv $MNT/home/$NEWUSER/.vimrc $MNT/home/$NEWUSER/.config/nvim/init.vim
cp -rfv $MNT/home/$NEWUSER/.vim/colors $MNT/home/$NEWUSER/.config/nvim/colors
fi
[[ $INSTALL_WMS =~ dwm ]] && suckless_install
if [[ $INSTALL_WMS == 'plasma' || $LOGIN_WM == 'startkde' || $INSTALL_WMS == 'gnome' || $LOGIN_WM == 'gnome-session' ]]
then
sed -i '/super/d' $HOME/.xprofile /root/.xprofile
fi
return 0
}
setup_xinit()
{
if [[ -e $MNT/home/$NEWUSER/.xinitrc ]]; then
sed -i "s/openbox-session/${LOGIN_WM}/g" $MNT/home/$NEWUSER/.xinitrc
else
printf "exec $LOGIN_WM\n" > $MNT/home/$NEWUSER/.xinitrc
fi
# automatic startx for login shells
local loginrc
case $MYSHELL in
"/bin/bash")
loginrc=".bash_profile"
;;
"/usr/bin/mksh")
loginrc=".profile"
cat >> $MNT/home/$NEWUSER/.mkshrc << EOF
# colors in less (manpager)
export LESS_TERMCAP_mb=$'\e[01;31m'
export LESS_TERMCAP_md=$'\e[01;31m'
export LESS_TERMCAP_me=$'\e[0m'
export LESS_TERMCAP_se=$'\e[0m'
export LESS_TERMCAP_so=$'\e[01;44;33m'
export LESS_TERMCAP_ue=$'\e[0m'
export LESS_TERMCAP_us=$'\e[01;32m'
export EDITOR=vim
export MANWIDTH=100
# source shell configs
for f in "\$HOME/.mksh/"*?.sh; do
. "\$f"
done
al-info
EOF
;;
*)
loginrc=".zprofile"
esac
if ! [[ ${EDIT_FILES[login]} =~ $loginrc ]]; then
# add the shell login file to the edit list after install
EDIT_FILES[login]+=" /home/$NEWUSER/$loginrc"
fi
if [[ $AUTOLOGIN == true ]]; then
sed -i "s/root/${NEWUSER}/g" $SERVICE/autologin.conf
cat > $MNT/home/$NEWUSER/$loginrc << EOF
# ~/$loginrc
# sourced by $(basename $MYSHELL) when used as a login shell
# automatically run startx when logging in on tty1
[[ ! \$DISPLAY && \$XDG_VTNR -eq 1 ]] && exec startx -- vt1
EOF
else
rm -rf $SERVICE
rm -rf $MNT/home/$NEWUSER/.{profile,zprofile,bash_profile}
fi
}
setup_lightdm()
{
rm -rf $SERVICE
rm -rf $MNT/home/$NEWUSER/.{xinitrc,profile,zprofile,bash_profile}
chrun 'systemctl set-default graphical.target && systemctl enable lightdm.service'
cat > $MNT/etc/lightdm/lightdm-gtk-greeter.conf << EOF
# LightDM GTK+ Configuration
[greeter]
active-monitor=0
default-user-image=/usr/share/icons/ArchLabs-Dark/64x64/places/distributor-logo-archlabs.png
background=/usr/share/backgrounds/archlabs/archlabs.jpg
theme-name=Adwaita-dark
icon-theme-name=Adwaita
font-name=DejaVu Sans Mono 11
position=30%,end 50%,end
EOF
}
login_manager()
{
printf "Setting up $LOGIN_TYPE\n"
SERVICE="$MNT/etc/systemd/system/getty@tty1.service.d"
# remove welcome message
sed -i '/printf/d' $MNT/root/.zshrc
# remove unneeded shell files from installation
case $MYSHELL in
"/bin/bash")
rm -rf $MNT/home/$NEWUSER/.{zsh,mksh}* $MNT/root/.{zsh,mksh}*
;;
"/usr/bin/mksh")
rm -rf $MNT/home/$NEWUSER/.{zsh,bash}* $MNT/home/$NEWUSER/.inputrc $MNT/root/.{zsh,bash}* $MNT/root/.inputrc
;;
"/usr/bin/zsh")
rm -rf $MNT/home/$NEWUSER/.{bash,mksh}* $MNT/home/$NEWUSER/.inputrc $MNT/root/.{bash,mksh}* $MNT/root/.inputrc
;;
esac
if [[ $LOGIN_TYPE == 'lightdm' ]]; then
setup_lightdm
else
setup_xinit
fi
}
run_mkinitcpio()
{
local add=""
[[ $LUKS && $SYS == 'UEFI' && $BOOTLDR == 'grub' ]] && luks_keyfile
[[ $LUKS ]] && add="encrypt"
[[ $LVM ]] && { [[ $add ]] && add+=" lvm2" || add+="lvm2"; }
sed -i "s/block filesystems/block ${add} filesystems ${HOOKS}/g" $MNT/etc/mkinitcpio.conf
chrun "mkinitcpio -p $KERNEL" 2>$ERR
echeck "mkinitcpio -p $KERNEL"
}
mirrorlist_sort()
{
printf "Sorting the mirrorlist\n"
if hash reflector >/dev/null 2>&1; then
$MIRROR_CMD --save $MNT/etc/pacman.d/mirrorlist --verbose ||
reflector --score 100 -l 50 -f 10 --sort rate --verbose --save $MNT/etc/pacman.d/mirrorlist
else
{ eval $MIRROR_CMD || curl -s 'https://www.archlinux.org/mirrorlist/all/'; } |
sed -e 's/^#Server/Server/' -e '/^#/d' | rankmirrors -v -t -n 10 - > $MNT/etc/pacman.d/mirrorlist
fi
}
package_operations()
{
# add the packages chosen during setup
if [[ $KERNEL == 'linux-lts' ]]; then
local inpkg="linux-lts $PACKAGES"
local rmpkg="archlabs-installer linux"
else
local inpkg="$PACKAGES"
local rmpkg="archlabs-installer"
fi
# update first to avoid database access errors
chrun "pacman -Syyu --noconfirm"
if [[ $BOOTLDR == 'grub' ]]; then
chrun "pacman -Rns $rmpkg grub --noconfirm"
else
chrun "pacman -Rns $rmpkg --noconfirm"
fi
chrun "pacman -S iputils --noconfirm"
chrun "pacman -S $inpkg archlabs-common archlabs-dARK archlabs-icons archlabs-scripts archlabs-skel-base archlabs-wallpapers gtk-engine-murrine gtk3 pavucontrol tumbler xorg-xinit base base-devel sudo git udisks2 mesa xorg-server xorg-apps xorg-drivers playerctl ffmpeg gstreamer libmad libmatroska gst-libav gst-plugins-base gst-plugins-good --needed --noconfirm"
if [[ $inpkg =~ (openbox|dwm|bspwm|i3) ]]; then
chrun "pacman -S arandr archlabs-networkmanager-dmenu xdg-user-dirs nitrogen polkit-gnome volumeicon xclip xdotool compton gnome-keyring dunst feh gsimplecal xfce4-power-manager xfce4-settings laptop-detect --needed --noconfirm"
fi
if ! [[ $INSTALL_WMS == 'plasma' || $INSTALL_WMS == 'gnome' || $INSTALL_WMS == 'cinnamon' ]]; then
chrun "pacman -S archlabs-ksuperkey --noconfirm --needed"
fi
sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" $MNT/etc/sudoers
return 0
}
suckless_install()
{
# install and setup dwm
printf "Installing and setting up dwm\n"
mkdir -pv $MNT/home/$NEWUSER/suckless
for i in dwm dmenu st; do
p="/home/$NEWUSER/suckless/$i"
chrun "git clone https://bitbucket.org/natemaia/$i $p"
e=$?
if (( e == 0 )); then
chrun "cd $p; rm -f config.h; make clean install; make clean"
else
printf "Failed to clone $i repo\n"
fi
done
if [[ -d /home/$NEWUSER/suckless/dwm ]]; then
printf "To configure dwm edit /home/$NEWUSER/suckless/dwm/config.h\n"
printf "You can then recompile it with 'sudo make clean install'\n"
sleep 2
fi
}
###############################################################################
# bootloader setup
setup_boot()
{
tput civis
if ! BOOTLDR="$(menubox "$_PrepMount" "$_MntBootBody" ${BOOTLDRS[$SYS]})"; then
return 1
fi
if [[ $BOOT_PART != "" ]]; then
mount_partition "$BOOT_PART" "${BMNTS[$SYS-$BOOTLDR]}" && SEP_BOOT=true || return 1
setup_boot_device
fi
setup_${BOOTLDR} || return 1
}
setup_grub()
{
# grub has by far the worst setup of the three however
# the configuration is shorter due to grub-mkconfig
EDIT_FILES[bootloader]="/etc/default/grub"
if [[ $SYS == 'BIOS' ]]; then
[[ $BOOT_DEVICE ]] || { select_device 'boot' || return 1; }
BCMDS[grub]="${BCMDS[grub]} --target=i386-pc $BOOT_DEVICE"
else
if [[ $ROOT_PART == */dev/mapper/* && ! $LVM && ! $LUKS_PASS ]]; then
luks_pass "$_LuksOpen" "" || return 1
fi
BCMDS[grub]="${BCMDS[grub]} --bootloader-id=$DIST"
fi
BCMDS[grub]="mkdir -p /run/udev &&
mkdir -p /run/lvm &&
mount --bind /hostrun/udev /run/udev &&
mount --bind /hostrun/lvm /run/lvm &&
${BCMDS[grub]} &&
grub-mkconfig -o /boot/grub/grub.cfg &&
umount /run/udev &&
umount /run/lvm"
return 0
}
setup_syslinux()
{
EDIT_FILES[bootloader]="/boot/syslinux/syslinux.cfg"
}
setup_systemd-boot()
{
EDIT_FILES[bootloader]="/boot/loader/entries/$DIST.conf"
}
prerun_grub()
{
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_DEV ]]; 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 == 'BIOS' && $LVM && $SEP_BOOT == false ]]; then
sed -i "s/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g" $cfg
fi
# needed for grub-probe module to work properly in the chroot
# once the grub install is done these will be umounted and removed
mkdir -p /run/lvm
mkdir -p /run/udev
mkdir -p $MNT/hostrun/lvm
mkdir -p $MNT/hostrun/udev
mount --bind /run/lvm $MNT/hostrun/lvm
mount --bind /run/udev $MNT/hostrun/udev
return 0
}
prerun_systemd-boot()
{
# no LVM then systemd-boot uses PARTUUID
[[ $ROOT_PART =~ /dev/mapper ]] || ROOT_PART_ID="PART$ROOT_PART_ID"
# create the boot entry configs
mkdir -p ${MNT}${BMNTS[$SYS-systemd-boot]}/loader/entries
cat > ${MNT}${BMNTS[$SYS-systemd-boot]}/loader/loader.conf << EOF
default $DIST
timeout 5
editor no
EOF
cat > ${MNT}${BMNTS[$SYS-systemd-boot]}/loader/entries/${DIST}.conf << EOF
title $DIST Linux
linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/${UCODE}.img")
initrd /initramfs-$KERNEL.img
options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
EOF
cat > ${MNT}${BMNTS[$SYS-systemd-boot]}/loader/entries/${DIST}-fallback.conf << EOF
title $DIST Linux Fallback
linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/${UCODE}.img")
initrd /initramfs-$KERNEL-fallback.img
options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
EOF
# add pacman hook to update the bootloader when systemd receives an update
mkdir -p $MNT/etc/pacman.d/hooks
cat > $MNT/etc/pacman.d/hooks/systemd-boot.hook << EOF
[Trigger]
Type = Package
Operation = Upgrade
Target = systemd
[Action]
Description = Updating systemd-boot
When = PostTransaction
Exec = /usr/bin/bootctl update
EOF
# systemd-boot requires this before running bootctl
systemd-machine-id-setup --root="$MNT"
return 0
}
prerun_syslinux()
{
mkdir -pv $MNT${BMNTS[$SYS-syslinux]}/syslinux
cp -rfv /usr/lib/syslinux/bios/* $MNT${BMNTS[$SYS-syslinux]}/syslinux/
cat > $cfgdir/syslinux.cfg << EOF
UI menu.c32
PROMPT 0
MENU TITLE $DIST Boot Menu
TIMEOUT 50
DEFAULT $DIST
LABEL $DIST
MENU LABEL $DIST Linux
LINUX ../vmlinuz-$KERNEL
APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
INITRD ../initramfs-$KERNEL.img$([[ $UCODE ]] && printf "\nINITRD %s" "../${UCODE}.img")
LABEL ${DIST}fallback
MENU LABEL $DIST Linux Fallback
LINUX ../vmlinuz-$KERNEL
APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
INITRD ../initramfs-$KERNEL-fallback.img$([[ $UCODE ]] && printf "\nINITRD %s" "../${UCODE}.img")
EOF
return 0
}
install_bootloader()
{
if ! [[ $ROOT_PART =~ /dev/mapper ]]; then
ROOT_PART_ID="UUID=$(blkid -s PARTUUID -o value $ROOT_PART)"
else
ROOT_PART_ID="$ROOT_PART"
fi
if [[ $SYS == 'UEFI' ]]; then
find ${MNT}${BMNTS[UEFI-$BOOTLDR]}/EFI/ -maxdepth 1 -mindepth 1 \
-name '[aA][rR][cC][hH][lL]abs' -type d -exec rm -rf '{}' \; >/dev/null 2>&1
find ${MNT}${BMNTS[UEFI-$BOOTLDR]}/EFI/ -maxdepth 1 -mindepth 1 \
-name '[Bb][oO][oO][tT]' -type d -exec rm -rf '{}' \; >/dev/null 2>&1
fi
if [[ $BOOTLDR != 'grub' ]]; then
rm -f $MNT/etc/default/grub 2>dev/null
find $MNT/boot/ -name 'grub*' -exec rm -rf '{}' \; >/dev/null 2>&1
fi
if [[ $BOOTLDR != 'syslinux' ]]; then
find $MNT/boot/ -name 'syslinux*' -exec rm -rf '{}' \; >/dev/null 2>&1
fi
prerun_$BOOTLDR
printf "Installing and setting up $BOOTLDR in ${BMNTS[$SYS-$BOOTLDR]}\n"
chrun "${BCMDS[$BOOTLDR]}" 2>$ERR
echeck "${BCMDS[$BOOTLDR]}"
if [[ -d $MNT/hostrun ]]; then
umount $MNT/hostrun/udev >/dev/null 2>&1
umount $MNT/hostrun/lvm >/dev/null 2>&1
rm -rf $MNT/hostrun >/dev/null 2>&1
fi
if [[ $BOOTLDR == 'grub' && $SYS == 'UEFI' ]]; then
local esp="${MNT}${BMNTS[$SYS-$BOOTLDR]}"
mkdir -pv $esp/EFI/BOOT
cp -fv $esp/EFI/$DIST/grubx64.efi $esp/EFI/BOOT/BOOTX64.EFI
fi
return 0
}
###############################################################################
# lvm functions
lvm_menu()
{
lvm_detect
tput civis
local choice
choice="$(dialog --cr-wrap --stdout --backtitle "$BT" \
--title " $_PrepLVM " --menu "$_LvmMenu" 0 0 6 \
"$_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
}
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" 1
modprobe dm-mod >/dev/null 2>$ERR
errshow 'modprobe dm-mod'
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
if ! DEL_VG="$(menubox "$_PrepLVM" "$_LvmSelVGBody" $VOL_GROUP_LIST)"; then
return 1
fi
return 0
}
get_lv_size()
{
tput cnorm
local ttl=" $_LvmCreateVG (LV:$VOL_COUNT) "
local msg="${VOLUME_GROUP}: ${GROUP_SIZE}$GROUP_SIZE_TYPE (${VOL_GROUP_MB}MB $_LvmLvSizeBody1).$_LvmLvSizeBody2"
if ! VOLUME_SIZE="$(getinput "$ttl" "$msg" "")"; then
return 1
fi
ERR_SIZE=0
(( ${#VOLUME_SIZE} == 0 || ${VOLUME_SIZE:0:1} == 0 )) && ERR_SIZE=1
if (( ERR_SIZE == 0 )); then
local lv="$((${#VOLUME_SIZE} - 1))"
for (( i=0; i<lv; i++ )); do
[[ ${VOLUME_SIZE:$i:1} != [0-9] ]] && { ERR_SIZE=1; break; }
done
if (( ERR_SIZE == 0 )); then
case ${VOLUME_SIZE:$lv:1} in
[mMgG]) ERR_SIZE=0 ;;
*) ERR_SIZE=1
esac
if (( ERR_SIZE == 0 )); then
local s=${VOLUME_SIZE:0:$lv}
local m=$((s * 1000))
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
if ! name="$(getinput "$_LvmCreateVG (LV:$VOL_COUNT)" "$msg" "$default" nolimit)"; then
return 1
fi
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
if ! group="$(getinput "$_LvmCreateVG" "$_LvmNameVgBody" "VolGroup" nolimit)"; then
return 1
fi
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
lvm_volume_name "$_LvmLvNameBody1" || { break; return 1; }
get_lv_size || { break; return 1; }
lvcreate -L "$VOLUME_SIZE" "$VOLUME_GROUP" -n "$VOLUME_NAME" >/dev/null 2>$ERR
errshow "lvcreate -L $VOLUME_SIZE $VOLUME_GROUP -n $VOLUME_NAME"
msgbox "$_LvmCreateVG (LV:$VOL_COUNT)" "$_Done LV $VOLUME_NAME ($VOLUME_SIZE) $_LvmPvDoneBody2."
((VOL_COUNT--))
done
return 0
}
lvm_volume_count()
{
if ! VOL_COUNT=$(dialog --cr-wrap --no-cancel --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); then
return 1
fi
return 0
}
lvm_partitions()
{
find_partitions 'part|crypt' || return 1
PARTS="$(awk 'NF > 0 {print $0 " off"}' <<< "$PARTS")"
tput civis
GROUP_PARTS=($(dialog --cr-wrap --no-cancel --stdout --backtitle "$BT" \
--title " $_LvmCreateVG " --checklist "$_LvmPvSelBody" 0 0 0 $PARTS))
(( ${#GROUP_PARTS[@]} >= 1 ))
}
lvm_create_group()
{
lvm_group_name || return 1
local msg="$_LvmPvConfBody1 $VOLUME_GROUP\n\n$_LvmPvConfBody2"
while ! yesno "$_LvmCreateVG" "$msg ${GROUP_PARTS[*]}\n"; do
lvm_partitions || { break; return 1; }
lvm_group_name || { break; return 1; }
done
vgcreate -f "$VOLUME_GROUP" "${GROUP_PARTS[@]}" >/dev/null 2>$ERR
errshow "vgcreate -f $VOLUME_GROUP ${GROUP_PARTS[*]}"
GROUP_SIZE=$(vgdisplay "$VOLUME_GROUP" | awk '/VG Size/ {
gsub(/[^0-9.]/, "")
print int($0)
}')
GROUP_SIZE_TYPE="$(vgdisplay "$VOLUME_GROUP" | awk '/VG Size/ {
print substr($NF, 0, 1)
}')"
if [[ $GROUP_SIZE_TYPE == 'G' ]]; then
VOL_GROUP_MB=$((GROUP_SIZE * 1000))
else
VOL_GROUP_MB=$GROUP_SIZE
fi
local msg="$_LvmPvDoneBody1 $VOLUME_GROUP ($GROUP_SIZE $GROUP_SIZE_TYPE)"
msgbox "$_LvmCreateVG" "$msg $_LvmPvDoneBody2\n"
return 0
}
lvm_create()
{
VOLUME_GROUP=""
GROUP_PARTS=()
VOL_GROUP_MB=0
umount_dir $MNT
lvm_partitions || return 1
lvm_create_group || return 1
lvm_volume_count || return 1
lvm_extra_lvs || return 1
lvm_volume_name "$_LvmLvNameBody1 $_LvmLvNameBody2 (${VOL_GROUP_MB}MB)" || return 1
lvcreate -l +100%FREE "$VOLUME_GROUP" -n "$VOLUME_NAME" >/dev/null 2>$ERR
errshow "lvcreate -l +100%FREE $VOLUME_GROUP -n $VOLUME_NAME"
LVM='logical volume'
tput civis
sleep 0.5
local msg="${_Done}$_LvmPvDoneBody1 $VOLUME_GROUP-$VOLUME_NAME (${VOLUME_SIZE:-${VOL_GROUP_MB}MB}) $_LvmPvDoneBody2."
msgbox "$_LvmCreateVG (LV:$VOL_COUNT)" "$msg\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE "${GROUP_PARTS[@]}")"
return 0
}
lvm_del_vg()
{
if lvm_show_vg && yesno "$_LvmDelVG" "$_LvmDelQ"; then
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=''
fi
return 0
}
###############################################################################
# luks functions
luks_menu()
{
tput civis
local choice
choice="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $_PrepLUKS " \
--menu "${_LuksMenuBody}${_LuksMenuBody2}${_LuksMenuBody3}" 0 0 6 \
"$_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_keycmd && return 0 ;;
*) return 0
esac
luks_menu
}
luks_open()
{
LUKS_PART=""
modprobe -a dm-mod dm_crypt
umount_dir $MNT
find_partitions 'part|crypt|lvm' || return 1
tput civis
if (( COUNT == 1 )); then
LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
infobox "$_LuksOpen" "${_OnlyOne}: $LUKS_PART\n" 1
elif ! LUKS_PART="$(menubox "$_LuksOpen" "$_LuksMenuBody" $PARTS)" || ! [[ $LUKS_PART ]]; then
return 1
fi
luks_pass "$_LuksOpen" "${LUKS_NAME:-cryptroot}" || return 1
infobox "$_LuksOpen" "$_LuksOpenWaitBody $LUKS_NAME $_LuksWaitBody2 $LUKS_PART\n" 0
cryptsetup open --type luks $LUKS_PART "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
errshow "cryptsetup open --type luks $LUKS_PART $LUKS_NAME"
LUKS='encrypted'
luks_show
return 0
}
luks_pass()
{
local title="$1"
local name="$2"
local pass pass2
LUKS_PASS=""
LUKS_NAME=""
tput cnorm
local values
if [[ $name == "" ]]; then
if ! values="$(dialog --stdout --no-cancel --separator '~' \
--ok-label "Submit" --backtitle "$BT" \
--title " $title " --insecure --mixedform \
"\nEnter the password to decrypt $ROOT_PART.
\nThis is needed to create a keyfile." 0 0 6 \
"$_Password" 1 1 "" 1 $((${#_Password} + 2)) $COLUMNS 0 1 \
"$_Password2" 2 1 "" 2 $((${#_Password2} + 2)) $COLUMNS 0 1)"; then
return 1
fi
pass="$(awk -F'~' '{print $1}' <<< "$values")"
pass2="$(awk -F'~' '{print $2}' <<< "$values")"
else
if ! values="$(dialog --stdout --no-cancel --separator '~' \
--ok-label "Submit" --backtitle "$BT" --title " $title " \
--insecure --mixedform "$_LuksOpenBody" 0 0 6 \
"$_Name" 1 1 "$name" 1 $((${#_Name} + 2)) $COLUMNS 0 0 \
"$_Password" 2 1 "" 2 $((${#_Password} + 2)) $COLUMNS 0 1 \
"$_Password2" 3 1 "" 3 $((${#_Password2} + 2)) $COLUMNS 0 1)"; then
return 1
fi
name="$(awk -F'~' '{print $1}' <<< "$values")"
pass="$(awk -F'~' '{print $2}' <<< "$values")"
pass2="$(awk -F'~' '{print $3}' <<< "$values")"
LUKS_NAME="$name"
fi
if [[ $pass == "" || "$pass" != "$pass2" ]]; then
msgbox "$_ErrTitle" "$_PassErr\n$_TryAgain"
luks_pass "$title" "$name" || return 1
fi
LUKS_PASS="$pass"
return 0
}
luks_setup()
{
LUKS_PART=""
modprobe -a dm-mod dm_crypt
umount_dir $MNT
find_partitions 'part|lvm' || return 1
tput civis
if (( COUNT == 1 )); then
LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
infobox "$_LuksEncrypt" "${_OnlyOne}: $LUKS_PART\n" 1
elif ! LUKS_PART="$(menubox "$_LuksEncrypt" "$_LuksEncryptBody" $PARTS)"; then
return 1
elif ! luks_pass "$_LuksEncrypt" "${LUKS_NAME:-cryptroot}"; then
return 1
fi
return 0
}
luks_default()
{
luks_setup || return 1
infobox "$_LuksEncrypt" "$_LuksCreateWaitBody $LUKS_NAME $_LuksWaitBody2 $LUKS_PART\n" 0
cryptsetup -q luksFormat $LUKS_PART <<< "$LUKS_PASS" 2>$ERR
errshow "cryptsetup -q luksFormat $LUKS_PART"
cryptsetup open $LUKS_PART "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
errshow "cryptsetup open $LUKS_PART $LUKS_NAME"
LUKS='encrypted'
luks_show
return 0
}
luks_keycmd()
{
if luks_setup; then
tput cnorm
local cipher
if ! cipher="$(getinput "$_PrepLUKS" "$_LuksCipherKey" "-s 512 -c aes-xts-plain64" nolimit)"; then
return 1
fi
infobox "$_LuksEncryptAdv" "$_LuksCreateWaitBody $LUKS_NAME $_LuksWaitBody2 $LUKS_PART\n" 0
cryptsetup -q $cipher luksFormat $LUKS_PART <<< "$LUKS_PASS" 2>$ERR
errshow "cryptsetup -q $cipher luksFormat $LUKS_PART"
cryptsetup open $LUKS_PART "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
errshow "cryptsetup open $LUKS_PART $LUKS_NAME"
luks_show
return 0
fi
return 1
}
luks_show()
{
tput civis
sleep 0.5
msgbox "$_LuksEncrypt" "${_LuksEncryptSucc}\n$(lsblk $LUKS_PART -o NAME,MODEL,TYPE,FSTYPE,SIZE)\n"
}
luks_keyfile()
{
if [[ ! -e $MNT/crypto_keyfile.bin && $LUKS_PASS && $LUKS_UUID ]]; then
local n
n="$(lsblk -lno NAME,UUID,TYPE | awk "/$LUKS_UUID/"' && /part|crypt|lvm/ {print $1}')"
local mkkey="dd bs=512 count=8 if=/dev/urandom of=/crypto_keyfile.bin"
mkkey="$mkkey && chmod 000 /crypto_keyfile.bin"
mkkey="$mkkey && cryptsetup luksAddKey /dev/$n /crypto_keyfile.bin <<< '$LUKS_PASS'"
chrun "$mkkey"
sed -i 's/FILES=()/FILES=(\/crypto_keyfile.bin)/g' $MNT/etc/mkinitcpio.conf 2>$ERR
fi
return 0
}
###############################################################################
# helper functions
chrun()
{
arch-chroot $MNT /bin/bash -c "$1"
}
json()
{
# get a value from http://api.ipstack.com in json format using my API key this includes: ip, geolocation, country name
curl -s "http://api.ipstack.com/$2" | python3 -c "import sys, json; print(json.load(sys.stdin)['$1'])"
}
src()
{
# source file ($1), if it fails we die with an error message
if ! . "$1" 2>/dev/null; then
printf "Failed to source file %s\n" "$1"
die 1
fi
return 0
}
ssd()
{
# returns 0 (true) when the device passed ($1) is NOT a rotational device
local i dev=$1
# check for LVM and or LUKS for their origin devices
if [[ $LUKS && ! $LVM && $dev =~ $LUKS_NAME ]]; then
dev="${LUKS_PART}"
elif [[ $LVM && ! $LUKS && ${#GROUP_PARTS[@]} -eq 1 && ${GROUP_PARTS[*]} =~ $dev ]]; then
dev="${GROUP_PARTS[*]}"
fi
dev=${dev#/dev/}
[[ $dev =~ nvme ]] && dev=${dev%p[0-9]*} || dev=${dev%[0-9]*}
i=$(cat /sys/block/$dev/queue/rotational 2>/dev/null)
(( ${i:-1} == 0 ))
}
die()
{
if (( $# >= 1 )); then
local exitcode=$1
else
local exitcode=0
fi
# reset SIGINT
trap - INT
tput cnorm
if [[ -d $MNT ]] && command cd /; then
umount_dir $MNT
if (( exitcode == 127 )); then
umount -l /run/archiso/bootmnt
systemctl -i reboot
fi
fi
exit $exitcode
}
sigint()
{
# used to trap SIGINT and cleanly exit the program
printf "CTRL-C caught\nCleaning up...\n"
die 1
}
print4()
{
# takes an arbitrary number of input fields and prints them out in fourths on separate lines
local str="$*"
if [[ ${#str} -gt $((COLUMNS - 5)) ]]; then
str="$(awk '{
p1=p2=p3=p4=""
p1=$1
q=int(NF / 4)
for (i=2; i<=q; i++) { p1=p1" "$i }
for (i=q; i<=q*2; i++) { p2=p2" "$i }
for (i=q*2; i<=q*3; i++) { p3=p3" "$i }
for (i=q*3; i<=NF; i++) { p4=p4" "$i }
printf "%s\n\t%s\n\t%s\n\t%s", p1, p2, p3, p4
}' <<< "$str")"
printf "%s\n" "$str"
elif [[ $str ]]; then
printf "%s\n" "$str"
fi
}
system_devices()
{
IGNORE_DEV="$(lsblk -lno NAME,MOUNTPOINT |
awk '/\/run\/archiso\/bootmnt/ {sub(/[1-9]/, ""); print $1}')"
if [[ $IGNORE_DEV ]]; then
SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE |
awk '/disk/ && !'"/$IGNORE_DEV/"' {print "/dev/" $1 " " $2}')"
else
SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE |
awk '/disk/ {print "/dev/" $1 " " $2}')"
fi
DEV_COUNT="$(wc -l <<< "$SYS_DEVS")"
}
system_identify()
{
local efidir="/sys/firmware/efi"
# for virtual machine remove the ucode
if [[ $VM ]]; then
UCODE=""
elif grep -q 'AuthenticAMD' /proc/cpuinfo; then
UCODE="amd-ucode"
elif grep -q 'GenuineIntel' /proc/cpuinfo; then
UCODE="intel-ucode"
fi
if grep -qi 'apple' /sys/class/dmi/id/sys_vendor; then
modprobe -r -q efivars
else
modprobe -q efivarfs
fi
if [[ -d $efidir ]]; then
SYS="UEFI"
grep -q $efidir/efivars <<< "$(mount)" ||
mount -t efivarfs efivarfs $efidir/efivars
else
SYS="BIOS"
fi
BT="$DIST Installer - $SYS - v$VER"
}
load_bcm()
{
infobox "Broadcom Wireless Setup" "\nLoading wifi kernel modules please wait...\n" 1
rmmod wl >/dev/null 2>&1
rmmod bcma >/dev/null 2>&1
rmmod b43 >/dev/null 2>&1
rmmod ssb >/dev/null 2>&1
modprobe wl >/dev/null 2>&1
depmod -a >/dev/null 2>&1
BROADCOM_WL=true
}
net_connect()
{
chk_connect() { curl -s --head 'https://www.archlinux.org/mirrorlist/all/' | sed '1q' | grep -qw '200'; }
if ! chk_connect; then
if [[ $(systemctl is-active NetworkManager) == "active" ]] && hash nmtui >/dev/null 2>&1; then
tput civis
printf "\e]P1191919"
printf "\e]P4191919"
nmtui-connect
printf "\e]P1D15355"
printf "\e]P4255a9b"
chk_connect || return 1
else
return 1
fi
fi
# if we've made it here we likely have a good connection
return 0
}
system_checks()
{
if [[ $(whoami) != "root" ]]; then
infobox "$_ErrTitle" "$_NotRoot\n$_Exit"
die 1
elif ! grep -qw 'lm' /proc/cpuinfo; then
infobox "$_ErrTitle" "$_Not64Bit\n$_Exit"
die 1
fi
# setup for specific broadcom chips
grep -q 'BCM4352' <<< "$(lspci -vnn -d 14e4:)" && load_bcm
# connect or confirm connection, otherwise bail
net_connect || { infobox "$_ErrTitle" "$_NoNetwork\n$_Exit" 3; die 1; }
}
prechecks()
{
if [[ $1 -ge 0 ]] && ! [[ $(lsblk -o MOUNTPOINT) =~ $MNT ]]; then
msgbox "$_ErrTitle" "$_ErrNoMount"
SELECTED=4
return 1
elif [[ $1 -ge 1 && ! $NEWUSER ]]; then
msgbox "$_ErrTitle" "\nYou need to create a user first.\n"
SELECTED=5
return 1
elif [[ $1 -ge 2 && $CONFIG_DONE != true ]]; then
msgbox "$_ErrTitle" "$_ErrNoConfig"
SELECTED=6
return 1
fi
return 0
}
errshow()
{
local last_exit_code=$?
(( last_exit_code == 0 )) && return 0
local err
err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
if [[ $err ]]; then
msgbox "$_ErrTitle" "\nERROR: $err"
else
msgbox "$_ErrTitle" "\nThe command exited abnormally: $1\n\nWith the no error message.\n"
fi
}
echeck()
{
local last_exit_code=$?
(( last_exit_code == 0 )) && return 0
local err
err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
if [[ $err ]]; then
msgbox "$_ErrTitle" "\nThe command exited abnormally: $1\n\nWith the following message: $err"
else
msgbox "$_ErrTitle" "\nThe command exited abnormally: $1\n\nWith the no error message.\n"
fi
[[ -e $DBG && $TERM == 'linux' ]] && less $DBG
die 1
}
debug()
{
set -x
exec 3>| $DBG
BASH_XTRACEFD=3
DEBUG=true
}
umount_dir()
{
swapoff -a
[[ -d $1 ]] && umount -R $1 >/dev/null 2>&1
return 0
}
msgbox()
{
tput civis
dialog --cr-wrap --backtitle "$BT" --title " $1 " --msgbox "$2\n" 0 0
}
menubox()
{
local title="$1"
local body="$2"
shift 2
local response
if ! response="$(dialog --cr-wrap --no-cancel --stdout --backtitle "$BT" --title " $title " --menu "$body" 0 0 0 "$@")"
then
return 1
fi
printf "%s" "$response"
}
checkbox()
{
local title="$1"
local body="$2"
shift 2
local response
if ! response="$(dialog --cr-wrap --no-cancel --stdout --backtitle "$BT" --title " $title " --checklist "$body" 0 0 0 "$@")"
then
return 1
fi
printf "%s" "$response"
}
getinput()
{
local answer
if [[ $# -eq 4 && $4 == 'nolimit' ]]; then
answer="$(dialog --cr-wrap --stdout --backtitle "$BT" --title " $1 " --inputbox "$2" 0 0 "$3")"
else
answer="$(dialog --cr-wrap --max-input 63 --stdout --backtitle "$BT" --title " $1 " --inputbox "$2" 0 0 "$3")"
fi
local e=$?
[[ $e -ne 0 || $answer == "" ]] && return 1
printf "%s" "$answer"
}
infobox()
{
local sec="$3"
tput civis
dialog --cr-wrap --backtitle "$BT" --title " $1 " --infobox "$2\n" 0 0
sleep ${sec:-2}
}
yesno()
{
tput civis
if [[ $# -eq 5 && $5 == "no" ]]; then
dialog --cr-wrap --backtitle "$BT" --defaultno --title " $1 " --yes-label "$3" --no-label "$4" --yesno "$2\n" 0 0
elif [[ $# -eq 4 ]]; then
dialog --cr-wrap --backtitle "$BT" --title " $1 " --yes-label "$3" --no-label "$4" --yesno "$2\n" 0 0
else
dialog --cr-wrap --backtitle "$BT" --title " $1 " --yesno "$2\n" 0 0
fi
}
select_language()
{
tput civis
local lang
lang=$(menubox "Select Language" \
"\nLanguage - sprache - taal - språk - lingua - idioma - nyelv - língua\n" \
"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)")
src $LNG/english.trans
FONT="ter-i16n"
case $lang in
1) LOC="en_US.UTF-8" ;;
2) src $LNG/spanish.trans && LOC="es_ES.UTF-8" ;;
3) src $LNG/p_brasil.trans && LOC="pt_BR.UTF-8" ;;
4) src $LNG/portuguese.trans && LOC="pt_PT.UTF-8" ;;
5) src $LNG/french.trans && LOC="fr_FR.UTF-8" ;;
6) src $LNG/russian.trans && LOC="ru_RU.UTF-8" FONT="LatKaCyrHeb-16" ;;
7) src $LNG/italian.trans && LOC="it_IT.UTF-8" ;;
8) src $LNG/dutch.trans && LOC="nl_NL.UTF-8" ;;
9) src $LNG/hungarian.trans && LOC="hu_HU.UTF-8" FONT="lat2-16" ;;
10) src $LNG/chinese.trans && LOC="zh_CN.UTF-8" ;;
*) die
esac
sed -i "s/#en_US.UTF-8/en_US.UTF-8/" /etc/locale.gen
if [[ $LOC != "en_US.UTF-8" ]]; then
sed -i "s/#${LOC}/${LOC}/" /etc/locale.gen
locale-gen >/dev/null 2>&1
fi
[[ $TERM == 'linux' ]] && setfont $FONT >/dev/null 2>&1
export LANG="$LOC"
return 0
}
###############################################################################
# entry point
# giant ugly variable container :P {
# BULK
# {
ERR="/tmp/errlog" # error log used internally
DBG="/tmp/debuglog" # debug log when passed -d
RUN="/run/archiso/bootmnt/arch/boot" # path for live /boot
LNG="/usr/share/archlabs/installer/lang" # translation file path
BT="$DIST Installer - v$VER" # backtitle used for dialogs
VM="$(dmesg | grep -i "hypervisor")" # is the system a vm
ROOT_PART="" # root partition
BOOT_PART="" # boot partition
BOOT_DEVICE="" # device used for BIOS grub install
AUTO_BOOT_PART="" # filled with the boot partition from auto_partiton()
BOOTLDR="" # bootloader selected
EXTRA_MNT="" # holder for additional partitions while mounting
EXTRA_MNTS="" # when an extra partition is mounted append it's info
SWAP_PART="" # swap partition or file path
SWAP_SIZE="" # when using a swapfile use this size
NEWUSER="" # username for the primary user
USER_PASS="" # password for the primary user
ROOT_PASS="" # root password
LOGIN_WM="" # default login session
LOGIN_TYPE="" # login manager can be lightdm or xinit
INSTALL_WMS="" # space separated list of chosen wm/de
KERNEL="" # kernel can be linux or linux-lts
WM_PACKAGES="" # full list of packages added during wm/de choice
PACKAGES="" # list of all packages to install including WM_PACKAGES
MYSHELL="" # login shell for root and the primary user
UCODE="" # cpu manufacturer microcode filename (if any)
HOOKS="shutdown" # list of additional HOOKS to add in /etc/mkinitcpio.conf
LUKS="" # empty when not using luks encryption
LUKS_DEV="" # boot parameter string for LUKS
LUKS_PART="" # partition used for encryption
LUKS_PASS="" # encryption password
LUKS_UUID="" # encrypted partition UUID
LUKS_NAME="" # name used for encryption
LVM="" # empty when not using lvm
GROUP_PARTS=() # partitions used for volume group
VOL_GROUP_MB=0 # available space in volume group
WARN=false # issued mounting/partitioning warning
CONFIG_DONE=false # basic configuration is finished
SEP_BOOT=false # separate boot partition for BIOS
AUTOLOGIN=false # enable autologin for xinit
BROADCOM_WL=false # fixes for broadcom cards eg. BCM4352
# }
# amount of RAM in the system in Mb
SYS_MEM="$(awk '/MemTotal/ {
print int($2 / 1024)"M"
}' /proc/meminfo)"
# parsed string of locales from /etc/locale.gen
LOCALES="$(awk '/\.UTF-8/ {
gsub(/# .*|#/, "")
if ($1) {
print $1 " -"
}
}' /etc/locale.gen)"
# parsed string of linux console keyboard mappings
CMAPS="$(find /usr/share/kbd/keymaps -name '*.map.gz' | awk '{
gsub(/\.map\.gz|.*\//, "")
print $1 " -"
}' | sort)"
# make sure these are defined for some dialog size calculation
[[ $LINES ]] || LINES=$(tput lines)
[[ $COLUMNS ]] || COLUMNS=$(tput cols)
# various associative arrays
# {
# command used to install each bootloader
declare -A BCMDS=(
[syslinux]="syslinux-install_update -iam"
[grub]="grub-install --recheck --force"
[systemd-boot]="bootctl --path=/boot install"
)
# boot partition mount points for each bootloader
declare -A BMNTS=(
[BIOS-grub]="/boot"
[UEFI-grub]="/boot/efi"
[BIOS-syslinux]="/boot"
[UEFI-systemd-boot]="/boot"
)
# bootloader options with respective boot partition mountpoint
declare -A BOOTLDRS=(
[BIOS]="grub ${BMNTS[BIOS-grub]} syslinux ${BMNTS[BIOS-syslinux]}"
[UEFI]="systemd-boot ${BMNTS[UEFI-systemd-boot]} grub ${BMNTS[UEFI-grub]}"
)
# match the wm name with the actual session name used for xinit
declare -A WM_SESSIONS=(
[dwm]='dwm'
[i3-gaps]='i3'
[bspwm]='bspwm'
[xfce4]='startxfce4'
[plasma]='startkde'
[gnome]='gnome-session'
[openbox]='openbox-session'
[cinnamon]='cinnamon-session'
)
# additional packages installed for each wm/de
declare -A WM_EXT=(
[gnome]=""
[plasma]="kdebase-meta"
[bspwm]="sxhkd archlabs-skel-bspwm rofi archlabs-polybar"
[xfce4]="xfce4-goodies xfce4-pulseaudio-plugin network-manager-applet volumeicon rofi archlabs-skel-xfce4 xdg-user-dirs"
[i3-gaps]="i3status perl-anyevent-i3 archlabs-skel-i3-gaps rofi archlabs-polybar"
[openbox]="obconf archlabs-skel-openbox jgmenu archlabs-polybar tint2 conky rofi"
)
# files the user can edit during the final stage of install
declare -A EDIT_FILES=(
[keyboard]="/etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard"
[console]="/etc/vconsole.conf"
[locale]="/etc/locale.conf /etc/default/locale"
[hostname]="/etc/hostname /etc/hosts"
[sudoers]="/etc/sudoers"
[mkinitcpio]="/etc/mkinitcpio.conf"
[fstab]="/etc/fstab"
[crypttab]="/etc/crypttab"
[bootloader]="/boot/loader/entries/$DIST.conf"
[pacman]="/etc/pacman.conf"
[login]="" # login files.. Populated later once login method is chosen
)
# PKG_EXT: if you add a package to $PACKAGES in any dialog
# and it uses/requires some additional packages,
# you can add them here to keep it simple: [package]="extra"
# duplicates are removed with `uniq` before install
declare -A PKG_EXT=(
[vlc]="qt4"
[mpd]="mpc"
[mupdf]="mupdf-tools"
[qt5ct]="qt5-styleplugins"
[vlc]="qt5ct qt5-styleplugins"
[zathura]="zathura-pdf-poppler"
[noto-fonts]="noto-fonts-emoji"
[cairo-dock]="cairo-dock-plug-ins"
[qbittorrent]="qt5ct qt5-styleplugins"
[qutebrowser]="qt5ct qt5-styleplugins"
[kdenlive]="kdebase-meta dvdauthor frei0r-plugins breeze breeze-gtk qt5ct qt5-styleplugins"
)
# mkfs command to format a partition as a given file system
declare -A 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"
)
# mount options for a given file system
declare -A FS_OPTS=([vfat]="" [ntfs]="" [ext2]="" [ext3]=""
[ext4]="discard - off dealloc - off nofail - off noacl - off relatime - off noatime - off nobarrier - off nodelalloc - off"
[jfs]="discard - off errors=continue - off errors=panic - off nointegrity - off"
[reiserfs]="acl - off nolog - off notail - off replayonly - off user_xattr - off"
[xfs]="discard - off filestreams - off ikeep - off largeio - off noalign - off nobarrier - off norecovery - off noquota - off wsync - off"
[nilfs2]="discard - off nobarrier - off errors=continue - off errors=panic - off order=relaxed - off order=strict - off norecovery - off"
[f2fs]="data_flush - off disable_roll_forward - off disable_ext_identify - off discard - off fastboot - off flush_merge - off inline_xattr - off inline_data - off inline_dentry - off no_heap - off noacl - off nobarrier - off noextent_cache - off noinline_data - off norecovery - off"
)
# }
# }
# trap Ctrl-C to properly exit
trap sigint INT
for arg in "$@"; do
[[ $arg =~ (--debug|-d) ]] && debug
done
# initial prep
#select_language
src $LNG/english.trans
FONT="ter-i16n"
LOC="en_US.UTF-8"
select_keymap
system_checks
system_identify
system_devices
msgbox "$_WelTitle $DIST Installer" "$_WelBody"
while true; do
main
done