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, Cnichi, Calamares, Arch Wiki.. Credit where credit is due
10 # bulk default values {
12 : ${DIST=ArchLabs} # distro name if not set
13 MNT=/mnt # install mountpoint
14 ANS=/tmp/ans # dialog answer file
15 BOOTDIR=boot # location to mount boot partition
16 FONT=ter-i16n # font used for the linux console
17 HOOKS=shutdown # list of additional mkinitcpio HOOKS
18 SEL=0 # currently selected menu item
19 SYS=Unknown # bios type to be determined: UEFI/BIOS
20 ERR=/tmp/errlog # error log used internally
21 DBG=/tmp/debuglog # debug log when passed -d
22 RUN=/run/archiso/bootmnt/arch/boot # path for live system /boot
23 VM="$(dmesg | grep -i hypervisor)" # system running in a virtual machine
24 export DIALOGOPTS="--cr-wrap" # see `man dialog`
26 BASE_PKGS="base xorg xorg-drivers sudo git gvfs gtk3 libmad libmatroska tumbler "
27 BASE_PKGS+="playerctl pulseaudio pulseaudio-alsa pavucontrol pamixer scrot xdg-user-dirs "
28 BASE_PKGS+="ffmpeg gstreamer gst-libav gst-plugins-base gst-plugins-good bash-completion xterm"
30 AL_BASE_PKGS="archlabs-keyring archlabs-icons archlabs-fonts archlabs-themes "
31 AL_BASE_PKGS+="archlabs-baph archlabs-wallpapers archlabs-scripts archlabs-skel-base"
33 WM_BASE_PKGS="arandr nitrogen polkit-gnome network-manager-applet "
34 WM_BASE_PKGS+="volumeicon xclip exo laptop-detect xdotool compton wmctrl feh "
35 WM_BASE_PKGS+="gnome-keyring dunst gsimplecal xfce4-power-manager xfce4-settings"
37 SYS_MEM="$(awk '/MemTotal/ {print int($2 / 1024) "M"}' /proc/meminfo)"
38 LOCALES="$(awk '/\.UTF-8/ {gsub(/# .*|#/, ""); if ($1) {print $1 " - "}}' /etc/locale.gen)"
39 CMAPS="$(find /usr/share/kbd/keymaps -name '*.map.gz' | awk '{gsub(/\.map\.gz|.*\//, ""); print $1 " - "}' | sort)"
41 [[ $LINES ]] || LINES=$(tput lines)
42 [[ $COLUMNS ]] || COLUMNS=$(tput cols)
46 # commands used to install each bootloader, however most get modified during runtime {
48 [refind-efi]='refind-install'
49 [grub]='grub-install --recheck --force' [syslinux]='syslinux-install_update -i -a -m'
50 [efistub]='efibootmgr -v -d /dev/sda -p 1 -c -l' [systemd-boot]='bootctl --path=/boot install'
53 # executable name for each wm/de used in ~/.xinitrc {
54 declare -A WM_SESSIONS=(
55 [dwm]='dwm' [i3-gaps]='i3' [bspwm]='bspwm' [awesome]='awesome' [plasma]='startkde' [xfce4]='startxfce4'
56 [gnome]='gnome-session' [fluxbox]='startfluxbox' [openbox]='openbox-session' [cinnamon]='cinnamon-session'
59 # packages installed for each wm/de, most are depends of the skel packages {
61 [dwm]='' [gnome]='' [cinnamon]='gnome-terminal' [plasma]='kdebase-meta'
62 [awesome]='archlabs-skel-awesome' [bspwm]='archlabs-skel-bspwm' [fluxbox]='archlabs-skel-fluxbox'
63 [i3-gaps]='archlabs-skel-i3-gaps' [openbox]='archlabs-skel-openbox' [xfce4]='archlabs-skel-xfce4 xfce4-goodies'
66 # files offered for editing after install is complete {
67 declare -A EDIT_FILES=(
68 [login]='' # login is populated once we know the username and shell
69 [fstab]='/etc/fstab' [sudoers]='/etc/sudoers' [crypttab]='/etc/crypttab' [pacman]='/etc/pacman.conf'
70 [console]='/etc/vconsole.conf' [mkinitcpio]='/etc/mkinitcpio.conf' [hostname]='/etc/hostname /etc/hosts'
71 [bootloader]="/boot/loader/entries/$DIST.conf" # ** based on bootloader
72 [locale]='/etc/locale.conf /etc/default/locale' [keyboard]='/etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard'
75 # mkfs command flags for filesystem formatting {
76 declare -A FS_CMD_FLAGS=(
77 [f2fs]='' [jfs]='-q' [xfs]='-f' [ntfs]='-q' [ext2]='-q' [ext3]='-q' [ext4]='-q' [vfat]='-F32' [nilfs2]='-q' [reiserfs]='-q'
80 # mount options for each filesystem {
82 [vfat]='' [ntfs]='' [ext2]='' [ext3]='' # NA
83 [jfs]='discard errors=continue errors=panic nointegrity'
84 [reiserfs]='acl nolog notail replayonly user_xattr off'
85 [ext4]='discard dealloc nofail noacl relatime noatime nobarrier nodelalloc'
86 [xfs]='discard filestreams ikeep largeio noalign nobarrier norecovery noquota wsync'
87 [nilfs2]='discard nobarrier errors=continue errors=panic order=relaxed order=strict norecovery'
88 [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'
91 # packages installed for each login option {
92 declare -A LOGIN_PKGS=(
93 [xinit]='xorg-xinit' [ly]='archlabs-ly' [gdm]='gdm' [sddm]='sddm'
94 [lightdm]='lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings accountsservice'
97 # extras installed for user selected packages {
98 # if a package requires additional packages that aren't already dependencies
99 # they can be added here eg. [package]="extra"
101 [vlc]='qt4' [mpd]='mpc' [mupdf]='mupdf-tools'
102 [rxvt-unicode]='urxvt-pearls' [zathura]='zathura-pdf-poppler' [noto-fonts]='noto-fonts-emoji' [cairo-dock]='cairo-dock-plug-ins' [qt5ct]='qt5-styleplugins'
103 [vlc]='qt5ct qt5-styleplugins' [qutebrowser]='qt5ct qt5-styleplugins' [qbittorrent]='qt5ct qt5-styleplugins' [transmission-qt]='qt5ct qt5-styleplugins'
104 [bluez]='bluez-libs bluez-utils bluez-tools bluez-plugins bluez-hid2hci' [kdenlive]='kdebase-meta dvdauthor frei0r-plugins breeze breeze-gtk qt5ct qt5-styleplugins'
107 # dialog text variables {
108 # Basics (somewhat in order)
109 _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"
110 _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"
111 _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"
112 _device="\nSelect a device to use from the list below.\n\nDevices (/dev) are the available drives on the system. /sda, /sdb, /sdc ..."
113 _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."
114 _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."
115 _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"
116 _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)."
117 _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."
118 _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."
119 _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."
120 _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"
121 _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."
122 _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."
123 _exmnt="\nWhere do you want the partition mounted?\n\nEnsure the name begins with a slash (/).\nExamples include: /usr, /home, /var, etc."
124 _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."
125 _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."
126 _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"
127 _timez="\nThe time zone is used to set the system clock.\n\nSelect your country or continent from the list below"
128 _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."
129 _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."
130 _login="\nSelect which of your session choices to use for the initial login.\n\nYou can be change this later by editing your ~/.xinitrc"
131 _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"
132 _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."
133 _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."
136 _luksnew="Basic LUKS Encryption"
137 _luksadv="Advanced LUKS Encryption"
138 _luksopen="Open Existing LUKS Partition"
139 _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."
140 _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."
141 _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)."
144 _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."
145 _lvmnew="Create Volume Group and Volume(s)"
146 _lvmdel="Delete an Existing Volume Group"
147 _lvmdelall="Delete ALL Volume Group(s) and Volume(s)"
148 _lvmvgname="\nEnter a name for the volume group (VG) being created from the partition(s) selected."
149 _lvmlvname="\nEnter a name for the logical volume (LV) being created.\n\nThis is similar to setting a label for a partition."
150 _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."
151 _lvmdelask="\nConfirm deletion of volume group(s) and logical volume(s).\n\nDeleting a volume group, will delete all logical volumes within it.\n"
154 _errexpart="\nCannot mount partition due to a problem with the mountpoint.\n\nEnsure it begins with a slash (/) followed by atleast one character.\n"
155 _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"
156 _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"
157 _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"
158 _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"
159 _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"
160 _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"
164 ###############################################################################
166 # main is the entry point which calls functions including outside of its block
167 # once those functions finished they always are returned here with the
168 # exception of install_main(), it exits upon completion
172 (( SEL < 12 )) && (( SEL++ ))
174 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Prepare " --default-item $SEL --cancel-label 'Exit' --menu "$_prep" 0 0 0 \
175 1 "Device tree (optional)" \
176 2 "Partitioning (optional)" \
177 3 "LUKS setup (optional)" \
178 4 "LVM setup (optional)" \
179 5 "Mount partitions" \
180 6 "System bootloader" \
181 7 "User and password" \
182 8 "System configuration" \
183 9 "Select WM/DE (optional)" \
184 10 "Select Packages (optional)" \
185 11 "View configuration (optional)" \
186 12 "Start the installation" 2>"$ANS"
189 [[ -z $WARN && $SEL =~ (2|5) ]] && { msg "Data Warning" "$_warn"; WARN=true; }
192 2) part_menu || (( SEL-- )) ;;
193 3) luks_menu || (( SEL-- )) ;;
194 4) lvm_menu || (( SEL-- )) ;;
195 5) mount_menu || (( SEL-- )) ;;
196 6) prechecks 0 && { select_boot || (( SEL-- )); } ;;
197 7) prechecks 1 && { select_mkuser || (( SEL-- )); } ;;
198 8) prechecks 2 && { select_config || (( SEL-- )); } ;;
199 9) prechecks 3 && { select_sessions || (( SEL-- )); } ;;
200 10) prechecks 3 && { select_packages || (( SEL-- )); } ;;
201 11) prechecks 3 && select_show ;;
202 12) prechecks 3 && install_main ;;
203 *) yesno "Exit" "\nUnmount partitions (if any) and exit the installer?\n" && die 0
209 if [[ $SYS == 'BIOS' ]]; then
210 dlg BOOTLDR menu "BIOS Bootloader" "\nSelect which bootloader to use." \
211 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
212 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network" || return 1
214 dlg BOOTLDR menu "UEFI Bootloader" "\nSelect which bootloader to use." \
215 "systemd-boot" "A simple UEFI boot manager which executes configured EFI images" \
216 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
217 "refind-efi" "A UEFI boot manager that aims to be platform neutral and simplify multi-boot" \
218 "efistub" "Boot the kernel image directly (no chainloading support)" \
219 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network (no chainloading support)" || return 1
226 local pkgs="${USER_PKGS// / } ${PACKAGES// / }"
227 [[ $INSTALL_WMS == *dwm* ]] && pkgs="dwm st dmenu $pkgs"
228 pkgs="${pkgs// / }" pkgs="${pkgs# }"
229 msg "Show Configuration" "
230 ---------- PARTITION CONFIGURATION ------------
232 Root Part: $ROOT_PART
233 Boot Part: ${BOOT_PART:-none}
234 Boot Device: ${BOOT_DEV:-none}
235 Swap Part/File: ${SWAP_PART:-none}
236 Swap Size: ${SWAP_SIZE:-none}
237 Extra Mounts: ${EXMNTS:-none}
238 Mkinit Hooks: ${HOOKS:-none}
240 LVM used: ${LVM:-none}
241 LUKS used: ${LUKS:-none}
243 ------------ SYSTEM CONFIGURATION -------------
245 Locale: ${MYLOCALE:-none}
246 Keymap: ${KEYMAP:-none}
247 Hostname: ${MYHOST:-none}
248 Timezone: ${ZONE:-none}/${SUBZ:-none}
250 ------------ USER CONFIGURATION ---------------
252 Username: ${NEWUSER:-none}
253 Login Shell: ${MYSHELL:-none}
254 Login Session: ${LOGIN_WM:-none}
255 Autologin: ${AUTOLOGIN:-none}
256 Login Type: ${LOGIN_TYPE:-none}
258 ----------- PACKAGE CONFIGURATION -------------
260 Kernel: ${KERNEL:-none}
261 Bootloader: ${BOOTLDR:-none}
262 Packages: ${pkgs:-none}
268 [[ $INSTALL_WMS ]] || return 0
270 AUTOLOGIN='' # no autologin unless using xinit
272 dlg LOGIN_TYPE menu "Login Management" "\nSelect what kind of login management to use." \
273 "xinit" "Console login without a display manager" \
274 "ly" "TUI display manager with a ncurses-like interface" \
275 "lightdm" "Lightweight display manager with a gtk greeter" \
276 "gdm" "Gnome display manager" \
277 "sddm" "Simple desktop display manager" || return 1
280 ly) EDIT_FILES[login]="/etc/ly/config.ini" ;;
281 gdm|sddm) EDIT_FILES[login]="" ;;
282 lightdm) EDIT_FILES[login]="/etc/lightdm/lightdm.conf /etc/lightdm/lightdm-gtk-greeter.conf" ;;
283 xinit) EDIT_FILES[login]="/home/$NEWUSER/.xinitrc /home/$NEWUSER/.xprofile"
284 if (( $(wc -w <<< "$INSTALL_WMS") > 1 )); then
285 dlg LOGIN_WM menu "Login Management" "$_login" $LOGIN_CHOICES || return 1
286 LOGIN_WM="${WM_SESSIONS[$LOGIN_WM]}"
288 [[ -z $LOGIN_WM ]] && LOGIN_WM="${WM_SESSIONS[${INSTALL_WMS%% *}]}"
289 yesno "Autologin" "$(sed "s|USER|$NEWUSER|g; s|RC|$LOGINRC|g" <<< "$_autologin")" && AUTOLOGIN=true || AUTOLOGIN=''
299 until [[ $CONFIG_DONE ]]; do
301 0) dlg MYSHELL menu "Shell" "\nChoose which shell to use." \
302 zsh 'A very advanced and programmable command interpreter (shell) for UNIX' \
303 bash 'The GNU Bourne Again shell, standard in many GNU/Linux distributions' \
304 mksh 'The MirBSD Korn Shell - an enhanced version of the public domain ksh' || return 1
306 1) dlg MYHOST input "Hostname" "$_hostname" "${DIST,,}" limit || { i=0; continue; } ;;
307 2) dlg MYLOCALE menu "Locale" "$_locale" $LOCALES || { i=1; continue; } ;;
309 until [[ $ZONE && $SUBZ ]]; do
310 dlg ZONE menu "Timezone" "$_timez" America - Australia - Asia - Atlantic - Africa - Europe - Indian - Pacific - Arctic - Antarctica - || break
311 dlg SUBZ menu "Timezone" "$_timesubz" $(awk '/'"$ZONE"'\// {gsub(/'"$ZONE"'\//, ""); print $3 " - "}' /usr/share/zoneinfo/zone.tab | sort) || continue
313 [[ $ZONE && $SUBZ ]] || { i=2; continue; } ;;
314 4) dlg KERNEL menu "Kernel" "\nChoose which kernel to use." \
315 linux 'Vanilla linux kernel and modules, with a few patches applied' \
316 linux-lts 'Long-term support (LTS) linux kernel and modules' \
317 linux-zen 'A effort of kernel hackers to provide the best kernel for everyday systems' \
318 linux-hardened 'A security-focused linux kernel with hardening patches to mitigate exploits' || { i=3; continue; }
322 (( i++ )) # progress through to the next choice
326 bash) LOGINRC='.bash_profile' ;;
327 zsh) LOGINRC='.zprofile' ;;
328 mksh) LOGINRC='.profile' ;;
339 until [[ $NEWUSER ]]; do
341 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " User " --mixedform "$_user" 0 0 0 \
342 "Username:" 1 1 "${ans[0]}" 1 11 "$COLUMNS" 0 0 \
343 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
344 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 \
345 "--- Root password, if left empty the user password will be used ---" 6 1 '' 6 68 "$COLUMNS" 0 2 \
346 "Password:" 8 1 '' 8 11 "$COLUMNS" 0 1 \
347 "Password2:" 9 1 '' 9 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
349 mapfile -t ans <"$ANS"
351 # root passwords empty, so use the user passwords
352 if [[ -z "${ans[4]}" && -z "${ans[5]}" ]]; then
357 # make sure a username was entered and that the passwords match
358 if [[ -z ${ans[0]} || ${ans[0]} =~ \ |\' || ${ans[0]} =~ [^a-z0-9] ]]; then
359 msg "Invalid Username" "\nInvalid user name.\n\nPlease try again.\n"; u=''
360 elif [[ -z "${ans[1]}" || "${ans[1]}" != "${ans[2]}" ]]; then
361 msg "Password Mismatch" "\nThe user passwords do not match.\n\nPlease try again.\n"
362 elif [[ "${ans[4]}" != "${ans[5]}" ]]; then
363 msg "Password Mismatch" "\nThe root passwords do not match.\n\nPlease try again.\n"
366 USER_PASS="${ans[1]}"
367 ROOT_PASS="${ans[4]}"
375 dlg KEYMAP menu "Keyboard Layout" "$_keymap" \
376 us English cm English gb English au English gh English \
377 za English ng English ca French 'cd' French gn French \
378 tg French fr French de German at German ch German \
379 es Spanish latam Spanish br Portuguese pt Portuguese ma Arabic \
380 sy Arabic ara Arabic ua Ukrainian cz Czech ru Russian \
381 sk Slovak nl Dutch it Italian hu Hungarian cn Chinese \
382 tw Taiwanese vn Vietnamese kr Korean jp Japanese th Thai \
383 la Lao pl Polish se Swedish is Icelandic 'fi' Finnish \
384 dk Danish be Belgian in Indian al Albanian am Armenian \
385 bd Bangla ba Bosnian 'bg' Bulgarian dz Berber mm Burmese \
386 hr Croatian gr Greek il Hebrew ir Persian iq Iraqi \
387 af Afghani fo Faroese ge Georgian ee Estonian kg Kyrgyz \
388 kz Kazakh lt Lithuanian mt Maltese mn Mongolian ro Romanian \
389 no Norwegian rs Serbian si Slovenian tj Tajik lk Sinhala \
390 tr Turkish uz Uzbek ie Irish pk Urdu 'mv' Dhivehi \
391 np Nepali et Amharic sn Wolof ml Bambara tz Swahili \
392 ke Swahili bw Tswana ph Filipino my Malay tm Turkmen \
393 id Indonesian bt Dzongkha lv Latvian md Moldavian mao Maori \
394 by Belarusian az Azerbaijani mk Macedonian kh Khmer epo Esperanto \
395 me Montenegrin || return 1
397 if [[ $CMAPS == *"$KEYMAP"* ]]; then
400 dlg CMAP menu "Console Keymap" "$_vconsole" $CMAPS || return 1
403 if [[ $TERM == 'linux' ]]; then
404 loadkeys "$CMAP" >/dev/null 2>&1
406 setxkbmap "$KEYMAP" >/dev/null 2>&1
415 dlg INSTALL_WMS check "Sessions" "$_sessions\n" \
416 openbox "A lightweight, powerful, and highly configurable stacking wm" "$(ofn openbox "${INSTALL_WMS[*]}")" \
417 i3-gaps "A fork of i3wm with more features including gaps" "$(ofn i3-gaps "${INSTALL_WMS[*]}")" \
418 dwm "A dynamic WM for X that manages windows in tiled, floating, or monocle layouts" "$(ofn dwm "${INSTALL_WMS[*]}")" \
419 bspwm "A tiling wm that represents windows as the leaves of a binary tree" "$(ofn bspwm "${INSTALL_WMS[*]}")" \
420 xfce4 "A lightweight and modular desktop environment based on gtk+2/3" "$(ofn xfce4 "${INSTALL_WMS[*]}")" \
421 awesome "A customized Awesome WM session created by @elanapan" "$(ofn awesome "${INSTALL_WMS[*]}")" \
422 fluxbox "A lightweight and highly-configurable window manager" "$(ofn fluxbox "${INSTALL_WMS[*]}")" \
423 plasma "A kde software project currently comprising a full desktop environment" "$(ofn plasma "${INSTALL_WMS[*]}")" \
424 gnome "A desktop environment that aims to be simple and easy to use" "$(ofn gnome "${INSTALL_WMS[*]}")" \
425 cinnamon "A desktop environment combining traditional desktop with modern effects" "$(ofn cinnamon "${INSTALL_WMS[*]}")"
427 [[ $INSTALL_WMS ]] || return 0
429 WM_PKGS="${INSTALL_WMS/dwm/}" # remove dwm from package list
430 WM_PKGS="${WM_PKGS// / }" # remove double spaces
431 WM_PKGS="${WM_PKGS# }" # remove leading space
433 for i in $INSTALL_WMS; do
434 LOGIN_CHOICES+="$i - "
435 [[ ${WM_EXT[$i]} && $WM_PKGS != *"${WM_EXT[$i]}"* ]] && WM_PKGS+=" ${WM_EXT[$i]}"
438 select_login || return 1
440 while IFS=' ' read -r pkg; do
441 [[ $PACKAGES != *"$pkg"* ]] && PACKAGES+=" $pkg"
449 dlg USER_PKGS check " Packages " "$_packages" \
450 abiword "A Fully-featured word processor" "$(ofn abiword "${USER_PKGS[*]}")" \
451 alacritty "A cross-platform, GPU-accelerated terminal emulator" "$(ofn alacritty "${USER_PKGS[*]}")" \
452 atom "An open-source text editor developed by GitHub" "$(ofn atom "${USER_PKGS[*]}")" \
453 audacious "A free and advanced audio player based on GTK+" "$(ofn audacious "${USER_PKGS[*]}")" \
454 audacity "A program that lets you manipulate digital audio waveforms" "$(ofn audacity "${USER_PKGS[*]}")" \
455 blueman "GUI bluetooth device manager" "$(ofn blueman "${USER_PKGS[*]}")" \
456 bluez "Simple CLI based bluetooth support" "$(ofn bluez "${USER_PKGS[*]}")" \
457 cairo-dock "Light eye-candy fully themable animated dock" "$(ofn cairo-dock "${USER_PKGS[*]}")" \
458 calligra "A set of applications for productivity" "$(ofn calligra "${USER_PKGS[*]}")" \
459 chromium "An open-source web browser based on the Blink rendering engine" "$(ofn chromium "${USER_PKGS[*]}")" \
460 clementine "A modern music player and library organizer" "$(ofn clementine "${USER_PKGS[*]}")" \
461 cmus "A small, fast and powerful console music player" "$(ofn cmus "${USER_PKGS[*]}")" \
462 deadbeef "A GTK+ audio player for GNU/Linux" "$(ofn deadbeef "${USER_PKGS[*]}")" \
463 deluge "A BitTorrent client written in python" "$(ofn deluge "${USER_PKGS[*]}")" \
464 emacs "An extensible, customizable, self-documenting real-time display editor" "$(ofn emacs "${USER_PKGS[*]}")" \
465 epiphany "A GNOME web browser based on the WebKit rendering engine" "$(ofn epiphany "${USER_PKGS[*]}")" \
466 evince "A document viewer" "$(ofn evince "${USER_PKGS[*]}")" \
467 evolution "Manage your email, contacts and schedule" "$(ofn evolution "${USER_PKGS[*]}")" \
468 file-roller "Create and modify archives" "$(ofn file-roller "${USER_PKGS[*]}")" \
469 firefox "A popular open-source web browser from Mozilla" "$(ofn firefox "${USER_PKGS[*]}")" \
470 gcolor2 "A simple GTK+2 color selector" "$(ofn gcolor2 "${USER_PKGS[*]}")" \
471 geany "A fast and lightweight IDE" "$(ofn geany "${USER_PKGS[*]}")" \
472 geary "A lightweight email client for the GNOME desktop" "$(ofn geary "${USER_PKGS[*]}")" \
473 gimp "GNU Image Manipulation Program" "$(ofn gimp "${USER_PKGS[*]}")" \
474 gnome-calculator "GNOME Scientific calculator" "$(ofn gnome-calculator "${USER_PKGS[*]}")" \
475 gnome-disk-utility "Disk Management Utility" "$(ofn gnome-disk-utility "${USER_PKGS[*]}")" \
476 gnome-system-monitor "View current processes and monitor system state" "$(ofn gnome-system-monitor "${USER_PKGS[*]}")" \
477 gparted "A GUI frontend for creating and manipulating partition tables" "$(ofn gparted "${USER_PKGS[*]}")" \
478 gpick "Advanced color picker using GTK+ toolkit" "$(ofn gpick "${USER_PKGS[*]}")" \
479 gpicview "Lightweight image viewer" "$(ofn gpicview "${USER_PKGS[*]}")" \
480 guvcview "Capture video from camera devices" "$(ofn guvcview "${USER_PKGS[*]}")" \
481 hexchat "A popular and easy to use graphical IRC client" "$(ofn hexchat "${USER_PKGS[*]}")" \
482 inkscape "Professional vector graphics editor" "$(ofn inkscape "${USER_PKGS[*]}")" \
483 irssi "Modular text mode IRC client" "$(ofn irssi "${USER_PKGS[*]}")" \
484 kdenlive "A popular non-linear video editor for Linux" "$(ofn kdenlive "${USER_PKGS[*]}")" \
485 krita "Edit and paint images" "$(ofn krita "${USER_PKGS[*]}")" \
486 libreoffice-fresh "Full featured office suite" "$(ofn libreoffice-fresh "${USER_PKGS[*]}")" \
487 lollypop "A new music playing application" "$(ofn lollypop "${USER_PKGS[*]}")" \
488 mousepad "A simple text editor" "$(ofn mousepad "${USER_PKGS[*]}")" \
489 mpd "A flexible, powerful, server-side application for playing music" "$(ofn mpd "${USER_PKGS[*]}")" \
490 mpv "A media player based on mplayer" "$(ofn mpv "${USER_PKGS[*]}")" \
491 mupdf "Lightweight PDF and XPS viewer" "$(ofn mupdf "${USER_PKGS[*]}")" \
492 mutt "Small but very powerful text-based mail client" "$(ofn mutt "${USER_PKGS[*]}")" \
493 nautilus "The default file manager for Gnome" "$(ofn nautilus "${USER_PKGS[*]}")" \
494 ncmpcpp "A mpd client and almost exact clone of ncmpc with some new features" "$(ofn ncmpcpp "${USER_PKGS[*]}")" \
495 neovim "A fork of Vim aiming to improve user experience, plugins, and GUIs." "$(ofn neovim "${USER_PKGS[*]}")" \
496 noto-fonts "Google Noto fonts" "$(ofn noto-fonts "${USER_PKGS[*]}")" \
497 noto-fonts-cjk "Google Noto CJK fonts (Chinese, Japanese, Korean)" "$(ofn noto-fonts-cjk "${USER_PKGS[*]}")" \
498 obs-studio "Free opensource streaming/recording software" "$(ofn obs-studio "${USER_PKGS[*]}")" \
499 openshot "An open-source, non-linear video editor for Linux" "$(ofn openshot "${USER_PKGS[*]}")" \
500 opera "A Fast and secure, free of charge web browser from Opera Software" "$(ofn opera "${USER_PKGS[*]}")" \
501 pcmanfm "A fast and lightweight file manager based in Lxde" "$(ofn pcmanfm "${USER_PKGS[*]}")" \
502 pidgin "Multi-protocol instant messaging client" "$(ofn pidgin "${USER_PKGS[*]}")" \
503 plank "An elegant, simple, and clean dock" "$(ofn plank "${USER_PKGS[*]}")" \
504 qbittorrent "An advanced BitTorrent client" "$(ofn qbittorrent "${USER_PKGS[*]}")" \
505 qpdfview "A tabbed PDF viewer" "$(ofn qpdfview "${USER_PKGS[*]}")" \
506 qt5ct "GUI for managing Qt based application themes, icons, and fonts" "$(ofn qt5ct "${USER_PKGS[*]}")" \
507 qutebrowser "A keyboard-focused vim-like web browser based on Python and PyQt5" "$(ofn qutebrowser "${USER_PKGS[*]}")" \
508 rhythmbox "A Music playback and management application" "$(ofn rhythmbox "${USER_PKGS[*]}")" \
509 rxvt-unicode "A unicode enabled rxvt-clone terminal emulator" "$(ofn rxvt-unicode "${USER_PKGS[*]}")" \
510 sakura "A terminal emulator based on GTK and VTE" "$(ofn sakura "${USER_PKGS[*]}")" \
511 simple-scan "Simple scanning utility" "$(ofn simple-scan "${USER_PKGS[*]}")" \
512 simplescreenrecorder "A feature-rich screen recorder" "$(ofn simplescreenrecorder "${USER_PKGS[*]}")" \
513 steam "A popular game distribution platform by Valve" "$(ofn steam "${USER_PKGS[*]}")" \
514 surf "A simple web browser based on WebKit2/GTK+" "$(ofn surf "${USER_PKGS[*]}")" \
515 terminator "Terminal emulator that supports tabs and grids" "$(ofn terminator "${USER_PKGS[*]}")" \
516 termite "A minimal VTE-based terminal emulator" "$(ofn termite "${USER_PKGS[*]}")" \
517 thunar "A modern file manager for the Xfce Desktop Environment" "$(ofn thunar "${USER_PKGS[*]}")" \
518 thunderbird "Standalone mail and news reader from mozilla" "$(ofn thunderbird "${USER_PKGS[*]}")" \
519 tilda "A GTK based drop down terminal for Linux and Unix" "$(ofn tilda "${USER_PKGS[*]}")" \
520 tilix "A tiling terminal emulator for Linux using GTK+ 3" "$(ofn tilix "${USER_PKGS[*]}")" \
521 transmission-cli "Free BitTorrent client CLI" "$(ofn transmission-cli "${USER_PKGS[*]}")" \
522 transmission-gtk "GTK+ Front end for transmission" "$(ofn transmission-gtk "${USER_PKGS[*]}")" \
523 transmission-qt "Qt Front end for transmission" "$(ofn transmission-qt "${USER_PKGS[*]}")" \
524 ttf-anonymous-pro "A family fixed-width fonts designed with code in mind" "$(ofn ttf-anonymous-pro "${USER_PKGS[*]}")" \
525 ttf-fira-code "Monospaced font with programming ligatures" "$(ofn ttf-fira-code "${USER_PKGS[*]}")" \
526 ttf-font-awesome "Iconic font designed for Bootstrap" "$(ofn ttf-font-awesome "${USER_PKGS[*]}")" \
527 ttf-hack "A hand groomed typeface based on Bitstream Vera Mono" "$(ofn ttf-hack "${USER_PKGS[*]}")" \
528 vlc "A free and open source cross-platform multimedia player" "$(ofn vlc "${USER_PKGS[*]}")" \
529 weechat "Fast, light and extensible IRC client" "$(ofn weechat "${USER_PKGS[*]}")" \
530 xapps "Common library for X-Apps project" "$(ofn xapps "${USER_PKGS[*]}")" \
531 xarchiver "A GTK+ frontend to various command line archivers" "$(ofn xarchiver "${USER_PKGS[*]}")" \
532 xed "A small and lightweight text editor. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
533 xfce4-terminal "A terminal emulator based in the Xfce Desktop Environment" "$(ofn xfce4-terminal "${USER_PKGS[*]}")" \
534 xreader "Document viewer for files like PDF and Postscript. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
535 zathura "Minimalistic document viewer" "$(ofn zathura "${USER_PKGS[*]}")"
537 if [[ $USER_PKGS ]]; then # add any needed PKG_EXT to the list
538 for i in $USER_PKGS; do
539 [[ ${PKG_EXT[$i]} && $USER_PKGS != *"${PKG_EXT[$i]}"* ]] && USER_PKGS+=" ${PKG_EXT[$i]}"
546 ###############################################################################
548 # non-essential partitioning helpers called by the user when using the optional
549 # partition menu and selecting a device to edit
553 no_bg_install || return 0
554 local device choice devhash
555 devhash="$(lsblk -f | base64)"
557 part_device || return 1
562 dlg choice menu "Edit Partitions" "$_part\n\n$(lsblk -no NAME,MODEL,SIZE,TYPE,FSTYPE $device)" \
563 "auto" "Whole device automatic partitioning" \
564 "shrink" "Shrink an existing ext or ntfs partition" \
565 "cfdisk" "Curses based variant of fdisk" \
566 "parted" "GNU partition editor" \
567 "fdisk" "Dialog-driven creation and manipulation of partitions" \
568 "done" "Return to the main menu"
570 if [[ -z $choice || $choice == 'done' ]]; then
572 elif [[ $choice == 'shrink' ]]; then
573 part_shrink "$device"
574 elif [[ $choice == 'auto' ]]; then
575 local root_size txt table boot_fs
576 root_size=$(lsblk -lno SIZE "$device" | awk 'NR == 1 {
579 print ($1 * 1000 - 512) / 1000 "G"
585 txt="\nWARNING:\n\nALL data on $device will be destroyed and the following partitions will be created\n\n- "
586 if [[ $SYS == 'BIOS' ]]; then
587 table="msdos" boot_fs="ext4"
588 txt+="An $boot_fs boot partition with the boot flag enabled (512M)\n- "
590 table="gpt" boot_fs="fat32"
591 txt+="A $boot_fs efi boot partition (512M)\n- "
593 txt+="An ext4 partition using all remaining space ($root_size)\n\nDo you want to continue?\n"
594 yesno "Auto Partition" "$txt" && part_auto "$device" "$table" "$boot_fs" "$root_size"
600 if [[ $devhash != "$(lsblk -f | base64)" ]]; then
601 msg "Probing Partitions" "\nInforming kernel of partition changes using partprobe\n" 0
602 partprobe >/dev/null 2>&1
603 [[ $choice == 'auto' ]] && return
611 if [[ $IGNORE_DEV ]]; then
612 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk "!/$IGNORE_DEV/"' && /disk|part|lvm|crypt|NAME/')"
614 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk '/disk|part|lvm|crypt|NAME/')"
616 msg "Device Tree" "\n\n$txt\n\n"
621 local device="$1" table="$2" boot_fs="$3" size="$4" dev_info=""
623 msg "Auto Partition" "\nRemoving partitions on $device and setting table to $table\n" 1
625 dev_info="$(parted -s "$device" print)"
628 while read -r PART; do
629 parted -s "$device" rm "$PART" >/dev/null 2>&1
630 done <<< "$(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r)"
632 [[ $(awk '/Table:/ {print $3}' <<< "$dev_info") != "$table" ]] && parted -s "$device" mklabel "$table" >/dev/null 2>&1
634 msg "Auto Partition" "\nCreating a 512M $boot_fs boot partition.\n" 1
635 if [[ $SYS == "BIOS" ]]; then
636 parted -s "$device" mkpart primary "$boot_fs" 1MiB 513MiB >/dev/null 2>&1
638 parted -s "$device" mkpart ESP "$boot_fs" 1MiB 513MiB >/dev/null 2>&1
643 AUTO_BOOT_PART=$(lsblk -lno NAME,TYPE "$device" | awk 'NR==2 {print "/dev/" $1}')
645 if [[ $SYS == "BIOS" ]]; then
646 mkfs.ext4 -q "$AUTO_BOOT_PART" >/dev/null 2>&1
648 mkfs.vfat -F32 "$AUTO_BOOT_PART" >/dev/null 2>&1
651 msg "Auto Partition" "\nCreating a $size ext4 root partition.\n" 0
652 parted -s "$device" mkpart primary ext4 513MiB 100% >/dev/null 2>&1
654 AUTO_ROOT_PART="$(lsblk -lno NAME,TYPE "$device" | awk 'NR==3 {print "/dev/" $1}')"
655 mkfs.ext4 -q "$AUTO_ROOT_PART" >/dev/null 2>&1
657 msg "Auto Partition" "\nProcess complete.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$device")\n"
664 local device="$1" fs=""
666 part_find "${device##*/}[^ ]" || return 1
667 (( COUNT == 1 )) && part="$(awk '{print $1}' <<< "${PARTS[@]}" )"
669 if (( COUNT == 1 )) || dlg part menu "Resize" "\nWhich partition on $device do you want to resize?" $PARTS; then
670 fs=$(lsblk -lno FSTYPE "$part")
673 msg "Resize" "\nGathering device size info.\n" 0
675 end=$(parted -s "$device" unit KiB print | awk '/^\s*'"$num"'/ {print $3}') # part size in KiB
676 devsize=$(parted -s "$device" unit KiB print | awk '/Disk '"${device//\//\\/}"':/ {print $3}') # whole device size in KiB
677 mount "$part" "$MNT" >/dev/null 2>&1; sleep 0.5
678 min=$(df --output=used --block-size=MiB "$part" | awk 'NR == 2 {print int($1) + 256}')
679 max=$(df --output=avail --block-size=MiB "$part" | awk 'NR == 2 {print int($1)}')
682 if dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Resize: $part " --rangebox "$_resize" 17 "$COLUMNS" "$min" "$max" $((max / 2)) 2>$ANS; then
684 size=$((size * 1024))
691 if ntfsresize -fc "$part"; then
692 ntfsresize -ff --size $(( (size * 1024) / 1000 ))k "$part" 2>$ERR # k=10^3 bytes
693 errshow "ntfsresize -f -s $(( (size * 1024) / 1000 ))k $part" || return 1
695 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"
700 e2fsck -f "$part"; sleep 0.5
701 resize2fs -f "$part" ${size}K 2>$ERR # K=2^10 bytes
702 errshow "resize2fs -f $part ${size}K" || return 1
706 parted "$device" resizepart "$num" ${size}KiB || return 1
709 if [[ $devsize == "$end" ]]; then
710 parted -s "$device" mkpart primary ext4 ${size}KiB 100% 2>$ERR
711 errshow "parted -s $device mkpart primary ext4 ${size}KiB 100%" || return 1
713 parted -s "$device" mkpart primary ext4 ${size}KiB ${end}KiB 2>$ERR
714 errshow "parted -s $device mkpart primary ext4 ${size}KiB ${end}KiB" || return 1
716 msg "Resize Complete" "\n$part has been successfully resized to $((size / 1024))M.\n" 1
718 "") msg "No Filesystem" "\nFor unformatted partitions, cfdisk can be used in the partition menu.\n" ;;
719 *) msg "Invalid Filesystem: $fs" "\nResizing only supports ext and ntfs.\n" ;;
724 ###############################################################################
725 # partition management functions
726 # these are helpers for use by other functions to do essential setup/teardown
730 local regexp="$1" err=''
732 # string of partitions as /TYPE/PART SIZE.. eg. /dev/sda1 256G
733 if [[ $IGNORE_DEV ]]; then
734 PARTS="$(lsblk -lno TYPE,NAME,SIZE | awk "/$regexp/"' && !'"/$IGNORE_DEV/"' {sub(/^part/, "/dev/"); sub(/^lvm|^crypt/, "/dev/mapper/"); print $1$2, $3}')"
736 PARTS="$(lsblk -lno TYPE,NAME,SIZE | awk "/$regexp/"' {sub(/^part/, "/dev/"); sub(/^lvm|^crypt/, "/dev/mapper/"); print $1$2 " " $3}')"
739 # ensure we have enough partitions for the system and action were trying to do
740 COUNT=$(wc -l <<< "$PARTS")
742 'part|lvm|crypt') [[ $COUNT -lt 1 || ($SYS == 'UEFI' && $COUNT -lt 2) ]] && err="$_errpart" ;;
743 'part|crypt') (( COUNT < 1 )) && err="$_lvmerr" ;;
744 'part|lvm') (( COUNT < 2 )) && err="$_lukserr" ;;
748 msg "Not Enough Partitions" "$err" 2
757 if [[ $1 == "$MNT/swapfile" && $SWAP_SIZE ]]; then
758 fallocate -l $SWAP_SIZE "$1" 2>$ERR
759 errshow "fallocate -l $SWAP_SIZE $1"
760 chmod 600 "$1" 2>$ERR
761 errshow "chmod 600 $1"
763 mkswap "$1" >/dev/null 2>$ERR
765 swapon "$1" >/dev/null 2>$ERR
772 local part="$1" mountp="${MNT}$2" fs=""
773 fs="$(lsblk -lno FSTYPE "$part")"
776 if [[ $fs && ${FS_OPTS[$fs]} && $part != "$BOOT_PART" && $part != "$AUTO_ROOT_PART" ]] && select_mntopts "$fs"; then
777 mount -o "$MNT_OPTS" "$part" "$mountp" >/dev/null 2>&1
779 mount "$part" "$mountp" >/dev/null 2>&1
782 part_mountconf "$part" "$mountp" || return 1
790 local part="$1" fs="$2" delay="$3"
792 msg "Format" "\nFormatting $part as $fs\n" 0
793 mkfs.$fs ${FS_CMD_FLAGS[$fs]} "$part" >/dev/null 2>$ERR
794 errshow "mkfs.$fs ${FS_CMD_FLAGS[$fs]} "$part"" || return 1
801 if [[ $DEV_COUNT -eq 1 && $SYS_DEVS ]]; then
802 DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
803 elif (( DEV_COUNT > 1 )); then
805 dlg DEVICE menu "Boot Device" "\nSelect the device to use for bootloader install." $SYS_DEVS
807 dlg DEVICE menu "Select Device" "$_device" $SYS_DEVS
809 [[ $DEVICE ]] || return 1
810 elif [[ $DEV_COUNT -lt 1 && ! $1 ]]; then
811 msg "Device Error" "\nNo available devices.\n\nExiting..\n" 2
815 [[ $1 ]] && BOOT_DEV="$DEVICE"
822 BOOT_DEV="${BOOT_PART%[1-9]}"
823 BOOT_PART_NUM="${BOOT_PART: -1}"
824 [[ $BOOT_PART = /dev/nvme* ]] && BOOT_DEV="${BOOT_PART%p[1-9]}"
825 if [[ $SYS == 'UEFI' ]]; then
826 parted -s $BOOT_DEV set $BOOT_PART_NUM esp on >/dev/null 2>&1
828 parted -s $BOOT_DEV set $BOOT_PART_NUM boot on >/dev/null 2>&1
835 local part="$1" devs=""
836 devs="$(lsblk -lno NAME,FSTYPE,TYPE)"
838 # Identify if $part is LUKS+LVM, LVM+LUKS, LVM alone, or LUKS alone
839 if lsblk -lno TYPE "$part" | grep -q 'crypt'; then
841 LUKS_NAME="${part#/dev/mapper/}"
842 for dev in $(awk '/lvm/ && /crypto_LUKS/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
843 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
844 LUKS_DEV="$LUKS_DEV cryptdevice=$dev:$LUKS_NAME"
849 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
850 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
851 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
852 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
856 elif lsblk -lno TYPE "$part" | grep -q 'lvm'; then
858 VNAME="${part#/dev/mapper/}"
859 for dev in $(awk '/crypt/ && /lvm2_member/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
860 if lsblk -lno NAME "$dev" | grep -q "$VNAME"; then
861 LUKS_NAME="${dev/\/dev\/mapper\//}"
865 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
866 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
867 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
868 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
879 if (( COUNT > 0 )); then
880 PARTS="$(sed "/${pt//\//\\/}/d" <<< "$PARTS")"
888 if grep -qw "$1" /proc/mounts; then
889 msg "Mount Success" "\nPartition $1 mounted at $2\n" 1
893 msg "Mount Fail" "\nPartition $1 failed to mount at $2\n" 2
898 ###############################################################################
900 # mount_menu is the entry point which calls all other functions
901 # once finished it returns to the main menu: main()
905 no_bg_install || return 0
908 part_find 'part|lvm|crypt' || { SEL=2; return 1; }
909 [[ $LUKS && $LUKS_PART ]] && part_countdec $LUKS_PART
910 [[ $LVM && $LVM_PARTS ]] && part_countdec $LVM_PARTS
911 select_root_partition || { ROOT_PART=''; return 1; }
912 select_boot_partition || { BOOT_PART=''; return 1; }
913 if [[ $BOOT_PART ]]; then
914 part_mount "$BOOT_PART" "/$BOOTDIR" && SEP_BOOT=true || return 1
917 select_swap || return 1
918 select_extra_partitions || return 1
925 local pts dev size isize
927 while read -r dev size; do # walk partition list and skip ones that are too small/big for swap
928 size_t="${size: -1:1}"
931 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 16) || ($size_t == 'M' && $isize -lt 100) ]] || pts+="$dev $size "
934 dlg SWAP_PART menu "Swap Setup" "\nSelect whether to use a swapfile, swap partition, or none." \
935 "none" "Don't allocate any swap space" \
936 "swapfile" "Allocate $SYS_MEM at /swapfile" \
939 if [[ -z $SWAP_PART || $SWAP_PART == "none" ]]; then
942 elif [[ $SWAP_PART == "swapfile" ]]; then
944 until [[ ${SWAP_SIZE:0:1} =~ [1-9] && ${SWAP_SIZE: -1} =~ (M|G) ]]; do
945 (( 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
946 dlg SWAP_SIZE input "Swap Setup" "$_swapsize" "$SYS_MEM" || { SWAP_PART=''; SWAP_SIZE=''; return 1; }
949 part_swap "$MNT/$SWAP_PART"
950 SWAP_PART="/$SWAP_PART"
951 elif [[ $PARTS == *"$SWAP_PART"* ]]; then
953 part_countdec $SWAP_PART
954 SWAP_SIZE="$(lsblk -lno SIZE $SWAP_PART)"
964 local fs="$1" opts=''
965 local title="${fs^} Mount Options"
967 for i in ${FS_OPTS[$fs]}; do
971 until [[ $MNT_OPTS ]]; do
972 dlg MNT_OPTS check "$title" "$_mount" $opts
973 [[ $MNT_OPTS ]] || return 1
974 MNT_OPTS="${MNT_OPTS// /,}"
975 yesno "$title" "\nConfirm the following options: $MNT_OPTS\n" || MNT_OPTS=''
984 until [[ $EXMNT ]]; do
985 dlg EXMNT input "Extra Mount $part" "$_exmnt" "/" || return 1
986 if [[ ${EXMNT:0:1} != "/" || ${#EXMNT} -le 1 || $EXMNT =~ \ |\' || $EXMNTS == *"$EXMNT"* ]]; then
987 msg "Mountpoint Error" "$_errexpart"
991 msg "Mount Extra" "\nMounting Finished\n\n\nNo extra partitions available to mount, returning to main menu.\n" 2
997 local part="$1" fs='' cur=''
998 local txt="\nSelect which filesystem to use for: $part\n\nDefault: ext4"
999 cur="$(lsblk -lno FSTYPE "$part" 2>/dev/null)"
1001 # bail early if the partition was created in part_auto()
1002 [[ $cur && $part == "$AUTO_ROOT_PART" ]] && return 0
1005 if [[ $cur && $FORMATTED == *"$part"* ]]; then
1006 dlg fs menu "Filesystem" "$txt\nCurrent: $cur" skip - ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1008 dlg fs menu "Filesystem" "$txt" ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1010 [[ $fs == 'skip' ]] && return 0
1011 yesno "Filesystem" "\nFormat $part as $fs?\n" || fs=''
1013 part_format "$part" "$fs" 0
1016 select_boot_partition()
1018 local pts dev size isize ptcount=0
1020 if [[ -z $BOOT_PART ]]; then
1021 if [[ $AUTO_BOOT_PART && -z $LVM && -z $LUKS ]]; then
1022 BOOT_PART="$AUTO_BOOT_PART"
1025 while read -r dev size; do # walk partition list and skip ones that are too small/big for boot
1026 size_t="${size: -1:1}"
1029 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1035 0) msg "EFI Boot Partition" "\nNo partitions available that meet size requirements!!\n\nReturning to the main menu.\n" 2; return 1 ;;
1036 1) msg "EFI Boot Partition" "\nOnly one partition available that meets size requirements.\n" 1; BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")" ;;
1037 *) dlg BOOT_PART menu "EFI Partition" "$_uefi" $pts ;;
1039 [[ $BOOT_PART ]] || return 1
1042 (( ptcount == 0 )) && return 0
1043 if [[ $LUKS && ! $LVM ]]; then
1044 dlg BOOT_PART menu "Boot Partition" "$_biosluks" $pts
1045 [[ $BOOT_PART ]] || return 1
1047 dlg BOOT_PART menu "Boot Partition" "$_bios" "skip" "no separate boot" $pts
1048 [[ -z $BOOT_PART || $BOOT_PART == "skip" ]] && { BOOT_PART=''; return 0; }
1055 if ([[ $SYS == 'BIOS' ]] && grep -q 'ext[34]' <<< "$(fsck -N "$BOOT_PART")") || ([[ $SYS == 'UEFI' ]] && grep -q 'fat' <<< "$(fsck -N "$BOOT_PART")"); then
1056 yesno "Format Boot Partition" "\nIMPORTANT:\n\nThe boot partition $BOOT_PART $_format" "Format $BOOT_PART" "Skip Formatting" 1 || return 0
1060 UEFI) part_format "$BOOT_PART" "vfat" 2 || return 1 ;;
1061 BIOS) part_format "$BOOT_PART" "ext4" 2 || return 1 ;;
1066 select_root_partition()
1068 if [[ -z $ROOT_PART ]]; then
1069 if [[ $AUTO_ROOT_PART && -z $LVM && -z $LUKS ]]; then
1070 ROOT_PART="$AUTO_ROOT_PART"
1071 msg "Mount Menu" "\nUsing partitions created during automatic format.\n" 2
1072 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1073 return 0 # we're done here
1075 local pts dev size isize ptcount=0
1077 # walk partition list and skip ones that are too small for / (root)
1078 while read -r dev size; do
1079 size_t="${size: -1:1}" # size type eg. K, M, G, T
1080 isize=${size:0:-1} # remove trailing size type character
1081 isize=${isize%.*} # remove any decimal (round down)
1082 [[ $size_t =~ [MK] || ($size_t == 'G' && $isize -lt 4) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1085 if (( ptcount == 1 )); then # only one available device
1086 msg "Root Partition (/)" "\nOnly one partition available that meets size requirements.\n" 2
1087 ROOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")"
1089 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
1094 if [[ -z $ROOT_PART ]] || ! select_filesystem "$ROOT_PART" || ! part_mount "$ROOT_PART"; then
1101 select_extra_partitions()
1105 # walk partition list and skip ones that are too small to be usable
1106 while read -r dev size; do
1107 [[ ${size: -1:1} =~ [KM] ]] && part_countdec "$dev"
1110 while (( COUNT > 0 )); do
1112 dlg part menu 'Mount Extra' "$_expart" 'done' 'finish mounting step' $PARTS || break
1113 if [[ $part == 'done' ]]; then
1115 elif select_filesystem "$part" && select_mountpoint && part_mount "$part" "$EXMNT"; then
1116 EXMNTS+="$part: $EXMNT "
1117 [[ $EXMNT == '/usr' && $HOOKS != *usr* ]] && HOOKS+=" usr"
1125 ###############################################################################
1127 # main is the entry point which calls all other install functions, once
1128 # complete it shows a dialog to edit files on the new system before reboot
1133 genfstab -U "$MNT" >"$MNT/etc/fstab" 2>$ERR 2>&1
1134 errshow 1 "genfstab -U $MNT >$MNT/etc/fstab"
1135 [[ -f $MNT/swapfile ]] && sed -i "s~${MNT}~~" "$MNT/etc/fstab"
1139 chrun "hwclock --systohc --utc" || chrun "hwclock --systohc --utc --directisa"
1142 chrun "chown -Rf $NEWUSER:users /home/$NEWUSER"
1145 dlg choice menu "Finalization" "$_edit" \
1146 finished "exit the installer and reboot" \
1147 keyboard "${EDIT_FILES[keyboard]}" \
1148 console "${EDIT_FILES[console]}" \
1149 locale "${EDIT_FILES[locale]}" \
1150 hostname "${EDIT_FILES[hostname]}" \
1151 sudoers "${EDIT_FILES[sudoers]}" \
1152 mkinitcpio "${EDIT_FILES[mkinitcpio]}" \
1153 fstab "${EDIT_FILES[fstab]}" \
1154 crypttab "${EDIT_FILES[crypttab]}" \
1155 bootloader "${EDIT_FILES[bootloader]}" \
1156 pacman "${EDIT_FILES[pacman]}" \
1157 login "${EDIT_FILES[login]}"
1159 if [[ -z $choice || $choice == 'finished' ]]; then
1160 [[ $DEBUG == true && -r $DBG ]] && ${EDITOR:-vim} $DBG
1164 for f in ${EDIT_FILES[$choice]}; do
1165 [[ -e ${MNT}$f ]] && exists+=" ${MNT}$f"
1167 if [[ $exists ]]; then
1168 ${EDITOR:-vim} -O $exists
1170 msg "File Missing" "\nThe file(s) selected do not exist:\n\n${EDIT_FILES[$choice]}\n"
1180 while kill -0 $BG_PID 2>/dev/null; do
1181 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
1188 sed -i 's/#\(Storage=\)volatile/\1auto/' "$MNT/etc/systemd/journald.conf"
1189 find "$MNT/boot" -name '*-ucode.img' -delete
1191 [[ $DIST != "ArchLabs" ]] || sed -i "s/ArchLabs/$DIST/g" "$MNT/etc/"{lsb-release,os-release}
1194 echo "Virtual machine detected, removing xorg configs"
1195 find "$MNT/etc/X11/xorg.conf.d/" -name '*.conf' -delete -printf "remove %p\n"
1196 elif lspci | grep ' VGA ' | grep -q 'Intel'; then
1197 echo "Creating Intel Tear Free config /etc/X11/xorg.conf.d/20-intel.conf"
1198 cat > "$MNT/etc/X11/xorg.conf.d/20-intel.conf" <<- EOF
1200 Identifier "Intel Graphics"
1202 Option "TearFree" "true"
1205 elif lspci | grep ' VGA ' | grep -q 'AMD/ATI.*RX'; then # newer RX cards can use the amdgpu driver
1206 echo "Creating AMD Tear Free config /etc/X11/xorg.conf.d/20-amdgpu.conf"
1207 cat > "$MNT/etc/X11/xorg.conf.d/20-amdgpu.conf" <<- EOF
1209 Identifier "AMD Graphics"
1211 Option "TearFree" "true"
1214 elif lspci | grep ' VGA ' | grep -q 'AMD/ATI.*HD [2-6][0-9]*'; then # older HD 2xxx-6xxx cards must use the radeon driver
1215 echo "Creating Radeon Tear Free config /etc/X11/xorg.conf.d/20-radeon.conf"
1216 cat > "$MNT/etc/X11/xorg.conf.d/20-radeon.conf" <<- EOF
1218 Identifier "AMD Graphics"
1220 Option "TearFree" "on"
1225 if [[ -e /run/archiso/sfs/airootfs ]]; then
1226 cp -vf "$RUN/x86_64/vmlinuz" "$MNT/boot/vmlinuz-linux" 2>$ERR 2>&1
1227 errshow 1 "cp -vf $RUN/x86_64/vmlinuz $MNT/boot/vmlinuz-linux"
1229 [[ -d /etc/netctl ]] && cp -rfv /etc/netctl "$MNT/etc/"
1230 [[ -f /etc/resolv.conf ]] && cp -fv /etc/resolv.conf "$MNT/etc/"
1231 [[ -e /etc/NetworkManager/system-connections ]] && cp -rvf /etc/NetworkManager/system-connections "$MNT/etc/NetworkManager/"
1233 echo "LANG=$MYLOCALE" > "$MNT/etc/locale.conf"
1234 cp -fv "$MNT/etc/locale.conf" "$MNT/etc/default/locale"
1235 sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${MYLOCALE}/${MYLOCALE}/g" "$MNT/etc/locale.gen"
1237 chrun "ln -svf /usr/share/zoneinfo/$ZONE/$SUBZ /etc/localtime"
1239 cat > "$MNT/etc/X11/xorg.conf.d/00-keyboard.conf" <<- EOF
1240 # Use localectl(1) to instruct systemd-localed to update it.
1241 Section "InputClass"
1242 Identifier "system-keyboard"
1243 MatchIsKeyboard "on"
1244 Option "XkbLayout" "$KEYMAP"
1248 cat > "$MNT/etc/default/keyboard" <<- EOF
1249 # KEYBOARD CONFIGURATION FILE
1250 # Consult the keyboard(5) manual page.
1257 printf "KEYMAP=%s\nFONT=%s\n" "$CMAP" "$FONT" > "$MNT/etc/vconsole.conf"
1258 echo "$MYHOST" > "$MNT/etc/hostname"
1259 cat > "$MNT/etc/hosts" <<- EOF
1262 ::1 localhost ip6-localhost ip6-loopback
1263 ff02::1 ip6-allnodes
1264 ff02::2 ip6-allrouters
1270 echo "Installing $BOOTLDR"
1272 if [[ $ROOT_PART == /dev/mapper* ]]; then
1273 ROOT_PART_ID="$ROOT_PART"
1275 local uuid_type="UUID"
1276 [[ $BOOTLDR =~ (systemd-boot|refind-efi|efistub) ]] && uuid_type="PARTUUID"
1277 ROOT_PART_ID="$uuid_type=$(blkid -s $uuid_type -o value $ROOT_PART)"
1280 if [[ $SYS == 'UEFI' ]]; then
1281 # remove our old install and generic BOOT/ dir
1282 echo "Removing conflicting boot directories"
1283 find "$MNT/$BOOTDIR/EFI/" -maxdepth 1 -mindepth 1 -iname "$DIST" -type d -delete -printf "remove %p\n"
1284 find "$MNT/$BOOTDIR/EFI/" -maxdepth 1 -mindepth 1 -iname 'BOOT' -type d -delete -printf "remove %p\n"
1288 chrun "${BCMDS[$BOOTLDR]}" 2>$ERR 2>&1
1289 errshow 1 "${BCMDS[$BOOTLDR]}"
1291 if [[ -d $MNT/hostrun ]]; then
1292 echo "Unmounting chroot directories"
1293 # cleanup the bind mounts we made earlier for the grub-probe module
1294 umount_dir "$MNT/hostrun/"{udev,lvm}
1295 rm -rf "$MNT/hostrun" >/dev/null 2>&1
1298 if [[ $SYS == 'UEFI' ]]; then
1299 # some UEFI firmware requires a generic esp/BOOT/BOOTX64.EFI
1300 mkdir -pv "$MNT/$BOOTDIR/EFI/BOOT"
1302 grub) cp -fv "$MNT/$BOOTDIR/EFI/$DIST/grubx64.efi" "$MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI" ;;
1303 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" ;;
1304 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"
1305 cp -fv "$MNT/$BOOTDIR/EFI/refind/refind_x64.efi" "$MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI" ;;
1314 local groups='audio,floppy,log,network,rfkill,scanner,storage,optical,power,wheel'
1316 rm -f "$MNT/root/.zshrc" # remove welcome message from root zshrc
1318 chrun "chpasswd <<< 'root:$ROOT_PASS'" 2>$ERR 2>&1
1319 errshow 1 "set root password"
1320 if [[ $MYSHELL != 'zsh' ]]; then # root uses zsh by default
1321 chrun "usermod -s /bin/$MYSHELL root" 2>$ERR 2>&1
1322 errshow 1 "usermod -s /bin/$MYSHELL root"
1323 # copy the default mkshrc to /root if it was selected
1324 [[ $MYSHELL == 'mksh' ]] && cp -fv "$MNT/etc/skel/.mkshrc" "$MNT/root/.mkshrc"
1327 echo "Creating new user $NEWUSER and setting password"
1328 chrun "useradd -m -u 1000 -g users -G $groups -s /bin/$MYSHELL $NEWUSER" 2>$ERR 2>&1
1329 errshow 1 "useradd -m -u 1000 -g users -G $groups -s /bin/$MYSHELL $NEWUSER"
1330 chrun "chpasswd <<< '$NEWUSER:$USER_PASS'" 2>$ERR 2>&1
1331 errshow 1 "set $NEWUSER password"
1333 chrun "pamixer --unmute; gtk-update-icon-cache /usr/share/icons/ArchLabs-Dark /usr/share/icons/ArchLabs-Light /usr/share/icons/ArchLabs"
1335 if [[ $INSTALL_WMS == *dwm* ]];then
1336 install_suckless "/home/$NEWUSER" chroot
1337 [[ $INSTALL_WMS == 'dwm' ]] && rm -rf "$MNT/home/$NEWUSER/.config/xfce4"
1340 [[ $INSTALL_WMS != *bspwm* && $INSTALL_WMS != *openbox* ]] && rm -rf "$MNT/home/$NEWUSER/.config/"{jgmenu,tint2}
1341 [[ $USER_PKGS != *geany* ]] && rm -rf "$MNT/home/$NEWUSER/.config/geany"
1342 [[ $MYSHELL != 'bash' ]] && rm -rf "$MNT/home/$NEWUSER/.bash"*
1343 [[ $MYSHELL != 'zsh' ]] && rm -rf "$MNT/home/$NEWUSER/.z"*
1345 # remove some commands from ~/.xprofile when using KDE or Gnome as the login session
1346 if [[ $LOGIN_WM =~ (startkde|gnome-session) || ($LOGIN_TYPE != 'xinit' && $WM_PKGS =~ (plasma|gnome)) ]]; then
1347 sed -i '/super/d; /nitrogen/d; /compton/d' "$MNT/home/$NEWUSER/.xprofile" "$MNT/root/.xprofile"
1348 elif [[ $LOGIN_WM == 'dwm' ]]; then # and dwm
1349 sed -i '/super/d; /compton/d' "$MNT/home/$NEWUSER/.xprofile" "$MNT/root/.xprofile"
1352 # create user home directories (Music, Documents, Downloads, etc..)
1353 chrun 'xdg-user-dirs-update'
1360 local serv="$MNT/etc/systemd/system/getty@tty1.service.d"
1361 echo "Setting up $LOGIN_TYPE"
1363 ly|sddm|gdm|lightdm)
1364 if [[ $LOGIN_WM == *dwm* ]]; then # dwm doesn't include an xsession file for display managers
1365 mkdir -p "$MNT/usr/share/xsessions"
1366 cat >"$MNT/usr/share/xsessions/dwm.desktop" <<- EOF
1370 Comment=Dynamic Window Manager
1375 rm -rf "$serv" "$MNT/home/$NEWUSER/.xinitrc"
1376 chrun "systemctl enable $LOGIN_TYPE.service" 2>$ERR 2>&1
1377 errshow 1 "systemctl enable $LOGIN_TYPE.service"
1378 ${LOGIN_TYPE}_config
1381 if [[ $INSTALL_WMS ]]; then
1382 sed -i "/exec/ c exec ${LOGIN_WM}" "$MNT/home/$NEWUSER/.xinitrc"
1383 elif [[ -e $MNT/home/$NEWUSER/.xinitrc ]]; then
1384 sed -i '/exec/d' "$MNT/home/$NEWUSER/.xinitrc"
1387 if [[ $AUTOLOGIN ]]; then
1388 sed -i "s/root/${NEWUSER}/g" $serv/autologin.conf
1389 cat > "$MNT/home/$NEWUSER/$LOGINRC" <<- EOF
1390 # automatically run startx when logging in on tty1
1391 [ -z "\$DISPLAY" ] && [ \$XDG_VTNR -eq 1 ] && startx
1403 local inpkg="$PACKAGES $USER_PKGS $AL_BASE_PKGS "
1405 if pacman -Qq archlabs-installer >/dev/null 2>&1; then
1406 rmpkg+="archlabs-installer "
1409 if [[ $MYSHELL == 'zsh' ]]; then
1410 inpkg+="zsh-completions "
1415 if [[ $INSTALL_WMS == 'dwm' ]]; then # dwm only needs a very limited package set
1416 inpkg+="nitrogen polkit-gnome gnome-keyring dunst "
1418 [[ $INSTALL_WMS =~ (plasma|gnome|cinnamon) ]] || inpkg+="archlabs-ksuperkey "
1419 [[ $INSTALL_WMS =~ (openbox|bspwm|i3-gaps|fluxbox) ]] && inpkg+="$WM_BASE_PKGS "
1422 # update and install crucial packages first to avoid issues
1423 chrun "pacman -Syyu $KERNEL $BASE_PKGS base-devel ${LOGIN_PKGS[$LOGIN_TYPE]} $MYSHELL --noconfirm --needed" 2>$ERR 2>&1
1424 errshow 1 "pacman -Syyu $KERNEL $BASE_PKGS base-devel ${LOGIN_PKGS[$LOGIN_TYPE]} $MYSHELL --noconfirm --needed"
1426 # remove the packages we don't want on the installed system
1427 [[ $rmpkg ]] && chrun "pacman -Rnsc $rmpkg --noconfirm"
1429 # reinstalling iputils fixes the network issue for non-root users
1430 chrun "pacman -S iputils $UCODE --noconfirm"
1432 # install the packages chosen throughout the install
1433 chrun "pacman -S $inpkg --needed --noconfirm" 2>$ERR 2>&1
1434 errshow 1 "pacman -S $inpkg --needed --noconfirm"
1436 # bootloader packages
1437 if [[ $BOOTLDR == 'grub' ]]; then
1438 [[ $SYS == 'UEFI' ]] && local efib="efibootmgr"
1439 chrun "pacman -S os-prober grub $efib --needed --noconfirm" 2>$ERR 2>&1
1440 errshow 1 "pacman -S os-prober grub $efib --needed --noconfirm"
1441 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1442 chrun "pacman -S refind-efi efibootmgr --needed --noconfirm" 2>$ERR 2>&1
1443 errshow 1 "pacman -S refind-efi efibootmgr --needed --noconfirm"
1444 elif [[ $SYS == 'UEFI' ]]; then
1445 chrun "pacman -S efibootmgr --needed --noconfirm" 2>$ERR 2>&1
1446 errshow 1 "pacman -S efibootmgr --needed --noconfirm"
1449 # allow members of the wheel group to run commands as root
1450 sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" "$MNT/etc/sudoers"
1455 install_mkinitcpio()
1458 [[ $LUKS ]] && add="encrypt"
1459 [[ $LVM ]] && { [[ $add ]] && add+=" lvm2" || add+="lvm2"; }
1460 sed -i "s/block filesystems/block ${add} filesystems ${HOOKS}/g" "$MNT/etc/mkinitcpio.conf"
1461 chrun "mkinitcpio -p $KERNEL" 2>$ERR 2>&1
1462 errshow 1 "mkinitcpio -p $KERNEL"
1465 install_mirrorlist()
1467 if hash reflector >/dev/null 2>&1; then
1468 reflector --verbose --score 80 -l 40 -f 5 --sort rate --save "$1"
1469 elif hash rankmirrors >/dev/null 2>&1; then
1470 echo "Sorting mirrorlist"
1471 local key="access_key=5f29642060ab983b31fdf4c2935d8c56"
1472 ip_add="$(curl -fsSL "http://api.ipstack.com/check&?$key&fields=ip" | python -c "import sys, json; print(json.load(sys.stdin)['ip'])")"
1473 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'])")"
1474 if [[ "$country" ]]; then
1475 if [[ $country =~ (CA|US) ]]; then
1476 # use both CA and US mirrors for CA or US countries
1477 mirror="https://www.archlinux.org/mirrorlist/?country=US&country=CA&use_mirror_status=on"
1478 elif [[ $country =~ (AU|NZ) ]]; then
1479 # use both AU and NZ mirrors for AU or NZ countries
1480 mirror="https://www.archlinux.org/mirrorlist/?country=AU&country=NZ&use_mirror_status=on"
1482 mirror="https://www.archlinux.org/mirrorlist/?country=${country}&use_mirror_status=on"
1484 else # no country code so just grab all mirrors, will be a very slow sort but we don't have other options
1485 mirror="https://www.archlinux.org/mirrorlist/?country=all&use_mirror_status=on"
1487 curl -fsSL "$mirror" | sed -e 's/^#Server/Server/' -e '/^#/d' | rankmirrors -n 6 - >"$1"
1493 install_background()
1495 ( rsync -a /run/archiso/sfs/airootfs/ "$MNT/" && install_mirrorlist "$MNT/etc/pacman.d/mirrorlist" >/dev/null 2>&1 ) &
1497 trap "kill $BG_PID 2>/dev/null" EXIT
1502 local dir="$1/suckless"
1505 if [[ $2 == 'chroot' ]]; then
1506 chrun "mkdir -pv '$dir'"
1507 for i in dwm dmenu st; do
1508 if chrun "git clone 'https://git.suckless.org/$i' '$dir/$i'"; then
1509 chrun "cd '$dir/$i' && make PREFIX=/usr install"
1511 printf "failed to clone %s repo\n" "$i"
1516 for i in dwm dmenu st; do
1517 if git clone "https://git.suckless.org/$i" "$dir/$i"; then
1518 cd "$dir/$i" && make PREFIX=/usr install
1520 printf "failed to clone %s repo\n" "$i"
1526 ###############################################################################
1527 # display manager config
1528 # these are called based on which DM is chosen after it is installed
1529 # additional config can be handled here, for now only lightdm has one
1533 cat > "$MNT/etc/lightdm/lightdm-gtk-greeter.conf" <<- EOF
1535 default-user-image=/usr/share/icons/ArchLabs-Dark/64x64/places/distributor-logo-archlabs.png
1536 background=/usr/share/backgrounds/archlabs/archlabs.jpg
1537 theme-name=Adwaita-dark
1538 icon-theme-name=Adwaita
1539 font-name=DejaVu Sans Mono 11
1540 position=30%,end 50%,end
1559 ###############################################################################
1561 # prerun_* set up the configs needed before actually running the commands
1562 # setup_* are run after selecting a bootloader and build the command used later
1563 # they can also be used for further user input as these run before control is taken away
1567 EDIT_FILES[bootloader]="/etc/default/grub"
1569 if [[ $SYS == 'BIOS' ]]; then
1570 [[ $BOOT_DEV ]] || { part_device 1 || return 1; }
1571 BCMDS[grub]="grub-install --recheck --force --target=i386-pc $BOOT_DEV"
1573 BCMDS[grub]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1574 grub-install --recheck --force --target=x86_64-efi --efi-directory=/$BOOTDIR --bootloader-id=$DIST"
1575 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1578 BCMDS[grub]="mkdir -p /run/udev /run/lvm &&
1579 mount --bind /hostrun/udev /run/udev &&
1580 mount --bind /hostrun/lvm /run/lvm &&
1582 grub-mkconfig -o /boot/grub/grub.cfg &&
1583 sleep 1 && umount /run/udev /run/lvm"
1590 sed -i "s/GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR=\"${DIST}\"/g; s/GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"\"/g" "$MNT/etc/default/grub"
1592 if [[ $LUKS_DEV ]]; then
1593 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
1594 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"
1597 if [[ $SYS == 'BIOS' && $LVM && -z $SEP_BOOT ]]; then
1598 sed -i "s/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g" "$MNT/etc/default/grub" 2>$ERR 2>&1
1599 errshow 1 "sed -i 's/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g' $MNT/etc/default/grub"
1602 # setup for os-prober module
1603 mkdir -p /run/{lvm,udev} "$MNT/hostrun/"{lvm,udev}
1604 mount --bind /run/lvm "$MNT/hostrun/lvm"
1605 mount --bind /run/udev "$MNT/hostrun/udev"
1612 EDIT_FILES[bootloader]=""
1617 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1618 efibootmgr -v -d $BOOT_DEV -p $BOOT_PART_NUM -c -L '${DIST} Linux' -l /vmlinuz-${KERNEL} \
1619 -u 'root=$ROOT_PART_ID rw $([[ $UCODE ]] && printf 'initrd=\%s.img ' "$UCODE")initrd=\initramfs-${KERNEL}.img'"
1624 if [[ $SYS == 'BIOS' ]]; then
1625 EDIT_FILES[bootloader]="/boot/syslinux/syslinux.cfg"
1627 EDIT_FILES[bootloader]="/boot/EFI/syslinux/syslinux.cfg"
1628 BCMDS[syslinux]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1629 efibootmgr -v -c -d $BOOT_DEV -p $BOOT_PART_NUM -l /EFI/syslinux/syslinux.efi -L $DIST"
1635 local c="$MNT/boot/syslinux"
1636 local s="/usr/lib/syslinux/bios"
1638 if [[ $SYS == 'UEFI' ]]; then
1639 c="$MNT/boot/EFI/syslinux"
1640 s="/usr/lib/syslinux/efi64"
1643 mkdir -pv "$c" 2>$ERR 2>&1
1644 errshow 1 "mkdir -pv $c"
1645 cp -rfv "$s/"* "$c/" 2>$ERR 2>&1
1646 errshow 1 "cp -rfv $s/* $c/"
1647 cp -fv "$RUN/syslinux/splash.png" "$c/" 2>$ERR 2>&1
1648 errshow 0 "cp -fv $RUN/syslinux/splash.png $c/"
1649 cat > "$c/syslinux.cfg" <<- EOF
1651 MENU TITLE $DIST Boot Menu
1652 MENU BACKGROUND splash.png
1656 # see: https://www.syslinux.org/wiki/index.php/Comboot/menu.c32
1665 MENU HELPMSGENDROW 29
1666 MENU COLOR border 30;44 #40ffffff #a0000000 std
1667 MENU COLOR title 1;36;44 #9033ccff #a0000000 std
1668 MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
1669 MENU COLOR unsel 37;44 #50ffffff #a0000000 std
1670 MENU COLOR help 37;40 #c0ffffff #a0000000 std
1671 MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
1672 MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
1673 MENU COLOR msg07 37;40 #90ffffff #a0000000 std
1674 MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
1677 MENU LABEL $DIST Linux
1678 LINUX $d/vmlinuz-$KERNEL
1679 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1680 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL.img
1682 LABEL ${DIST}fallback
1683 MENU LABEL $DIST Linux Fallback
1684 LINUX $d/vmlinuz-$KERNEL
1685 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1686 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL-fallback.img
1693 EDIT_FILES[bootloader]="/boot/refind_linux.conf"
1694 BCMDS[refind-efi]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1; refind-install"
1699 cat > "$MNT/boot/refind_linux.conf" <<- EOF
1700 "$DIST Linux" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1701 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1702 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL.img"
1703 "$DIST Linux Fallback" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1704 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1705 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL-fallback.img"
1707 mkdir -p "$MNT/etc/pacman.d/hooks"
1708 cat > "$MNT/etc/pacman.d/hooks/refind.hook" <<- EOF
1715 Description = Updating rEFInd on ESP
1716 When = PostTransaction
1717 Exec = /usr/bin/refind-install
1721 setup_systemd-boot()
1723 EDIT_FILES[bootloader]="/boot/loader/entries/$DIST.conf"
1724 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1; bootctl --path=/boot install"
1727 prerun_systemd-boot()
1729 mkdir -p "$MNT/boot/loader/entries"
1730 cat > "$MNT/boot/loader/loader.conf" <<- EOF
1735 cat > "$MNT/boot/loader/entries/$DIST.conf" <<- EOF
1737 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1738 initrd /initramfs-$KERNEL.img
1739 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1741 cat > "$MNT/boot/loader/entries/$DIST-fallback.conf" <<- EOF
1742 title $DIST Linux Fallback
1743 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1744 initrd /initramfs-$KERNEL-fallback.img
1745 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1747 mkdir -p "$MNT/etc/pacman.d/hooks"
1748 cat > "$MNT/etc/pacman.d/hooks/systemd-boot.hook" <<- EOF
1755 Description = Updating systemd-boot
1756 When = PostTransaction
1757 Exec = /usr/bin/bootctl update
1759 systemd-machine-id-setup --root="$MNT"
1763 ###############################################################################
1768 no_bg_install || return 1
1772 dlg choice menu "Logical Volume Management" "$_lvmmenu" \
1773 "$_lvmnew" "vgcreate -f, lvcreate -L -n" \
1774 "$_lvmdel" "vgremove -f" \
1775 "$_lvmdelall" "lvrmeove, vgremove, pvremove -f" \
1776 "Back" "Return to the main menu"
1778 "$_lvmnew") lvm_create && break ;;
1779 "$_lvmdel") lvm_delgroup && yesno "$_lvmdel" "$_lvmdelask" && vgremove -f "$DEL_VG" >/dev/null 2>&1 ;;
1780 "$_lvmdelall") lvm_del_all ;;
1791 pv="$(pvs -o pv_name --noheading 2>/dev/null)"
1792 v="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
1793 VGROUP="$(vgs -o vg_name --noheading 2>/dev/null)"
1795 if [[ $VGROUP && $v && $pv ]]; then
1796 msg "LVM Setup" "\nActivating existing logical volume management.\n" 0
1797 modprobe dm-mod >/dev/null 2>$ERR
1798 errshow 'modprobe dm-mod'
1799 vgscan >/dev/null 2>&1
1800 vgchange -ay >/dev/null 2>&1
1806 VGROUP='' LVM_PARTS='' VGROUP_MB=0
1808 lvm_mkgroup || return 1
1809 local txt="\nThe last (or only) logical volume will automatically use all remaining space in the volume group."
1810 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 -
1811 [[ $VOL_COUNT ]] || return 1
1812 lvm_extra_lvs || return 1
1813 lvm_volume_name "$_lvmlvname\nNOTE: This LV will use up all remaining space in the volume group (${VGROUP_MB}MB)" || return 1
1814 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating volume $VNAME from remaining space in $VGROUP\n" 0
1815 lvcreate -l +100%FREE "$VGROUP" -n "$VNAME" >/dev/null 2>$ERR
1816 errshow "lvcreate -l +100%FREE $VGROUP -n $VNAME" || return 1
1817 LVM='logical volume'; sleep 0.5
1818 txt="\nDone, volume: $VGROUP-$VNAME (${VOLUME_SIZE:-${VGROUP_MB}MB}) has been created.\n"
1819 msg "$_lvmnew (LV:$VOL_COUNT)" "$txt\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE $LVM_PARTS)\n"
1825 local txt="${VGROUP}: ${SIZE}$SIZE_UNIT (${VGROUP_MB}MB remaining).$_lvmlvsize"
1829 dlg VOLUME_SIZE input "$_lvmnew (LV:$VOL_COUNT)" "$txt" ''
1830 if [[ -z $VOLUME_SIZE ]]; then
1832 break # allow bailing with escape or an empty choice
1833 elif (( ${VOLUME_SIZE:0:1} == 0 )); then
1834 ERR_SIZE=1 # size values can't begin with '0'
1836 # walk the string and make sure all but the last char are digits
1837 local lv=$((${#VOLUME_SIZE} - 1))
1838 for (( i=0; i<lv; i++ )); do
1839 [[ ${VOLUME_SIZE:$i:1} =~ [0-9] ]] || { ERR_SIZE=1; break; }
1841 if (( ERR_SIZE != 1 )); then
1842 case ${VOLUME_SIZE:$lv:1} in
1843 [mMgG]) local s=${VOLUME_SIZE:0:$lv} m=$((s * 1000))
1844 case ${VOLUME_SIZE:$lv:1} in
1845 [Gg]) (( m >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - m)) ;;
1846 [Mm]) (( ${VOLUME_SIZE:0:$lv} >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - s)) ;;
1853 if (( ERR_SIZE )); then
1854 msg "Invalid Logical Volume Size" "$_lvmerrlvsize"
1867 until [[ $named ]]; do
1868 lvm_partitions || return 1
1869 lvm_group_name || return 1
1870 yesno "$_lvmnew" "\nCreate volume group: $VGROUP\n\nusing these partition(s): $LVM_PARTS\n" && named=true
1873 msg "$_lvmnew" "\nCreating volume group: $VGROUP\n" 0
1874 vgcreate -f "$VGROUP" $LVM_PARTS >/dev/null 2>$ERR
1875 errshow "vgcreate -f $VGROUP $LVM_PARTS" || return 1
1877 SIZE=$(vgdisplay "$VGROUP" | awk '/VG Size/ { gsub(/[^0-9.]/, ""); print int($0) }')
1878 SIZE_UNIT="$(vgdisplay "$VGROUP" | awk '/VG Size/ { print substr($NF, 0, 1) }')"
1880 if [[ $SIZE_UNIT == 'G' ]]; then
1881 VGROUP_MB=$((SIZE * 1000))
1886 msg "$_lvmnew" "\nVolume group $VGROUP (${SIZE}$SIZE_UNIT) successfully created\n"
1892 pv="$(pvs -o pv_name --noheading 2>/dev/null)"
1893 v="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
1894 VGROUP="$(vgs -o vg_name --noheading 2>/dev/null)"
1896 if [[ $VGROUP || $v || $pv ]]; then
1897 if yesno "$_lvmdelall" "$_lvmdelask"; then
1898 for i in $v; do lvremove -f "/dev/mapper/$i" >/dev/null 2>&1; done
1899 for i in $VGROUP; do vgremove -f "$i" >/dev/null 2>&1; done
1900 for i in $pv; do pvremove -f "$i" >/dev/null 2>&1; done
1904 msg "Delete LVM" "\nNo LVMs to remove...\n" 2
1914 for i in $(lvs --noheadings | awk '{print $2}' | uniq); do
1915 VOL_GROUP_LIST+="$i $(vgdisplay "$i" | awk '/VG Size/ {print $3$4}') "
1918 [[ $VOL_GROUP_LIST ]] || { msg "No Groups" "\nNo volume groups found."; return 1; }
1920 dlg DEL_VG menu "Logical Volume Management" "\nSelect volume group to delete.\n\nAll logical volumes within will also be deleted." $VOL_GROUP_LIST
1926 while (( VOL_COUNT > 1 )); do
1927 lvm_volume_name "$_lvmlvname" && lvm_lv_size || return 1
1928 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating a $VOLUME_SIZE volume $VNAME in $VGROUP\n" 0
1929 lvcreate -L "$VOLUME_SIZE" "$VGROUP" -n "$VNAME" >/dev/null 2>$ERR
1930 errshow "lvcreate -L $VOLUME_SIZE $VGROUP -n $VNAME" || return 1
1931 msg "$_lvmnew (LV:$VOL_COUNT)" "\nDone, logical volume (LV) $VNAME ($VOLUME_SIZE) has been created.\n"
1939 part_find 'part|crypt' || return 1
1940 PARTS="$(awk 'NF > 0 {print $0 " off"}' <<< "$PARTS")"
1941 dlg LVM_PARTS check "$_lvmnew" "\nSelect the partition(s) to use for the physical volume (PV)." $PARTS
1948 until [[ $VGROUP ]]; do
1949 dlg VGROUP input "$_lvmnew" "$_lvmvgname" "lvgroup"
1950 if [[ -z $VGROUP ]]; then
1952 elif [[ ${VGROUP:0:1} == "/" || $VGROUP =~ \ |\' ]] || vgdisplay | grep -q "$VGROUP"; then
1953 msg "LVM Name Error" "$_lvmerrvgname"
1963 local txt="$1" default="mainvolume"
1964 (( VOL_COUNT > 1 )) && default="extvolume$VOL_COUNT"
1965 until [[ $VNAME ]]; do
1966 dlg VNAME input "$_lvmnew (LV:$VOL_COUNT)" "\n$txt" "$default"
1967 if [[ -z $VNAME ]]; then
1969 elif [[ ${VNAME:0:1} == "/" || $VNAME =~ \ |\' ]] || lsblk | grep -q "$VNAME"; then
1970 msg "LVM Name Error" "$_lvmerlvname"
1977 ###############################################################################
1983 no_bg_install || return 1
1984 dlg choice menu "LUKS Encryption" "$_luksmenu" \
1985 "$_luksnew" "cryptsetup -q luksFormat" \
1986 "$_luksopen" "cryptsetup open --type luks" \
1987 "$_luksadv" "cryptsetup -q -s -c luksFormat" \
1988 "Back" "Return to the main menu"
1991 "$_luksnew") luks_basic || return 1 ;;
1992 "$_luksopen") luks_open || return 1 ;;
1993 "$_luksadv") luks_advanced || return 1 ;;
2001 modprobe -a dm-mod dm_crypt >/dev/null 2>&1
2003 part_find 'part|crypt|lvm' || return 1
2005 if (( COUNT == 1 )); then
2006 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2008 dlg LUKS_PART menu "$_luksopen" "\nSelect which partition to open." $PARTS
2011 [[ $LUKS_PART ]] || return 1
2013 luks_pass "$_luksopen" || return 1
2014 msg "$_luksopen" "\nOpening encrypted partition: $LUKS_NAME\n\nUsing device/volume: $LUKS_PART\n" 0
2015 cryptsetup open --type luks "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2016 errshow "cryptsetup open --type luks $LUKS_PART $LUKS_NAME" || return 1
2017 LUKS='encrypted'; luks_show
2025 typeset -a ans=(cryptroot) # default name to start
2027 until [[ $LUKS_PASS ]]; do
2029 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " --mixedform "$_luksomenu" 0 0 0 \
2030 "Name:" 1 1 "${ans[0]}" 1 7 "$COLUMNS" 0 0 \
2031 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
2032 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
2034 mapfile -t ans <"$ANS"
2036 if [[ -z "${ans[0]}" ]]; then
2037 msg "Name Empty" "\nEncrypted device name cannot be empty.\n\nPlease try again.\n" 2
2038 elif [[ -z "${ans[1]}" || "${ans[1]}" != "${ans[2]}" ]]; then
2039 LUKS_NAME="${ans[0]}"
2040 msg "Password Mismatch" "\nThe passwords entered do not match.\n\nPlease try again.\n" 2
2042 LUKS_NAME="${ans[0]}"
2043 LUKS_PASS="${ans[1]}"
2053 msg "$_luksnew" "\nEncrypted partition ready for mounting.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$LUKS_PART")\n\n"
2058 modprobe -a dm-mod dm_crypt >/dev/null 2>&1
2060 part_find 'part|lvm' || return 1
2062 if [[ $AUTO_ROOT_PART ]]; then
2063 LUKS_PART="$AUTO_ROOT_PART"
2064 elif (( COUNT == 1 )); then
2065 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2067 dlg LUKS_PART menu "$_luksnew" "\nSelect the partition you want to encrypt." $PARTS
2070 [[ $LUKS_PART ]] || return 1
2071 luks_pass "$_luksnew"
2076 luks_setup || return 1
2077 msg "$_luksnew" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2078 cryptsetup -q luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2>$ERR
2079 errshow "cryptsetup -q luksFormat $LUKS_PART" || return 1
2080 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2081 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2082 LUKS='encrypted'; luks_show
2090 dlg cipher input "LUKS Encryption" "$_lukskey" "-s 512 -c aes-xts-plain64"
2091 [[ $cipher ]] || return 1
2092 msg "$_luksadv" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2093 cryptsetup -q $cipher luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2>$ERR
2094 errshow "cryptsetup -q $cipher luksFormat $LUKS_PART" || return 1
2095 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2096 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2103 ###############################################################################
2105 # some help avoid repetition and improve usability of some commands
2106 # others are initial setup functions used before reaching the main loop
2110 [[ "$2" == *"$1"* ]] && printf "on" || printf "off"
2115 # cleanup and exit the installer cleanly with exit code $1
2116 local e="$1" # when e is 127 unmount /run/archiso/bootmnt and reboot
2120 if [[ -d $MNT ]]; then
2122 if (( e == 127 )); then
2123 umount_dir /run/archiso/bootmnt && sleep 0.5 && reboot -f
2131 local var="$1" # assign output from dialog to var
2132 local dlg_t="$2" # dialog type (menu, check, input)
2133 local title="$3" # dialog title
2134 local body="$4" # dialog message
2135 local n=0 # number of items to display for menu and check dialogs
2137 shift 4 # shift off args assigned above
2139 # adjust n when passed a large list
2140 local l=$((LINES - 20))
2141 (( ($# / 2) > l )) && n=$l
2145 menu) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --menu "$body" 0 0 $n "$@" 2>"$ANS" || return 1 ;;
2146 check) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --checklist "$body" 0 0 $n "$@" 2>"$ANS" || return 1 ;;
2149 local def="$1" # assign default value for input
2151 if [[ $1 == 'limit' ]]; then
2152 dialog --backtitle "$DIST Installer - $SYS - v$VER" --max-input 63 --title " $title " --inputbox "$body" 0 0 "$def" 2>"$ANS" || return 1
2154 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --inputbox "$body" 0 0 "$def" 2>"$ANS" || return 1
2158 # if answer file isn't empty read from it into $var
2159 [[ -s "$ANS" ]] && printf -v "$var" "%s" "$(< "$ANS")"
2164 # displays a message dialog
2165 # when more than 2 args the message will disappear after sleep time ($3)
2171 dialog --backtitle "$DIST Installer - $SYS - v$VER" --sleep "$1" --title " $title " --infobox "$body\n" 0 0
2173 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --msgbox "$body\n" 0 0
2181 if ! select_keymap; then
2184 elif ! net_connect; then
2185 msg "Not Connected" "\nRunning live requires an active internet connection.\n\nExiting..\n" 2
2187 elif (( $(awk '/MemTotal/ {print int($2 / 1024)}' /proc/meminfo) < 2500)); then
2188 msg "Not Enough Memory" "\nRunning live requires at least 2.5G of system memory.\n\nExiting..\n" 2
2192 echo "Sorting mirrorlist first"
2193 mount /run/archiso/cowspace -o remount,size=2G
2194 install_mirrorlist "/etc/pacman.d/mirrorlist"
2195 pacman -Syyu --noconfirm || die 1
2196 pacman -S $BASE_PKGS $AL_BASE_PKGS xorg-xinit --needed --noconfirm || die 1
2198 i3-gaps|openbox|fluxbox|bspwm|awesome) pacman -S "$ses" $WM_BASE_PKGS ${WM_EXT[$ses]} --needed --noconfirm || die 1 ;;
2199 gnome|plasma|cinnamon|xfce4) pacman -S "$ses" ${WM_EXT[$ses]} --needed --noconfirm || die 1 ;;
2200 dwm) { pacman -S git --needed --noconfirm || die 1; }; install_suckless "/root" nochroot ;;
2203 gtk-update-icon-cache /usr/share/icons/ArchLabs-Dark /usr/share/icons/ArchLabs-Light /usr/share/icons/ArchLabs
2204 pacman -Scc --noconfirm
2205 rm -rf "/var/cache/pacman/pkg/"*
2206 cp -rfT /etc/skel /root || die 1
2207 sed -i "/exec/ c exec ${WM_SESSIONS[$ses]}" /root/.xinitrc
2208 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]}"
2216 usage: $1 [-hdl] [session]
2219 -h, --help print this message and exit
2220 -l, --live install and setup a live session
2221 -d, --debug enable xtrace and log output to $DBG
2224 i3-gaps - A fork of i3wm with more features including gaps
2225 openbox - A lightweight, powerful, and highly configurable stacking wm
2226 dwm - A dynamic WM for X that manages windows in tiled, floating, or monocle layouts
2227 awesome - A customized Awesome WM session created by @elanapan
2228 bspwm - A tiling wm that represents windows as the leaves of a binary tree
2229 fluxbox - A lightweight and highly-configurable window manager
2230 gnome - A desktop environment that aims to be simple and easy to use
2231 cinnamon - A desktop environment combining traditional desktop with modern effects
2232 plasma - A kde software project currently comprising a full desktop environment
2233 xfce4 - A lightweight and modular desktop environment based on gtk+2/3
2237 set the DIST environment variable before launching the installer eg.
2243 set the EDITOR environment variable before launching the installer eg.
2253 local title="$1" body="$2" yes='Yes' no='No'
2254 (( $# >= 3 )) && yes="$3"
2255 (( $# >= 4 )) && no="$4"
2257 if (( $# == 5 )); then
2258 dialog --backtitle "$DIST Installer - $SYS - v$VER" --defaultno --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2260 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2266 arch-chroot "$MNT" bash -c "$1"
2271 export PS4='| ${BASH_SOURCE} LINE:${LINENO} FUNC:${FUNCNAME[0]:+ ${FUNCNAME[0]}()} |> '
2281 "\e]P0191919" # #191919
2282 "\e]P1D15355" # #D15355
2283 "\e]P2609960" # #609960
2284 "\e]P3FFCC66" # #FFCC66
2285 "\e]P4255A9B" # #255A9B
2286 "\e]P5AF86C8" # #AF86C8
2287 "\e]P62EC8D3" # #2EC8D3
2288 "\e]P7949494" # #949494
2289 "\e]P8191919" # #191919
2290 "\e]P9D15355" # #D15355
2291 "\e]PA609960" # #609960
2292 "\e]PBFF9157" # #FF9157
2293 "\e]PC4E88CF" # #4E88CF
2294 "\e]PDAF86C8" # #AF86C8
2295 "\e]PE2ec8d3" # #2ec8d3
2296 "\e]PFE1E1E1" # #E1E1E1
2299 [[ $TERM == 'linux' ]] && printf "%b" "${colors[@]}" && clear
2304 [ $? -eq 0 ] && return 0
2306 local fatal=0 err=""
2307 err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
2308 [[ -z $err ]] && err="no error message was found"
2310 (( $1 == 1 )) && { fatal=1; shift; }
2312 local txt="\nCommand: $1\n\n\n\nError: $err\n\n"
2314 if (( fatal )); then
2315 msg "Install Error" "${txt}Errors at this stage are fatal, the install cannot continue.\n"
2316 [[ -r $DBG && $TERM == 'linux' ]] && less "$DBG"
2320 msg "Install Error" "${txt}Errors at this stage are non-fatal and may be fixed or ignored depending on the error.\n"
2328 if (( $1 >= 0 )) && ! grep -qw "$MNT" /proc/mounts; then
2329 msg "Not Mounted" "\nPartition(s) must be mounted first.\n" 2
2331 elif [[ $1 -ge 1 && -z $BOOTLDR ]]; then
2332 msg "No Bootloader" "\nBootloader must be selected first.\n" 2
2334 elif [[ $1 -ge 2 && (-z $NEWUSER || -z $USER_PASS) ]]; then
2335 msg "No User" "\nA user must be created first.\n" 2
2337 elif [[ $1 -ge 3 && -z $CONFIG_DONE ]]; then
2338 msg "Not Configured" "\nSystem configuration must be done first.\n" 2
2341 (( i )) # return code
2346 mount | grep -q 'swap' && swapoff -a
2348 if [[ -d $dir ]] && mount | grep -q "on $dir "; then
2349 if ! umount "$dir" 2>/dev/null; then
2351 umount -f "$dir" 2>/dev/null || umount -l "$dir"
2359 msg "Network Connect" "\nVerifying network connection\n" 0
2360 curl -sIN --connect-timeout 5 'https://www.archlinux.org/' | sed '1q' | grep -q '200'
2365 if chk_connect; then
2367 elif hash nmtui >/dev/null 2>&1; then
2369 if [[ $TERM == 'linux' ]]; then
2370 printf "%b" "\e]P1191919" "\e]P4191919"
2372 printf "%b" "\e]P1D15355" "\e]P4255a9b"
2377 elif hash wifi-menu >dev/null 2>&1; then
2387 [[ $BG_PID ]] || return 0
2388 msg "Install Running" "\nA background install process is currently running.\n" 2
2394 IGNORE_DEV="$(lsblk -lno NAME,MOUNTPOINT | awk '/\/run\/archiso\/bootmnt/ {sub(/[1-9]/, ""); print $1}')"
2396 if [[ $IGNORE_DEV ]]; then
2397 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ && !'"/$IGNORE_DEV/"' {print "/dev/" $1 " " $2}')"
2399 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ {print "/dev/" $1 " " $2}')"
2402 if [[ -z $SYS_DEVS ]]; then
2403 msg "Device Error" "\nNo available devices...\n\nExiting..\n" 2
2408 while read -r line; do
2410 done <<< "$SYS_DEVS"
2417 # amd-ucode is not needed it's provided by linux-firmware
2418 # elif grep -q 'AuthenticAMD' /proc/cpuinfo; then
2420 elif grep -q 'GenuineIntel' /proc/cpuinfo; then
2424 modprobe -q efivarfs >/dev/null 2>&1
2426 _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\nTo begin the install you should have:\n\n - A root (/) partition mounted."
2427 if [[ -d /sys/firmware/efi/efivars ]]; then
2429 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars
2430 _prep+="\n - An EFI boot partition mounted."
2434 _prep+="\n\nOnce finished mounting, a portion of the install can be done in the background while you continue configuring the system:\n"
2435 _prep+="\n - Choose the system bootloader.\n - Create a user and password."
2436 _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."
2439 ###############################################################################
2442 # enable some nicer colours in the linux console
2445 if (( UID != 0 )); then
2446 msg "Not Root" "\nThis installer must be run as root or using sudo.\n\nExiting..\n" 2
2448 elif ! grep -qwm 1 'lm' /proc/cpuinfo; then
2449 msg "Not x86_64 Architecture" "\nThis installer only supports x86_64 architectures.\n\nExiting..\n" 2
2453 -d|--debug) debug ;;
2454 -h|--help) usage "$0" ;;
2457 gnome|cinnamon|dwm|plasma|xfce4|i3-gaps|openbox|fluxbox|bspwm|awesome) live "$2" ;;
2458 *) echo "error: invalid session for -l, --live, see -h, --help"; die 1 ;;
2463 # trap ^C to perform cleanup
2464 trap 'printf "\n^C\n" && die 1' INT
2469 msg "Welcome to the $DIST Installer" "$_welcome"
2471 if ! select_keymap; then
2473 elif ! net_connect; then
2474 msg "Not Connected" "\nThis installer requires an active internet connection.\n\nExiting..\n" 2
2483 # vim:fdm=marker:fmr={,}