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
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 USER_CMD="" # optional command(s) entered by the user to run in the chroot
30 export DIALOGOPTS="--cr-wrap" # dialog environment variable to hold default options, see `man dialog`
32 BASE_PKGS="base xorg xorg-drivers sudo git gvfs gtk3 libmad libmatroska tumbler "
33 BASE_PKGS+="playerctl pulseaudio pulseaudio-alsa pavucontrol pamixer scrot xdg-user-dirs "
34 BASE_PKGS+="ffmpeg gstreamer gst-libav gst-plugins-base gst-plugins-good bash-completion xterm"
36 AL_BASE_PKGS="archlabs-keyring archlabs-icons archlabs-fonts archlabs-themes "
37 AL_BASE_PKGS+="archlabs-baph archlabs-wallpapers archlabs-scripts archlabs-skel-base"
39 WM_BASE_PKGS="arandr nitrogen polkit-gnome network-manager-applet "
40 WM_BASE_PKGS+="volumeicon xclip exo laptop-detect xdotool compton wmctrl feh "
41 WM_BASE_PKGS+="gnome-keyring dunst gsimplecal xfce4-power-manager xfce4-settings"
43 SYS_MEM="$(awk '/MemTotal/ {print int($2 / 1024) "M"}' /proc/meminfo)"
44 LOCALES="$(awk '/\.UTF-8/ {gsub(/# .*|#/, ""); if ($1) {print $1 " - "}}' /etc/locale.gen)"
45 CMAPS="$(find /usr/share/kbd/keymaps -name '*.map.gz' | awk '{gsub(/\.map\.gz|.*\//, ""); print $1 " - "}' | sort)"
47 [[ $LINES ]] || LINES=$(tput lines)
48 [[ $COLUMNS ]] || COLUMNS=$(tput cols)
52 # commands used to install each bootloader, however most get modified during runtime {
54 [refind-efi]='refind-install'
55 [grub]='grub-install --recheck --force' [syslinux]='syslinux-install_update -i -a -m'
56 [efistub]='efibootmgr -v -d /dev/sda -p 1 -c -l' [systemd-boot]='bootctl --path=/boot install'
59 # executable name for each wm/de used in ~/.xinitrc {
60 declare -A WM_SESSIONS=(
61 [dwm]='dwm' [jwm]='jwm' [i3-gaps]='i3' [bspwm]='bspwm' [awesome]='awesome' [plasma]='startkde' [xfce4]='startxfce4'
62 [gnome]='gnome-session' [fluxbox]='startfluxbox' [openbox]='openbox-session' [cinnamon]='cinnamon-session'
65 # packages installed for each wm/de, most are depends of the skel packages {
67 [dwm]='' [jwm]='' [gnome]='' [cinnamon]='gnome-terminal' [plasma]='kdebase-meta'
68 [awesome]='archlabs-skel-awesome' [bspwm]='archlabs-skel-bspwm' [fluxbox]='archlabs-skel-fluxbox'
69 [i3-gaps]='archlabs-skel-i3-gaps' [openbox]='archlabs-skel-openbox' [xfce4]='archlabs-skel-xfce4 xfce4-goodies'
72 # files offered for editing after install is complete {
73 declare -A EDIT_FILES=(
74 [login]='' # login is populated once we know the username and shell
75 [fstab]='/etc/fstab' [sudoers]='/etc/sudoers' [crypttab]='/etc/crypttab' [pacman]='/etc/pacman.conf'
76 [console]='/etc/vconsole.conf' [mkinitcpio]='/etc/mkinitcpio.conf' [hostname]='/etc/hostname /etc/hosts'
77 [bootloader]="/boot/loader/entries/$DIST.conf" # ** based on bootloader
78 [locale]='/etc/locale.conf /etc/default/locale' [keyboard]='/etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard'
81 # mkfs command flags for filesystem formatting {
82 declare -A FS_CMD_FLAGS=(
83 [f2fs]='' [jfs]='-q' [xfs]='-f' [ntfs]='-q' [ext2]='-q' [ext3]='-q' [ext4]='-q' [vfat]='-F32' [nilfs2]='-q' [reiserfs]='-q'
86 # mount options for each filesystem {
88 [vfat]='' [ntfs]='' [ext2]='' [ext3]='' # NA
89 [jfs]='discard errors=continue errors=panic nointegrity'
90 [reiserfs]='acl nolog notail replayonly user_xattr off'
91 [ext4]='discard dealloc nofail noacl relatime noatime nobarrier nodelalloc'
92 [xfs]='discard filestreams ikeep largeio noalign nobarrier norecovery noquota wsync'
93 [nilfs2]='discard nobarrier errors=continue errors=panic order=relaxed order=strict norecovery'
94 [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'
97 # packages installed for each login option {
98 declare -A LOGIN_PKGS=(
99 [xinit]='xorg-xinit' [ly]='archlabs-ly' [gdm]='gdm' [sddm]='sddm'
100 [lightdm]='lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings accountsservice'
103 # extras installed for user selected packages {
104 # if a package requires additional packages that aren't already dependencies
105 # they can be added here eg. [package]="extra"
107 [vlc]='qt4' [mpd]='mpc' [mupdf]='mupdf-tools'
108 [rxvt-unicode]='urxvt-pearls' [zathura]='zathura-pdf-poppler' [noto-fonts]='noto-fonts-emoji' [cairo-dock]='cairo-dock-plug-ins' [qt5ct]='qt5-styleplugins'
109 [vlc]='qt5ct qt5-styleplugins' [qutebrowser]='qt5ct qt5-styleplugins' [qbittorrent]='qt5ct qt5-styleplugins' [transmission-qt]='qt5ct qt5-styleplugins'
110 [bluez]='bluez-libs bluez-utils bluez-tools bluez-plugins bluez-hid2hci' [kdenlive]='kdebase-meta dvdauthor frei0r-plugins breeze breeze-gtk qt5ct qt5-styleplugins'
113 # dialog text variables {
114 # Basics (somewhat in order)
115 _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"
116 _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"
117 _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"
118 _device="\nSelect a device to use from the list below.\n\nDevices (/dev) are the available drives on the system. /sda, /sdb, /sdc ..."
119 _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."
120 _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."
121 _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"
122 _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)."
123 _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."
124 _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."
125 _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."
126 _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"
127 _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."
128 _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."
129 _exmnt="\nWhere do you want the partition mounted?\n\nEnsure the name begins with a slash (/).\nExamples include: /usr, /home, /var, etc."
130 _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."
131 _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."
132 _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"
133 _timez="\nThe time zone is used to set the system clock.\n\nSelect your country or continent from the list below"
134 _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."
135 _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."
136 _login="\nSelect which of your session choices to use for the initial login.\n\nYou can be change this later by editing your ~/.xinitrc"
137 _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"
138 _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."
139 _usercmd="\nEnter command(s) to be run in the newly installed system (chroot).\n\nAn example use case would be installing packages or editing files not offered in the menus.\n\nBecause the command will be run in a chroot not everything may function correctly, additionally the command will not be sanity checked, it's your system so exercise caution.\n\nYou may string more than one command together by using standard bash syntax.\n"
140 _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."
143 _luksnew="Basic LUKS Encryption"
144 _luksadv="Advanced LUKS Encryption"
145 _luksopen="Open Existing LUKS Partition"
146 _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."
147 _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."
148 _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)."
151 _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."
152 _lvmnew="Create Volume Group and Volume(s)"
153 _lvmdel="Delete an Existing Volume Group"
154 _lvmdelall="Delete ALL Volume Group(s) and Volume(s)"
155 _lvmvgname="\nEnter a name for the volume group (VG) being created from the partition(s) selected."
156 _lvmlvname="\nEnter a name for the logical volume (LV) being created.\n\nThis is similar to setting a label for a partition."
157 _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."
158 _lvmdelask="\nConfirm deletion of volume group(s) and logical volume(s).\n\nDeleting a volume group, will delete all logical volumes within it.\n"
161 _errexpart="\nCannot mount partition due to a problem with the mountpoint.\n\nEnsure it begins with a slash (/) followed by atleast one character.\n"
162 _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"
163 _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"
164 _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"
165 _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"
166 _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"
167 _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"
171 ###############################################################################
173 # main is the entry point which calls functions including outside of its block
174 # once those functions finished they always are returned here with the
175 # exception of install_main(), it exits upon completion
179 (( SEL < 13 )) && (( SEL++ ))
181 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Prepare " --default-item $SEL --cancel-label 'Exit' --menu "$_prep" 0 0 0 \
182 1 "Show device tree" \
183 2 "Partitioning helpers" \
184 3 "LUKS encryption setup" \
185 4 "Logical volume management setup" \
186 5 "* Mount system partitions" \
187 6 "* Select system bootloader" \
188 7 "* Create user and password" \
189 8 "* Basic system configuration" \
190 9 "Select window manager or desktop" \
191 10 "Select additional packages" \
192 11 "View configuration selections" \
193 12 "Add a command to be run on the system during install" \
194 13 "* Confirm choices and start the installation" 2> "$ANS"
197 [[ -z $WARN && $SEL =~ (2|5) ]] && { msg "Data Warning" "$_warn"; WARN=true; }
200 2) part_menu || (( SEL-- )) ;;
201 3) luks_menu || (( SEL-- )) ;;
202 4) lvm_menu || (( SEL-- )) ;;
203 5) mount_menu || (( SEL-- )) ;;
204 6) prechecks 0 && { select_boot || (( SEL-- )); } ;;
205 7) prechecks 1 && { select_mkuser || (( SEL-- )); } ;;
206 8) prechecks 2 && { select_config || (( SEL-- )); } ;;
207 9) prechecks 3 && { select_sessions || (( SEL-- )); } ;;
208 10) prechecks 3 && { select_packages || (( SEL-- )); } ;;
209 11) prechecks 3 && select_show ;;
210 12) prechecks 3 && select_usercmd ;;
211 13) prechecks 3 && install_main ;;
212 *) yesno "Exit" "\nUnmount partitions (if any) and exit the installer?\n" && die 0
218 if [[ $SYS == 'BIOS' ]]; then
219 dlg BOOTLDR menu "BIOS Bootloader" "\nSelect which bootloader to use." \
220 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
221 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network" || return 1
223 dlg BOOTLDR menu "UEFI Bootloader" "\nSelect which bootloader to use." \
224 "systemd-boot" "A simple UEFI boot manager which executes configured EFI images" \
225 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
226 "refind-efi" "A UEFI boot manager that aims to be platform neutral and simplify multi-boot" \
227 "efistub" "Boot the kernel image directly (no chainloading support)" \
228 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network (no chainloading support)" || return 1
235 local pkgs="${USER_PKGS// / } ${PACKAGES// / }"
236 [[ $INSTALL_WMS == *dwm* ]] && pkgs="dwm st dmenu $pkgs"
237 pkgs="${pkgs// / }" pkgs="${pkgs# }"
238 msg "Show Configuration" "
239 ---------- PARTITION CONFIGURATION ------------
241 Root Part: $ROOT_PART
242 Boot Part: ${BOOT_PART:-none}
243 Boot Device: ${BOOT_DEV:-none}
244 Swap Part/File: ${SWAP_PART:-none}
245 Swap Size: ${SWAP_SIZE:-none}
246 Extra Mounts: ${EXMNTS:-none}
247 Mkinit Hooks: ${HOOKS:-none}
249 LVM used: ${LVM:-none}
250 LUKS used: ${LUKS:-none}
252 ------------ SYSTEM CONFIGURATION -------------
254 Locale: ${MYLOCALE:-none}
255 Keymap: ${KEYMAP:-none}
256 Hostname: ${MYHOST:-none}
257 Timezone: ${ZONE:-none}/${SUBZ:-none}
259 ------------ USER CONFIGURATION ---------------
261 Username: ${NEWUSER:-none}
262 Login Shell: ${MYSHELL:-none}
263 Login Session: ${LOGIN_WM:-none}
264 Autologin: ${AUTOLOGIN:-none}
265 Login Type: ${LOGIN_TYPE:-none}
267 ----------- PACKAGE CONFIGURATION -------------
269 Kernel: ${KERNEL:-none}
270 Bootloader: ${BOOTLDR:-none}
271 Packages: ${pkgs:-none}
277 AUTOLOGIN='' # no autologin unless using xinit
279 dlg LOGIN_TYPE menu "Login Management" "\nSelect what kind of login management to use." \
280 "xinit" "Console login without a display manager" \
281 "ly" "TUI display manager with a ncurses-like interface" \
282 "lightdm" "Lightweight display manager with a gtk greeter" \
283 "gdm" "Gnome display manager" \
284 "sddm" "Simple desktop display manager" || return 1
287 ly) EDIT_FILES[login]="/etc/ly/config.ini" ;;
288 gdm|sddm) EDIT_FILES[login]="" ;;
289 lightdm) EDIT_FILES[login]="/etc/lightdm/lightdm.conf /etc/lightdm/lightdm-gtk-greeter.conf" ;;
290 xinit) EDIT_FILES[login]="/home/$NEWUSER/.xinitrc /home/$NEWUSER/.xprofile"
291 if (( $(wc -w <<< "$INSTALL_WMS") > 1 )); then
292 dlg LOGIN_WM menu "Login Management" "$_login" $LOGIN_CHOICES || return 1
293 LOGIN_WM="${WM_SESSIONS[$LOGIN_WM]}"
295 [[ -z $LOGIN_WM ]] && LOGIN_WM="${WM_SESSIONS[${INSTALL_WMS%% *}]}"
296 yesno "Autologin" "$(sed "s|USER|$NEWUSER|g; s|RC|$LOGINRC|g" <<< "$_autologin")" && AUTOLOGIN=true || AUTOLOGIN=''
306 until [[ $CONFIG_DONE ]]; do
308 0) dlg MYSHELL menu "Shell" "\nChoose which shell to use." \
309 zsh 'A very advanced and programmable command interpreter (shell) for UNIX' \
310 bash 'The GNU Bourne Again shell, standard in many GNU/Linux distributions' \
311 mksh 'The MirBSD Korn Shell - an enhanced version of the public domain ksh' || return 1
313 1) dlg MYHOST input "Hostname" "$_hostname" "${DIST,,}" limit || { i=0; continue; } ;;
314 2) dlg MYLOCALE menu "Locale" "$_locale" $LOCALES || { i=1; continue; } ;;
316 until [[ $ZONE && $SUBZ ]]; do
317 dlg ZONE menu "Timezone" "$_timez" America - Australia - Asia - Atlantic - Africa - Europe - Indian - Pacific - Arctic - Antarctica - || break
318 dlg SUBZ menu "Timezone" "$_timesubz" $(awk '/'"$ZONE"'\// {gsub(/'"$ZONE"'\//, ""); print $3 " - "}' /usr/share/zoneinfo/zone.tab | sort) || continue
320 [[ $ZONE && $SUBZ ]] || { i=2; continue; } ;;
321 4) dlg KERNEL menu "Kernel" "\nChoose which kernel to use." \
322 linux 'Vanilla linux kernel and modules, with a few patches applied' \
323 linux-lts 'Long-term support (LTS) linux kernel and modules' \
324 linux-zen 'A effort of kernel hackers to provide the best kernel for everyday systems' \
325 linux-hardened 'A security-focused linux kernel with hardening patches to mitigate exploits' || { i=3; continue; }
329 (( i++ )) # progress through to the next choice
333 bash) LOGINRC='.bash_profile' ;;
334 zsh) LOGINRC='.zprofile' ;;
335 mksh) LOGINRC='.profile' ;;
346 until [[ $NEWUSER ]]; do
348 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " User " --mixedform "$_user" 0 0 0 \
349 "Username:" 1 1 "${ans[0]}" 1 11 "$COLUMNS" 0 0 \
350 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
351 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 \
352 "--- Root password, if left empty the user password will be used ---" 6 1 '' 6 68 "$COLUMNS" 0 2 \
353 "Password:" 8 1 '' 8 11 "$COLUMNS" 0 1 \
354 "Password2:" 9 1 '' 9 12 "$COLUMNS" 0 1 2> "$ANS" || return 1
356 mapfile -t ans <"$ANS"
358 # root passwords empty, so use the user passwords
359 if [[ -z "${ans[4]}" && -z "${ans[5]}" ]]; then
364 # make sure a username was entered and that the passwords match
365 if [[ -z ${ans[0]} || ${ans[0]} =~ \ |\' || ${ans[0]} =~ [^a-z0-9] ]]; then
366 msg "Invalid Username" "\nInvalid user name.\n\nPlease try again.\n"; u=''
367 elif [[ -z "${ans[1]}" || "${ans[1]}" != "${ans[2]}" ]]; then
368 msg "Password Mismatch" "\nThe user passwords do not match.\n\nPlease try again.\n"
369 elif [[ "${ans[4]}" != "${ans[5]}" ]]; then
370 msg "Password Mismatch" "\nThe root passwords do not match.\n\nPlease try again.\n"
373 USER_PASS="${ans[1]}"
374 ROOT_PASS="${ans[4]}"
382 dlg KEYMAP menu "Keyboard Layout" "$_keymap" \
383 us English cm English gb English au English gh English \
384 za English ng English ca French 'cd' French gn French \
385 tg French fr French de German at German ch German \
386 es Spanish latam Spanish br Portuguese pt Portuguese ma Arabic \
387 sy Arabic ara Arabic ua Ukrainian cz Czech ru Russian \
388 sk Slovak nl Dutch it Italian hu Hungarian cn Chinese \
389 tw Taiwanese vn Vietnamese kr Korean jp Japanese th Thai \
390 la Lao pl Polish se Swedish is Icelandic 'fi' Finnish \
391 dk Danish be Belgian in Indian al Albanian am Armenian \
392 bd Bangla ba Bosnian 'bg' Bulgarian dz Berber mm Burmese \
393 hr Croatian gr Greek il Hebrew ir Persian iq Iraqi \
394 af Afghani fo Faroese ge Georgian ee Estonian kg Kyrgyz \
395 kz Kazakh lt Lithuanian mt Maltese mn Mongolian ro Romanian \
396 no Norwegian rs Serbian si Slovenian tj Tajik lk Sinhala \
397 tr Turkish uz Uzbek ie Irish pk Urdu 'mv' Dhivehi \
398 np Nepali et Amharic sn Wolof ml Bambara tz Swahili \
399 ke Swahili bw Tswana ph Filipino my Malay tm Turkmen \
400 id Indonesian bt Dzongkha lv Latvian md Moldavian mao Maori \
401 by Belarusian az Azerbaijani mk Macedonian kh Khmer epo Esperanto \
402 me Montenegrin || return 1
404 if [[ $CMAPS == *"$KEYMAP"* ]]; then
407 dlg CMAP menu "Console Keymap" "$_vconsole" $CMAPS || return 1
410 if [[ $TERM == 'linux' ]]; then
411 loadkeys "$CMAP" > /dev/null 2>&1
413 setxkbmap "$KEYMAP" > /dev/null 2>&1
421 dlg MYHOST input "User Command" "$_usercmd" "$USER_CMD" nolimit
427 dlg INSTALL_WMS check "Sessions" "$_sessions\n" \
428 i3-gaps "A fork of i3wm with more features including gaps" "$(ofn i3-gaps "${INSTALL_WMS[*]}")" \
429 openbox "A lightweight, powerful, and highly configurable stacking wm" "$(ofn openbox "${INSTALL_WMS[*]}")" \
430 dwm "A dynamic WM for X that manages windows in tiled, floating, or monocle layouts" "$(ofn dwm "${INSTALL_WMS[*]}")" \
431 bspwm "A tiling wm that represents windows as the leaves of a binary tree" "$(ofn bspwm "${INSTALL_WMS[*]}")" \
432 jwm "A lightweight window manager for Xorg written in C" "$(ofn jwm "${INSTALL_WMS[*]}")" \
433 xfce4 "A lightweight and modular desktop environment based on gtk+2/3" "$(ofn xfce4 "${INSTALL_WMS[*]}")" \
434 awesome "A customized Awesome WM session created by @elanapan" "$(ofn awesome "${INSTALL_WMS[*]}")" \
435 fluxbox "A lightweight and highly-configurable window manager" "$(ofn fluxbox "${INSTALL_WMS[*]}")" \
436 plasma "A kde software project currently comprising a full desktop environment" "$(ofn plasma "${INSTALL_WMS[*]}")" \
437 gnome "A desktop environment that aims to be simple and easy to use" "$(ofn gnome "${INSTALL_WMS[*]}")" \
438 cinnamon "A desktop environment combining traditional desktop with modern effects" "$(ofn cinnamon "${INSTALL_WMS[*]}")"
440 [[ $INSTALL_WMS ]] || return 0
441 WM_PKGS="${INSTALL_WMS/dwm/}"
442 WM_PKGS="${WM_PKGS// / }"
443 WM_PKGS="${WM_PKGS# }"
445 for i in $INSTALL_WMS; do
446 LOGIN_CHOICES+="$i - "
447 [[ ${WM_EXT[$i]} && $WM_PKGS != *"${WM_EXT[$i]}"* ]] && WM_PKGS+=" ${WM_EXT[$i]}"
450 select_login || return 1
452 while IFS=' ' read -r pkg; do
453 [[ $PACKAGES != *"$pkg"* ]] && PACKAGES+=" $pkg"
461 dlg USER_PKGS check " Packages " "$_packages" \
462 abiword "A Fully-featured word processor" "$(ofn abiword "${USER_PKGS[*]}")" \
463 alacritty "A cross-platform, GPU-accelerated terminal emulator" "$(ofn alacritty "${USER_PKGS[*]}")" \
464 atom "An open-source text editor developed by GitHub" "$(ofn atom "${USER_PKGS[*]}")" \
465 audacious "A free and advanced audio player based on GTK+" "$(ofn audacious "${USER_PKGS[*]}")" \
466 audacity "A program that lets you manipulate digital audio waveforms" "$(ofn audacity "${USER_PKGS[*]}")" \
467 blueman "GUI bluetooth device manager" "$(ofn blueman "${USER_PKGS[*]}")" \
468 bluez "Simple CLI based bluetooth support" "$(ofn bluez "${USER_PKGS[*]}")" \
469 cairo-dock "Light eye-candy fully themable animated dock" "$(ofn cairo-dock "${USER_PKGS[*]}")" \
470 calligra "A set of applications for productivity" "$(ofn calligra "${USER_PKGS[*]}")" \
471 chromium "An open-source web browser based on the Blink rendering engine" "$(ofn chromium "${USER_PKGS[*]}")" \
472 clementine "A modern music player and library organizer" "$(ofn clementine "${USER_PKGS[*]}")" \
473 cmus "A small, fast and powerful console music player" "$(ofn cmus "${USER_PKGS[*]}")" \
474 deadbeef "A GTK+ audio player for GNU/Linux" "$(ofn deadbeef "${USER_PKGS[*]}")" \
475 deluge "A BitTorrent client written in python" "$(ofn deluge "${USER_PKGS[*]}")" \
476 emacs "An extensible, customizable, self-documenting real-time display editor" "$(ofn emacs "${USER_PKGS[*]}")" \
477 epiphany "A GNOME web browser based on the WebKit rendering engine" "$(ofn epiphany "${USER_PKGS[*]}")" \
478 evince "A document viewer" "$(ofn evince "${USER_PKGS[*]}")" \
479 evolution "Manage your email, contacts and schedule" "$(ofn evolution "${USER_PKGS[*]}")" \
480 file-roller "Create and modify archives" "$(ofn file-roller "${USER_PKGS[*]}")" \
481 firefox "A popular open-source web browser from Mozilla" "$(ofn firefox "${USER_PKGS[*]}")" \
482 gcolor2 "A simple GTK+2 color selector" "$(ofn gcolor2 "${USER_PKGS[*]}")" \
483 geany "A fast and lightweight IDE" "$(ofn geany "${USER_PKGS[*]}")" \
484 geary "A lightweight email client for the GNOME desktop" "$(ofn geary "${USER_PKGS[*]}")" \
485 gimp "GNU Image Manipulation Program" "$(ofn gimp "${USER_PKGS[*]}")" \
486 gnome-calculator "GNOME Scientific calculator" "$(ofn gnome-calculator "${USER_PKGS[*]}")" \
487 gnome-disk-utility "Disk Management Utility" "$(ofn gnome-disk-utility "${USER_PKGS[*]}")" \
488 gnome-system-monitor "View current processes and monitor system state" "$(ofn gnome-system-monitor "${USER_PKGS[*]}")" \
489 gparted "A GUI frontend for creating and manipulating partition tables" "$(ofn gparted "${USER_PKGS[*]}")" \
490 gpick "Advanced color picker using GTK+ toolkit" "$(ofn gpick "${USER_PKGS[*]}")" \
491 gpicview "Lightweight image viewer" "$(ofn gpicview "${USER_PKGS[*]}")" \
492 guvcview "Capture video from camera devices" "$(ofn guvcview "${USER_PKGS[*]}")" \
493 hexchat "A popular and easy to use graphical IRC client" "$(ofn hexchat "${USER_PKGS[*]}")" \
494 inkscape "Professional vector graphics editor" "$(ofn inkscape "${USER_PKGS[*]}")" \
495 irssi "Modular text mode IRC client" "$(ofn irssi "${USER_PKGS[*]}")" \
496 kdenlive "A popular non-linear video editor for Linux" "$(ofn kdenlive "${USER_PKGS[*]}")" \
497 krita "Edit and paint images" "$(ofn krita "${USER_PKGS[*]}")" \
498 libreoffice-fresh "Full featured office suite" "$(ofn libreoffice-fresh "${USER_PKGS[*]}")" \
499 lollypop "A new music playing application" "$(ofn lollypop "${USER_PKGS[*]}")" \
500 mousepad "A simple text editor" "$(ofn mousepad "${USER_PKGS[*]}")" \
501 mpd "A flexible, powerful, server-side application for playing music" "$(ofn mpd "${USER_PKGS[*]}")" \
502 mpv "A media player based on mplayer" "$(ofn mpv "${USER_PKGS[*]}")" \
503 mupdf "Lightweight PDF and XPS viewer" "$(ofn mupdf "${USER_PKGS[*]}")" \
504 mutt "Small but very powerful text-based mail client" "$(ofn mutt "${USER_PKGS[*]}")" \
505 nautilus "The default file manager for Gnome" "$(ofn nautilus "${USER_PKGS[*]}")" \
506 ncmpcpp "A mpd client and almost exact clone of ncmpc with some new features" "$(ofn ncmpcpp "${USER_PKGS[*]}")" \
507 neovim "A fork of Vim aiming to improve user experience, plugins, and GUIs." "$(ofn neovim "${USER_PKGS[*]}")" \
508 noto-fonts "Google Noto fonts" "$(ofn noto-fonts "${USER_PKGS[*]}")" \
509 noto-fonts-cjk "Google Noto CJK fonts (Chinese, Japanese, Korean)" "$(ofn noto-fonts-cjk "${USER_PKGS[*]}")" \
510 obs-studio "Free opensource streaming/recording software" "$(ofn obs-studio "${USER_PKGS[*]}")" \
511 openshot "An open-source, non-linear video editor for Linux" "$(ofn openshot "${USER_PKGS[*]}")" \
512 opera "A Fast and secure, free of charge web browser from Opera Software" "$(ofn opera "${USER_PKGS[*]}")" \
513 pcmanfm "A fast and lightweight file manager based in Lxde" "$(ofn pcmanfm "${USER_PKGS[*]}")" \
514 pidgin "Multi-protocol instant messaging client" "$(ofn pidgin "${USER_PKGS[*]}")" \
515 plank "An elegant, simple, and clean dock" "$(ofn plank "${USER_PKGS[*]}")" \
516 qbittorrent "An advanced BitTorrent client" "$(ofn qbittorrent "${USER_PKGS[*]}")" \
517 qpdfview "A tabbed PDF viewer" "$(ofn qpdfview "${USER_PKGS[*]}")" \
518 qt5ct "GUI for managing Qt based application themes, icons, and fonts" "$(ofn qt5ct "${USER_PKGS[*]}")" \
519 qutebrowser "A keyboard-focused vim-like web browser based on Python and PyQt5" "$(ofn qutebrowser "${USER_PKGS[*]}")" \
520 rhythmbox "A Music playback and management application" "$(ofn rhythmbox "${USER_PKGS[*]}")" \
521 rxvt-unicode "A unicode enabled rxvt-clone terminal emulator" "$(ofn rxvt-unicode "${USER_PKGS[*]}")" \
522 sakura "A terminal emulator based on GTK and VTE" "$(ofn sakura "${USER_PKGS[*]}")" \
523 simple-scan "Simple scanning utility" "$(ofn simple-scan "${USER_PKGS[*]}")" \
524 simplescreenrecorder "A feature-rich screen recorder" "$(ofn simplescreenrecorder "${USER_PKGS[*]}")" \
525 steam "A popular game distribution platform by Valve" "$(ofn steam "${USER_PKGS[*]}")" \
526 surf "A simple web browser based on WebKit2/GTK+" "$(ofn surf "${USER_PKGS[*]}")" \
527 terminator "Terminal emulator that supports tabs and grids" "$(ofn terminator "${USER_PKGS[*]}")" \
528 termite "A minimal VTE-based terminal emulator" "$(ofn termite "${USER_PKGS[*]}")" \
529 thunar "A modern file manager for the Xfce Desktop Environment" "$(ofn thunar "${USER_PKGS[*]}")" \
530 thunderbird "Standalone mail and news reader from mozilla" "$(ofn thunderbird "${USER_PKGS[*]}")" \
531 tilda "A GTK based drop down terminal for Linux and Unix" "$(ofn tilda "${USER_PKGS[*]}")" \
532 tilix "A tiling terminal emulator for Linux using GTK+ 3" "$(ofn tilix "${USER_PKGS[*]}")" \
533 transmission-cli "Free BitTorrent client CLI" "$(ofn transmission-cli "${USER_PKGS[*]}")" \
534 transmission-gtk "GTK+ Front end for transmission" "$(ofn transmission-gtk "${USER_PKGS[*]}")" \
535 transmission-qt "Qt Front end for transmission" "$(ofn transmission-qt "${USER_PKGS[*]}")" \
536 ttf-anonymous-pro "A family fixed-width fonts designed with code in mind" "$(ofn ttf-anonymous-pro "${USER_PKGS[*]}")" \
537 ttf-fira-code "Monospaced font with programming ligatures" "$(ofn ttf-fira-code "${USER_PKGS[*]}")" \
538 ttf-font-awesome "Iconic font designed for Bootstrap" "$(ofn ttf-font-awesome "${USER_PKGS[*]}")" \
539 ttf-hack "A hand groomed typeface based on Bitstream Vera Mono" "$(ofn ttf-hack "${USER_PKGS[*]}")" \
540 vlc "A free and open source cross-platform multimedia player" "$(ofn vlc "${USER_PKGS[*]}")" \
541 weechat "Fast, light and extensible IRC client" "$(ofn weechat "${USER_PKGS[*]}")" \
542 xapps "Common library for X-Apps project" "$(ofn xapps "${USER_PKGS[*]}")" \
543 xarchiver "A GTK+ frontend to various command line archivers" "$(ofn xarchiver "${USER_PKGS[*]}")" \
544 xed "A small and lightweight text editor. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
545 xfce4-terminal "A terminal emulator based in the Xfce Desktop Environment" "$(ofn xfce4-terminal "${USER_PKGS[*]}")" \
546 xreader "Document viewer for files like PDF and Postscript. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
547 zathura "Minimalistic document viewer" "$(ofn zathura "${USER_PKGS[*]}")"
549 if [[ $USER_PKGS ]]; then # add any needed PKG_EXT to the list
550 for i in $USER_PKGS; do
551 [[ ${PKG_EXT[$i]} && $USER_PKGS != *"${PKG_EXT[$i]}"* ]] && USER_PKGS+=" ${PKG_EXT[$i]}"
558 ###############################################################################
560 # non-essential partitioning helpers called by the user when using the optional
561 # partition menu and selecting a device to edit
565 no_bg_install || return 0
566 local device choice devhash
567 devhash="$(lsblk -f | base64)"
569 part_device || return 1
574 dlg choice menu "Edit Partitions" "$_part\n\n$(lsblk -no NAME,MODEL,SIZE,TYPE,FSTYPE $device)" \
575 "auto" "Whole device automatic partitioning" \
576 "shrink" "Shrink an existing ext or ntfs partition" \
577 "cfdisk" "Curses based variant of fdisk" \
578 "parted" "GNU partition editor" \
579 "fdisk" "Dialog-driven creation and manipulation of partitions" \
580 "done" "Return to the main menu"
582 if [[ -z $choice || $choice == 'done' ]]; then
584 elif [[ $choice == 'shrink' ]]; then
585 part_shrink "$device"
586 elif [[ $choice == 'auto' ]]; then
587 local root_size txt table boot_fs
588 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"}}')
589 txt="\nWARNING:\n\nALL data on $device will be destroyed and the following partitions will be created\n\n- "
590 if [[ $SYS == 'BIOS' ]]; then
591 table="msdos" boot_fs="ext4"
592 txt+="An $boot_fs boot partition with the boot flag enabled (512M)\n- "
594 table="gpt" boot_fs="fat32"
595 txt+="A $boot_fs efi boot partition (512M)\n- "
597 txt+="An ext4 partition using all remaining space ($root_size)\n\nDo you want to continue?\n"
598 yesno "Auto Partition" "$txt" && part_auto "$device" "$table" "$boot_fs" "$root_size"
604 if [[ $devhash != "$(lsblk -f | base64)" ]]; then
605 msg "Probing Partitions" "\nInforming kernel of partition changes using partprobe\n" 0
606 partprobe > /dev/null 2>&1
607 [[ $choice == 'auto' ]] && return
615 if [[ $IGNORE_DEV ]]; then
616 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk "!/$IGNORE_DEV/"' && /disk|part|lvm|crypt|NAME/')"
618 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk '/disk|part|lvm|crypt|NAME/')"
620 msg "Device Tree" "\n\n$txt\n\n"
625 local device="$1" table="$2" boot_fs="$3" size="$4" dev_info=""
627 msg "Auto Partition" "\nRemoving partitions on $device and setting table to $table\n" 1
629 dev_info="$(parted -s "$device" print)"
632 while read -r PART; do
633 parted -s "$device" rm "$PART" > /dev/null 2>&1
634 done <<< "$(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r)"
636 [[ $(awk '/Table:/ {print $3}' <<< "$dev_info") != "$table" ]] && parted -s "$device" mklabel "$table" > /dev/null 2>&1
638 msg "Auto Partition" "\nCreating a 512M $boot_fs boot partition.\n" 1
639 if [[ $SYS == "BIOS" ]]; then
640 parted -s "$device" mkpart primary "$boot_fs" 1MiB 513MiB > /dev/null 2>&1
642 parted -s "$device" mkpart ESP "$boot_fs" 1MiB 513MiB > /dev/null 2>&1
647 AUTO_BOOT_PART=$(lsblk -lno NAME,TYPE "$device" | awk 'NR==2 {print "/dev/" $1}')
649 if [[ $SYS == "BIOS" ]]; then
650 mkfs.ext4 -q "$AUTO_BOOT_PART" > /dev/null 2>&1
652 mkfs.vfat -F32 "$AUTO_BOOT_PART" > /dev/null 2>&1
655 msg "Auto Partition" "\nCreating a $size ext4 root partition.\n" 0
656 parted -s "$device" mkpart primary ext4 513MiB 100% > /dev/null 2>&1
658 AUTO_ROOT_PART="$(lsblk -lno NAME,TYPE "$device" | awk 'NR==3 {print "/dev/" $1}')"
659 mkfs.ext4 -q "$AUTO_ROOT_PART" > /dev/null 2>&1
661 msg "Auto Partition" "\nProcess complete.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$device")\n"
668 local device="$1" fs=""
670 part_find "${device##*/}[^ ]" || return 1
671 (( COUNT == 1 )) && part="$(awk '{print $1}' <<< "${PARTS[@]}" )"
673 if (( COUNT == 1 )) || dlg part menu "Resize" "\nWhich partition on $device do you want to resize?" $PARTS; then
674 fs=$(lsblk -lno FSTYPE "$part")
677 msg "Resize" "\nGathering device size info.\n" 0
679 end=$(parted -s "$device" unit KiB print | awk '/^\s*'"$num"'/ {print $3}') # part size in KiB
680 devsize=$(parted -s "$device" unit KiB print | awk '/Disk '"${device//\//\\/}"':/ {print $3}') # whole device size in KiB
681 mount "$part" "$MNT" > /dev/null 2>&1; sleep 0.5
682 min=$(df --output=used --block-size=MiB "$part" | awk 'NR == 2 {print int($1) + 256}')
683 max=$(df --output=avail --block-size=MiB "$part" | awk 'NR == 2 {print int($1)}')
686 if dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Resize: $part " --rangebox "$_resize" 17 "$COLUMNS" "$min" "$max" $((max / 2)) 2> $ANS; then
688 size=$((size * 1024))
695 if ntfsresize -fc "$part"; then
696 ntfsresize -ff --size $(( (size * 1024) / 1000 ))k "$part" 2> $ERR # k=10^3 bytes
697 errshow "ntfsresize -f -s $(( (size * 1024) / 1000 ))k $part" || return 1
699 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"
704 e2fsck -f "$part"; sleep 0.5
705 resize2fs -f "$part" ${size}K 2> $ERR # K=2^10 bytes
706 errshow "resize2fs -f $part ${size}K" || return 1
710 parted "$device" resizepart "$num" ${size}KiB || return 1
713 if [[ $devsize == "$end" ]]; then
714 parted -s "$device" mkpart primary ext4 ${size}KiB 100% 2> $ERR
715 errshow "parted -s $device mkpart primary ext4 ${size}KiB 100%" || return 1
717 parted -s "$device" mkpart primary ext4 ${size}KiB ${end}KiB 2> $ERR
718 errshow "parted -s $device mkpart primary ext4 ${size}KiB ${end}KiB" || return 1
720 msg "Resize Complete" "\n$part has been successfully resized to $((size / 1024))M.\n" 1
722 "") msg "No Filesystem" "\nFor unformatted partitions, cfdisk can be used in the partition menu.\n" ;;
723 *) msg "Invalid Filesystem: $fs" "\nResizing only supports ext and ntfs.\n" ;;
728 ###############################################################################
729 # partition management functions
730 # these are helpers for use by other functions to do essential setup/teardown
734 local regexp="$1" err=''
736 # string of partitions as /TYPE/PART SIZE.. eg. /dev/sda1 256G
737 if [[ $IGNORE_DEV ]]; then
738 PARTS="$(lsblk -lno TYPE,NAME,SIZE | awk "/$regexp/"' && !'"/$IGNORE_DEV/"' {sub(/^part/, "/dev/"); sub(/^lvm|^crypt/, "/dev/mapper/"); print $1$2, $3}')"
740 PARTS="$(lsblk -lno TYPE,NAME,SIZE | awk "/$regexp/"' {sub(/^part/, "/dev/"); sub(/^lvm|^crypt/, "/dev/mapper/"); print $1$2 " " $3}')"
743 # ensure we have enough partitions for the system and action were trying to do
744 COUNT=$(wc -l <<< "$PARTS")
746 'part|lvm|crypt') [[ $COUNT -lt 1 || ($SYS == 'UEFI' && $COUNT -lt 2) ]] && err="$_errpart" ;;
747 'part|crypt') (( COUNT < 1 )) && err="$_lvmerr" ;;
748 'part|lvm') (( COUNT < 2 )) && err="$_lukserr" ;;
752 msg "Not Enough Partitions" "$err" 2
761 if [[ $1 == "$MNT/swapfile" && $SWAP_SIZE ]]; then
762 fallocate -l $SWAP_SIZE "$1" 2> $ERR
763 errshow "fallocate -l $SWAP_SIZE $1"
764 chmod 600 "$1" 2> $ERR
765 errshow "chmod 600 $1"
767 mkswap "$1" > /dev/null 2> $ERR
769 swapon "$1" > /dev/null 2> $ERR
776 local part="$1" mountp="${MNT}$2" fs=""
777 fs="$(lsblk -lno FSTYPE "$part")"
780 if [[ $fs && ${FS_OPTS[$fs]} && $part != "$BOOT_PART" && $part != "$AUTO_ROOT_PART" ]] && select_mntopts "$fs"; then
781 mount -o "$MNT_OPTS" "$part" "$mountp" > /dev/null 2>&1
783 mount "$part" "$mountp" > /dev/null 2>&1
786 part_mountconf "$part" "$mountp" || return 1
794 local part="$1" fs="$2" delay="$3"
796 msg "Format" "\nFormatting $part as $fs\n" 0
797 mkfs.$fs ${FS_CMD_FLAGS[$fs]} "$part" > /dev/null 2> $ERR
798 errshow "mkfs.$fs ${FS_CMD_FLAGS[$fs]} "$part"" || return 1
805 if [[ $DEV_COUNT -eq 1 && $SYS_DEVS ]]; then
806 DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
807 elif (( DEV_COUNT > 1 )); then
809 dlg DEVICE menu "Boot Device" "\nSelect the device to use for bootloader install." $SYS_DEVS
811 dlg DEVICE menu "Select Device" "$_device" $SYS_DEVS
813 [[ $DEVICE ]] || return 1
814 elif [[ $DEV_COUNT -lt 1 && ! $1 ]]; then
815 msg "Device Error" "\nNo available devices.\n\nExiting..\n" 2
819 [[ $1 ]] && BOOT_DEV="$DEVICE"
826 BOOT_DEV="${BOOT_PART%[1-9]}"
827 BOOT_PART_NUM="${BOOT_PART: -1}"
828 [[ $BOOT_PART = /dev/nvme* ]] && BOOT_DEV="${BOOT_PART%p[1-9]}"
829 if [[ $SYS == 'UEFI' ]]; then
830 parted -s $BOOT_DEV set $BOOT_PART_NUM esp on > /dev/null 2>&1
832 parted -s $BOOT_DEV set $BOOT_PART_NUM boot on > /dev/null 2>&1
839 local part="$1" devs=""
840 devs="$(lsblk -lno NAME,FSTYPE,TYPE)"
842 # Identify if $part is LUKS+LVM, LVM+LUKS, LVM alone, or LUKS alone
843 if lsblk -lno TYPE "$part" | grep -q 'crypt'; then
845 LUKS_NAME="${part#/dev/mapper/}"
846 for dev in $(awk '/lvm/ && /crypto_LUKS/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
847 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
848 LUKS_DEV="$LUKS_DEV cryptdevice=$dev:$LUKS_NAME"
853 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
854 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
855 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
856 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
860 elif lsblk -lno TYPE "$part" | grep -q 'lvm'; then
862 VNAME="${part#/dev/mapper/}"
863 for dev in $(awk '/crypt/ && /lvm2_member/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
864 if lsblk -lno NAME "$dev" | grep -q "$VNAME"; then
865 LUKS_NAME="${dev/\/dev\/mapper\//}"
869 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
870 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
871 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
872 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
883 if (( COUNT > 0 )); then
884 PARTS="$(sed "/${pt//\//\\/}/d" <<< "$PARTS")"
892 if grep -qw "$1" /proc/mounts; then
893 msg "Mount Success" "\nPartition $1 mounted at $2\n" 1
897 msg "Mount Fail" "\nPartition $1 failed to mount at $2\n" 2
902 ###############################################################################
904 # mount_menu is the entry point which calls all other functions
905 # once finished it returns to the main menu: main()
909 no_bg_install || return 0
912 part_find 'part|lvm|crypt' || { SEL=2; return 1; }
913 [[ $LUKS && $LUKS_PART ]] && part_countdec $LUKS_PART
914 [[ $LVM && $LVM_PARTS ]] && part_countdec $LVM_PARTS
915 select_root_partition || { ROOT_PART=''; return 1; }
916 select_boot_partition || { BOOT_PART=''; return 1; }
917 if [[ $BOOT_PART ]]; then
918 part_mount "$BOOT_PART" "/$BOOTDIR" && SEP_BOOT=true || return 1
921 select_swap || return 1
922 select_extra_partitions || return 1
929 local pts dev size isize
931 while read -r dev size; do # walk partition list and skip ones that are too small/big for swap
932 size_t="${size: -1:1}"
935 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 16) || ($size_t == 'M' && $isize -lt 100) ]] || pts+="$dev $size "
938 dlg SWAP_PART menu "Swap Setup" "\nSelect whether to use a swapfile, swap partition, or none." \
939 "none" "Don't allocate any swap space" \
940 "swapfile" "Allocate $SYS_MEM at /swapfile" \
943 if [[ -z $SWAP_PART || $SWAP_PART == "none" ]]; then
946 elif [[ $SWAP_PART == "swapfile" ]]; then
948 until [[ ${SWAP_SIZE:0:1} =~ [1-9] && ${SWAP_SIZE: -1} =~ (M|G) ]]; do
949 (( 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
950 dlg SWAP_SIZE input "Swap Setup" "$_swapsize" "$SYS_MEM" || { SWAP_PART=''; SWAP_SIZE=''; return 1; }
953 part_swap "$MNT/$SWAP_PART"
954 SWAP_PART="/$SWAP_PART"
955 elif [[ $PARTS == *"$SWAP_PART"* ]]; then
957 part_countdec $SWAP_PART
958 SWAP_SIZE="$(lsblk -lno SIZE $SWAP_PART)"
968 local fs="$1" opts=''
969 local title="${fs^} Mount Options"
971 for i in ${FS_OPTS[$fs]}; do
975 until [[ $MNT_OPTS ]]; do
976 dlg MNT_OPTS check "$title" "$_mount" $opts
977 [[ $MNT_OPTS ]] || return 1
978 MNT_OPTS="${MNT_OPTS// /,}"
979 yesno "$title" "\nConfirm the following options: $MNT_OPTS\n" || MNT_OPTS=''
988 until [[ $EXMNT ]]; do
989 dlg EXMNT input "Extra Mount $part" "$_exmnt" "/" || return 1
990 if [[ ${EXMNT:0:1} != "/" || ${#EXMNT} -le 1 || $EXMNT =~ \ |\' || $EXMNTS == *"$EXMNT"* ]]; then
991 msg "Mountpoint Error" "$_errexpart"
995 msg "Mount Extra" "\nMounting Finished\n\n\nNo extra partitions available to mount, returning to main menu.\n" 2
1001 local part="$1" fs='' cur=''
1002 local txt="\nSelect which filesystem to use for: $part\n\nDefault: ext4"
1003 cur="$(lsblk -lno FSTYPE "$part" 2> /dev/null)"
1005 # bail early if the partition was created in part_auto()
1006 [[ $cur && $part == "$AUTO_ROOT_PART" ]] && return 0
1009 if [[ $cur && $FORMATTED == *"$part"* ]]; then
1010 dlg fs menu "Filesystem" "$txt\nCurrent: $cur" skip - ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1012 dlg fs menu "Filesystem" "$txt" ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1014 [[ $fs == 'skip' ]] && return 0
1015 yesno "Filesystem" "\nFormat $part as $fs?\n" || fs=''
1017 part_format "$part" "$fs" 0
1020 select_boot_partition()
1022 local pts dev size isize ptcount=0
1024 if [[ -z $BOOT_PART ]]; then
1025 if [[ $AUTO_BOOT_PART && -z $LVM && -z $LUKS ]]; then
1026 BOOT_PART="$AUTO_BOOT_PART"
1029 while read -r dev size; do # walk partition list and skip ones that are too small/big for boot
1030 size_t="${size: -1:1}"
1033 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1039 0) msg "EFI Boot Partition" "\nNo partitions available that meet size requirements!!\n\nReturning to the main menu.\n" 2; return 1 ;;
1040 1) msg "EFI Boot Partition" "\nOnly one partition available that meets size requirements.\n" 1; BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")" ;;
1041 *) dlg BOOT_PART menu "EFI Partition" "$_uefi" $pts ;;
1043 [[ $BOOT_PART ]] || return 1
1046 (( ptcount == 0 )) && return 0
1047 if [[ $LUKS && ! $LVM ]]; then
1048 dlg BOOT_PART menu "Boot Partition" "$_biosluks" $pts
1049 [[ $BOOT_PART ]] || return 1
1051 dlg BOOT_PART menu "Boot Partition" "$_bios" "skip" "no separate boot" $pts
1052 [[ -z $BOOT_PART || $BOOT_PART == "skip" ]] && { BOOT_PART=''; return 0; }
1059 if ([[ $SYS == 'BIOS' ]] && grep -q 'ext[34]' <<< "$(fsck -N "$BOOT_PART")") || ([[ $SYS == 'UEFI' ]] && grep -q 'fat' <<< "$(fsck -N "$BOOT_PART")"); then
1060 yesno "Format Boot Partition" "\nIMPORTANT:\n\nThe boot partition $BOOT_PART $_format" "Format $BOOT_PART" "Skip Formatting" 1 || return 0
1064 UEFI) part_format "$BOOT_PART" "vfat" 2 || return 1 ;;
1065 BIOS) part_format "$BOOT_PART" "ext4" 2 || return 1 ;;
1070 select_root_partition()
1072 if [[ -z $ROOT_PART ]]; then
1073 if [[ $AUTO_ROOT_PART && -z $LVM && -z $LUKS ]]; then
1074 ROOT_PART="$AUTO_ROOT_PART"
1075 msg "Mount Menu" "\nUsing partitions created during automatic format.\n" 2
1076 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1077 return 0 # we're done here
1079 local pts dev size isize ptcount=0
1081 # walk partition list and skip ones that are too small for / (root)
1082 while read -r dev size; do
1083 size_t="${size: -1:1}" # size type eg. K, M, G, T
1084 isize=${size:0:-1} # remove trailing size type character
1085 isize=${isize%.*} # remove any decimal (round down)
1086 [[ $size_t =~ [MK] || ($size_t == 'G' && $isize -lt 4) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1089 if (( ptcount == 1 )); then # only one available device
1090 msg "Root Partition (/)" "\nOnly one partition available that meets size requirements.\n" 2
1091 ROOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")"
1093 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
1098 if [[ -z $ROOT_PART ]] || ! select_filesystem "$ROOT_PART" || ! part_mount "$ROOT_PART"; then
1105 select_extra_partitions()
1109 # walk partition list and skip ones that are too small to be usable
1110 while read -r dev size; do
1111 [[ ${size: -1:1} =~ [KM] ]] && part_countdec "$dev"
1114 while (( COUNT > 0 )); do
1116 dlg part menu 'Mount Extra' "$_expart" 'done' 'finish mounting step' $PARTS || break
1117 if [[ $part == 'done' ]]; then
1119 elif select_filesystem "$part" && select_mountpoint && part_mount "$part" "$EXMNT"; then
1120 EXMNTS+="$part: $EXMNT "
1121 [[ $EXMNT == '/usr' && $HOOKS != *usr* ]] && HOOKS+=" usr"
1129 ###############################################################################
1131 # main is the entry point which calls all other install functions, once
1132 # complete it shows a dialog to edit files on the new system before reboot
1137 genfstab -U "$MNT" > "$MNT/etc/fstab" 2> "$ERR" 2>&1
1138 errshow 1 "genfstab -U $MNT > $MNT/etc/fstab"
1139 [[ -f $MNT/swapfile ]] && sed -i "s~${MNT}~~" "$MNT/etc/fstab"
1141 # video driver tearfree configs, MUST be done after package install to support nvidia
1142 install_tearfree_conf "$MNT/etc/X11/xorg.conf.d"
1145 chrun "hwclock --systohc --utc" || chrun "hwclock --systohc --utc --directisa"
1148 chrun "chown -Rf $NEWUSER:users /home/$NEWUSER"
1149 if [[ "$USER_CMD" ]]; then
1150 chrun "$USER_CMD" 2> "$ERR" 2>&1
1151 errshow 0 "$USER_CMD"
1155 dlg choice menu "Finalization" "$_edit" \
1156 finished "exit the installer and reboot" \
1157 keyboard "${EDIT_FILES[keyboard]}" \
1158 console "${EDIT_FILES[console]}" \
1159 locale "${EDIT_FILES[locale]}" \
1160 hostname "${EDIT_FILES[hostname]}" \
1161 sudoers "${EDIT_FILES[sudoers]}" \
1162 mkinitcpio "${EDIT_FILES[mkinitcpio]}" \
1163 fstab "${EDIT_FILES[fstab]}" \
1164 crypttab "${EDIT_FILES[crypttab]}" \
1165 bootloader "${EDIT_FILES[bootloader]}" \
1166 pacman "${EDIT_FILES[pacman]}" \
1167 login "${EDIT_FILES[login]}"
1169 if [[ -z $choice || $choice == 'finished' ]]; then
1170 [[ $DEBUG == true && -r $DBG ]] && ${EDITOR:-vim} "$DBG"
1175 for f in ${EDIT_FILES[$choice]}; do
1176 if [[ -e ${MNT}$f ]]; then
1177 ${EDITOR:-vim} "${MNT}$f"
1179 msg "File Missing" "\nThe file(s) selected do not exist:\n\n${MNT}$f\n"
1190 while kill -0 $BG_PID 2> /dev/null; do
1191 clear; printf "\nA background install process is still running...\n"; sleep 1
1197 rm -rf "$MNT/etc/mkinitcpio-archiso.conf"
1198 find "$MNT/usr/lib/initcpio" -name 'archiso*' -type f -delete
1200 # remove/disable customizations done to airootfs during building
1201 chrun "systemctl disable pacman-init.service choose-mirror.service" > /dev/null 2>&1
1202 rm -f "$MNT/etc/systemd/scripts/choose-mirror"
1203 rm -f "$MNT/etc/systemd/system/"{choose-mirror.service,etc-pacman.d-gnupg.mount,pacman-init.service}
1204 sed -i 's/#\(Storage=\)volatile/\1auto/' "$MNT/etc/systemd/journald.conf"
1205 sed -i 's/#\(HandleSuspendKey=\)ignore/\1suspend/' "$MNT/etc/systemd/logind.conf"
1206 sed -i 's/#\(HandleHibernateKey=\)ignore/\1hibernate/' "$MNT/etc/systemd/logind.conf"
1207 sed -i 's/#\(HandleLidSwitch=\)ignore/\1suspend/' "$MNT/etc/systemd/logind.conf"
1208 find "$MNT/boot" -name '*-ucode.img' -delete
1210 # changing distro name?
1211 [[ $DIST != "ArchLabs" ]] || sed -i "s/ArchLabs/$DIST/g" "$MNT/etc/"{lsb-release,os-release}
1213 # vmlinuz, if this isn't copied the standard kernel may fail mkinitcpio
1214 cp -vf "$RUN/x86_64/vmlinuz" "$MNT/boot/vmlinuz-linux" 2> $ERR 2>&1
1215 errshow 1 "cp -vf $RUN/x86_64/vmlinuz $MNT/boot/vmlinuz-linux"
1217 # copy network settings
1218 [[ -d /etc/netctl ]] && cp -rfv /etc/netctl "$MNT/etc/"
1219 [[ -f /etc/resolv.conf ]] && cp -fv /etc/resolv.conf "$MNT/etc/"
1220 [[ -e /etc/NetworkManager/system-connections ]] && cp -rvf /etc/NetworkManager/system-connections "$MNT/etc/NetworkManager/"
1222 echo "LANG=$MYLOCALE" > "$MNT/etc/locale.conf"
1223 cp -fv "$MNT/etc/locale.conf" "$MNT/etc/default/locale"
1224 sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${MYLOCALE}/${MYLOCALE}/g" "$MNT/etc/locale.gen"
1226 chrun "ln -svf /usr/share/zoneinfo/$ZONE/$SUBZ /etc/localtime"
1228 cat > "$MNT/etc/X11/xorg.conf.d/00-keyboard.conf" <<- EOF
1229 # Use localectl(1) to instruct systemd-localed to update it.
1230 Section "InputClass"
1231 Identifier "system-keyboard"
1232 MatchIsKeyboard "on"
1233 Option "XkbLayout" "$KEYMAP"
1237 cat > "$MNT/etc/default/keyboard" <<- EOF
1238 # KEYBOARD CONFIGURATION FILE
1239 # Consult the keyboard(5) manual page.
1246 printf "KEYMAP=%s\nFONT=%s\n" "$CMAP" "$FONT" > "$MNT/etc/vconsole.conf"
1248 echo "$MYHOST" > "$MNT/etc/hostname"
1249 cat > "$MNT/etc/hosts" <<- EOF
1252 ::1 localhost ip6-localhost ip6-loopback
1253 ff02::1 ip6-allnodes
1254 ff02::2 ip6-allrouters
1260 echo "Installing $BOOTLDR"
1262 if [[ $ROOT_PART == /dev/mapper* ]]; then
1263 ROOT_PART_ID="$ROOT_PART"
1265 local uuid_type="UUID"
1266 [[ $BOOTLDR =~ (systemd-boot|refind-efi|efistub) ]] && uuid_type="PARTUUID"
1267 ROOT_PART_ID="$uuid_type=$(blkid -s $uuid_type -o value $ROOT_PART)"
1270 if [[ $SYS == 'UEFI' ]]; then
1271 # remove our old install and generic BOOT/ dir
1272 echo "Removing conflicting boot directories"
1273 find "$MNT/$BOOTDIR/EFI/" -maxdepth 1 -mindepth 1 -iname "$DIST" -type d -delete -printf "remove %p\n"
1274 find "$MNT/$BOOTDIR/EFI/" -maxdepth 1 -mindepth 1 -iname 'BOOT' -type d -delete -printf "remove %p\n"
1278 chrun "${BCMDS[$BOOTLDR]}" 2> $ERR 2>&1
1279 errshow 1 "${BCMDS[$BOOTLDR]}"
1281 if [[ -d $MNT/hostrun ]]; then
1282 echo "Unmounting chroot directories"
1283 # cleanup the bind mounts we made earlier for the grub-probe module
1284 umount_dir "$MNT/hostrun/"{udev,lvm}
1285 rm -rf "$MNT/hostrun" > /dev/null 2>&1
1288 if [[ $SYS == 'UEFI' ]]; then
1289 # some UEFI firmware requires a generic esp/BOOT/BOOTX64.EFI
1290 mkdir -pv "$MNT/$BOOTDIR/EFI/BOOT"
1292 grub) cp -fv "$MNT/$BOOTDIR/EFI/$DIST/grubx64.efi" "$MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI" ;;
1293 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" ;;
1294 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"
1295 cp -fv "$MNT/$BOOTDIR/EFI/refind/refind_x64.efi" "$MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI" ;;
1304 local groups='audio,video,floppy,log,network,rfkill,scanner,storage,optical,power,wheel'
1305 [[ -e $MNT/etc/X11/xorg.conf.d/20-nvida.conf && -e $MNT/usr/bin/optirun ]] && groups+=',bumblebee'
1307 rm -f "$MNT/root/.zlogin" # remove welcome message
1309 chrun "chpasswd <<< 'root:$ROOT_PASS'" 2> "$ERR" 2>&1
1310 errshow 1 "set root password"
1311 if [[ $MYSHELL != 'zsh' ]]; then # root uses zsh by default
1312 chrun "usermod -s /bin/$MYSHELL root" 2> "$ERR" 2>&1
1313 errshow 1 "usermod -s /bin/$MYSHELL root"
1314 # copy the default mkshrc to /root if it was selected
1315 [[ $MYSHELL == 'mksh' ]] && cp -fv "$MNT/etc/skel/.mkshrc" "$MNT/root/.mkshrc"
1318 echo "Creating new user $NEWUSER and setting password"
1319 chrun "useradd -m -u 1000 -g users -G $groups -s /bin/$MYSHELL $NEWUSER" 2> "$ERR" 2>&1
1320 errshow 1 "useradd -m -u 1000 -g users -G $groups -s /bin/$MYSHELL $NEWUSER"
1321 chrun "chpasswd <<< '$NEWUSER:$USER_PASS'" 2> "$ERR" 2>&1
1322 errshow 1 "set $NEWUSER password"
1324 if [[ $INSTALL_WMS == *dwm* ]];then
1325 install_suckless "/home/$NEWUSER" chroot
1326 [[ $INSTALL_WMS == 'dwm' ]] && rm -rf "$MNT/home/$NEWUSER/.config/xfce4"
1328 [[ $INSTALL_WMS == *jwm* ]] && cp -rf "$MNT/etc/system.jwmrc" "$MNT/home/$NEWUSER/.jwmrc"
1329 [[ $INSTALL_WMS != *bspwm* && $INSTALL_WMS != *openbox* ]] && rm -rf "$MNT/home/$NEWUSER/.config/"{jgmenu,tint2}
1330 [[ $USER_PKGS != *geany* ]] && rm -rf "$MNT/home/$NEWUSER/.config/geany"
1331 [[ $MYSHELL != 'bash' ]] && rm -rf "$MNT/home/$NEWUSER/.bash"*
1332 [[ $MYSHELL != 'zsh' ]] && rm -rf "$MNT/home/$NEWUSER/.z"*
1334 # remove some commands from ~/.xprofile when using KDE or Gnome as the login session
1335 if [[ $LOGIN_WM =~ (startkde|gnome-session) || ($LOGIN_TYPE != 'xinit' && $WM_PKGS =~ (plasma|gnome)) ]]; then
1336 sed -i '/super/d; /nitrogen/d; /compton/d' "$MNT/home/$NEWUSER/.xprofile" "$MNT/root/.xprofile"
1337 elif [[ $LOGIN_WM == 'dwm' ]]; then # and dwm
1338 sed -i '/super/d; /compton/d' "$MNT/home/$NEWUSER/.xprofile" "$MNT/root/.xprofile"
1346 local serv="$MNT/etc/systemd/system/getty@tty1.service.d"
1347 echo "Setting up $LOGIN_TYPE"
1349 ly|sddm|gdm|lightdm)
1350 if [[ $LOGIN_WM == *dwm* ]]; then # dwm doesn't include an xsession file for display managers
1351 mkdir -p "$MNT/usr/share/xsessions"
1352 cat > "$MNT/usr/share/xsessions/dwm.desktop" <<- EOF
1356 Comment=Dynamic Window Manager
1361 rm -rf "$serv" "$MNT/home/$NEWUSER/.xinitrc"
1362 chrun "systemctl enable $LOGIN_TYPE.service" 2> $ERR 2>&1
1363 errshow 1 "systemctl enable $LOGIN_TYPE.service"
1364 ${LOGIN_TYPE}_config
1367 if [[ $INSTALL_WMS ]]; then
1368 sed -i "/exec/ c exec ${LOGIN_WM}" "$MNT/home/$NEWUSER/.xinitrc"
1369 elif [[ -e $MNT/home/$NEWUSER/.xinitrc ]]; then
1370 sed -i '/exec/d' "$MNT/home/$NEWUSER/.xinitrc"
1373 if [[ $AUTOLOGIN ]]; then
1374 sed -i "s/root/${NEWUSER}/g" $serv/autologin.conf
1375 cat > "$MNT/home/$NEWUSER/$LOGINRC" <<- EOF
1376 # automatically run startx when logging in on tty1
1377 [ \$XDG_VTNR -eq 1 ] && exec startx
1389 local inpkg="$PACKAGES $USER_PKGS $AL_BASE_PKGS "
1391 if pacman -Qq archlabs-installer > /dev/null 2>&1; then
1392 rmpkg+="archlabs-installer "
1395 if [[ $MYSHELL == 'zsh' ]]; then
1396 inpkg+="zsh-completions "
1401 if [[ $INSTALL_WMS =~ (openbox|bspwm|i3-gaps|fluxbox) ]]; then
1402 inpkg+="$WM_BASE_PKGS "
1403 elif [[ $INSTALL_WMS == 'dwm' ]]; then # dwm only needs a very limited package set
1404 inpkg+="nitrogen polkit-gnome gnome-keyring dunst "
1407 # update and install crucial packages first to avoid issues
1408 chrun "pacman -Syyu $KERNEL $BASE_PKGS base-devel ${LOGIN_PKGS[$LOGIN_TYPE]} $MYSHELL --noconfirm --needed" 2> $ERR 2>&1
1409 errshow 1 "pacman -Syyu $KERNEL $BASE_PKGS base-devel ${LOGIN_PKGS[$LOGIN_TYPE]} $MYSHELL --noconfirm --needed"
1411 # remove the packages we don't want on the installed system
1412 [[ $rmpkg ]] && chrun "pacman -Rnsc $rmpkg --noconfirm"
1414 # reinstalling iputils fixes the network issue for non-root users
1415 chrun "pacman -S iputils $UCODE --noconfirm"
1417 # install the packages chosen throughout the install
1418 chrun "pacman -S $inpkg --needed --noconfirm" 2> $ERR 2>&1
1419 errshow 1 "pacman -S $inpkg --needed --noconfirm"
1421 # bootloader packages
1422 if [[ $BOOTLDR == 'grub' ]]; then
1423 [[ $SYS == 'UEFI' ]] && local efib="efibootmgr"
1424 chrun "pacman -S os-prober grub $efib --needed --noconfirm" 2> $ERR 2>&1
1425 errshow 1 "pacman -S os-prober grub $efib --needed --noconfirm"
1426 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1427 chrun "pacman -S refind-efi efibootmgr --needed --noconfirm" 2> $ERR 2>&1
1428 errshow 1 "pacman -S refind-efi efibootmgr --needed --noconfirm"
1429 elif [[ $SYS == 'UEFI' ]]; then
1430 chrun "pacman -S efibootmgr --needed --noconfirm" 2> $ERR 2>&1
1431 errshow 1 "pacman -S efibootmgr --needed --noconfirm"
1434 if [[ $VM ]] && dmesg | grep -qi 'vbox'; then
1436 linux) chrun "pacman -S virtualbox-guest-utils virtualbox-guest-modules-arch --needed --noconfirm" ;;
1437 *) chrun "pacman -S virtualbox-guest-utils virtualbox-guest-modules-dkms ${KERNEL}-headers --needed --noconfirm" ;;
1441 # allow members of the wheel group to run commands as root
1442 sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" "$MNT/etc/sudoers"
1449 local dir="$1/suckless"
1451 if [[ $2 == 'chroot' ]]; then
1452 chrun "mkdir -pv '$dir'"
1453 for i in dwm dmenu st; do
1454 if chrun "git clone 'https://git.suckless.org/$i' '$dir/$i'"; then
1455 chrun "cd '$dir/$i' && make PREFIX=/usr install"
1457 printf "failed to clone %s repo\n" "$i"
1462 for i in dwm dmenu st; do
1463 if git clone "https://git.suckless.org/$i" "$dir/$i"; then
1464 cd "$dir/$i" && make PREFIX=/usr install
1466 printf "failed to clone %s repo\n" "$i"
1472 install_mkinitcpio()
1475 [[ $LUKS ]] && add="encrypt"
1476 [[ $LVM ]] && { [[ $add ]] && add+=" lvm2" || add+="lvm2"; }
1477 sed -i "s/block filesystems/block ${add} filesystems ${HOOKS}/g" "$MNT/etc/mkinitcpio.conf"
1478 chrun "mkinitcpio -p $KERNEL" 2> $ERR 2>&1
1479 errshow 1 "mkinitcpio -p $KERNEL"
1482 install_mirrorlist()
1484 if hash reflector > /dev/null 2>&1; then
1485 reflector --verbose --score 80 -l 40 -f 5 --sort rate --save "$1"
1486 elif hash rankmirrors > /dev/null 2>&1; then
1487 echo "Sorting mirrorlist"
1488 local key="access_key=5f29642060ab983b31fdf4c2935d8c56"
1489 ip_add="$(curl -fsSL "http://api.ipstack.com/check&?$key&fields=ip" | python -c "import sys, json; print(json.load(sys.stdin)['ip'])")"
1490 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'])")"
1491 if [[ "$country" ]]; then
1492 if [[ $country =~ (CA|US) ]]; then
1493 # use both CA and US mirrors for CA or US countries
1494 mirror="https://www.archlinux.org/mirrorlist/?country=US&country=CA&use_mirror_status=on"
1495 elif [[ $country =~ (AU|NZ) ]]; then
1496 # use both AU and NZ mirrors for AU or NZ countries
1497 mirror="https://www.archlinux.org/mirrorlist/?country=AU&country=NZ&use_mirror_status=on"
1499 mirror="https://www.archlinux.org/mirrorlist/?country=${country}&use_mirror_status=on"
1501 else # no country code so just grab all mirrors, will be a very slow sort but we don't have other options
1502 mirror="https://www.archlinux.org/mirrorlist/?country=all&use_mirror_status=on"
1504 curl -fsSL "$mirror" | sed -e 's/^#Server/Server/' -e '/^#/d' | rankmirrors -n 6 - > "$1"
1508 install_background()
1510 ( rsync -a /run/archiso/sfs/airootfs/ "$MNT/" && install_mirrorlist "$MNT/etc/pacman.d/mirrorlist" > /dev/null 2>&1 ) &
1512 trap "kill $BG_PID 2> /dev/null" EXIT
1515 install_tearfree_conf()
1520 echo "Virtual machine detected, removing xorg configs"
1521 find "$xpath/" -name '*.conf' -delete -printf "remove %p\n"
1522 elif lspci | grep ' VGA ' | grep -q 'Intel'; then
1523 echo "Creating Intel Tear Free config /etc/X11/xorg.conf.d/20-intel.conf"
1524 cat > "$xpath/20-intel.conf" <<- EOF
1526 Identifier "Intel Graphics"
1528 Option "TearFree" "true"
1531 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
1532 echo "Creating AMD Tear Free config /etc/X11/xorg.conf.d/20-amdgpu.conf"
1533 cat > "$xpath/20-amdgpu.conf" <<- EOF
1535 Identifier "AMD Graphics"
1537 Option "TearFree" "true"
1540 elif lspci | grep ' VGA ' | grep -q 'AMD/ATI.*HD [2-6][0-9]*'; then # older HD 2xxx-6xxx cards must use the radeon driver
1541 echo "Creating Radeon Tear Free config /etc/X11/xorg.conf.d/20-radeon.conf"
1542 cat > "$xpath/20-radeon.conf" <<- EOF
1544 Identifier "AMD Graphics"
1546 Option "TearFree" "on"
1549 elif lspci | grep ' VGA ' | grep -q 'NVIDIA'; then # nvidia cards require a bit of checking for notebook gpus
1550 echo "Trying nvidia driver install"
1551 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
1552 if [[ $xpath == *"$MNT"* ]]; then
1553 chrun "nvidia-installer --bumblebee"
1555 nvidia-installer --bumblebee
1558 if [[ $xpath == *"$MNT"* ]]; then
1559 chrun "nvidia-installer" # unsure which card so try auto detection
1564 if [[ -e $xpath/20-nvidia.conf ]]; then
1565 echo "NVIDIA driver installed"
1566 if [[ $xpath == *"$MNT"* ]]; then
1567 echo "Trying to load the driver for live session"
1570 echo "To enable driver vsync:"
1571 echo -e "\trun nvidia-settings (as root) on first boot\n\tenable 'ForceFullCompositionPipeline' under the advanced settings"
1572 echo -e "\tlastly save the change to your nvida xorg config /etc/X11/xorg.conf.d/20-nvidia.conf"
1573 echo -e "\tand remove everything but the Device and Screen sections from the file"
1575 echo "Unable to install nvidia driver"
1580 if lspci | grep ' VGA ' | grep -q 'Intel\|AMD/ATI'; then
1581 if [[ $xpath == *"$MNT"* ]]; then
1582 sed 's/xrender/glx/g' "$MNT/etc/skel/.config/compton.conf"
1584 sed 's/xrender/glx/g' /etc/skel/.config/compton.conf
1588 # remove nvidia installer from installed system when not running nvidia gpu
1589 [[ $xpath == *"$MNT"* ]] && rm -rf "$MNT/usr/bin/nvidia-installer" "$MNT/var/lib/nvidia-installer"
1592 ###############################################################################
1593 # display manager config
1594 # these are called based on which DM is chosen after it is installed
1595 # additional config can be handled here, for now only lightdm has one
1614 cat > "$MNT/etc/lightdm/lightdm-gtk-greeter.conf" <<- EOF
1616 default-user-image=/usr/share/icons/ArchLabs-Dark/64x64/places/distributor-logo-archlabs.png
1617 background=/usr/share/backgrounds/archlabs/archlabs.jpg
1618 theme-name=Adwaita-dark
1619 icon-theme-name=Adwaita
1620 font-name=DejaVu Sans Mono 11
1621 position=30%,end 50%,end
1625 ###############################################################################
1627 # prerun_* set up the configs needed before actually running the commands
1628 # setup_* are run after selecting a bootloader and build the command used later
1629 # they can also be used for further user input as these run before control is taken away
1633 EDIT_FILES[bootloader]="/etc/default/grub"
1635 if [[ $SYS == 'BIOS' ]]; then
1636 [[ $BOOT_DEV ]] || { part_device 1 || return 1; }
1637 BCMDS[grub]="grub-install --recheck --force --target=i386-pc $BOOT_DEV"
1639 BCMDS[grub]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1640 grub-install --recheck --force --target=x86_64-efi --efi-directory=/$BOOTDIR --bootloader-id=$DIST"
1641 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1644 BCMDS[grub]="mkdir -p /run/udev /run/lvm &&
1645 mount --bind /hostrun/udev /run/udev &&
1646 mount --bind /hostrun/lvm /run/lvm &&
1648 grub-mkconfig -o /boot/grub/grub.cfg &&
1649 sleep 1 && umount /run/udev /run/lvm"
1656 sed -i "s/GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR=\"${DIST}\"/g; s/GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"\"/g" "$MNT/etc/default/grub"
1658 if [[ $LUKS_DEV ]]; then
1659 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
1660 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"
1663 if [[ $SYS == 'BIOS' && $LVM && -z $SEP_BOOT ]]; then
1664 sed -i "s/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g" "$MNT/etc/default/grub" 2> $ERR 2>&1
1665 errshow 1 "sed -i 's/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g' $MNT/etc/default/grub"
1668 # setup for os-prober module
1669 mkdir -p /run/{lvm,udev} "$MNT/hostrun/"{lvm,udev}
1670 mount --bind /run/lvm "$MNT/hostrun/lvm"
1671 mount --bind /run/udev "$MNT/hostrun/udev"
1678 EDIT_FILES[bootloader]=""
1683 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1684 efibootmgr -v -d $BOOT_DEV -p $BOOT_PART_NUM -c -L '${DIST} Linux' -l /vmlinuz-${KERNEL} \
1685 -u 'root=$ROOT_PART_ID rw $([[ $UCODE ]] && printf 'initrd=\%s.img ' "$UCODE")initrd=\initramfs-${KERNEL}.img'"
1690 if [[ $SYS == 'BIOS' ]]; then
1691 EDIT_FILES[bootloader]="/boot/syslinux/syslinux.cfg"
1693 EDIT_FILES[bootloader]="/boot/EFI/syslinux/syslinux.cfg"
1694 BCMDS[syslinux]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1695 efibootmgr -v -c -d $BOOT_DEV -p $BOOT_PART_NUM -l /EFI/syslinux/syslinux.efi -L $DIST"
1701 local c="$MNT/boot/syslinux"
1702 local s="/usr/lib/syslinux/bios"
1704 if [[ $SYS == 'UEFI' ]]; then
1705 c="$MNT/boot/EFI/syslinux"
1706 s="/usr/lib/syslinux/efi64"
1709 mkdir -pv "$c" 2> $ERR 2>&1
1710 errshow 1 "mkdir -pv $c"
1711 cp -rfv "$s/"* "$c/" 2> $ERR 2>&1
1712 errshow 1 "cp -rfv $s/* $c/"
1713 cp -fv "$RUN/syslinux/splash.png" "$c/" 2> $ERR 2>&1
1714 errshow 0 "cp -fv $RUN/syslinux/splash.png $c/"
1715 cat > "$c/syslinux.cfg" <<- EOF
1717 MENU TITLE $DIST Boot Menu
1718 MENU BACKGROUND splash.png
1722 # see: https://www.syslinux.org/wiki/index.php/Comboot/menu.c32
1731 MENU HELPMSGENDROW 29
1732 MENU COLOR border 30;44 #40ffffff #a0000000 std
1733 MENU COLOR title 1;36;44 #9033ccff #a0000000 std
1734 MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
1735 MENU COLOR unsel 37;44 #50ffffff #a0000000 std
1736 MENU COLOR help 37;40 #c0ffffff #a0000000 std
1737 MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
1738 MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
1739 MENU COLOR msg07 37;40 #90ffffff #a0000000 std
1740 MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
1743 MENU LABEL $DIST Linux
1744 LINUX $d/vmlinuz-$KERNEL
1745 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1746 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL.img
1748 LABEL ${DIST}fallback
1749 MENU LABEL $DIST Linux Fallback
1750 LINUX $d/vmlinuz-$KERNEL
1751 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1752 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL-fallback.img
1759 EDIT_FILES[bootloader]="/boot/refind_linux.conf"
1760 BCMDS[refind-efi]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1; refind-install"
1765 cat > "$MNT/boot/refind_linux.conf" <<- EOF
1766 "$DIST Linux" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1767 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1768 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL.img"
1769 "$DIST Linux Fallback" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1770 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1771 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL-fallback.img"
1773 mkdir -p "$MNT/etc/pacman.d/hooks"
1774 cat > "$MNT/etc/pacman.d/hooks/refind.hook" <<- EOF
1781 Description = Updating rEFInd on ESP
1782 When = PostTransaction
1783 Exec = /usr/bin/refind-install
1787 setup_systemd-boot()
1789 EDIT_FILES[bootloader]="/boot/loader/entries/$DIST.conf"
1790 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1; bootctl --path=/boot install"
1793 prerun_systemd-boot()
1795 mkdir -p "$MNT/boot/loader/entries"
1796 cat > "$MNT/boot/loader/loader.conf" <<- EOF
1801 cat > "$MNT/boot/loader/entries/$DIST.conf" <<- EOF
1803 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1804 initrd /initramfs-$KERNEL.img
1805 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1807 cat > "$MNT/boot/loader/entries/$DIST-fallback.conf" <<- EOF
1808 title $DIST Linux Fallback
1809 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1810 initrd /initramfs-$KERNEL-fallback.img
1811 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1813 mkdir -p "$MNT/etc/pacman.d/hooks"
1814 cat > "$MNT/etc/pacman.d/hooks/systemd-boot.hook" <<- EOF
1821 Description = Updating systemd-boot
1822 When = PostTransaction
1823 Exec = /usr/bin/bootctl update
1825 systemd-machine-id-setup --root="$MNT"
1829 ###############################################################################
1834 no_bg_install || return 1
1838 dlg choice menu "Logical Volume Management" "$_lvmmenu" \
1839 "$_lvmnew" "vgcreate -f, lvcreate -L -n" \
1840 "$_lvmdel" "vgremove -f" \
1841 "$_lvmdelall" "lvrmeove, vgremove, pvremove -f" \
1842 "Back" "Return to the main menu"
1844 "$_lvmnew") lvm_create && break ;;
1845 "$_lvmdel") lvm_delgroup && yesno "$_lvmdel" "$_lvmdelask" && vgremove -f "$DEL_VG" > /dev/null 2>&1 ;;
1846 "$_lvmdelall") lvm_del_all ;;
1857 pv="$(pvs -o pv_name --noheading 2> /dev/null)"
1858 v="$(lvs -o vg_name,lv_name --noheading --separator - 2> /dev/null)"
1859 VGROUP="$(vgs -o vg_name --noheading 2> /dev/null)"
1861 if [[ $VGROUP && $v && $pv ]]; then
1862 msg "LVM Setup" "\nActivating existing logical volume management.\n" 0
1863 modprobe dm-mod > /dev/null 2> $ERR
1864 errshow 'modprobe dm-mod'
1865 vgscan > /dev/null 2>&1
1866 vgchange -ay > /dev/null 2>&1
1872 VGROUP='' LVM_PARTS='' VGROUP_MB=0
1874 lvm_mkgroup || return 1
1875 local txt="\nThe last (or only) logical volume will automatically use all remaining space in the volume group."
1876 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 -
1877 [[ $VOL_COUNT ]] || return 1
1878 lvm_extra_lvs || return 1
1879 lvm_volume_name "$_lvmlvname\nNOTE: This LV will use up all remaining space in the volume group (${VGROUP_MB}MB)" || return 1
1880 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating volume $VNAME from remaining space in $VGROUP\n" 0
1881 lvcreate -l +100%FREE "$VGROUP" -n "$VNAME" > /dev/null 2> $ERR
1882 errshow "lvcreate -l +100%FREE $VGROUP -n $VNAME" || return 1
1883 LVM='logical volume'; sleep 0.5
1884 txt="\nDone, volume: $VGROUP-$VNAME (${VOLUME_SIZE:-${VGROUP_MB}MB}) has been created.\n"
1885 msg "$_lvmnew (LV:$VOL_COUNT)" "$txt\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE $LVM_PARTS)\n"
1891 local txt="${VGROUP}: ${SIZE}$SIZE_UNIT (${VGROUP_MB}MB remaining).$_lvmlvsize"
1895 dlg VOLUME_SIZE input "$_lvmnew (LV:$VOL_COUNT)" "$txt" ''
1896 if [[ -z $VOLUME_SIZE ]]; then
1898 break # allow bailing with escape or an empty choice
1899 elif (( ${VOLUME_SIZE:0:1} == 0 )); then
1900 ERR_SIZE=1 # size values can't begin with '0'
1902 # walk the string and make sure all but the last char are digits
1903 local lv=$((${#VOLUME_SIZE} - 1))
1904 for (( i=0; i<lv; i++ )); do
1905 [[ ${VOLUME_SIZE:$i:1} =~ [0-9] ]] || { ERR_SIZE=1; break; }
1907 if (( ERR_SIZE != 1 )); then
1908 case ${VOLUME_SIZE:$lv:1} in
1909 [mMgG]) local s=${VOLUME_SIZE:0:$lv} m=$((s * 1000))
1910 case ${VOLUME_SIZE:$lv:1} in
1911 [Gg]) (( m >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - m)) ;;
1912 [Mm]) (( ${VOLUME_SIZE:0:$lv} >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - s)) ;;
1919 if (( ERR_SIZE )); then
1920 msg "Invalid Logical Volume Size" "$_lvmerrlvsize"
1933 until [[ $named ]]; do
1934 lvm_partitions || return 1
1935 lvm_group_name || return 1
1936 yesno "$_lvmnew" "\nCreate volume group: $VGROUP\n\nusing these partition(s): $LVM_PARTS\n" && named=true
1939 msg "$_lvmnew" "\nCreating volume group: $VGROUP\n" 0
1940 vgcreate -f "$VGROUP" $LVM_PARTS > /dev/null 2> $ERR
1941 errshow "vgcreate -f $VGROUP $LVM_PARTS" || return 1
1943 SIZE=$(vgdisplay "$VGROUP" | awk '/VG Size/ { gsub(/[^0-9.]/, ""); print int($0) }')
1944 SIZE_UNIT="$(vgdisplay "$VGROUP" | awk '/VG Size/ { print substr($NF, 0, 1) }')"
1946 if [[ $SIZE_UNIT == 'G' ]]; then
1947 VGROUP_MB=$((SIZE * 1000))
1952 msg "$_lvmnew" "\nVolume group $VGROUP (${SIZE}$SIZE_UNIT) successfully created\n"
1958 pv="$(pvs -o pv_name --noheading 2> /dev/null)"
1959 v="$(lvs -o vg_name,lv_name --noheading --separator - 2> /dev/null)"
1960 VGROUP="$(vgs -o vg_name --noheading 2> /dev/null)"
1962 if [[ $VGROUP || $v || $pv ]]; then
1963 if yesno "$_lvmdelall" "$_lvmdelask"; then
1964 for i in $v; do lvremove -f "/dev/mapper/$i" > /dev/null 2>&1; done
1965 for i in $VGROUP; do vgremove -f "$i" > /dev/null 2>&1; done
1966 for i in $pv; do pvremove -f "$i" > /dev/null 2>&1; done
1970 msg "Delete LVM" "\nNo LVMs to remove...\n" 2
1980 for i in $(lvs --noheadings | awk '{print $2}' | uniq); do
1981 VOL_GROUP_LIST+="$i $(vgdisplay "$i" | awk '/VG Size/ {print $3$4}') "
1984 [[ $VOL_GROUP_LIST ]] || { msg "No Groups" "\nNo volume groups found."; return 1; }
1986 dlg DEL_VG menu "Logical Volume Management" "\nSelect volume group to delete.\n\nAll logical volumes within will also be deleted." $VOL_GROUP_LIST
1992 while (( VOL_COUNT > 1 )); do
1993 lvm_volume_name "$_lvmlvname" && lvm_lv_size || return 1
1994 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating a $VOLUME_SIZE volume $VNAME in $VGROUP\n" 0
1995 lvcreate -L "$VOLUME_SIZE" "$VGROUP" -n "$VNAME" > /dev/null 2> $ERR
1996 errshow "lvcreate -L $VOLUME_SIZE $VGROUP -n $VNAME" || return 1
1997 msg "$_lvmnew (LV:$VOL_COUNT)" "\nDone, logical volume (LV) $VNAME ($VOLUME_SIZE) has been created.\n"
2005 part_find 'part|crypt' || return 1
2006 PARTS="$(awk 'NF > 0 {print $0 " off"}' <<< "$PARTS")"
2007 dlg LVM_PARTS check "$_lvmnew" "\nSelect the partition(s) to use for the physical volume (PV)." $PARTS
2014 until [[ $VGROUP ]]; do
2015 dlg VGROUP input "$_lvmnew" "$_lvmvgname" "lvgroup"
2016 if [[ -z $VGROUP ]]; then
2018 elif [[ ${VGROUP:0:1} == "/" || $VGROUP =~ \ |\' ]] || vgdisplay | grep -q "$VGROUP"; then
2019 msg "LVM Name Error" "$_lvmerrvgname"
2029 local txt="$1" default="mainvolume"
2030 (( VOL_COUNT > 1 )) && default="extvolume$VOL_COUNT"
2031 until [[ $VNAME ]]; do
2032 dlg VNAME input "$_lvmnew (LV:$VOL_COUNT)" "\n$txt" "$default"
2033 if [[ -z $VNAME ]]; then
2035 elif [[ ${VNAME:0:1} == "/" || $VNAME =~ \ |\' ]] || lsblk | grep -q "$VNAME"; then
2036 msg "LVM Name Error" "$_lvmerlvname"
2043 ###############################################################################
2049 no_bg_install || return 1
2050 dlg choice menu "LUKS Encryption" "$_luksmenu" \
2051 "$_luksnew" "cryptsetup -q luksFormat" \
2052 "$_luksopen" "cryptsetup open --type luks" \
2053 "$_luksadv" "cryptsetup -q -s -c luksFormat" \
2054 "Back" "Return to the main menu"
2057 "$_luksnew") luks_basic || return 1 ;;
2058 "$_luksopen") luks_open || return 1 ;;
2059 "$_luksadv") luks_advanced || return 1 ;;
2067 modprobe -a dm-mod dm_crypt > /dev/null 2>&1
2069 part_find 'part|crypt|lvm' || return 1
2071 if (( COUNT == 1 )); then
2072 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2074 dlg LUKS_PART menu "$_luksopen" "\nSelect which partition to open." $PARTS
2077 [[ $LUKS_PART ]] || return 1
2079 luks_pass "$_luksopen" || return 1
2080 msg "$_luksopen" "\nOpening encrypted partition: $LUKS_NAME\n\nUsing device/volume: $LUKS_PART\n" 0
2081 cryptsetup open --type luks "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> $ERR
2082 errshow "cryptsetup open --type luks $LUKS_PART $LUKS_NAME" || return 1
2083 LUKS='encrypted'; luks_show
2091 typeset -a ans=(cryptroot) # default name to start
2093 until [[ $LUKS_PASS ]]; do
2095 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " --mixedform "$_luksomenu" 0 0 0 \
2096 "Name:" 1 1 "${ans[0]}" 1 7 "$COLUMNS" 0 0 \
2097 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
2098 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 2> "$ANS" || return 1
2100 mapfile -t ans <"$ANS"
2102 if [[ -z "${ans[0]}" ]]; then
2103 msg "Name Empty" "\nEncrypted device name cannot be empty.\n\nPlease try again.\n" 2
2104 elif [[ -z "${ans[1]}" || "${ans[1]}" != "${ans[2]}" ]]; then
2105 LUKS_NAME="${ans[0]}"
2106 msg "Password Mismatch" "\nThe passwords entered do not match.\n\nPlease try again.\n" 2
2108 LUKS_NAME="${ans[0]}"
2109 LUKS_PASS="${ans[1]}"
2119 msg "$_luksnew" "\nEncrypted partition ready for mounting.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$LUKS_PART")\n\n"
2124 modprobe -a dm-mod dm_crypt > /dev/null 2>&1
2126 part_find 'part|lvm' || return 1
2128 if [[ $AUTO_ROOT_PART ]]; then
2129 LUKS_PART="$AUTO_ROOT_PART"
2130 elif (( COUNT == 1 )); then
2131 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2133 dlg LUKS_PART menu "$_luksnew" "\nSelect the partition you want to encrypt." $PARTS
2136 [[ $LUKS_PART ]] || return 1
2137 luks_pass "$_luksnew"
2142 luks_setup || return 1
2143 msg "$_luksnew" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2144 cryptsetup -q luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2> $ERR
2145 errshow "cryptsetup -q luksFormat $LUKS_PART" || return 1
2146 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> $ERR
2147 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2148 LUKS='encrypted'; luks_show
2156 dlg cipher input "LUKS Encryption" "$_lukskey" "-s 512 -c aes-xts-plain64"
2157 [[ $cipher ]] || return 1
2158 msg "$_luksadv" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2159 cryptsetup -q $cipher luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2> $ERR
2160 errshow "cryptsetup -q $cipher luksFormat $LUKS_PART" || return 1
2161 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> $ERR
2162 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2169 ###############################################################################
2171 # some help avoid repetition and improve usability of some commands
2172 # others are initial setup functions used before reaching the main loop
2176 [[ "$2" == *"$1"* ]] && printf "on" || printf "off"
2181 # cleanup and exit the installer cleanly with exit code $1
2182 local e="$1" # when e is 127 unmount /run/archiso/bootmnt and reboot
2186 if [[ -d $MNT ]]; then
2188 (( e == 127 )) && umount_dir /run/archiso/bootmnt && sleep 0.5 && reboot -f
2195 local var="$1" # assign output from dialog to var
2196 local dlg_t="$2" # dialog type (menu, check, input)
2197 local title="$3" # dialog title
2198 local body="$4" # dialog message
2199 local n=0 # number of items to display for menu and check dialogs
2201 shift 4 # shift off args assigned above
2203 # adjust n when passed a large list
2204 local l=$((LINES - 20))
2205 (( ($# / 2) > l )) && n=$l
2209 menu) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --menu "$body" 0 0 $n "$@" 2> "$ANS" || return 1 ;;
2210 check) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --checklist "$body" 0 0 $n "$@" 2> "$ANS" || return 1 ;;
2213 local def="$1" # assign default value for input
2215 if [[ $1 == 'limit' ]]; then
2216 dialog --backtitle "$DIST Installer - $SYS - v$VER" --max-input 63 --title " $title " --inputbox "$body" 0 0 "$def" 2> "$ANS" || return 1
2218 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --inputbox "$body" 0 0 "$def" 2> "$ANS" || return 1
2222 # if answer file isn't empty read from it into $var
2223 [[ -s "$ANS" ]] && printf -v "$var" "%s" "$(< "$ANS")"
2228 # displays a message dialog
2229 # when more than 2 args the message will disappear after sleep time ($3)
2235 dialog --backtitle "$DIST Installer - $SYS - v$VER" --sleep "$1" --title " $title " --infobox "$body\n" 0 0
2237 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --msgbox "$body\n" 0 0
2245 if ! select_keymap; then
2248 elif ! net_connect; then
2249 msg "Not Connected" "\nRunning live requires an active internet connection to install packages.\n\nExiting..\n" 2
2251 elif (( $(awk '/MemTotal/ {print int($2 / 1024)}' /proc/meminfo) < 2500)); then
2252 msg "Not Enough Memory" "\nLive session requires at least 2.5G of system memory for installing packages.\n\nExiting..\n" 2
2257 echo "Sorting mirrorlist"
2258 mount /run/archiso/cowspace -o remount,size=2G
2259 install_mirrorlist "/etc/pacman.d/mirrorlist"
2260 pacman -Syyu --noconfirm || die 1
2261 rm -rf /var/cache/pacman/pkg/*
2262 pacman -S $BASE_PKGS $AL_BASE_PKGS xorg-xinit --needed --noconfirm || die 1
2263 rm -rf /var/cache/pacman/pkg/*
2265 i3-gaps|openbox|fluxbox|bspwm|awesome|xfce4|jwm) pacman -S "$ses" $WM_BASE_PKGS ${WM_EXT[$ses]} --needed --noconfirm || die 1 ;;
2266 gnome|plasma|cinnamon) pacman -S "$ses" ${WM_EXT[$ses]} --needed --noconfirm || die 1 ;;
2267 dwm) { pacman -S git --needed --noconfirm || die 1; }; install_suckless "/root" nochroot ;;
2269 rm -rf /var/cache/pacman/pkg/*
2270 [[ $VM ]] && dmesg | grep -qi 'vbox' && pacman -S virtualbox-guest-utils virtualbox-guest-modules-arch --needed --noconfirm
2271 pacman -Scc --noconfirm
2272 rm -rf /var/cache/pacman/pkg/*
2273 cp -rfT /etc/skel /root
2274 install_tearfree_conf "/etc/X11/xorg.conf.d"
2276 plasma|gnome|cinnamon) sed -i '/super/d; /nitrogen/d; /compton/d' /root/.xprofile ;;
2277 dwm) sed -i '/super/d; /compton/d' /root/.xprofile ;;
2280 echo -e "pulseaudio &\n(sleep 1; pamixer --unmute --set-volume 50) &" >> /root/.xprofile
2281 sed -i "/exec/ c exec ${WM_SESSIONS[$ses]}" /root/.xinitrc
2282 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]}"
2289 usage: $1 [-hdl] [session]
2292 -h, --help print this message and exit
2293 -l, --live install and setup a live session
2294 -d, --debug enable xtrace and log output to $DBG
2297 i3-gaps - A fork of i3wm with more features including gaps
2298 openbox - A lightweight, powerful, and highly configurable stacking wm
2299 dwm - A dynamic WM for X that manages windows in tiled, floating, or monocle layouts
2300 awesome - A customized Awesome WM session created by @elanapan
2301 bspwm - A tiling wm that represents windows as the leaves of a binary tree
2302 fluxbox - A lightweight and highly-configurable window manager
2303 gnome - A desktop environment that aims to be simple and easy to use
2304 cinnamon - A desktop environment combining traditional desktop with modern effects
2305 plasma - A kde software project currently comprising a full desktop environment
2306 xfce4 - A lightweight and modular desktop environment based on gtk+2/3
2310 set the DIST environment variable before launching the installer eg.
2314 root/boot partition:
2316 set the ROOT_PART and/or BOOT_PART environment variables before launching the installer eg.
2318 ROOT_PART='/dev/sda2' BOOT_PART='/dev/sda1' $1
2322 set the EDITOR environment variable before launching the installer eg.
2332 local title="$1" body="$2" yes='Yes' no='No'
2333 (( $# >= 3 )) && yes="$3"
2334 (( $# >= 4 )) && no="$4"
2336 if (( $# == 5 )); then
2337 dialog --backtitle "$DIST Installer - $SYS - v$VER" --defaultno --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2339 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2345 arch-chroot "$MNT" bash -c "$1"
2350 export PS4='| ${BASH_SOURCE} LINE:${LINENO} FUNC:${FUNCNAME[0]:+ ${FUNCNAME[0]}()} |> '
2360 "\e]P0191919" # #191919
2361 "\e]P1D15355" # #D15355
2362 "\e]P2609960" # #609960
2363 "\e]P3FFCC66" # #FFCC66
2364 "\e]P4255A9B" # #255A9B
2365 "\e]P5AF86C8" # #AF86C8
2366 "\e]P62EC8D3" # #2EC8D3
2367 "\e]P7949494" # #949494
2368 "\e]P8191919" # #191919
2369 "\e]P9D15355" # #D15355
2370 "\e]PA609960" # #609960
2371 "\e]PBFF9157" # #FF9157
2372 "\e]PC4E88CF" # #4E88CF
2373 "\e]PDAF86C8" # #AF86C8
2374 "\e]PE2ec8d3" # #2ec8d3
2375 "\e]PFE1E1E1" # #E1E1E1
2378 [[ $TERM == 'linux' ]] && printf "%b" "${colors[@]}" && clear
2383 [ $? -eq 0 ] && return 0
2385 local fatal=0 err=""
2386 err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
2387 [[ -z $err ]] && err="no error message was found"
2389 (( $1 == 1 )) && { fatal=1; shift; }
2391 local txt="\nCommand: $1\n\n\n\nError: $err\n\n"
2393 if (( fatal )); then
2394 msg "Install Error" "${txt}Errors at this stage are fatal, the install cannot continue.\n"
2395 [[ -r $DBG && $TERM == 'linux' ]] && less "$DBG"
2399 msg "Install Error" "${txt}Errors at this stage are non-fatal and may be fixed or ignored depending on the error.\n"
2407 if (( $1 >= 0 )) && ! grep -qw "$MNT" /proc/mounts; then
2408 msg "Not Mounted" "\nPartition(s) must be mounted first.\n" 2
2410 elif [[ $1 -ge 1 && -z $BOOTLDR ]]; then
2411 msg "No Bootloader" "\nBootloader must be selected first.\n" 2
2413 elif [[ $1 -ge 2 && (-z $NEWUSER || -z $USER_PASS) ]]; then
2414 msg "No User" "\nA user must be created first.\n" 2
2416 elif [[ $1 -ge 3 && -z $CONFIG_DONE ]]; then
2417 msg "Not Configured" "\nSystem configuration must be done first.\n" 2
2420 (( i )) # return code
2425 mount | grep -q 'swap' && swapoff -a
2427 if [[ -d $dir ]] && mount | grep -q "on $dir "; then
2428 if ! umount "$dir" 2> /dev/null; then
2430 umount -f "$dir" 2> /dev/null || umount -l "$dir"
2438 msg "Network Connect" "\nVerifying network connection\n" 0
2439 curl -sIN --connect-timeout 5 'https://www.archlinux.org/' | sed '1q' | grep -q '200'
2444 if chk_connect; then
2446 elif hash nmtui > /dev/null 2>&1; then
2448 if [[ $TERM == 'linux' ]]; then
2449 printf "%b" "\e]P1191919" "\e]P4191919"
2451 printf "%b" "\e]P1D15355" "\e]P4255a9b"
2456 elif hash wifi-menu > /dev/null 2>&1; then
2466 [[ $BG_PID ]] || return 0
2467 msg "Install Running" "\nA background install process is currently running.\n" 2
2473 IGNORE_DEV="$(lsblk -lno NAME,MOUNTPOINT | awk '/\/run\/archiso\/bootmnt/ {sub(/[1-9]/, ""); print $1}')"
2475 if [[ $IGNORE_DEV ]]; then
2476 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ && !'"/$IGNORE_DEV/"' {print "/dev/" $1 " " $2}')"
2478 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ {print "/dev/" $1 " " $2}')"
2481 if [[ -z $SYS_DEVS ]]; then
2482 msg "Device Error" "\nNo available devices...\n\nExiting..\n" 2
2487 while read -r line; do
2489 done <<< "$SYS_DEVS"
2496 # amd-ucode is not needed it's provided by linux-firmware
2497 # elif grep -q 'AuthenticAMD' /proc/cpuinfo; then
2499 elif grep -q 'GenuineIntel' /proc/cpuinfo; then
2503 modprobe -q efivarfs > /dev/null 2>&1
2505 _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."
2506 if [[ -d /sys/firmware/efi/efivars ]]; then
2508 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars
2509 _prep+="\n - An EFI boot partition mounted."
2513 _prep+="\n\nOnce finished mounting, a portion of the install can be done in the background while you continue configuring the system:\n"
2514 _prep+="\n - Choose the system bootloader.\n - Create a user and password."
2515 _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."
2518 ###############################################################################
2521 # enable some nicer colours in the linux console
2524 if (( UID != 0 )); then
2525 msg "Not Root" "\nThis installer must be run as root or using sudo.\n\nExiting..\n" 2
2527 elif ! grep -qwm 1 'lm' /proc/cpuinfo; then
2528 msg "Not x86_64 Architecture" "\nThis installer only supports x86_64 architectures.\n\nExiting..\n" 2
2532 # trap ^C to perform cleanup
2533 trap 'printf "\n^C\n" && die 1' INT
2535 while getopts ":hl:d" OPT; do
2540 if [[ "${!WM_SESSIONS[@]}" =~ $OPTARG ]]; then
2543 echo "error: invalid session for -l, see -h for help"; die 1
2546 \?) echo "error: invalid option: -$OPTARG"; die 1 ;;
2553 msg "Welcome to the $DIST Installer" "$_welcome"
2555 if ! select_keymap; then
2557 elif ! net_connect; then
2558 msg "Not Connected" "\nThis installer requires an active internet connection.\n\nExiting..\n" 2
2565 # vim:fdm=marker:fmr={,}