3 # This program is free software, provided under the GNU GPL
4 # Written by Nathaniel Maia for use in Archlabs
5 # Some ideas and code reworked from other resources
6 # AIF, Calamares, and the Arch Wiki.. Credit where credit is due
8 # check for syntax errors
13 # bulk default values {
15 : ${DIST=ArchLabs} # distro name if not set
16 MNT=/mnt # installation root mountpoint
17 ANS=/tmp/ans # dialog answer output file
18 BOOTDIR=boot # location to mount boot partition
19 FONT=ter-i16n # font used for the linux console
20 HOOKS=shutdown # additional mkinitcpio HOOKS
21 SEL=0 # currently selected menu item
22 SYS=Unknown # bios type, to be determined: UEFI/BIOS
23 ERR=/tmp/errlog # stderr log used internally by errshow()
24 DBG=/tmp/debuglog # debug log file when passed -d
25 RUN=/run/archiso/bootmnt/arch/boot # path for live system /boot
26 VM="$(dmesg | grep -i hypervisor)" # system running in a virtual machine
27 EXMNTS="" # extra partitions that were mounted, used to verify mountpoint and show user
28 FORMATTED="" # partitions that have been formatted, allows skipping the format step
29 export DIALOGOPTS="--cr-wrap" # dialog environment variable to hold default options, see `man dialog`
31 BASE_PKGS="base xorg xorg-drivers sudo git gvfs gtk3 libmad libmatroska tumbler "
32 BASE_PKGS+="playerctl pulseaudio pulseaudio-alsa pavucontrol pamixer scrot xdg-user-dirs "
33 BASE_PKGS+="ffmpeg gstreamer gst-libav gst-plugins-base gst-plugins-good bash-completion xterm"
35 AL_BASE_PKGS="archlabs-keyring archlabs-icons archlabs-fonts archlabs-themes "
36 AL_BASE_PKGS+="archlabs-baph archlabs-wallpapers archlabs-scripts archlabs-skel-base"
38 WM_BASE_PKGS="arandr nitrogen polkit-gnome network-manager-applet "
39 WM_BASE_PKGS+="volumeicon xclip exo laptop-detect xdotool compton wmctrl feh "
40 WM_BASE_PKGS+="gnome-keyring dunst gsimplecal xfce4-power-manager xfce4-settings"
42 SYS_MEM="$(awk '/MemTotal/ {print int($2 / 1024) "M"}' /proc/meminfo)"
43 LOCALES="$(awk '/\.UTF-8/ {gsub(/# .*|#/, ""); if ($1) {print $1 " - "}}' /etc/locale.gen)"
44 CMAPS="$(find /usr/share/kbd/keymaps -name '*.map.gz' | awk '{gsub(/\.map\.gz|.*\//, ""); print $1 " - "}' | sort)"
46 [[ $LINES ]] || LINES=$(tput lines)
47 [[ $COLUMNS ]] || COLUMNS=$(tput cols)
51 # commands used to install each bootloader, however most get modified during runtime {
53 [refind-efi]='refind-install'
54 [grub]='grub-install --recheck --force' [syslinux]='syslinux-install_update -i -a -m'
55 [efistub]='efibootmgr -v -d /dev/sda -p 1 -c -l' [systemd-boot]='bootctl --path=/boot install'
58 # executable name for each wm/de used in ~/.xinitrc {
59 declare -A WM_SESSIONS=(
60 [dwm]='dwm' [i3-gaps]='i3' [bspwm]='bspwm' [awesome]='awesome' [plasma]='startkde' [xfce4]='startxfce4'
61 [gnome]='gnome-session' [fluxbox]='startfluxbox' [openbox]='openbox-session' [cinnamon]='cinnamon-session'
64 # packages installed for each wm/de, most are depends of the skel packages {
66 [dwm]='' [gnome]='' [cinnamon]='gnome-terminal' [plasma]='kdebase-meta'
67 [awesome]='archlabs-skel-awesome' [bspwm]='archlabs-skel-bspwm' [fluxbox]='archlabs-skel-fluxbox'
68 [i3-gaps]='archlabs-skel-i3-gaps' [openbox]='archlabs-skel-openbox' [xfce4]='archlabs-skel-xfce4 xfce4-goodies'
71 # files offered for editing after install is complete {
72 declare -A EDIT_FILES=(
73 [login]='' # login is populated once we know the username and shell
74 [fstab]='/etc/fstab' [sudoers]='/etc/sudoers' [crypttab]='/etc/crypttab' [pacman]='/etc/pacman.conf'
75 [console]='/etc/vconsole.conf' [mkinitcpio]='/etc/mkinitcpio.conf' [hostname]='/etc/hostname /etc/hosts'
76 [bootloader]="/boot/loader/entries/$DIST.conf" # ** based on bootloader
77 [locale]='/etc/locale.conf /etc/default/locale' [keyboard]='/etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard'
80 # mkfs command flags for filesystem formatting {
81 declare -A FS_CMD_FLAGS=(
82 [f2fs]='' [jfs]='-q' [xfs]='-f' [ntfs]='-q' [ext2]='-q' [ext3]='-q' [ext4]='-q' [vfat]='-F32' [nilfs2]='-q' [reiserfs]='-q'
85 # mount options for each filesystem {
87 [vfat]='' [ntfs]='' [ext2]='' [ext3]='' # NA
88 [jfs]='discard errors=continue errors=panic nointegrity'
89 [reiserfs]='acl nolog notail replayonly user_xattr off'
90 [ext4]='discard dealloc nofail noacl relatime noatime nobarrier nodelalloc'
91 [xfs]='discard filestreams ikeep largeio noalign nobarrier norecovery noquota wsync'
92 [nilfs2]='discard nobarrier errors=continue errors=panic order=relaxed order=strict norecovery'
93 [f2fs]='discard fastboot flush_merge data_flush inline_xattr inline_data noinline_data inline_dentry no_heap noacl nobarrier norecovery noextent_cache disable_roll_forward disable_ext_identify'
96 # packages installed for each login option {
97 declare -A LOGIN_PKGS=(
98 [xinit]='xorg-xinit' [ly]='archlabs-ly' [gdm]='gdm' [sddm]='sddm'
99 [lightdm]='lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings accountsservice'
102 # extras installed for user selected packages {
103 # if a package requires additional packages that aren't already dependencies
104 # they can be added here eg. [package]="extra"
106 [vlc]='qt4' [mpd]='mpc' [mupdf]='mupdf-tools'
107 [rxvt-unicode]='urxvt-pearls' [zathura]='zathura-pdf-poppler' [noto-fonts]='noto-fonts-emoji' [cairo-dock]='cairo-dock-plug-ins' [qt5ct]='qt5-styleplugins'
108 [vlc]='qt5ct qt5-styleplugins' [qutebrowser]='qt5ct qt5-styleplugins' [qbittorrent]='qt5ct qt5-styleplugins' [transmission-qt]='qt5ct qt5-styleplugins'
109 [bluez]='bluez-libs bluez-utils bluez-tools bluez-plugins bluez-hid2hci' [kdenlive]='kdebase-meta dvdauthor frei0r-plugins breeze breeze-gtk qt5ct qt5-styleplugins'
112 # dialog text variables {
113 # Basics (somewhat in order)
114 _welcome="\nThis will help you get $DIST installed and setup on your system.\n\nIf you are unsure about a section the default option will be listed or\nthe first selected item will be the default.\n\n\nMenu Navigation:\n\n - Select items with the arrow keys or the option number.\n - Use [Space] to toggle check boxes and [Enter] to accept.\n - Switch between fields using [Tab] or the arrow keys.\n - Use [Page Up] and [Page Down] to jump whole pages\n - Press the highlighted key of an option to select it.\n"
115 _keymap="\nPick which keymap to use for the system from the list below\n\nThis is used once a graphical environment is running (Xorg).\n\nSystem default: us"
116 _vconsole="\nSelect the console keymap, the console is the tty shell you reach before starting a graphical environment (Xorg).\n\nIts keymap is seperate from the one used by the graphical environments, though many do use the same such as 'us' English.\n\nSystem default: us"
117 _device="\nSelect a device to use from the list below.\n\nDevices (/dev) are the available drives on the system. /sda, /sdb, /sdc ..."
118 _resize="\nSelect a new filesystem size in MB, a new partition will be created from the free space but will be left unformatted.\nThe lowest size is just enough to fit the currently in use space on the partition while the default is set to split the free space evenly.\n\nUse Tab or the arrow keys move the cursor between the buttons and the value, when the cursor is on the value, you can edit it by:\n\n - left/right cursor movement to select a digit to modify\n - +/- characters to increment/decrement the digit by one\n - 0 through 9 to set the digit to the given value\n\nSome keys are also recognized in all cursor positions:\n\n - Home/End set the value to its maximum or minimum\n - Pageup/Pagedown increment the value so that the slider moves by one column."
119 _mount="\nUse [Space] to toggle mount options from below, press [Enter] when done to confirm selection.\n\nNot selecting any and confirming will run an automatic mount."
120 _warn="\nIMPORTANT:\n\nChoose carefully when editing, formatting, and mounting partitions or your DATA MAY BE LOST.\n\nTo mount a partition without formatting it, select 'skip' when prompted to choose a filesystem during the mounting stage.\nThis can only be used for partitions that already contain a filesystem and cannot be the root (/) partition, it needs to be formatted before install.\n"
121 _part="\nFull device auto partitioning is available for beginners otherwise cfdisk is recommended.\n\n - All systems will require a root partition (8G or greater).\n - UEFI or BIOS using LUKS without LVM require a separate boot partition (100-512M)."
122 _uefi="\nSelect the EFI boot partition (/boot), required for UEFI boot.\n\nIt's usually the first partition on the device, 100-512M, and will be formatted as vfat/fat32 if not already."
123 _bios="\nDo you want to use a separate boot partition? (optional)\n\nIt's usually the first partition on the device, 100-512M, and will be formatted as ext3/4 if not already."
124 _biosluks="\nSelect the boot partition (/boot), required for LUKS.\n\nIt's usually the first partition on the device, 100-512M, and will be formatted as ext3/4 if not already."
125 _format="is already formatted correctly.\n\nFor a clean install, previously existing partitions should be reformatted, however this removes ALL data (bootloaders) on the partition so choose carefully.\n\nDo you want to reformat the partition?\n"
126 _swapsize="\nEnter the size of the swapfile in megabytes (M) or gigabytes (G).\n\neg. 100M will create a 100 megabyte swapfile, while 10G will create a 10 gigabyte swapfile.\n\nFor ease of use and as an example it is filled in to match the size of your system memory (RAM).\n\nMust be greater than 1, contain only whole numbers, and end with either M or G."
127 _expart="\nYou can now choose any additional partitions you want mounted, you'll be asked for a mountpoint after.\n\nSelect 'done' to finish the mounting step and begin unpacking the base system in the background."
128 _exmnt="\nWhere do you want the partition mounted?\n\nEnsure the name begins with a slash (/).\nExamples include: /usr, /home, /var, etc."
129 _user="\nEnter a name and password for the new user account.\n\nThe name must not use capital letters, contain any periods (.), end with a hyphen (-), or include any colons (:)\n\nNOTE: Use [Up], [Down], or [Tab] to switch between fields, and [Enter] to accept."
130 _hostname="\nEnter a hostname for the new system.\n\nA hostname is used to identify systems on the network.\n\nIt's restricted to alphanumeric characters (a-z, A-Z, 0-9).\nIt can contain hyphens (-) BUT NOT at the beggining or end."
131 _locale="\nLocale determines the system language and currency formats.\n\nThe format for locale names is languagecode_COUNTRYCODE\n\neg. en_US is: english United States\n en_GB is: english Great Britain"
132 _timez="\nThe time zone is used to set the system clock.\n\nSelect your country or continent from the list below"
133 _timesubz="\nSelect the nearest city to you or one with the same time zone.\n\nTIP: Pressing the first letter of the city name repeatedly will navigate between entries beggining with that letter."
134 _sessions="\nUse [Space] to toggle available sessions, use [Enter] to accept the selection and continue.\n\nA basic package set will be installed for compatibility and functionality."
135 _login="\nSelect which of your session choices to use for the initial login.\n\nYou can be change this later by editing your ~/.xinitrc"
136 _autologin="\nDo you want autologin enabled for USER?\n\nIf so the following two files will be created (disable autologin by removing them):\n\n - /home/USER/RC (run startx when logging in on tty1)\n - /etc/systemd/system/getty@tty1.service.d/autologin.conf (login USER without password)\n"
137 _packages="\nUse [Space] to move a package into the selected area and press [Enter] to accept the selection.\n\nPackages may be installed by your DE/WM (if any), or for the packages you select."
138 _edit="\nBefore exiting you can select configuration files to review/change.\n\nIf you need to make other changes with the drives still mounted, use Ctrl-z to pause the installer, when finished type 'fg' and [Enter] to resume the installer, if you want to avoid the automatic reboot using Ctrl-c will cleanly exit."
141 _luksnew="Basic LUKS Encryption"
142 _luksadv="Advanced LUKS Encryption"
143 _luksopen="Open Existing LUKS Partition"
144 _luksmenu="\nA seperate boot partition without encryption or logical volume management (LVM) is required (except BIOS systems using grub).\n\nBasic uses the default encryption settings, and is recommended for beginners. Advanced allows cypher and key size parameters to be entered manually."
145 _luksomenu="\nEnter a name and password for the encrypted device.\n\nIt is not necessary to prefix the name with /dev/mapper/,an example has been provided."
146 _lukskey="Once the specified flags have been amended, they will automatically be used with the 'cryptsetup -q luksFormat /dev/...' command.\n\nNOTE: Do not specify any additional flags such as -v (--verbose) or -y (--verify-passphrase)."
149 _lvmmenu="\nLogical volume management (LVM) allows 'virtual' hard drives (volume groups) and partitions (logical volumes) to be created from existing device partitions.\n\nA volume group must be created first, then one or more logical volumes within it.\n\nLVM can also be used with an encrypted partition to create multiple logical volumes (e.g. root and home) within it."
150 _lvmnew="Create Volume Group and Volume(s)"
151 _lvmdel="Delete an Existing Volume Group"
152 _lvmdelall="Delete ALL Volume Group(s) and Volume(s)"
153 _lvmvgname="\nEnter a name for the volume group (VG) being created from the partition(s) selected."
154 _lvmlvname="\nEnter a name for the logical volume (LV) being created.\n\nThis is similar to setting a label for a partition."
155 _lvmlvsize="\nEnter what size you want the logical volume (LV) to be in megabytes (M) or gigabytes (G).\n\neg. 100M will create a 100 megabyte volume, 10G will create a 10 gigabyte volume."
156 _lvmdelask="\nConfirm deletion of volume group(s) and logical volume(s).\n\nDeleting a volume group, will delete all logical volumes within it.\n"
159 _errexpart="\nCannot mount partition due to a problem with the mountpoint.\n\nEnsure it begins with a slash (/) followed by atleast one character.\n"
160 _errpart="\nYou need create the partiton(s) first.\n\n\nBIOS systems require at least one partition (ROOT).\n\nUEFI systems require at least two (ROOT and EFI).\n"
161 _lukserr="\nA minimum of two partitions are required for encryption:\n\n 1. root (/) - standard or LVM.\n 2. boot (/boot) - standard (unless using LVM on BIOS systems).\n"
162 _lvmerr="\nThere are no viable partitions available to use for LVM, a minimum of one is required.\n\nIf LVM is already in use, deactivating it will allow the partition(s) to be used again.\n"
163 _lvmerrvgname="\nInvalid name entered.\n\nThe volume group name may be alpha-numeric, but may not contain spaces, start with a '/', or already be in use.\n"
164 _lvmerlvname="\nInvalid name entered.\n\nThe logical volume (LV) name may be alpha-numeric, but may not contain spaces or be preceded with a '/'\n"
165 _lvmerrlvsize="\nInvalid value Entered.\n\nMust be a numeric value with 'M' (megabytes) or 'G' (gigabytes) at the end.\n\neg. 400M, 10G, 250G, etc...\n\nThe value may also not be equal to or greater than the remaining size of the volume group.\n"
169 ###############################################################################
171 # main is the entry point which calls functions including outside of its block
172 # once those functions finished they always are returned here with the
173 # exception of install_main(), it exits upon completion
177 (( SEL < 12 )) && (( SEL++ ))
179 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Prepare " --default-item $SEL --cancel-label 'Exit' --menu "$_prep" 0 0 0 \
180 1 "Show device tree" \
181 2 "Partitioning helpers" \
182 3 "LUKS encryption setup" \
183 4 "Logical volume management setup" \
184 5 "* Mount system partitions" \
185 6 "* Select system bootloader" \
186 7 "* Create user and password" \
187 8 "* Basic system configuration" \
188 9 "Select window manager or desktop" \
189 10 "Select additional packages" \
190 11 "View configuration selections" \
191 12 "* Confirm choices and start the installation" 2> "$ANS"
194 [[ -z $WARN && $SEL =~ (2|5) ]] && { msg "Data Warning" "$_warn"; WARN=true; }
197 2) part_menu || (( SEL-- )) ;;
198 3) luks_menu || (( SEL-- )) ;;
199 4) lvm_menu || (( SEL-- )) ;;
200 5) mount_menu || (( SEL-- )) ;;
201 6) prechecks 0 && { select_boot || (( SEL-- )); } ;;
202 7) prechecks 1 && { select_mkuser || (( SEL-- )); } ;;
203 8) prechecks 2 && { select_config || (( SEL-- )); } ;;
204 9) prechecks 3 && { select_sessions || (( SEL-- )); } ;;
205 10) prechecks 3 && { select_packages || (( SEL-- )); } ;;
206 11) prechecks 3 && select_show ;;
207 12) prechecks 3 && install_main ;;
208 *) yesno "Exit" "\nUnmount partitions (if any) and exit the installer?\n" && die 0
214 if [[ $SYS == 'BIOS' ]]; then
215 dlg BOOTLDR menu "BIOS Bootloader" "\nSelect which bootloader to use." \
216 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
217 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network" || return 1
219 dlg BOOTLDR menu "UEFI Bootloader" "\nSelect which bootloader to use." \
220 "systemd-boot" "A simple UEFI boot manager which executes configured EFI images" \
221 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
222 "refind-efi" "A UEFI boot manager that aims to be platform neutral and simplify multi-boot" \
223 "efistub" "Boot the kernel image directly (no chainloading support)" \
224 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network (no chainloading support)" || return 1
231 local pkgs="${USER_PKGS// / } ${PACKAGES// / }"
232 [[ $INSTALL_WMS == *dwm* ]] && pkgs="dwm st dmenu $pkgs"
233 pkgs="${pkgs// / }" pkgs="${pkgs# }"
234 msg "Show Configuration" "
235 ---------- PARTITION CONFIGURATION ------------
237 Root Part: $ROOT_PART
238 Boot Part: ${BOOT_PART:-none}
239 Boot Device: ${BOOT_DEV:-none}
240 Swap Part/File: ${SWAP_PART:-none}
241 Swap Size: ${SWAP_SIZE:-none}
242 Extra Mounts: ${EXMNTS:-none}
243 Mkinit Hooks: ${HOOKS:-none}
245 LVM used: ${LVM:-none}
246 LUKS used: ${LUKS:-none}
248 ------------ SYSTEM CONFIGURATION -------------
250 Locale: ${MYLOCALE:-none}
251 Keymap: ${KEYMAP:-none}
252 Hostname: ${MYHOST:-none}
253 Timezone: ${ZONE:-none}/${SUBZ:-none}
255 ------------ USER CONFIGURATION ---------------
257 Username: ${NEWUSER:-none}
258 Login Shell: ${MYSHELL:-none}
259 Login Session: ${LOGIN_WM:-none}
260 Autologin: ${AUTOLOGIN:-none}
261 Login Type: ${LOGIN_TYPE:-none}
263 ----------- PACKAGE CONFIGURATION -------------
265 Kernel: ${KERNEL:-none}
266 Bootloader: ${BOOTLDR:-none}
267 Packages: ${pkgs:-none}
273 [[ $INSTALL_WMS ]] || return 0
275 AUTOLOGIN='' # no autologin unless using xinit
277 dlg LOGIN_TYPE menu "Login Management" "\nSelect what kind of login management to use." \
278 "xinit" "Console login without a display manager" \
279 "ly" "TUI display manager with a ncurses-like interface" \
280 "lightdm" "Lightweight display manager with a gtk greeter" \
281 "gdm" "Gnome display manager" \
282 "sddm" "Simple desktop display manager" || return 1
285 ly) EDIT_FILES[login]="/etc/ly/config.ini" ;;
286 gdm|sddm) EDIT_FILES[login]="" ;;
287 lightdm) EDIT_FILES[login]="/etc/lightdm/lightdm.conf /etc/lightdm/lightdm-gtk-greeter.conf" ;;
288 xinit) EDIT_FILES[login]="/home/$NEWUSER/.xinitrc /home/$NEWUSER/.xprofile"
289 if (( $(wc -w <<< "$INSTALL_WMS") > 1 )); then
290 dlg LOGIN_WM menu "Login Management" "$_login" $LOGIN_CHOICES || return 1
291 LOGIN_WM="${WM_SESSIONS[$LOGIN_WM]}"
293 [[ -z $LOGIN_WM ]] && LOGIN_WM="${WM_SESSIONS[${INSTALL_WMS%% *}]}"
294 yesno "Autologin" "$(sed "s|USER|$NEWUSER|g; s|RC|$LOGINRC|g" <<< "$_autologin")" && AUTOLOGIN=true || AUTOLOGIN=''
304 until [[ $CONFIG_DONE ]]; do
306 0) dlg MYSHELL menu "Shell" "\nChoose which shell to use." \
307 zsh 'A very advanced and programmable command interpreter (shell) for UNIX' \
308 bash 'The GNU Bourne Again shell, standard in many GNU/Linux distributions' \
309 mksh 'The MirBSD Korn Shell - an enhanced version of the public domain ksh' || return 1
311 1) dlg MYHOST input "Hostname" "$_hostname" "${DIST,,}" limit || { i=0; continue; } ;;
312 2) dlg MYLOCALE menu "Locale" "$_locale" $LOCALES || { i=1; continue; } ;;
314 until [[ $ZONE && $SUBZ ]]; do
315 dlg ZONE menu "Timezone" "$_timez" America - Australia - Asia - Atlantic - Africa - Europe - Indian - Pacific - Arctic - Antarctica - || break
316 dlg SUBZ menu "Timezone" "$_timesubz" $(awk '/'"$ZONE"'\// {gsub(/'"$ZONE"'\//, ""); print $3 " - "}' /usr/share/zoneinfo/zone.tab | sort) || continue
318 [[ $ZONE && $SUBZ ]] || { i=2; continue; } ;;
319 4) dlg KERNEL menu "Kernel" "\nChoose which kernel to use." \
320 linux 'Vanilla linux kernel and modules, with a few patches applied' \
321 linux-lts 'Long-term support (LTS) linux kernel and modules' \
322 linux-zen 'A effort of kernel hackers to provide the best kernel for everyday systems' \
323 linux-hardened 'A security-focused linux kernel with hardening patches to mitigate exploits' || { i=3; continue; }
327 (( i++ )) # progress through to the next choice
331 bash) LOGINRC='.bash_profile' ;;
332 zsh) LOGINRC='.zprofile' ;;
333 mksh) LOGINRC='.profile' ;;
344 until [[ $NEWUSER ]]; do
346 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " User " --mixedform "$_user" 0 0 0 \
347 "Username:" 1 1 "${ans[0]}" 1 11 "$COLUMNS" 0 0 \
348 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
349 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 \
350 "--- Root password, if left empty the user password will be used ---" 6 1 '' 6 68 "$COLUMNS" 0 2 \
351 "Password:" 8 1 '' 8 11 "$COLUMNS" 0 1 \
352 "Password2:" 9 1 '' 9 12 "$COLUMNS" 0 1 2> "$ANS" || return 1
354 mapfile -t ans <"$ANS"
356 # root passwords empty, so use the user passwords
357 if [[ -z "${ans[4]}" && -z "${ans[5]}" ]]; then
362 # make sure a username was entered and that the passwords match
363 if [[ -z ${ans[0]} || ${ans[0]} =~ \ |\' || ${ans[0]} =~ [^a-z0-9] ]]; then
364 msg "Invalid Username" "\nInvalid user name.\n\nPlease try again.\n"; u=''
365 elif [[ -z "${ans[1]}" || "${ans[1]}" != "${ans[2]}" ]]; then
366 msg "Password Mismatch" "\nThe user passwords do not match.\n\nPlease try again.\n"
367 elif [[ "${ans[4]}" != "${ans[5]}" ]]; then
368 msg "Password Mismatch" "\nThe root passwords do not match.\n\nPlease try again.\n"
371 USER_PASS="${ans[1]}"
372 ROOT_PASS="${ans[4]}"
380 dlg KEYMAP menu "Keyboard Layout" "$_keymap" \
381 us English cm English gb English au English gh English \
382 za English ng English ca French 'cd' French gn French \
383 tg French fr French de German at German ch German \
384 es Spanish latam Spanish br Portuguese pt Portuguese ma Arabic \
385 sy Arabic ara Arabic ua Ukrainian cz Czech ru Russian \
386 sk Slovak nl Dutch it Italian hu Hungarian cn Chinese \
387 tw Taiwanese vn Vietnamese kr Korean jp Japanese th Thai \
388 la Lao pl Polish se Swedish is Icelandic 'fi' Finnish \
389 dk Danish be Belgian in Indian al Albanian am Armenian \
390 bd Bangla ba Bosnian 'bg' Bulgarian dz Berber mm Burmese \
391 hr Croatian gr Greek il Hebrew ir Persian iq Iraqi \
392 af Afghani fo Faroese ge Georgian ee Estonian kg Kyrgyz \
393 kz Kazakh lt Lithuanian mt Maltese mn Mongolian ro Romanian \
394 no Norwegian rs Serbian si Slovenian tj Tajik lk Sinhala \
395 tr Turkish uz Uzbek ie Irish pk Urdu 'mv' Dhivehi \
396 np Nepali et Amharic sn Wolof ml Bambara tz Swahili \
397 ke Swahili bw Tswana ph Filipino my Malay tm Turkmen \
398 id Indonesian bt Dzongkha lv Latvian md Moldavian mao Maori \
399 by Belarusian az Azerbaijani mk Macedonian kh Khmer epo Esperanto \
400 me Montenegrin || return 1
402 if [[ $CMAPS == *"$KEYMAP"* ]]; then
405 dlg CMAP menu "Console Keymap" "$_vconsole" $CMAPS || return 1
408 if [[ $TERM == 'linux' ]]; then
409 loadkeys "$CMAP" > /dev/null 2>&1
411 setxkbmap "$KEYMAP" > /dev/null 2>&1
420 dlg INSTALL_WMS check "Sessions" "$_sessions\n" \
421 openbox "A lightweight, powerful, and highly configurable stacking wm" "$(ofn openbox "${INSTALL_WMS[*]}")" \
422 i3-gaps "A fork of i3wm with more features including gaps" "$(ofn i3-gaps "${INSTALL_WMS[*]}")" \
423 dwm "A dynamic WM for X that manages windows in tiled, floating, or monocle layouts" "$(ofn dwm "${INSTALL_WMS[*]}")" \
424 bspwm "A tiling wm that represents windows as the leaves of a binary tree" "$(ofn bspwm "${INSTALL_WMS[*]}")" \
425 xfce4 "A lightweight and modular desktop environment based on gtk+2/3" "$(ofn xfce4 "${INSTALL_WMS[*]}")" \
426 awesome "A customized Awesome WM session created by @elanapan" "$(ofn awesome "${INSTALL_WMS[*]}")" \
427 fluxbox "A lightweight and highly-configurable window manager" "$(ofn fluxbox "${INSTALL_WMS[*]}")" \
428 plasma "A kde software project currently comprising a full desktop environment" "$(ofn plasma "${INSTALL_WMS[*]}")" \
429 gnome "A desktop environment that aims to be simple and easy to use" "$(ofn gnome "${INSTALL_WMS[*]}")" \
430 cinnamon "A desktop environment combining traditional desktop with modern effects" "$(ofn cinnamon "${INSTALL_WMS[*]}")"
432 [[ $INSTALL_WMS ]] || return 0
434 WM_PKGS="${INSTALL_WMS/dwm/}" # remove dwm from package list
435 WM_PKGS="${WM_PKGS// / }" # remove double spaces
436 WM_PKGS="${WM_PKGS# }" # remove leading space
438 for i in $INSTALL_WMS; do
439 LOGIN_CHOICES+="$i - "
440 [[ ${WM_EXT[$i]} && $WM_PKGS != *"${WM_EXT[$i]}"* ]] && WM_PKGS+=" ${WM_EXT[$i]}"
443 select_login || return 1
445 while IFS=' ' read -r pkg; do
446 [[ $PACKAGES != *"$pkg"* ]] && PACKAGES+=" $pkg"
454 dlg USER_PKGS check " Packages " "$_packages" \
455 abiword "A Fully-featured word processor" "$(ofn abiword "${USER_PKGS[*]}")" \
456 alacritty "A cross-platform, GPU-accelerated terminal emulator" "$(ofn alacritty "${USER_PKGS[*]}")" \
457 atom "An open-source text editor developed by GitHub" "$(ofn atom "${USER_PKGS[*]}")" \
458 audacious "A free and advanced audio player based on GTK+" "$(ofn audacious "${USER_PKGS[*]}")" \
459 audacity "A program that lets you manipulate digital audio waveforms" "$(ofn audacity "${USER_PKGS[*]}")" \
460 blueman "GUI bluetooth device manager" "$(ofn blueman "${USER_PKGS[*]}")" \
461 bluez "Simple CLI based bluetooth support" "$(ofn bluez "${USER_PKGS[*]}")" \
462 cairo-dock "Light eye-candy fully themable animated dock" "$(ofn cairo-dock "${USER_PKGS[*]}")" \
463 calligra "A set of applications for productivity" "$(ofn calligra "${USER_PKGS[*]}")" \
464 chromium "An open-source web browser based on the Blink rendering engine" "$(ofn chromium "${USER_PKGS[*]}")" \
465 clementine "A modern music player and library organizer" "$(ofn clementine "${USER_PKGS[*]}")" \
466 cmus "A small, fast and powerful console music player" "$(ofn cmus "${USER_PKGS[*]}")" \
467 deadbeef "A GTK+ audio player for GNU/Linux" "$(ofn deadbeef "${USER_PKGS[*]}")" \
468 deluge "A BitTorrent client written in python" "$(ofn deluge "${USER_PKGS[*]}")" \
469 emacs "An extensible, customizable, self-documenting real-time display editor" "$(ofn emacs "${USER_PKGS[*]}")" \
470 epiphany "A GNOME web browser based on the WebKit rendering engine" "$(ofn epiphany "${USER_PKGS[*]}")" \
471 evince "A document viewer" "$(ofn evince "${USER_PKGS[*]}")" \
472 evolution "Manage your email, contacts and schedule" "$(ofn evolution "${USER_PKGS[*]}")" \
473 file-roller "Create and modify archives" "$(ofn file-roller "${USER_PKGS[*]}")" \
474 firefox "A popular open-source web browser from Mozilla" "$(ofn firefox "${USER_PKGS[*]}")" \
475 gcolor2 "A simple GTK+2 color selector" "$(ofn gcolor2 "${USER_PKGS[*]}")" \
476 geany "A fast and lightweight IDE" "$(ofn geany "${USER_PKGS[*]}")" \
477 geary "A lightweight email client for the GNOME desktop" "$(ofn geary "${USER_PKGS[*]}")" \
478 gimp "GNU Image Manipulation Program" "$(ofn gimp "${USER_PKGS[*]}")" \
479 gnome-calculator "GNOME Scientific calculator" "$(ofn gnome-calculator "${USER_PKGS[*]}")" \
480 gnome-disk-utility "Disk Management Utility" "$(ofn gnome-disk-utility "${USER_PKGS[*]}")" \
481 gnome-system-monitor "View current processes and monitor system state" "$(ofn gnome-system-monitor "${USER_PKGS[*]}")" \
482 gparted "A GUI frontend for creating and manipulating partition tables" "$(ofn gparted "${USER_PKGS[*]}")" \
483 gpick "Advanced color picker using GTK+ toolkit" "$(ofn gpick "${USER_PKGS[*]}")" \
484 gpicview "Lightweight image viewer" "$(ofn gpicview "${USER_PKGS[*]}")" \
485 guvcview "Capture video from camera devices" "$(ofn guvcview "${USER_PKGS[*]}")" \
486 hexchat "A popular and easy to use graphical IRC client" "$(ofn hexchat "${USER_PKGS[*]}")" \
487 inkscape "Professional vector graphics editor" "$(ofn inkscape "${USER_PKGS[*]}")" \
488 irssi "Modular text mode IRC client" "$(ofn irssi "${USER_PKGS[*]}")" \
489 kdenlive "A popular non-linear video editor for Linux" "$(ofn kdenlive "${USER_PKGS[*]}")" \
490 krita "Edit and paint images" "$(ofn krita "${USER_PKGS[*]}")" \
491 libreoffice-fresh "Full featured office suite" "$(ofn libreoffice-fresh "${USER_PKGS[*]}")" \
492 lollypop "A new music playing application" "$(ofn lollypop "${USER_PKGS[*]}")" \
493 mousepad "A simple text editor" "$(ofn mousepad "${USER_PKGS[*]}")" \
494 mpd "A flexible, powerful, server-side application for playing music" "$(ofn mpd "${USER_PKGS[*]}")" \
495 mpv "A media player based on mplayer" "$(ofn mpv "${USER_PKGS[*]}")" \
496 mupdf "Lightweight PDF and XPS viewer" "$(ofn mupdf "${USER_PKGS[*]}")" \
497 mutt "Small but very powerful text-based mail client" "$(ofn mutt "${USER_PKGS[*]}")" \
498 nautilus "The default file manager for Gnome" "$(ofn nautilus "${USER_PKGS[*]}")" \
499 ncmpcpp "A mpd client and almost exact clone of ncmpc with some new features" "$(ofn ncmpcpp "${USER_PKGS[*]}")" \
500 neovim "A fork of Vim aiming to improve user experience, plugins, and GUIs." "$(ofn neovim "${USER_PKGS[*]}")" \
501 noto-fonts "Google Noto fonts" "$(ofn noto-fonts "${USER_PKGS[*]}")" \
502 noto-fonts-cjk "Google Noto CJK fonts (Chinese, Japanese, Korean)" "$(ofn noto-fonts-cjk "${USER_PKGS[*]}")" \
503 obs-studio "Free opensource streaming/recording software" "$(ofn obs-studio "${USER_PKGS[*]}")" \
504 openshot "An open-source, non-linear video editor for Linux" "$(ofn openshot "${USER_PKGS[*]}")" \
505 opera "A Fast and secure, free of charge web browser from Opera Software" "$(ofn opera "${USER_PKGS[*]}")" \
506 pcmanfm "A fast and lightweight file manager based in Lxde" "$(ofn pcmanfm "${USER_PKGS[*]}")" \
507 pidgin "Multi-protocol instant messaging client" "$(ofn pidgin "${USER_PKGS[*]}")" \
508 plank "An elegant, simple, and clean dock" "$(ofn plank "${USER_PKGS[*]}")" \
509 qbittorrent "An advanced BitTorrent client" "$(ofn qbittorrent "${USER_PKGS[*]}")" \
510 qpdfview "A tabbed PDF viewer" "$(ofn qpdfview "${USER_PKGS[*]}")" \
511 qt5ct "GUI for managing Qt based application themes, icons, and fonts" "$(ofn qt5ct "${USER_PKGS[*]}")" \
512 qutebrowser "A keyboard-focused vim-like web browser based on Python and PyQt5" "$(ofn qutebrowser "${USER_PKGS[*]}")" \
513 rhythmbox "A Music playback and management application" "$(ofn rhythmbox "${USER_PKGS[*]}")" \
514 rxvt-unicode "A unicode enabled rxvt-clone terminal emulator" "$(ofn rxvt-unicode "${USER_PKGS[*]}")" \
515 sakura "A terminal emulator based on GTK and VTE" "$(ofn sakura "${USER_PKGS[*]}")" \
516 simple-scan "Simple scanning utility" "$(ofn simple-scan "${USER_PKGS[*]}")" \
517 simplescreenrecorder "A feature-rich screen recorder" "$(ofn simplescreenrecorder "${USER_PKGS[*]}")" \
518 steam "A popular game distribution platform by Valve" "$(ofn steam "${USER_PKGS[*]}")" \
519 surf "A simple web browser based on WebKit2/GTK+" "$(ofn surf "${USER_PKGS[*]}")" \
520 terminator "Terminal emulator that supports tabs and grids" "$(ofn terminator "${USER_PKGS[*]}")" \
521 termite "A minimal VTE-based terminal emulator" "$(ofn termite "${USER_PKGS[*]}")" \
522 thunar "A modern file manager for the Xfce Desktop Environment" "$(ofn thunar "${USER_PKGS[*]}")" \
523 thunderbird "Standalone mail and news reader from mozilla" "$(ofn thunderbird "${USER_PKGS[*]}")" \
524 tilda "A GTK based drop down terminal for Linux and Unix" "$(ofn tilda "${USER_PKGS[*]}")" \
525 tilix "A tiling terminal emulator for Linux using GTK+ 3" "$(ofn tilix "${USER_PKGS[*]}")" \
526 transmission-cli "Free BitTorrent client CLI" "$(ofn transmission-cli "${USER_PKGS[*]}")" \
527 transmission-gtk "GTK+ Front end for transmission" "$(ofn transmission-gtk "${USER_PKGS[*]}")" \
528 transmission-qt "Qt Front end for transmission" "$(ofn transmission-qt "${USER_PKGS[*]}")" \
529 ttf-anonymous-pro "A family fixed-width fonts designed with code in mind" "$(ofn ttf-anonymous-pro "${USER_PKGS[*]}")" \
530 ttf-fira-code "Monospaced font with programming ligatures" "$(ofn ttf-fira-code "${USER_PKGS[*]}")" \
531 ttf-font-awesome "Iconic font designed for Bootstrap" "$(ofn ttf-font-awesome "${USER_PKGS[*]}")" \
532 ttf-hack "A hand groomed typeface based on Bitstream Vera Mono" "$(ofn ttf-hack "${USER_PKGS[*]}")" \
533 vlc "A free and open source cross-platform multimedia player" "$(ofn vlc "${USER_PKGS[*]}")" \
534 weechat "Fast, light and extensible IRC client" "$(ofn weechat "${USER_PKGS[*]}")" \
535 xapps "Common library for X-Apps project" "$(ofn xapps "${USER_PKGS[*]}")" \
536 xarchiver "A GTK+ frontend to various command line archivers" "$(ofn xarchiver "${USER_PKGS[*]}")" \
537 xed "A small and lightweight text editor. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
538 xfce4-terminal "A terminal emulator based in the Xfce Desktop Environment" "$(ofn xfce4-terminal "${USER_PKGS[*]}")" \
539 xreader "Document viewer for files like PDF and Postscript. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
540 zathura "Minimalistic document viewer" "$(ofn zathura "${USER_PKGS[*]}")"
542 if [[ $USER_PKGS ]]; then # add any needed PKG_EXT to the list
543 for i in $USER_PKGS; do
544 [[ ${PKG_EXT[$i]} && $USER_PKGS != *"${PKG_EXT[$i]}"* ]] && USER_PKGS+=" ${PKG_EXT[$i]}"
551 ###############################################################################
553 # non-essential partitioning helpers called by the user when using the optional
554 # partition menu and selecting a device to edit
558 no_bg_install || return 0
559 local device choice devhash
560 devhash="$(lsblk -f | base64)"
562 part_device || return 1
567 dlg choice menu "Edit Partitions" "$_part\n\n$(lsblk -no NAME,MODEL,SIZE,TYPE,FSTYPE $device)" \
568 "auto" "Whole device automatic partitioning" \
569 "shrink" "Shrink an existing ext or ntfs partition" \
570 "cfdisk" "Curses based variant of fdisk" \
571 "parted" "GNU partition editor" \
572 "fdisk" "Dialog-driven creation and manipulation of partitions" \
573 "done" "Return to the main menu"
575 if [[ -z $choice || $choice == 'done' ]]; then
577 elif [[ $choice == 'shrink' ]]; then
578 part_shrink "$device"
579 elif [[ $choice == 'auto' ]]; then
580 local root_size txt table boot_fs
581 root_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"}}')
582 txt="\nWARNING:\n\nALL data on $device will be destroyed and the following partitions will be created\n\n- "
583 if [[ $SYS == 'BIOS' ]]; then
584 table="msdos" boot_fs="ext4"
585 txt+="An $boot_fs boot partition with the boot flag enabled (512M)\n- "
587 table="gpt" boot_fs="fat32"
588 txt+="A $boot_fs efi boot partition (512M)\n- "
590 txt+="An ext4 partition using all remaining space ($root_size)\n\nDo you want to continue?\n"
591 yesno "Auto Partition" "$txt" && part_auto "$device" "$table" "$boot_fs" "$root_size"
597 if [[ $devhash != "$(lsblk -f | base64)" ]]; then
598 msg "Probing Partitions" "\nInforming kernel of partition changes using partprobe\n" 0
599 partprobe > /dev/null 2>&1
600 [[ $choice == 'auto' ]] && return
608 if [[ $IGNORE_DEV ]]; then
609 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk "!/$IGNORE_DEV/"' && /disk|part|lvm|crypt|NAME/')"
611 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk '/disk|part|lvm|crypt|NAME/')"
613 msg "Device Tree" "\n\n$txt\n\n"
618 local device="$1" table="$2" boot_fs="$3" size="$4" dev_info=""
620 msg "Auto Partition" "\nRemoving partitions on $device and setting table to $table\n" 1
622 dev_info="$(parted -s "$device" print)"
625 while read -r PART; do
626 parted -s "$device" rm "$PART" > /dev/null 2>&1
627 done <<< "$(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r)"
629 [[ $(awk '/Table:/ {print $3}' <<< "$dev_info") != "$table" ]] && parted -s "$device" mklabel "$table" > /dev/null 2>&1
631 msg "Auto Partition" "\nCreating a 512M $boot_fs boot partition.\n" 1
632 if [[ $SYS == "BIOS" ]]; then
633 parted -s "$device" mkpart primary "$boot_fs" 1MiB 513MiB > /dev/null 2>&1
635 parted -s "$device" mkpart ESP "$boot_fs" 1MiB 513MiB > /dev/null 2>&1
640 AUTO_BOOT_PART=$(lsblk -lno NAME,TYPE "$device" | awk 'NR==2 {print "/dev/" $1}')
642 if [[ $SYS == "BIOS" ]]; then
643 mkfs.ext4 -q "$AUTO_BOOT_PART" > /dev/null 2>&1
645 mkfs.vfat -F32 "$AUTO_BOOT_PART" > /dev/null 2>&1
648 msg "Auto Partition" "\nCreating a $size ext4 root partition.\n" 0
649 parted -s "$device" mkpart primary ext4 513MiB 100% > /dev/null 2>&1
651 AUTO_ROOT_PART="$(lsblk -lno NAME,TYPE "$device" | awk 'NR==3 {print "/dev/" $1}')"
652 mkfs.ext4 -q "$AUTO_ROOT_PART" > /dev/null 2>&1
654 msg "Auto Partition" "\nProcess complete.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$device")\n"
661 local device="$1" fs=""
663 part_find "${device##*/}[^ ]" || return 1
664 (( COUNT == 1 )) && part="$(awk '{print $1}' <<< "${PARTS[@]}" )"
666 if (( COUNT == 1 )) || dlg part menu "Resize" "\nWhich partition on $device do you want to resize?" $PARTS; then
667 fs=$(lsblk -lno FSTYPE "$part")
670 msg "Resize" "\nGathering device size info.\n" 0
672 end=$(parted -s "$device" unit KiB print | awk '/^\s*'"$num"'/ {print $3}') # part size in KiB
673 devsize=$(parted -s "$device" unit KiB print | awk '/Disk '"${device//\//\\/}"':/ {print $3}') # whole device size in KiB
674 mount "$part" "$MNT" > /dev/null 2>&1; sleep 0.5
675 min=$(df --output=used --block-size=MiB "$part" | awk 'NR == 2 {print int($1) + 256}')
676 max=$(df --output=avail --block-size=MiB "$part" | awk 'NR == 2 {print int($1)}')
679 if dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Resize: $part " --rangebox "$_resize" 17 "$COLUMNS" "$min" "$max" $((max / 2)) 2> $ANS; then
681 size=$((size * 1024))
688 if ntfsresize -fc "$part"; then
689 ntfsresize -ff --size $(( (size * 1024) / 1000 ))k "$part" 2> $ERR # k=10^3 bytes
690 errshow "ntfsresize -f -s $(( (size * 1024) / 1000 ))k $part" || return 1
692 msg "Resize" "\nThe ntfs partition $part cannot be resized because it is scheduled for a consistency check.\n\nTo do a consistency check in windows open command prompt as admin and run:\n\n\tchkdsk /f /r /x\n"
697 e2fsck -f "$part"; sleep 0.5
698 resize2fs -f "$part" ${size}K 2> $ERR # K=2^10 bytes
699 errshow "resize2fs -f $part ${size}K" || return 1
703 parted "$device" resizepart "$num" ${size}KiB || return 1
706 if [[ $devsize == "$end" ]]; then
707 parted -s "$device" mkpart primary ext4 ${size}KiB 100% 2> $ERR
708 errshow "parted -s $device mkpart primary ext4 ${size}KiB 100%" || return 1
710 parted -s "$device" mkpart primary ext4 ${size}KiB ${end}KiB 2> $ERR
711 errshow "parted -s $device mkpart primary ext4 ${size}KiB ${end}KiB" || return 1
713 msg "Resize Complete" "\n$part has been successfully resized to $((size / 1024))M.\n" 1
715 "") msg "No Filesystem" "\nFor unformatted partitions, cfdisk can be used in the partition menu.\n" ;;
716 *) msg "Invalid Filesystem: $fs" "\nResizing only supports ext and ntfs.\n" ;;
721 ###############################################################################
722 # partition management functions
723 # these are helpers for use by other functions to do essential setup/teardown
727 local regexp="$1" err=''
729 # string of partitions as /TYPE/PART SIZE.. eg. /dev/sda1 256G
730 if [[ $IGNORE_DEV ]]; then
731 PARTS="$(lsblk -lno TYPE,NAME,SIZE | awk "/$regexp/"' && !'"/$IGNORE_DEV/"' {sub(/^part/, "/dev/"); sub(/^lvm|^crypt/, "/dev/mapper/"); print $1$2, $3}')"
733 PARTS="$(lsblk -lno TYPE,NAME,SIZE | awk "/$regexp/"' {sub(/^part/, "/dev/"); sub(/^lvm|^crypt/, "/dev/mapper/"); print $1$2 " " $3}')"
736 # ensure we have enough partitions for the system and action were trying to do
737 COUNT=$(wc -l <<< "$PARTS")
739 'part|lvm|crypt') [[ $COUNT -lt 1 || ($SYS == 'UEFI' && $COUNT -lt 2) ]] && err="$_errpart" ;;
740 'part|crypt') (( COUNT < 1 )) && err="$_lvmerr" ;;
741 'part|lvm') (( COUNT < 2 )) && err="$_lukserr" ;;
745 msg "Not Enough Partitions" "$err" 2
754 if [[ $1 == "$MNT/swapfile" && $SWAP_SIZE ]]; then
755 fallocate -l $SWAP_SIZE "$1" 2> $ERR
756 errshow "fallocate -l $SWAP_SIZE $1"
757 chmod 600 "$1" 2> $ERR
758 errshow "chmod 600 $1"
760 mkswap "$1" > /dev/null 2> $ERR
762 swapon "$1" > /dev/null 2> $ERR
769 local part="$1" mountp="${MNT}$2" fs=""
770 fs="$(lsblk -lno FSTYPE "$part")"
773 if [[ $fs && ${FS_OPTS[$fs]} && $part != "$BOOT_PART" && $part != "$AUTO_ROOT_PART" ]] && select_mntopts "$fs"; then
774 mount -o "$MNT_OPTS" "$part" "$mountp" > /dev/null 2>&1
776 mount "$part" "$mountp" > /dev/null 2>&1
779 part_mountconf "$part" "$mountp" || return 1
787 local part="$1" fs="$2" delay="$3"
789 msg "Format" "\nFormatting $part as $fs\n" 0
790 mkfs.$fs ${FS_CMD_FLAGS[$fs]} "$part" > /dev/null 2> $ERR
791 errshow "mkfs.$fs ${FS_CMD_FLAGS[$fs]} "$part"" || return 1
798 if [[ $DEV_COUNT -eq 1 && $SYS_DEVS ]]; then
799 DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
800 elif (( DEV_COUNT > 1 )); then
802 dlg DEVICE menu "Boot Device" "\nSelect the device to use for bootloader install." $SYS_DEVS
804 dlg DEVICE menu "Select Device" "$_device" $SYS_DEVS
806 [[ $DEVICE ]] || return 1
807 elif [[ $DEV_COUNT -lt 1 && ! $1 ]]; then
808 msg "Device Error" "\nNo available devices.\n\nExiting..\n" 2
812 [[ $1 ]] && BOOT_DEV="$DEVICE"
819 BOOT_DEV="${BOOT_PART%[1-9]}"
820 BOOT_PART_NUM="${BOOT_PART: -1}"
821 [[ $BOOT_PART = /dev/nvme* ]] && BOOT_DEV="${BOOT_PART%p[1-9]}"
822 if [[ $SYS == 'UEFI' ]]; then
823 parted -s $BOOT_DEV set $BOOT_PART_NUM esp on > /dev/null 2>&1
825 parted -s $BOOT_DEV set $BOOT_PART_NUM boot on > /dev/null 2>&1
832 local part="$1" devs=""
833 devs="$(lsblk -lno NAME,FSTYPE,TYPE)"
835 # Identify if $part is LUKS+LVM, LVM+LUKS, LVM alone, or LUKS alone
836 if lsblk -lno TYPE "$part" | grep -q 'crypt'; then
838 LUKS_NAME="${part#/dev/mapper/}"
839 for dev in $(awk '/lvm/ && /crypto_LUKS/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
840 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
841 LUKS_DEV="$LUKS_DEV cryptdevice=$dev:$LUKS_NAME"
846 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
847 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
848 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
849 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
853 elif lsblk -lno TYPE "$part" | grep -q 'lvm'; then
855 VNAME="${part#/dev/mapper/}"
856 for dev in $(awk '/crypt/ && /lvm2_member/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
857 if lsblk -lno NAME "$dev" | grep -q "$VNAME"; then
858 LUKS_NAME="${dev/\/dev\/mapper\//}"
862 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
863 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
864 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
865 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
876 if (( COUNT > 0 )); then
877 PARTS="$(sed "/${pt//\//\\/}/d" <<< "$PARTS")"
885 if grep -qw "$1" /proc/mounts; then
886 msg "Mount Success" "\nPartition $1 mounted at $2\n" 1
890 msg "Mount Fail" "\nPartition $1 failed to mount at $2\n" 2
895 ###############################################################################
897 # mount_menu is the entry point which calls all other functions
898 # once finished it returns to the main menu: main()
902 no_bg_install || return 0
905 part_find 'part|lvm|crypt' || { SEL=2; return 1; }
906 [[ $LUKS && $LUKS_PART ]] && part_countdec $LUKS_PART
907 [[ $LVM && $LVM_PARTS ]] && part_countdec $LVM_PARTS
908 select_root_partition || { ROOT_PART=''; return 1; }
909 select_boot_partition || { BOOT_PART=''; return 1; }
910 if [[ $BOOT_PART ]]; then
911 part_mount "$BOOT_PART" "/$BOOTDIR" && SEP_BOOT=true || return 1
914 select_swap || return 1
915 select_extra_partitions || return 1
922 local pts dev size isize
924 while read -r dev size; do # walk partition list and skip ones that are too small/big for swap
925 size_t="${size: -1:1}"
928 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 16) || ($size_t == 'M' && $isize -lt 100) ]] || pts+="$dev $size "
931 dlg SWAP_PART menu "Swap Setup" "\nSelect whether to use a swapfile, swap partition, or none." \
932 "none" "Don't allocate any swap space" \
933 "swapfile" "Allocate $SYS_MEM at /swapfile" \
936 if [[ -z $SWAP_PART || $SWAP_PART == "none" ]]; then
939 elif [[ $SWAP_PART == "swapfile" ]]; then
941 until [[ ${SWAP_SIZE:0:1} =~ [1-9] && ${SWAP_SIZE: -1} =~ (M|G) ]]; do
942 (( i > 0 )) && msg "Swap Size Error" "\nSwap size must be 1(M|G) or greater, and can only contain whole numbers\n\nSize entered: $SWAP_SIZE\n" 2
943 dlg SWAP_SIZE input "Swap Setup" "$_swapsize" "$SYS_MEM" || { SWAP_PART=''; SWAP_SIZE=''; return 1; }
946 part_swap "$MNT/$SWAP_PART"
947 SWAP_PART="/$SWAP_PART"
948 elif [[ $PARTS == *"$SWAP_PART"* ]]; then
950 part_countdec $SWAP_PART
951 SWAP_SIZE="$(lsblk -lno SIZE $SWAP_PART)"
961 local fs="$1" opts=''
962 local title="${fs^} Mount Options"
964 for i in ${FS_OPTS[$fs]}; do
968 until [[ $MNT_OPTS ]]; do
969 dlg MNT_OPTS check "$title" "$_mount" $opts
970 [[ $MNT_OPTS ]] || return 1
971 MNT_OPTS="${MNT_OPTS// /,}"
972 yesno "$title" "\nConfirm the following options: $MNT_OPTS\n" || MNT_OPTS=''
981 until [[ $EXMNT ]]; do
982 dlg EXMNT input "Extra Mount $part" "$_exmnt" "/" || return 1
983 if [[ ${EXMNT:0:1} != "/" || ${#EXMNT} -le 1 || $EXMNT =~ \ |\' || $EXMNTS == *"$EXMNT"* ]]; then
984 msg "Mountpoint Error" "$_errexpart"
988 msg "Mount Extra" "\nMounting Finished\n\n\nNo extra partitions available to mount, returning to main menu.\n" 2
994 local part="$1" fs='' cur=''
995 local txt="\nSelect which filesystem to use for: $part\n\nDefault: ext4"
996 cur="$(lsblk -lno FSTYPE "$part" 2> /dev/null)"
998 # bail early if the partition was created in part_auto()
999 [[ $cur && $part == "$AUTO_ROOT_PART" ]] && return 0
1002 if [[ $cur && $FORMATTED == *"$part"* ]]; then
1003 dlg fs menu "Filesystem" "$txt\nCurrent: $cur" skip - ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1005 dlg fs menu "Filesystem" "$txt" ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1007 [[ $fs == 'skip' ]] && return 0
1008 yesno "Filesystem" "\nFormat $part as $fs?\n" || fs=''
1010 part_format "$part" "$fs" 0
1013 select_boot_partition()
1015 local pts dev size isize ptcount=0
1017 if [[ -z $BOOT_PART ]]; then
1018 if [[ $AUTO_BOOT_PART && -z $LVM && -z $LUKS ]]; then
1019 BOOT_PART="$AUTO_BOOT_PART"
1022 while read -r dev size; do # walk partition list and skip ones that are too small/big for boot
1023 size_t="${size: -1:1}"
1026 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1032 0) msg "EFI Boot Partition" "\nNo partitions available that meet size requirements!!\n\nReturning to the main menu.\n" 2; return 1 ;;
1033 1) msg "EFI Boot Partition" "\nOnly one partition available that meets size requirements.\n" 1; BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")" ;;
1034 *) dlg BOOT_PART menu "EFI Partition" "$_uefi" $pts ;;
1036 [[ $BOOT_PART ]] || return 1
1039 (( ptcount == 0 )) && return 0
1040 if [[ $LUKS && ! $LVM ]]; then
1041 dlg BOOT_PART menu "Boot Partition" "$_biosluks" $pts
1042 [[ $BOOT_PART ]] || return 1
1044 dlg BOOT_PART menu "Boot Partition" "$_bios" "skip" "no separate boot" $pts
1045 [[ -z $BOOT_PART || $BOOT_PART == "skip" ]] && { BOOT_PART=''; return 0; }
1052 if ([[ $SYS == 'BIOS' ]] && grep -q 'ext[34]' <<< "$(fsck -N "$BOOT_PART")") || ([[ $SYS == 'UEFI' ]] && grep -q 'fat' <<< "$(fsck -N "$BOOT_PART")"); then
1053 yesno "Format Boot Partition" "\nIMPORTANT:\n\nThe boot partition $BOOT_PART $_format" "Format $BOOT_PART" "Skip Formatting" 1 || return 0
1057 UEFI) part_format "$BOOT_PART" "vfat" 2 || return 1 ;;
1058 BIOS) part_format "$BOOT_PART" "ext4" 2 || return 1 ;;
1063 select_root_partition()
1065 if [[ -z $ROOT_PART ]]; then
1066 if [[ $AUTO_ROOT_PART && -z $LVM && -z $LUKS ]]; then
1067 ROOT_PART="$AUTO_ROOT_PART"
1068 msg "Mount Menu" "\nUsing partitions created during automatic format.\n" 2
1069 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1070 return 0 # we're done here
1072 local pts dev size isize ptcount=0
1074 # walk partition list and skip ones that are too small for / (root)
1075 while read -r dev size; do
1076 size_t="${size: -1:1}" # size type eg. K, M, G, T
1077 isize=${size:0:-1} # remove trailing size type character
1078 isize=${isize%.*} # remove any decimal (round down)
1079 [[ $size_t =~ [MK] || ($size_t == 'G' && $isize -lt 4) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1082 if (( ptcount == 1 )); then # only one available device
1083 msg "Root Partition (/)" "\nOnly one partition available that meets size requirements.\n" 2
1084 ROOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")"
1086 dlg ROOT_PART menu "Mount Root" "\nSelect the root (/) partition, this is where $DIST will be installed.\n\nDevices smaller than 8G will not be shown here." $pts
1091 if [[ -z $ROOT_PART ]] || ! select_filesystem "$ROOT_PART" || ! part_mount "$ROOT_PART"; then
1098 select_extra_partitions()
1102 # walk partition list and skip ones that are too small to be usable
1103 while read -r dev size; do
1104 [[ ${size: -1:1} =~ [KM] ]] && part_countdec "$dev"
1107 while (( COUNT > 0 )); do
1109 dlg part menu 'Mount Extra' "$_expart" 'done' 'finish mounting step' $PARTS || break
1110 if [[ $part == 'done' ]]; then
1112 elif select_filesystem "$part" && select_mountpoint && part_mount "$part" "$EXMNT"; then
1113 EXMNTS+="$part: $EXMNT "
1114 [[ $EXMNT == '/usr' && $HOOKS != *usr* ]] && HOOKS+=" usr"
1122 ###############################################################################
1124 # main is the entry point which calls all other install functions, once
1125 # complete it shows a dialog to edit files on the new system before reboot
1130 genfstab -U "$MNT" > "$MNT/etc/fstab" 2> $ERR 2>&1
1131 errshow 1 "genfstab -U $MNT > $MNT/etc/fstab"
1132 [[ -f $MNT/swapfile ]] && sed -i "s~${MNT}~~" "$MNT/etc/fstab"
1134 # video driver tearfree configs, MUST be done after package install to support nvidia
1135 install_tearfree_conf "$MNT/etc/X11/xorg.conf.d"
1138 chrun "hwclock --systohc --utc" || chrun "hwclock --systohc --utc --directisa"
1141 chrun "chown -Rf $NEWUSER:users /home/$NEWUSER"
1144 dlg choice menu "Finalization" "$_edit" \
1145 finished "exit the installer and reboot" \
1146 keyboard "${EDIT_FILES[keyboard]}" \
1147 console "${EDIT_FILES[console]}" \
1148 locale "${EDIT_FILES[locale]}" \
1149 hostname "${EDIT_FILES[hostname]}" \
1150 sudoers "${EDIT_FILES[sudoers]}" \
1151 mkinitcpio "${EDIT_FILES[mkinitcpio]}" \
1152 fstab "${EDIT_FILES[fstab]}" \
1153 crypttab "${EDIT_FILES[crypttab]}" \
1154 bootloader "${EDIT_FILES[bootloader]}" \
1155 pacman "${EDIT_FILES[pacman]}" \
1156 login "${EDIT_FILES[login]}"
1158 if [[ -z $choice || $choice == 'finished' ]]; then
1159 [[ $DEBUG == true && -r $DBG ]] && ${EDITOR:-vim} $DBG
1163 for f in ${EDIT_FILES[$choice]}; do
1164 [[ -e ${MNT}$f ]] && exists+=" ${MNT}$f"
1166 if [[ $exists ]]; then
1167 ${EDITOR:-vim} -O $exists
1169 msg "File Missing" "\nThe file(s) selected do not exist:\n\n${EDIT_FILES[$choice]}\n"
1179 while kill -0 $BG_PID 2> /dev/null; do
1180 clear; printf "\nA background install process is still running...\n"; sleep 1
1186 rm -rf "$MNT/etc/mkinitcpio-archiso.conf"
1187 find "$MNT/usr/lib/initcpio" -name 'archiso*' -type f -delete
1189 # remove/disable customizations done to airootfs during building
1190 chrun "systemctl disable pacman-init.service choose-mirror.service" > /dev/null 2>&1
1191 rm -f "$MNT/etc/systemd/scripts/choose-mirror"
1192 rm -f "$MNT/etc/systemd/system/"{choose-mirror.service,etc-pacman.d-gnupg.mount,pacman-init.service}
1193 sed -i 's/#\(Storage=\)volatile/\1auto/' "$MNT/etc/systemd/journald.conf"
1194 sed -i 's/#\(HandleSuspendKey=\)ignore/\1suspend/' "$MNT/etc/systemd/logind.conf"
1195 sed -i 's/#\(HandleHibernateKey=\)ignore/\1hibernate/' "$MNT/etc/systemd/logind.conf"
1196 sed -i 's/#\(HandleLidSwitch=\)ignore/\1suspend/' "$MNT/etc/systemd/logind.conf"
1197 find "$MNT/boot" -name '*-ucode.img' -delete
1199 # changing distro name?
1200 [[ $DIST != "ArchLabs" ]] || sed -i "s/ArchLabs/$DIST/g" "$MNT/etc/"{lsb-release,os-release}
1202 # vmlinuz, if this isn't copied the standard kernel may fail mkinitcpio
1203 cp -vf "$RUN/x86_64/vmlinuz" "$MNT/boot/vmlinuz-linux" 2> $ERR 2>&1
1204 errshow 1 "cp -vf $RUN/x86_64/vmlinuz $MNT/boot/vmlinuz-linux"
1206 # copy network settings
1207 [[ -d /etc/netctl ]] && cp -rfv /etc/netctl "$MNT/etc/"
1208 [[ -f /etc/resolv.conf ]] && cp -fv /etc/resolv.conf "$MNT/etc/"
1209 [[ -e /etc/NetworkManager/system-connections ]] && cp -rvf /etc/NetworkManager/system-connections "$MNT/etc/NetworkManager/"
1211 echo "LANG=$MYLOCALE" > "$MNT/etc/locale.conf"
1212 cp -fv "$MNT/etc/locale.conf" "$MNT/etc/default/locale"
1213 sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${MYLOCALE}/${MYLOCALE}/g" "$MNT/etc/locale.gen"
1215 chrun "ln -svf /usr/share/zoneinfo/$ZONE/$SUBZ /etc/localtime"
1217 cat > "$MNT/etc/X11/xorg.conf.d/00-keyboard.conf" <<- EOF
1218 # Use localectl(1) to instruct systemd-localed to update it.
1219 Section "InputClass"
1220 Identifier "system-keyboard"
1221 MatchIsKeyboard "on"
1222 Option "XkbLayout" "$KEYMAP"
1226 cat > "$MNT/etc/default/keyboard" <<- EOF
1227 # KEYBOARD CONFIGURATION FILE
1228 # Consult the keyboard(5) manual page.
1235 printf "KEYMAP=%s\nFONT=%s\n" "$CMAP" "$FONT" > "$MNT/etc/vconsole.conf"
1237 echo "$MYHOST" > "$MNT/etc/hostname"
1238 cat > "$MNT/etc/hosts" <<- EOF
1241 ::1 localhost ip6-localhost ip6-loopback
1242 ff02::1 ip6-allnodes
1243 ff02::2 ip6-allrouters
1249 echo "Installing $BOOTLDR"
1251 if [[ $ROOT_PART == /dev/mapper* ]]; then
1252 ROOT_PART_ID="$ROOT_PART"
1254 local uuid_type="UUID"
1255 [[ $BOOTLDR =~ (systemd-boot|refind-efi|efistub) ]] && uuid_type="PARTUUID"
1256 ROOT_PART_ID="$uuid_type=$(blkid -s $uuid_type -o value $ROOT_PART)"
1259 if [[ $SYS == 'UEFI' ]]; then
1260 # remove our old install and generic BOOT/ dir
1261 echo "Removing conflicting boot directories"
1262 find "$MNT/$BOOTDIR/EFI/" -maxdepth 1 -mindepth 1 -iname "$DIST" -type d -delete -printf "remove %p\n"
1263 find "$MNT/$BOOTDIR/EFI/" -maxdepth 1 -mindepth 1 -iname 'BOOT' -type d -delete -printf "remove %p\n"
1267 chrun "${BCMDS[$BOOTLDR]}" 2> $ERR 2>&1
1268 errshow 1 "${BCMDS[$BOOTLDR]}"
1270 if [[ -d $MNT/hostrun ]]; then
1271 echo "Unmounting chroot directories"
1272 # cleanup the bind mounts we made earlier for the grub-probe module
1273 umount_dir "$MNT/hostrun/"{udev,lvm}
1274 rm -rf "$MNT/hostrun" > /dev/null 2>&1
1277 if [[ $SYS == 'UEFI' ]]; then
1278 # some UEFI firmware requires a generic esp/BOOT/BOOTX64.EFI
1279 mkdir -pv "$MNT/$BOOTDIR/EFI/BOOT"
1281 grub) cp -fv "$MNT/$BOOTDIR/EFI/$DIST/grubx64.efi" "$MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI" ;;
1282 syslinux) cp -rf "$MNT/$BOOTDIR/EFI/syslinux/"* "$MNT/$BOOTDIR/EFI/BOOT/" && cp -f "$MNT/$BOOTDIR/EFI/syslinux/syslinux.efi" "$MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI" ;;
1283 refind-efi) sed -i '/#extra_kernel_version_strings/ c extra_kernel_version_strings linux-hardened,linux-zen,linux-lts,linux' "$MNT/$BOOTDIR/EFI/refind/refind.conf"
1284 cp -fv "$MNT/$BOOTDIR/EFI/refind/refind_x64.efi" "$MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI" ;;
1293 local groups='audio,video,floppy,log,network,rfkill,scanner,storage,optical,power,wheel'
1294 if [[ -e $MNT/etc/X11/xorg.conf.d/20-nvida.conf && -e $MNT/usr/bin/optirun ]]; then
1295 groups+=',bumblebee'
1298 rm -f "$MNT/root/.zlogin" # remove welcome message
1300 chrun "chpasswd <<< 'root:$ROOT_PASS'" 2> $ERR 2>&1
1301 errshow 1 "set root password"
1302 if [[ $MYSHELL != 'zsh' ]]; then # root uses zsh by default
1303 chrun "usermod -s /bin/$MYSHELL root" 2> $ERR 2>&1
1304 errshow 1 "usermod -s /bin/$MYSHELL root"
1305 # copy the default mkshrc to /root if it was selected
1306 [[ $MYSHELL == 'mksh' ]] && cp -fv "$MNT/etc/skel/.mkshrc" "$MNT/root/.mkshrc"
1309 echo "Creating new user $NEWUSER and setting password"
1310 chrun "useradd -m -u 1000 -g users -G $groups -s /bin/$MYSHELL $NEWUSER" 2> $ERR 2>&1
1311 errshow 1 "useradd -m -u 1000 -g users -G $groups -s /bin/$MYSHELL $NEWUSER"
1312 chrun "chpasswd <<< '$NEWUSER:$USER_PASS'" 2> $ERR 2>&1
1313 errshow 1 "set $NEWUSER password"
1315 if [[ $INSTALL_WMS == *dwm* ]];then
1316 install_suckless "/home/$NEWUSER" chroot
1317 [[ $INSTALL_WMS == 'dwm' ]] && rm -rf "$MNT/home/$NEWUSER/.config/xfce4"
1320 [[ $INSTALL_WMS != *bspwm* && $INSTALL_WMS != *openbox* ]] && rm -rf "$MNT/home/$NEWUSER/.config/"{jgmenu,tint2}
1321 [[ $USER_PKGS != *geany* ]] && rm -rf "$MNT/home/$NEWUSER/.config/geany"
1322 [[ $MYSHELL != 'bash' ]] && rm -rf "$MNT/home/$NEWUSER/.bash"*
1323 [[ $MYSHELL != 'zsh' ]] && rm -rf "$MNT/home/$NEWUSER/.z"*
1325 # remove some commands from ~/.xprofile when using KDE or Gnome as the login session
1326 if [[ $LOGIN_WM =~ (startkde|gnome-session) || ($LOGIN_TYPE != 'xinit' && $WM_PKGS =~ (plasma|gnome)) ]]; then
1327 sed -i '/super/d; /nitrogen/d; /compton/d' "$MNT/home/$NEWUSER/.xprofile" "$MNT/root/.xprofile"
1328 elif [[ $LOGIN_WM == 'dwm' ]]; then # and dwm
1329 sed -i '/super/d; /compton/d' "$MNT/home/$NEWUSER/.xprofile" "$MNT/root/.xprofile"
1332 # create user home directories (Music, Documents, Downloads, etc..)
1333 chrun 'xdg-user-dirs-update'
1340 local serv="$MNT/etc/systemd/system/getty@tty1.service.d"
1341 echo "Setting up $LOGIN_TYPE"
1343 ly|sddm|gdm|lightdm)
1344 if [[ $LOGIN_WM == *dwm* ]]; then # dwm doesn't include an xsession file for display managers
1345 mkdir -p "$MNT/usr/share/xsessions"
1346 cat > "$MNT/usr/share/xsessions/dwm.desktop" <<- EOF
1350 Comment=Dynamic Window Manager
1355 rm -rf "$serv" "$MNT/home/$NEWUSER/.xinitrc"
1356 chrun "systemctl enable $LOGIN_TYPE.service" 2> $ERR 2>&1
1357 errshow 1 "systemctl enable $LOGIN_TYPE.service"
1358 ${LOGIN_TYPE}_config
1361 if [[ $INSTALL_WMS ]]; then
1362 sed -i "/exec/ c exec ${LOGIN_WM}" "$MNT/home/$NEWUSER/.xinitrc"
1363 elif [[ -e $MNT/home/$NEWUSER/.xinitrc ]]; then
1364 sed -i '/exec/d' "$MNT/home/$NEWUSER/.xinitrc"
1367 if [[ $AUTOLOGIN ]]; then
1368 sed -i "s/root/${NEWUSER}/g" $serv/autologin.conf
1369 cat > "$MNT/home/$NEWUSER/$LOGINRC" <<- EOF
1370 # automatically run startx when logging in on tty1
1371 [ -z "\$DISPLAY" ] && [ \$XDG_VTNR -eq 1 ] && startx
1383 local inpkg="$PACKAGES $USER_PKGS $AL_BASE_PKGS "
1385 if pacman -Qq archlabs-installer > /dev/null 2>&1; then
1386 rmpkg+="archlabs-installer "
1389 if [[ $VM ]] && dmesg | grep -qi 'vbox'; then
1390 inpkg+="virtualbox-guest-utils "
1392 linux) inpkg+="virtualbox-guest-modules-arch " ;;
1393 *) inpkg+="virtualbox-guest-modules-dkms ${KERNEL}-headers " ;;
1397 if [[ $MYSHELL == 'zsh' ]]; then
1398 inpkg+="zsh-completions "
1403 if [[ $INSTALL_WMS =~ (openbox|bspwm|i3-gaps|fluxbox) ]]; then
1404 inpkg+="$WM_BASE_PKGS "
1405 elif [[ $INSTALL_WMS == 'dwm' ]]; then # dwm only needs a very limited package set
1406 inpkg+="nitrogen polkit-gnome gnome-keyring dunst "
1409 # update and install crucial packages first to avoid issues
1410 chrun "pacman -Syyu $KERNEL $BASE_PKGS base-devel ${LOGIN_PKGS[$LOGIN_TYPE]} $MYSHELL --noconfirm --needed" 2> $ERR 2>&1
1411 errshow 1 "pacman -Syyu $KERNEL $BASE_PKGS base-devel ${LOGIN_PKGS[$LOGIN_TYPE]} $MYSHELL --noconfirm --needed"
1413 # remove the packages we don't want on the installed system
1414 [[ $rmpkg ]] && chrun "pacman -Rnsc $rmpkg --noconfirm"
1416 # reinstalling iputils fixes the network issue for non-root users
1417 chrun "pacman -S iputils $UCODE --noconfirm"
1419 # install the packages chosen throughout the install
1420 chrun "pacman -S $inpkg --needed --noconfirm" 2> $ERR 2>&1
1421 errshow 1 "pacman -S $inpkg --needed --noconfirm"
1423 # bootloader packages
1424 if [[ $BOOTLDR == 'grub' ]]; then
1425 [[ $SYS == 'UEFI' ]] && local efib="efibootmgr"
1426 chrun "pacman -S os-prober grub $efib --needed --noconfirm" 2> $ERR 2>&1
1427 errshow 1 "pacman -S os-prober grub $efib --needed --noconfirm"
1428 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1429 chrun "pacman -S refind-efi efibootmgr --needed --noconfirm" 2> $ERR 2>&1
1430 errshow 1 "pacman -S refind-efi efibootmgr --needed --noconfirm"
1431 elif [[ $SYS == 'UEFI' ]]; then
1432 chrun "pacman -S efibootmgr --needed --noconfirm" 2> $ERR 2>&1
1433 errshow 1 "pacman -S efibootmgr --needed --noconfirm"
1436 # allow members of the wheel group to run commands as root
1437 sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" "$MNT/etc/sudoers"
1444 local dir="$1/suckless"
1447 if [[ $2 == 'chroot' ]]; then
1448 chrun "mkdir -pv '$dir'"
1449 for i in dwm dmenu st; do
1450 if chrun "git clone 'https://git.suckless.org/$i' '$dir/$i'"; then
1451 chrun "cd '$dir/$i' && make PREFIX=/usr install"
1453 printf "failed to clone %s repo\n" "$i"
1458 for i in dwm dmenu st; do
1459 if git clone "https://git.suckless.org/$i" "$dir/$i"; then
1460 cd "$dir/$i" && make PREFIX=/usr install
1462 printf "failed to clone %s repo\n" "$i"
1468 install_mkinitcpio()
1471 [[ $LUKS ]] && add="encrypt"
1472 [[ $LVM ]] && { [[ $add ]] && add+=" lvm2" || add+="lvm2"; }
1473 sed -i "s/block filesystems/block ${add} filesystems ${HOOKS}/g" "$MNT/etc/mkinitcpio.conf"
1474 chrun "mkinitcpio -p $KERNEL" 2> $ERR 2>&1
1475 errshow 1 "mkinitcpio -p $KERNEL"
1478 install_mirrorlist()
1480 if hash reflector > /dev/null 2>&1; then
1481 reflector --verbose --score 80 -l 40 -f 5 --sort rate --save "$1"
1482 elif hash rankmirrors > /dev/null 2>&1; then
1483 echo "Sorting mirrorlist"
1484 local key="access_key=5f29642060ab983b31fdf4c2935d8c56"
1485 ip_add="$(curl -fsSL "http://api.ipstack.com/check&?$key&fields=ip" | python -c "import sys, json; print(json.load(sys.stdin)['ip'])")"
1486 country="$(curl -fsSL "http://api.ipstack.com/$ip_add?$key&fields=country_code" | python -c "import sys, json; print(json.load(sys.stdin)['country_code'])")"
1487 if [[ "$country" ]]; then
1488 if [[ $country =~ (CA|US) ]]; then
1489 # use both CA and US mirrors for CA or US countries
1490 mirror="https://www.archlinux.org/mirrorlist/?country=US&country=CA&use_mirror_status=on"
1491 elif [[ $country =~ (AU|NZ) ]]; then
1492 # use both AU and NZ mirrors for AU or NZ countries
1493 mirror="https://www.archlinux.org/mirrorlist/?country=AU&country=NZ&use_mirror_status=on"
1495 mirror="https://www.archlinux.org/mirrorlist/?country=${country}&use_mirror_status=on"
1497 else # no country code so just grab all mirrors, will be a very slow sort but we don't have other options
1498 mirror="https://www.archlinux.org/mirrorlist/?country=all&use_mirror_status=on"
1500 curl -fsSL "$mirror" | sed -e 's/^#Server/Server/' -e '/^#/d' | rankmirrors -n 6 - > "$1"
1504 install_background()
1506 ( rsync -a /run/archiso/sfs/airootfs/ "$MNT/" && install_mirrorlist "$MNT/etc/pacman.d/mirrorlist" > /dev/null 2>&1 ) &
1508 trap "kill $BG_PID 2> /dev/null" EXIT
1511 install_tearfree_conf()
1516 echo "Virtual machine detected, removing xorg configs"
1517 find "$xpath/" -name '*.conf' -delete -printf "remove %p\n"
1518 elif lspci | grep ' VGA ' | grep -q 'Intel'; then
1519 echo "Creating Intel Tear Free config /etc/X11/xorg.conf.d/20-intel.conf"
1520 cat > "$xpath/20-intel.conf" <<- EOF
1522 Identifier "Intel Graphics"
1524 Option "TearFree" "true"
1527 elif lspci | grep ' VGA ' | grep -q 'AMD/ATI.*RX\|AMD/ATI.*R[579]'; then # newer RX, R5, R7, and R9 cards can use the amdgpu driver
1528 echo "Creating AMD Tear Free config /etc/X11/xorg.conf.d/20-amdgpu.conf"
1529 cat > "$xpath/20-amdgpu.conf" <<- EOF
1531 Identifier "AMD Graphics"
1533 Option "TearFree" "true"
1536 elif lspci | grep ' VGA ' | grep -q 'AMD/ATI.*HD [2-6][0-9]*'; then # older HD 2xxx-6xxx cards must use the radeon driver
1537 echo "Creating Radeon Tear Free config /etc/X11/xorg.conf.d/20-radeon.conf"
1538 cat > "$xpath/20-radeon.conf" <<- EOF
1540 Identifier "AMD Graphics"
1542 Option "TearFree" "on"
1545 elif lspci | grep ' VGA ' | grep -q 'NVIDIA'; then # nvidia cards require a bit of checking for notebook gpus
1546 echo "Trying nvidia driver install"
1547 if lspci | grep ' VGA ' | grep -q 'Intel\|AMD' && lspci | grep ' VGA ' | grep -q 'NVIDIA.*[6-9][1-8][05]M[X]\?\|NVIDIA.*Quadro.*[KMP][1-6][0-2][0]*M'; then # optimus
1548 if [[ $xpath == *"$MNT"* ]]; then
1549 chrun "nvidia-installer --bumblebee"
1551 nvidia-installer --bumblebee
1554 if [[ $xpath == *"$MNT"* ]]; then
1555 chrun "nvidia-installer" # unsure which card so try auto detection
1560 if [[ -e $xpath/20-nvidia.conf ]]; then
1561 echo "NVIDIA driver installed"
1562 if [[ $xpath == *"$MNT"* ]]; then
1563 echo "Trying to load the driver for live session"
1566 echo "To enable driver vsync:"
1567 echo -e "\trun nvidia-settings (as root) on first boot\n\tenable 'ForceFullCompositionPipeline' under the advanced settings"
1568 echo -e "\tlastly save the change to your nvida xorg config /etc/X11/xorg.conf.d/20-nvidia.conf"
1569 echo -e "\tand remove everything but the Device and Screen sections from the file"
1571 echo "Unable to install nvidia driver"
1576 # remove nvidia installer from installed system when not running nvidia gpu
1577 [[ $xpath == *"$MNT"* ]] && rm -rf "$MNT/usr/bin/nvidia-installer" "$MNT/var/lib/nvidia-installer"
1580 ###############################################################################
1581 # display manager config
1582 # these are called based on which DM is chosen after it is installed
1583 # additional config can be handled here, for now only lightdm has one
1587 cat > "$MNT/etc/lightdm/lightdm-gtk-greeter.conf" <<- EOF
1589 default-user-image=/usr/share/icons/ArchLabs-Dark/64x64/places/distributor-logo-archlabs.png
1590 background=/usr/share/backgrounds/archlabs/archlabs.jpg
1591 theme-name=Adwaita-dark
1592 icon-theme-name=Adwaita
1593 font-name=DejaVu Sans Mono 11
1594 position=30%,end 50%,end
1613 ###############################################################################
1615 # prerun_* set up the configs needed before actually running the commands
1616 # setup_* are run after selecting a bootloader and build the command used later
1617 # they can also be used for further user input as these run before control is taken away
1621 EDIT_FILES[bootloader]="/etc/default/grub"
1623 if [[ $SYS == 'BIOS' ]]; then
1624 [[ $BOOT_DEV ]] || { part_device 1 || return 1; }
1625 BCMDS[grub]="grub-install --recheck --force --target=i386-pc $BOOT_DEV"
1627 BCMDS[grub]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1628 grub-install --recheck --force --target=x86_64-efi --efi-directory=/$BOOTDIR --bootloader-id=$DIST"
1629 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1632 BCMDS[grub]="mkdir -p /run/udev /run/lvm &&
1633 mount --bind /hostrun/udev /run/udev &&
1634 mount --bind /hostrun/lvm /run/lvm &&
1636 grub-mkconfig -o /boot/grub/grub.cfg &&
1637 sleep 1 && umount /run/udev /run/lvm"
1644 sed -i "s/GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR=\"${DIST}\"/g; s/GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"\"/g" "$MNT/etc/default/grub"
1646 if [[ $LUKS_DEV ]]; then
1647 sed -i "s~#GRUB_ENABLE_CRYPTODISK~GRUB_ENABLE_CRYPTODISK~g; s~GRUB_CMDLINE_LINUX=.*~GRUB_CMDLINE_LINUX=\"${LUKS_DEV}\"~g" "$MNT/etc/default/grub" 2> $ERR 2>&1
1648 errshow 1 "sed -i 's~#GRUB_ENABLE_CRYPTODISK~GRUB_ENABLE_CRYPTODISK~g; s~GRUB_CMDLINE_LINUX=.*~GRUB_CMDLINE_LINUX=\"${LUKS_DEV}\"~g' $MNT/etc/default/grub"
1651 if [[ $SYS == 'BIOS' && $LVM && -z $SEP_BOOT ]]; then
1652 sed -i "s/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g" "$MNT/etc/default/grub" 2> $ERR 2>&1
1653 errshow 1 "sed -i 's/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g' $MNT/etc/default/grub"
1656 # setup for os-prober module
1657 mkdir -p /run/{lvm,udev} "$MNT/hostrun/"{lvm,udev}
1658 mount --bind /run/lvm "$MNT/hostrun/lvm"
1659 mount --bind /run/udev "$MNT/hostrun/udev"
1666 EDIT_FILES[bootloader]=""
1671 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1672 efibootmgr -v -d $BOOT_DEV -p $BOOT_PART_NUM -c -L '${DIST} Linux' -l /vmlinuz-${KERNEL} \
1673 -u 'root=$ROOT_PART_ID rw $([[ $UCODE ]] && printf 'initrd=\%s.img ' "$UCODE")initrd=\initramfs-${KERNEL}.img'"
1678 if [[ $SYS == 'BIOS' ]]; then
1679 EDIT_FILES[bootloader]="/boot/syslinux/syslinux.cfg"
1681 EDIT_FILES[bootloader]="/boot/EFI/syslinux/syslinux.cfg"
1682 BCMDS[syslinux]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1683 efibootmgr -v -c -d $BOOT_DEV -p $BOOT_PART_NUM -l /EFI/syslinux/syslinux.efi -L $DIST"
1689 local c="$MNT/boot/syslinux"
1690 local s="/usr/lib/syslinux/bios"
1692 if [[ $SYS == 'UEFI' ]]; then
1693 c="$MNT/boot/EFI/syslinux"
1694 s="/usr/lib/syslinux/efi64"
1697 mkdir -pv "$c" 2> $ERR 2>&1
1698 errshow 1 "mkdir -pv $c"
1699 cp -rfv "$s/"* "$c/" 2> $ERR 2>&1
1700 errshow 1 "cp -rfv $s/* $c/"
1701 cp -fv "$RUN/syslinux/splash.png" "$c/" 2> $ERR 2>&1
1702 errshow 0 "cp -fv $RUN/syslinux/splash.png $c/"
1703 cat > "$c/syslinux.cfg" <<- EOF
1705 MENU TITLE $DIST Boot Menu
1706 MENU BACKGROUND splash.png
1710 # see: https://www.syslinux.org/wiki/index.php/Comboot/menu.c32
1719 MENU HELPMSGENDROW 29
1720 MENU COLOR border 30;44 #40ffffff #a0000000 std
1721 MENU COLOR title 1;36;44 #9033ccff #a0000000 std
1722 MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
1723 MENU COLOR unsel 37;44 #50ffffff #a0000000 std
1724 MENU COLOR help 37;40 #c0ffffff #a0000000 std
1725 MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
1726 MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
1727 MENU COLOR msg07 37;40 #90ffffff #a0000000 std
1728 MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
1731 MENU LABEL $DIST Linux
1732 LINUX $d/vmlinuz-$KERNEL
1733 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1734 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL.img
1736 LABEL ${DIST}fallback
1737 MENU LABEL $DIST Linux Fallback
1738 LINUX $d/vmlinuz-$KERNEL
1739 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1740 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL-fallback.img
1747 EDIT_FILES[bootloader]="/boot/refind_linux.conf"
1748 BCMDS[refind-efi]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1; refind-install"
1753 cat > "$MNT/boot/refind_linux.conf" <<- EOF
1754 "$DIST Linux" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1755 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1756 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL.img"
1757 "$DIST Linux Fallback" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1758 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1759 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL-fallback.img"
1761 mkdir -p "$MNT/etc/pacman.d/hooks"
1762 cat > "$MNT/etc/pacman.d/hooks/refind.hook" <<- EOF
1769 Description = Updating rEFInd on ESP
1770 When = PostTransaction
1771 Exec = /usr/bin/refind-install
1775 setup_systemd-boot()
1777 EDIT_FILES[bootloader]="/boot/loader/entries/$DIST.conf"
1778 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1; bootctl --path=/boot install"
1781 prerun_systemd-boot()
1783 mkdir -p "$MNT/boot/loader/entries"
1784 cat > "$MNT/boot/loader/loader.conf" <<- EOF
1789 cat > "$MNT/boot/loader/entries/$DIST.conf" <<- EOF
1791 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1792 initrd /initramfs-$KERNEL.img
1793 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1795 cat > "$MNT/boot/loader/entries/$DIST-fallback.conf" <<- EOF
1796 title $DIST Linux Fallback
1797 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1798 initrd /initramfs-$KERNEL-fallback.img
1799 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1801 mkdir -p "$MNT/etc/pacman.d/hooks"
1802 cat > "$MNT/etc/pacman.d/hooks/systemd-boot.hook" <<- EOF
1809 Description = Updating systemd-boot
1810 When = PostTransaction
1811 Exec = /usr/bin/bootctl update
1813 systemd-machine-id-setup --root="$MNT"
1817 ###############################################################################
1822 no_bg_install || return 1
1826 dlg choice menu "Logical Volume Management" "$_lvmmenu" \
1827 "$_lvmnew" "vgcreate -f, lvcreate -L -n" \
1828 "$_lvmdel" "vgremove -f" \
1829 "$_lvmdelall" "lvrmeove, vgremove, pvremove -f" \
1830 "Back" "Return to the main menu"
1832 "$_lvmnew") lvm_create && break ;;
1833 "$_lvmdel") lvm_delgroup && yesno "$_lvmdel" "$_lvmdelask" && vgremove -f "$DEL_VG" > /dev/null 2>&1 ;;
1834 "$_lvmdelall") lvm_del_all ;;
1845 pv="$(pvs -o pv_name --noheading 2> /dev/null)"
1846 v="$(lvs -o vg_name,lv_name --noheading --separator - 2> /dev/null)"
1847 VGROUP="$(vgs -o vg_name --noheading 2> /dev/null)"
1849 if [[ $VGROUP && $v && $pv ]]; then
1850 msg "LVM Setup" "\nActivating existing logical volume management.\n" 0
1851 modprobe dm-mod > /dev/null 2> $ERR
1852 errshow 'modprobe dm-mod'
1853 vgscan > /dev/null 2>&1
1854 vgchange -ay > /dev/null 2>&1
1860 VGROUP='' LVM_PARTS='' VGROUP_MB=0
1862 lvm_mkgroup || return 1
1863 local txt="\nThe last (or only) logical volume will automatically use all remaining space in the volume group."
1864 dlg VOL_COUNT menu "$_lvmnew" "\nSelect the number of logical volumes (LVs) to create in: $VGROUP\n$txt" 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -
1865 [[ $VOL_COUNT ]] || return 1
1866 lvm_extra_lvs || return 1
1867 lvm_volume_name "$_lvmlvname\nNOTE: This LV will use up all remaining space in the volume group (${VGROUP_MB}MB)" || return 1
1868 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating volume $VNAME from remaining space in $VGROUP\n" 0
1869 lvcreate -l +100%FREE "$VGROUP" -n "$VNAME" > /dev/null 2> $ERR
1870 errshow "lvcreate -l +100%FREE $VGROUP -n $VNAME" || return 1
1871 LVM='logical volume'; sleep 0.5
1872 txt="\nDone, volume: $VGROUP-$VNAME (${VOLUME_SIZE:-${VGROUP_MB}MB}) has been created.\n"
1873 msg "$_lvmnew (LV:$VOL_COUNT)" "$txt\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE $LVM_PARTS)\n"
1879 local txt="${VGROUP}: ${SIZE}$SIZE_UNIT (${VGROUP_MB}MB remaining).$_lvmlvsize"
1883 dlg VOLUME_SIZE input "$_lvmnew (LV:$VOL_COUNT)" "$txt" ''
1884 if [[ -z $VOLUME_SIZE ]]; then
1886 break # allow bailing with escape or an empty choice
1887 elif (( ${VOLUME_SIZE:0:1} == 0 )); then
1888 ERR_SIZE=1 # size values can't begin with '0'
1890 # walk the string and make sure all but the last char are digits
1891 local lv=$((${#VOLUME_SIZE} - 1))
1892 for (( i=0; i<lv; i++ )); do
1893 [[ ${VOLUME_SIZE:$i:1} =~ [0-9] ]] || { ERR_SIZE=1; break; }
1895 if (( ERR_SIZE != 1 )); then
1896 case ${VOLUME_SIZE:$lv:1} in
1897 [mMgG]) local s=${VOLUME_SIZE:0:$lv} m=$((s * 1000))
1898 case ${VOLUME_SIZE:$lv:1} in
1899 [Gg]) (( m >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - m)) ;;
1900 [Mm]) (( ${VOLUME_SIZE:0:$lv} >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - s)) ;;
1907 if (( ERR_SIZE )); then
1908 msg "Invalid Logical Volume Size" "$_lvmerrlvsize"
1921 until [[ $named ]]; do
1922 lvm_partitions || return 1
1923 lvm_group_name || return 1
1924 yesno "$_lvmnew" "\nCreate volume group: $VGROUP\n\nusing these partition(s): $LVM_PARTS\n" && named=true
1927 msg "$_lvmnew" "\nCreating volume group: $VGROUP\n" 0
1928 vgcreate -f "$VGROUP" $LVM_PARTS > /dev/null 2> $ERR
1929 errshow "vgcreate -f $VGROUP $LVM_PARTS" || return 1
1931 SIZE=$(vgdisplay "$VGROUP" | awk '/VG Size/ { gsub(/[^0-9.]/, ""); print int($0) }')
1932 SIZE_UNIT="$(vgdisplay "$VGROUP" | awk '/VG Size/ { print substr($NF, 0, 1) }')"
1934 if [[ $SIZE_UNIT == 'G' ]]; then
1935 VGROUP_MB=$((SIZE * 1000))
1940 msg "$_lvmnew" "\nVolume group $VGROUP (${SIZE}$SIZE_UNIT) successfully created\n"
1946 pv="$(pvs -o pv_name --noheading 2> /dev/null)"
1947 v="$(lvs -o vg_name,lv_name --noheading --separator - 2> /dev/null)"
1948 VGROUP="$(vgs -o vg_name --noheading 2> /dev/null)"
1950 if [[ $VGROUP || $v || $pv ]]; then
1951 if yesno "$_lvmdelall" "$_lvmdelask"; then
1952 for i in $v; do lvremove -f "/dev/mapper/$i" > /dev/null 2>&1; done
1953 for i in $VGROUP; do vgremove -f "$i" > /dev/null 2>&1; done
1954 for i in $pv; do pvremove -f "$i" > /dev/null 2>&1; done
1958 msg "Delete LVM" "\nNo LVMs to remove...\n" 2
1968 for i in $(lvs --noheadings | awk '{print $2}' | uniq); do
1969 VOL_GROUP_LIST+="$i $(vgdisplay "$i" | awk '/VG Size/ {print $3$4}') "
1972 [[ $VOL_GROUP_LIST ]] || { msg "No Groups" "\nNo volume groups found."; return 1; }
1974 dlg DEL_VG menu "Logical Volume Management" "\nSelect volume group to delete.\n\nAll logical volumes within will also be deleted." $VOL_GROUP_LIST
1980 while (( VOL_COUNT > 1 )); do
1981 lvm_volume_name "$_lvmlvname" && lvm_lv_size || return 1
1982 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating a $VOLUME_SIZE volume $VNAME in $VGROUP\n" 0
1983 lvcreate -L "$VOLUME_SIZE" "$VGROUP" -n "$VNAME" > /dev/null 2> $ERR
1984 errshow "lvcreate -L $VOLUME_SIZE $VGROUP -n $VNAME" || return 1
1985 msg "$_lvmnew (LV:$VOL_COUNT)" "\nDone, logical volume (LV) $VNAME ($VOLUME_SIZE) has been created.\n"
1993 part_find 'part|crypt' || return 1
1994 PARTS="$(awk 'NF > 0 {print $0 " off"}' <<< "$PARTS")"
1995 dlg LVM_PARTS check "$_lvmnew" "\nSelect the partition(s) to use for the physical volume (PV)." $PARTS
2002 until [[ $VGROUP ]]; do
2003 dlg VGROUP input "$_lvmnew" "$_lvmvgname" "lvgroup"
2004 if [[ -z $VGROUP ]]; then
2006 elif [[ ${VGROUP:0:1} == "/" || $VGROUP =~ \ |\' ]] || vgdisplay | grep -q "$VGROUP"; then
2007 msg "LVM Name Error" "$_lvmerrvgname"
2017 local txt="$1" default="mainvolume"
2018 (( VOL_COUNT > 1 )) && default="extvolume$VOL_COUNT"
2019 until [[ $VNAME ]]; do
2020 dlg VNAME input "$_lvmnew (LV:$VOL_COUNT)" "\n$txt" "$default"
2021 if [[ -z $VNAME ]]; then
2023 elif [[ ${VNAME:0:1} == "/" || $VNAME =~ \ |\' ]] || lsblk | grep -q "$VNAME"; then
2024 msg "LVM Name Error" "$_lvmerlvname"
2031 ###############################################################################
2037 no_bg_install || return 1
2038 dlg choice menu "LUKS Encryption" "$_luksmenu" \
2039 "$_luksnew" "cryptsetup -q luksFormat" \
2040 "$_luksopen" "cryptsetup open --type luks" \
2041 "$_luksadv" "cryptsetup -q -s -c luksFormat" \
2042 "Back" "Return to the main menu"
2045 "$_luksnew") luks_basic || return 1 ;;
2046 "$_luksopen") luks_open || return 1 ;;
2047 "$_luksadv") luks_advanced || return 1 ;;
2055 modprobe -a dm-mod dm_crypt > /dev/null 2>&1
2057 part_find 'part|crypt|lvm' || return 1
2059 if (( COUNT == 1 )); then
2060 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2062 dlg LUKS_PART menu "$_luksopen" "\nSelect which partition to open." $PARTS
2065 [[ $LUKS_PART ]] || return 1
2067 luks_pass "$_luksopen" || return 1
2068 msg "$_luksopen" "\nOpening encrypted partition: $LUKS_NAME\n\nUsing device/volume: $LUKS_PART\n" 0
2069 cryptsetup open --type luks "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> $ERR
2070 errshow "cryptsetup open --type luks $LUKS_PART $LUKS_NAME" || return 1
2071 LUKS='encrypted'; luks_show
2079 typeset -a ans=(cryptroot) # default name to start
2081 until [[ $LUKS_PASS ]]; do
2083 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " --mixedform "$_luksomenu" 0 0 0 \
2084 "Name:" 1 1 "${ans[0]}" 1 7 "$COLUMNS" 0 0 \
2085 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
2086 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 2> "$ANS" || return 1
2088 mapfile -t ans <"$ANS"
2090 if [[ -z "${ans[0]}" ]]; then
2091 msg "Name Empty" "\nEncrypted device name cannot be empty.\n\nPlease try again.\n" 2
2092 elif [[ -z "${ans[1]}" || "${ans[1]}" != "${ans[2]}" ]]; then
2093 LUKS_NAME="${ans[0]}"
2094 msg "Password Mismatch" "\nThe passwords entered do not match.\n\nPlease try again.\n" 2
2096 LUKS_NAME="${ans[0]}"
2097 LUKS_PASS="${ans[1]}"
2107 msg "$_luksnew" "\nEncrypted partition ready for mounting.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$LUKS_PART")\n\n"
2112 modprobe -a dm-mod dm_crypt > /dev/null 2>&1
2114 part_find 'part|lvm' || return 1
2116 if [[ $AUTO_ROOT_PART ]]; then
2117 LUKS_PART="$AUTO_ROOT_PART"
2118 elif (( COUNT == 1 )); then
2119 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2121 dlg LUKS_PART menu "$_luksnew" "\nSelect the partition you want to encrypt." $PARTS
2124 [[ $LUKS_PART ]] || return 1
2125 luks_pass "$_luksnew"
2130 luks_setup || return 1
2131 msg "$_luksnew" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2132 cryptsetup -q luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2> $ERR
2133 errshow "cryptsetup -q luksFormat $LUKS_PART" || return 1
2134 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> $ERR
2135 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2136 LUKS='encrypted'; luks_show
2144 dlg cipher input "LUKS Encryption" "$_lukskey" "-s 512 -c aes-xts-plain64"
2145 [[ $cipher ]] || return 1
2146 msg "$_luksadv" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2147 cryptsetup -q $cipher luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2> $ERR
2148 errshow "cryptsetup -q $cipher luksFormat $LUKS_PART" || return 1
2149 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> $ERR
2150 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2157 ###############################################################################
2159 # some help avoid repetition and improve usability of some commands
2160 # others are initial setup functions used before reaching the main loop
2164 [[ "$2" == *"$1"* ]] && printf "on" || printf "off"
2169 # cleanup and exit the installer cleanly with exit code $1
2170 local e="$1" # when e is 127 unmount /run/archiso/bootmnt and reboot
2174 if [[ -d $MNT ]]; then
2176 if (( e == 127 )); then
2177 umount_dir /run/archiso/bootmnt && sleep 0.5 && reboot -f
2185 local var="$1" # assign output from dialog to var
2186 local dlg_t="$2" # dialog type (menu, check, input)
2187 local title="$3" # dialog title
2188 local body="$4" # dialog message
2189 local n=0 # number of items to display for menu and check dialogs
2191 shift 4 # shift off args assigned above
2193 # adjust n when passed a large list
2194 local l=$((LINES - 20))
2195 (( ($# / 2) > l )) && n=$l
2199 menu) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --menu "$body" 0 0 $n "$@" 2> "$ANS" || return 1 ;;
2200 check) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --checklist "$body" 0 0 $n "$@" 2> "$ANS" || return 1 ;;
2203 local def="$1" # assign default value for input
2205 if [[ $1 == 'limit' ]]; then
2206 dialog --backtitle "$DIST Installer - $SYS - v$VER" --max-input 63 --title " $title " --inputbox "$body" 0 0 "$def" 2> "$ANS" || return 1
2208 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --inputbox "$body" 0 0 "$def" 2> "$ANS" || return 1
2212 # if answer file isn't empty read from it into $var
2213 [[ -s "$ANS" ]] && printf -v "$var" "%s" "$(< "$ANS")"
2218 # displays a message dialog
2219 # when more than 2 args the message will disappear after sleep time ($3)
2225 dialog --backtitle "$DIST Installer - $SYS - v$VER" --sleep "$1" --title " $title " --infobox "$body\n" 0 0
2227 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --msgbox "$body\n" 0 0
2235 if ! select_keymap; then
2238 elif ! net_connect; then
2239 msg "Not Connected" "\nRunning live requires an active internet connection to install packages.\n\nExiting..\n" 2
2241 elif (( $(awk '/MemTotal/ {print int($2 / 1024)}' /proc/meminfo) < 2500)); then
2242 msg "Not Enough Memory" "\nLive session requires at least 2.5G of system memory for installing packages.\n\nExiting..\n" 2
2247 echo "Sorting mirrorlist"
2248 mount /run/archiso/cowspace -o remount,size=2G
2249 install_mirrorlist "/etc/pacman.d/mirrorlist"
2250 pacman -Syyu --noconfirm || die 1
2251 rm -rf "/var/cache/pacman/pkg/"*
2252 pacman -S $BASE_PKGS $AL_BASE_PKGS xorg-xinit --needed --noconfirm || die 1
2253 rm -rf "/var/cache/pacman/pkg/"*
2255 i3-gaps|openbox|fluxbox|bspwm|awesome|xfce4) pacman -S "$ses" $WM_BASE_PKGS ${WM_EXT[$ses]} --needed --noconfirm || die 1 ;;
2256 gnome|plasma|cinnamon) pacman -S "$ses" ${WM_EXT[$ses]} --needed --noconfirm || die 1 ;;
2257 dwm) { pacman -S git --needed --noconfirm || die 1; }; install_suckless "/root" nochroot ;;
2259 rm -rf "/var/cache/pacman/pkg/"*
2260 [[ $VM ]] && dmesg | grep -qi 'vbox' && pacman -S virtualbox-guest-utils virtualbox-guest-modules-arch --needed --noconfirm
2261 pacman -Scc --noconfirm
2262 rm -rf "/var/cache/pacman/pkg/"*
2263 cp -rfT /etc/skel /root
2264 install_tearfree_conf "/etc/X11/xorg.conf.d"
2266 plasma|gnome|cinnamon) sed -i '/super/d; /nitrogen/d; /compton/d' /root/.xprofile ;;
2267 dwm) sed -i '/super/d; /compton/d' /root/.xprofile ;;
2270 echo -e "pulseaudio &\n(sleep 1; pamixer --unmute --set-volume 50) &" >> /root/.xprofile
2271 sed -i "/exec/ c exec ${WM_SESSIONS[$ses]}" /root/.xinitrc
2272 printf "\n%s has been set as the login session in ~/.xinitrc, to start the session simply run\n\n\tstartx\n\n" "${WM_SESSIONS[$ses]}"
2279 usage: $1 [-hdl] [session]
2282 -h, --help print this message and exit
2283 -l, --live install and setup a live session
2284 -d, --debug enable xtrace and log output to $DBG
2287 i3-gaps - A fork of i3wm with more features including gaps
2288 openbox - A lightweight, powerful, and highly configurable stacking wm
2289 dwm - A dynamic WM for X that manages windows in tiled, floating, or monocle layouts
2290 awesome - A customized Awesome WM session created by @elanapan
2291 bspwm - A tiling wm that represents windows as the leaves of a binary tree
2292 fluxbox - A lightweight and highly-configurable window manager
2293 gnome - A desktop environment that aims to be simple and easy to use
2294 cinnamon - A desktop environment combining traditional desktop with modern effects
2295 plasma - A kde software project currently comprising a full desktop environment
2296 xfce4 - A lightweight and modular desktop environment based on gtk+2/3
2300 set the DIST environment variable before launching the installer eg.
2304 root/boot partition:
2306 set the ROOT_PART and/or BOOT_PART environment variables before launching the installer eg.
2308 ROOT_PART='/dev/sda2' BOOT_PART='/dev/sda1' $1
2312 set the EDITOR environment variable before launching the installer eg.
2322 local title="$1" body="$2" yes='Yes' no='No'
2323 (( $# >= 3 )) && yes="$3"
2324 (( $# >= 4 )) && no="$4"
2326 if (( $# == 5 )); then
2327 dialog --backtitle "$DIST Installer - $SYS - v$VER" --defaultno --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2329 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2335 arch-chroot "$MNT" bash -c "$1"
2340 export PS4='| ${BASH_SOURCE} LINE:${LINENO} FUNC:${FUNCNAME[0]:+ ${FUNCNAME[0]}()} |> '
2350 "\e]P0191919" # #191919
2351 "\e]P1D15355" # #D15355
2352 "\e]P2609960" # #609960
2353 "\e]P3FFCC66" # #FFCC66
2354 "\e]P4255A9B" # #255A9B
2355 "\e]P5AF86C8" # #AF86C8
2356 "\e]P62EC8D3" # #2EC8D3
2357 "\e]P7949494" # #949494
2358 "\e]P8191919" # #191919
2359 "\e]P9D15355" # #D15355
2360 "\e]PA609960" # #609960
2361 "\e]PBFF9157" # #FF9157
2362 "\e]PC4E88CF" # #4E88CF
2363 "\e]PDAF86C8" # #AF86C8
2364 "\e]PE2ec8d3" # #2ec8d3
2365 "\e]PFE1E1E1" # #E1E1E1
2368 [[ $TERM == 'linux' ]] && printf "%b" "${colors[@]}" && clear
2373 [ $? -eq 0 ] && return 0
2375 local fatal=0 err=""
2376 err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
2377 [[ -z $err ]] && err="no error message was found"
2379 (( $1 == 1 )) && { fatal=1; shift; }
2381 local txt="\nCommand: $1\n\n\n\nError: $err\n\n"
2383 if (( fatal )); then
2384 msg "Install Error" "${txt}Errors at this stage are fatal, the install cannot continue.\n"
2385 [[ -r $DBG && $TERM == 'linux' ]] && less "$DBG"
2389 msg "Install Error" "${txt}Errors at this stage are non-fatal and may be fixed or ignored depending on the error.\n"
2397 if (( $1 >= 0 )) && ! grep -qw "$MNT" /proc/mounts; then
2398 msg "Not Mounted" "\nPartition(s) must be mounted first.\n" 2
2400 elif [[ $1 -ge 1 && -z $BOOTLDR ]]; then
2401 msg "No Bootloader" "\nBootloader must be selected first.\n" 2
2403 elif [[ $1 -ge 2 && (-z $NEWUSER || -z $USER_PASS) ]]; then
2404 msg "No User" "\nA user must be created first.\n" 2
2406 elif [[ $1 -ge 3 && -z $CONFIG_DONE ]]; then
2407 msg "Not Configured" "\nSystem configuration must be done first.\n" 2
2410 (( i )) # return code
2415 mount | grep -q 'swap' && swapoff -a
2417 if [[ -d $dir ]] && mount | grep -q "on $dir "; then
2418 if ! umount "$dir" 2> /dev/null; then
2420 umount -f "$dir" 2> /dev/null || umount -l "$dir"
2428 msg "Network Connect" "\nVerifying network connection\n" 0
2429 curl -sIN --connect-timeout 5 'https://www.archlinux.org/' | sed '1q' | grep -q '200'
2434 if chk_connect; then
2436 elif hash nmtui > /dev/null 2>&1; then
2438 if [[ $TERM == 'linux' ]]; then
2439 printf "%b" "\e]P1191919" "\e]P4191919"
2441 printf "%b" "\e]P1D15355" "\e]P4255a9b"
2446 elif hash wifi-menu > /dev/null 2>&1; then
2456 [[ $BG_PID ]] || return 0
2457 msg "Install Running" "\nA background install process is currently running.\n" 2
2463 IGNORE_DEV="$(lsblk -lno NAME,MOUNTPOINT | awk '/\/run\/archiso\/bootmnt/ {sub(/[1-9]/, ""); print $1}')"
2465 if [[ $IGNORE_DEV ]]; then
2466 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ && !'"/$IGNORE_DEV/"' {print "/dev/" $1 " " $2}')"
2468 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ {print "/dev/" $1 " " $2}')"
2471 if [[ -z $SYS_DEVS ]]; then
2472 msg "Device Error" "\nNo available devices...\n\nExiting..\n" 2
2477 while read -r line; do
2479 done <<< "$SYS_DEVS"
2486 # amd-ucode is not needed it's provided by linux-firmware
2487 # elif grep -q 'AuthenticAMD' /proc/cpuinfo; then
2489 elif grep -q 'GenuineIntel' /proc/cpuinfo; then
2493 modprobe -q efivarfs > /dev/null 2>&1
2495 _prep="\nOnce a step is finished a step you will be returned here, if the step was successful the cursor will be advanced to the next step.\nIf a step is unsuccessful the cursor will be placed on the step required to advance (when possible).\n\nSteps beginning with an asterix (*) are required before continuing.\n\nTo begin the install you should have:\n\n - A root (/) partition mounted."
2496 if [[ -d /sys/firmware/efi/efivars ]]; then
2498 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars
2499 _prep+="\n - An EFI boot partition mounted."
2503 _prep+="\n\nOnce finished mounting, a portion of the install can be done in the background while you continue configuring the system:\n"
2504 _prep+="\n - Choose the system bootloader.\n - Create a user and password."
2505 _prep+="\n - Basic system configuration, kernel, shell, login, packages, etc..\n\nOnce you're happy with the choices and the required steps are complete, the main install can be started."
2508 ###############################################################################
2511 # enable some nicer colours in the linux console
2514 if (( UID != 0 )); then
2515 msg "Not Root" "\nThis installer must be run as root or using sudo.\n\nExiting..\n" 2
2517 elif ! grep -qwm 1 'lm' /proc/cpuinfo; then
2518 msg "Not x86_64 Architecture" "\nThis installer only supports x86_64 architectures.\n\nExiting..\n" 2
2522 # trap ^C to perform cleanup
2523 trap 'printf "\n^C\n" && die 1' INT
2525 while getopts ":hl:d" OPT; do
2530 if [[ "${!WM_SESSIONS[@]}" =~ $OPTARG ]]; then
2533 echo "error: invalid session for -l, see -h for help"; die 1
2536 \?) echo "error: invalid option: -$OPTARG"; die 1 ;;
2543 msg "Welcome to the $DIST Installer" "$_welcome"
2545 if ! select_keymap; then
2547 elif ! net_connect; then
2548 msg "Not Connected" "\nThis installer requires an active internet connection.\n\nExiting..\n" 2
2555 # vim:fdm=marker:fmr={,}