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-perls' [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 _prep="\nThis is the installer main menu, once a step is complete you will return here.\n\nOn successful completion of a step the cursor will be advanced to the next step\nOn failure the cursor will be placed on the step required to advance (when possible).\n\nSteps beginning with an asterix (*) are required.\n\nOnce you're happy with the choices and the required steps are complete, selecting the final step will begin the install."
119 _device="\nSelect a device to use from the list below.\n\nDevices (/dev) are the available drives on the system. /sda, /sdb, /sdc ..."
120 _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."
121 _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."
122 _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"
123 _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)."
124 _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."
125 _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."
126 _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."
127 _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"
128 _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."
129 _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."
130 _exmnt="\nWhere do you want the partition mounted?\n\nEnsure the name begins with a slash (/).\nExamples include: /usr, /home, /var, etc."
131 _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."
132 _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."
133 _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"
134 _timez="\nThe time zone is used to set the system clock.\n\nSelect your country or continent from the list below"
135 _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."
136 _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."
137 _login="\nSelect which of your session choices to use for the initial login.\n\nYou can be change this later by editing your ~/.xinitrc"
138 _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"
139 _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."
140 _usercmd="\nEnter command to be run in the newly installed system (chroot) below.\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 every command will function correctly, additionally the command will not be sanity checked, it's your system so exercise caution.\n\nMore than one command may be run using standard bash syntax.\n"
141 _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."
144 _luksnew="Basic LUKS Encryption"
145 _luksadv="Advanced LUKS Encryption"
146 _luksopen="Open Existing LUKS Partition"
147 _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."
148 _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."
149 _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)."
152 _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."
153 _lvmnew="Create Volume Group and Volume(s)"
154 _lvmdel="Delete an Existing Volume Group"
155 _lvmdelall="Delete ALL Volume Group(s) and Volume(s)"
156 _lvmvgname="\nEnter a name for the volume group (VG) being created from the partition(s) selected."
157 _lvmlvname="\nEnter a name for the logical volume (LV) being created.\n\nThis is similar to setting a label for a partition."
158 _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."
159 _lvmdelask="\nConfirm deletion of volume group(s) and logical volume(s).\n\nDeleting a volume group, will delete all logical volumes within it.\n"
162 _errexpart="\nCannot mount partition due to a problem with the mountpoint.\n\nEnsure it begins with a slash (/) followed by atleast one character.\n"
163 _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"
164 _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"
165 _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"
166 _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"
167 _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"
168 _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"
172 ###############################################################################
174 # main is the entry point which calls functions including outside of its block
175 # once those functions finished they always are returned here with the
176 # exception of install_main(), it exits upon completion
180 (( SEL < 13 )) && (( SEL++ ))
182 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Prepare " --default-item $SEL --cancel-label 'Exit' --menu "$_prep" 0 0 0 \
183 1 "Show device tree" \
185 3 "LUKS encryption" \
186 4 "Logical volume management" \
187 5 "* Mount partitions" \
188 6 "* Select bootloader" \
189 7 "* Username and password" \
190 8 "* System configuration" \
191 9 "Select window manager or desktop" \
192 10 "Select additional packages" \
193 11 "View configuration selections" \
194 12 "Run a command on the installed system" \
195 13 "* Confirm choices and start the installation" 2> "$ANS"
198 [[ -z $WARN && $SEL =~ (2|5) ]] && { msg "Data Warning" "$_warn"; WARN=true; }
201 2) part_menu || (( SEL-- )) ;;
202 3) luks_menu || (( SEL-- )) ;;
203 4) lvm_menu || (( SEL-- )) ;;
204 5) mount_menu || (( SEL-- )) ;;
205 6) prechecks 0 && { select_boot || (( SEL-- )); } ;;
206 7) prechecks 1 && { select_mkuser || (( SEL-- )); } ;;
207 8) prechecks 2 && { select_config || (( SEL-- )); } ;;
208 9) prechecks 3 && { select_sessions || (( SEL-- )); } ;;
209 10) prechecks 3 && { select_packages || (( SEL-- )); } ;;
210 11) prechecks 3 && select_show ;;
211 12) prechecks 3 && select_usercmd ;;
212 13) prechecks 3 && install_main ;;
213 *) yesno "Exit" "\nUnmount partitions (if any) and exit the installer?\n" && die 0
219 if [[ $SYS == 'BIOS' ]]; then
220 dlg BOOTLDR menu "BIOS Bootloader" "\nSelect which bootloader to use." \
221 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
222 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network" || return 1
224 dlg BOOTLDR menu "UEFI Bootloader" "\nSelect which bootloader to use." \
225 "systemd-boot" "A simple UEFI boot manager which executes configured EFI images" \
226 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
227 "refind-efi" "A UEFI boot manager that aims to be platform neutral and simplify multi-boot" \
228 "efistub" "Boot the kernel image directly (no chainloading support)" \
229 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network (no chainloading support)" || return 1
236 local pkgs="${USER_PKGS// / } ${PACKAGES// / }"
237 [[ $INSTALL_WMS == *dwm* ]] && pkgs="dwm st dmenu $pkgs"
238 pkgs="${pkgs// / }" pkgs="${pkgs# }"
239 msg "Show Configuration" "
240 ---------- PARTITION CONFIGURATION ------------
242 Root Part: $ROOT_PART
243 Boot Part: ${BOOT_PART:-none}
244 Boot Device: ${BOOT_DEV:-none}
245 Swap Part/File: ${SWAP_PART:-none}
246 Swap Size: ${SWAP_SIZE:-none}
247 Extra Mounts: ${EXMNTS:-none}
248 Mkinit Hooks: ${HOOKS:-none}
250 LVM used: ${LVM:-none}
251 LUKS used: ${LUKS:-none}
253 ------------ SYSTEM CONFIGURATION -------------
255 Locale: ${MYLOCALE:-none}
256 Keymap: ${KEYMAP:-none}
257 Hostname: ${MYHOST:-none}
258 Timezone: ${ZONE:-none}/${SUBZ:-none}
260 ------------ USER CONFIGURATION ---------------
262 Username: ${NEWUSER:-none}
263 Login Shell: ${MYSHELL:-none}
264 Login Session: ${LOGIN_WM:-none}
265 Autologin: ${AUTOLOGIN:-none}
266 Login Type: ${LOGIN_TYPE:-none}
268 ----------- PACKAGE CONFIGURATION -------------
270 Kernel: ${KERNEL:-none}
271 Bootloader: ${BOOTLDR:-none}
272 Packages: ${pkgs:-none}
278 AUTOLOGIN='' # no autologin unless using xinit
280 dlg LOGIN_TYPE menu "Login Management" "\nSelect what kind of login management to use." \
281 "xinit" "Console login without a display manager" \
282 "ly" "TUI display manager with a ncurses-like interface" \
283 "lightdm" "Lightweight display manager with a gtk greeter" \
284 "gdm" "Gnome display manager" \
285 "sddm" "Simple desktop display manager" || return 1
288 ly) EDIT_FILES[login]="/etc/ly/config.ini" ;;
289 gdm|sddm) EDIT_FILES[login]="" ;;
290 lightdm) EDIT_FILES[login]="/etc/lightdm/lightdm.conf /etc/lightdm/lightdm-gtk-greeter.conf" ;;
291 xinit) EDIT_FILES[login]="/home/$NEWUSER/.xinitrc /home/$NEWUSER/.xprofile"
292 if (( $(wc -w <<< "$INSTALL_WMS") > 1 )); then
293 dlg LOGIN_WM menu "Login Management" "$_login" $LOGIN_CHOICES || return 1
294 LOGIN_WM="${WM_SESSIONS[$LOGIN_WM]}"
296 [[ -z $LOGIN_WM ]] && LOGIN_WM="${WM_SESSIONS[${INSTALL_WMS%% *}]}"
297 yesno "Autologin" "$(sed "s|USER|$NEWUSER|g; s|RC|$LOGINRC|g" <<< "$_autologin")" && AUTOLOGIN=true || AUTOLOGIN=''
307 until [[ $CONFIG_DONE ]]; do
309 0) dlg MYSHELL menu "Shell" "\nChoose which shell to use." \
310 zsh 'A very advanced and programmable command interpreter (shell) for UNIX' \
311 bash 'The GNU Bourne Again shell, standard in many GNU/Linux distributions' \
312 mksh 'The MirBSD Korn Shell - an enhanced version of the public domain ksh' || return 1
314 1) dlg MYHOST input "Hostname" "$_hostname" "${DIST,,}" limit || { i=0; continue; } ;;
315 2) dlg MYLOCALE menu "Locale" "$_locale" $LOCALES || { i=1; continue; } ;;
317 until [[ $ZONE && $SUBZ ]]; do
318 dlg ZONE menu "Timezone" "$_timez" America - Australia - Asia - Atlantic - Africa - Europe - Indian - Pacific - Arctic - Antarctica - || break
319 dlg SUBZ menu "Timezone" "$_timesubz" $(awk '/'"$ZONE"'\// {gsub(/'"$ZONE"'\//, ""); print $3 " - "}' /usr/share/zoneinfo/zone.tab | sort) || continue
321 [[ $ZONE && $SUBZ ]] || { i=2; continue; } ;;
322 4) dlg KERNEL menu "Kernel" "\nChoose which kernel to use." \
323 linux 'Vanilla linux kernel and modules, with a few patches applied' \
324 linux-lts 'Long-term support (LTS) linux kernel and modules' \
325 linux-zen 'A effort of kernel hackers to provide the best kernel for everyday systems' \
326 linux-hardened 'A security-focused linux kernel with hardening patches to mitigate exploits' || { i=3; continue; }
330 (( i++ )) # progress through to the next choice
334 bash) LOGINRC='.bash_profile' ;;
335 zsh) LOGINRC='.zprofile' ;;
336 mksh) LOGINRC='.profile' ;;
347 until [[ $NEWUSER ]]; do
349 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " User " --mixedform "$_user" 0 0 0 \
350 "Username:" 1 1 "${ans[0]}" 1 11 "$COLUMNS" 0 0 \
351 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
352 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 \
353 "--- Root password, if left empty the user password will be used ---" 6 1 '' 6 68 "$COLUMNS" 0 2 \
354 "Password:" 8 1 '' 8 11 "$COLUMNS" 0 1 \
355 "Password2:" 9 1 '' 9 12 "$COLUMNS" 0 1 2> "$ANS" || return 1
357 mapfile -t ans <"$ANS"
359 # root passwords empty, so use the user passwords
360 if [[ -z "${ans[4]}" && -z "${ans[5]}" ]]; then
365 # make sure a username was entered and that the passwords match
366 if [[ -z ${ans[0]} || ${ans[0]} =~ \ |\' || ${ans[0]} =~ [^a-z0-9] ]]; then
367 msg "Invalid Username" "\nInvalid user name.\n\nPlease try again.\n"; u=''
368 elif [[ -z "${ans[1]}" || "${ans[1]}" != "${ans[2]}" ]]; then
369 msg "Password Mismatch" "\nThe user passwords do not match.\n\nPlease try again.\n"
370 elif [[ "${ans[4]}" != "${ans[5]}" ]]; then
371 msg "Password Mismatch" "\nThe root passwords do not match.\n\nPlease try again.\n"
374 USER_PASS="${ans[1]}"
375 ROOT_PASS="${ans[4]}"
383 dlg KEYMAP menu "Keyboard Layout" "$_keymap" \
384 us English cm English gb English au English gh English \
385 za English ng English ca French 'cd' French gn French \
386 tg French fr French de German at German ch German \
387 es Spanish latam Spanish br Portuguese pt Portuguese ma Arabic \
388 sy Arabic ara Arabic ua Ukrainian cz Czech ru Russian \
389 sk Slovak nl Dutch it Italian hu Hungarian cn Chinese \
390 tw Taiwanese vn Vietnamese kr Korean jp Japanese th Thai \
391 la Lao pl Polish se Swedish is Icelandic 'fi' Finnish \
392 dk Danish be Belgian in Indian al Albanian am Armenian \
393 bd Bangla ba Bosnian 'bg' Bulgarian dz Berber mm Burmese \
394 hr Croatian gr Greek il Hebrew ir Persian iq Iraqi \
395 af Afghani fo Faroese ge Georgian ee Estonian kg Kyrgyz \
396 kz Kazakh lt Lithuanian mt Maltese mn Mongolian ro Romanian \
397 no Norwegian rs Serbian si Slovenian tj Tajik lk Sinhala \
398 tr Turkish uz Uzbek ie Irish pk Urdu 'mv' Dhivehi \
399 np Nepali et Amharic sn Wolof ml Bambara tz Swahili \
400 ke Swahili bw Tswana ph Filipino my Malay tm Turkmen \
401 id Indonesian bt Dzongkha lv Latvian md Moldavian mao Maori \
402 by Belarusian az Azerbaijani mk Macedonian kh Khmer epo Esperanto \
403 me Montenegrin || return 1
405 if [[ $CMAPS == *"$KEYMAP"* ]]; then
408 dlg CMAP menu "Console Keymap" "$_vconsole" $CMAPS || return 1
411 if [[ $TERM == 'linux' ]]; then
412 loadkeys "$CMAP" > /dev/null 2>&1
414 setxkbmap "$KEYMAP" > /dev/null 2>&1
422 dlg USER_CMD input "User Command" "$_usercmd" "$USER_CMD" nolimit
428 dlg INSTALL_WMS check "Sessions" "$_sessions\n" \
429 i3-gaps "A fork of i3wm with more features including gaps" "$(ofn i3-gaps "${INSTALL_WMS[*]}")" \
430 openbox "A lightweight, powerful, and highly configurable stacking wm" "$(ofn openbox "${INSTALL_WMS[*]}")" \
431 dwm "A dynamic WM for X that manages windows in tiled, floating, or monocle layouts" "$(ofn dwm "${INSTALL_WMS[*]}")" \
432 bspwm "A tiling wm that represents windows as the leaves of a binary tree" "$(ofn bspwm "${INSTALL_WMS[*]}")" \
433 jwm "A lightweight window manager for Xorg written in C" "$(ofn jwm "${INSTALL_WMS[*]}")" \
434 xfce4 "A lightweight and modular desktop environment based on gtk+2/3" "$(ofn xfce4 "${INSTALL_WMS[*]}")" \
435 awesome "A customized Awesome WM session created by @elanapan" "$(ofn awesome "${INSTALL_WMS[*]}")" \
436 fluxbox "A lightweight and highly-configurable window manager" "$(ofn fluxbox "${INSTALL_WMS[*]}")" \
437 plasma "A kde software project currently comprising a full desktop environment" "$(ofn plasma "${INSTALL_WMS[*]}")" \
438 gnome "A desktop environment that aims to be simple and easy to use" "$(ofn gnome "${INSTALL_WMS[*]}")" \
439 cinnamon "A desktop environment combining traditional desktop with modern effects" "$(ofn cinnamon "${INSTALL_WMS[*]}")"
441 [[ $INSTALL_WMS ]] || return 0
442 WM_PKGS="${INSTALL_WMS/dwm/}"
443 WM_PKGS="${WM_PKGS// / }"
444 WM_PKGS="${WM_PKGS# }"
446 for i in $INSTALL_WMS; do
447 LOGIN_CHOICES+="$i - "
448 [[ ${WM_EXT[$i]} && $WM_PKGS != *"${WM_EXT[$i]}"* ]] && WM_PKGS+=" ${WM_EXT[$i]}"
451 select_login || return 1
453 while IFS=' ' read -r pkg; do
454 [[ $PACKAGES != *"$pkg"* ]] && PACKAGES+=" $pkg"
462 dlg USER_PKGS check " Packages " "$_packages" \
463 abiword "A Fully-featured word processor" "$(ofn abiword "${USER_PKGS[*]}")" \
464 alacritty "A cross-platform, GPU-accelerated terminal emulator" "$(ofn alacritty "${USER_PKGS[*]}")" \
465 atom "An open-source text editor developed by GitHub" "$(ofn atom "${USER_PKGS[*]}")" \
466 audacious "A free and advanced audio player based on GTK+" "$(ofn audacious "${USER_PKGS[*]}")" \
467 audacity "A program that lets you manipulate digital audio waveforms" "$(ofn audacity "${USER_PKGS[*]}")" \
468 blueman "GUI bluetooth device manager" "$(ofn blueman "${USER_PKGS[*]}")" \
469 bluez "Simple CLI based bluetooth support" "$(ofn bluez "${USER_PKGS[*]}")" \
470 cairo-dock "Light eye-candy fully themable animated dock" "$(ofn cairo-dock "${USER_PKGS[*]}")" \
471 calligra "A set of applications for productivity" "$(ofn calligra "${USER_PKGS[*]}")" \
472 chromium "An open-source web browser based on the Blink rendering engine" "$(ofn chromium "${USER_PKGS[*]}")" \
473 clementine "A modern music player and library organizer" "$(ofn clementine "${USER_PKGS[*]}")" \
474 cmus "A small, fast and powerful console music player" "$(ofn cmus "${USER_PKGS[*]}")" \
475 deadbeef "A GTK+ audio player for GNU/Linux" "$(ofn deadbeef "${USER_PKGS[*]}")" \
476 deluge "A BitTorrent client written in python" "$(ofn deluge "${USER_PKGS[*]}")" \
477 emacs "An extensible, customizable, self-documenting real-time display editor" "$(ofn emacs "${USER_PKGS[*]}")" \
478 epiphany "A GNOME web browser based on the WebKit rendering engine" "$(ofn epiphany "${USER_PKGS[*]}")" \
479 evince "A document viewer" "$(ofn evince "${USER_PKGS[*]}")" \
480 evolution "Manage your email, contacts and schedule" "$(ofn evolution "${USER_PKGS[*]}")" \
481 file-roller "Create and modify archives" "$(ofn file-roller "${USER_PKGS[*]}")" \
482 firefox "A popular open-source web browser from Mozilla" "$(ofn firefox "${USER_PKGS[*]}")" \
483 gcolor2 "A simple GTK+2 color selector" "$(ofn gcolor2 "${USER_PKGS[*]}")" \
484 geany "A fast and lightweight IDE" "$(ofn geany "${USER_PKGS[*]}")" \
485 geary "A lightweight email client for the GNOME desktop" "$(ofn geary "${USER_PKGS[*]}")" \
486 gimp "GNU Image Manipulation Program" "$(ofn gimp "${USER_PKGS[*]}")" \
487 gnome-calculator "GNOME Scientific calculator" "$(ofn gnome-calculator "${USER_PKGS[*]}")" \
488 gnome-disk-utility "Disk Management Utility" "$(ofn gnome-disk-utility "${USER_PKGS[*]}")" \
489 gnome-system-monitor "View current processes and monitor system state" "$(ofn gnome-system-monitor "${USER_PKGS[*]}")" \
490 gparted "A GUI frontend for creating and manipulating partition tables" "$(ofn gparted "${USER_PKGS[*]}")" \
491 gpick "Advanced color picker using GTK+ toolkit" "$(ofn gpick "${USER_PKGS[*]}")" \
492 gpicview "Lightweight image viewer" "$(ofn gpicview "${USER_PKGS[*]}")" \
493 guvcview "Capture video from camera devices" "$(ofn guvcview "${USER_PKGS[*]}")" \
494 hexchat "A popular and easy to use graphical IRC client" "$(ofn hexchat "${USER_PKGS[*]}")" \
495 inkscape "Professional vector graphics editor" "$(ofn inkscape "${USER_PKGS[*]}")" \
496 irssi "Modular text mode IRC client" "$(ofn irssi "${USER_PKGS[*]}")" \
497 kdenlive "A popular non-linear video editor for Linux" "$(ofn kdenlive "${USER_PKGS[*]}")" \
498 krita "Edit and paint images" "$(ofn krita "${USER_PKGS[*]}")" \
499 libreoffice-fresh "Full featured office suite" "$(ofn libreoffice-fresh "${USER_PKGS[*]}")" \
500 lollypop "A new music playing application" "$(ofn lollypop "${USER_PKGS[*]}")" \
501 mousepad "A simple text editor" "$(ofn mousepad "${USER_PKGS[*]}")" \
502 mpd "A flexible, powerful, server-side application for playing music" "$(ofn mpd "${USER_PKGS[*]}")" \
503 mpv "A media player based on mplayer" "$(ofn mpv "${USER_PKGS[*]}")" \
504 mupdf "Lightweight PDF and XPS viewer" "$(ofn mupdf "${USER_PKGS[*]}")" \
505 mutt "Small but very powerful text-based mail client" "$(ofn mutt "${USER_PKGS[*]}")" \
506 nautilus "The default file manager for Gnome" "$(ofn nautilus "${USER_PKGS[*]}")" \
507 ncmpcpp "A mpd client and almost exact clone of ncmpc with some new features" "$(ofn ncmpcpp "${USER_PKGS[*]}")" \
508 neovim "A fork of Vim aiming to improve user experience, plugins, and GUIs." "$(ofn neovim "${USER_PKGS[*]}")" \
509 noto-fonts "Google Noto fonts" "$(ofn noto-fonts "${USER_PKGS[*]}")" \
510 noto-fonts-cjk "Google Noto CJK fonts (Chinese, Japanese, Korean)" "$(ofn noto-fonts-cjk "${USER_PKGS[*]}")" \
511 obs-studio "Free opensource streaming/recording software" "$(ofn obs-studio "${USER_PKGS[*]}")" \
512 openshot "An open-source, non-linear video editor for Linux" "$(ofn openshot "${USER_PKGS[*]}")" \
513 opera "A Fast and secure, free of charge web browser from Opera Software" "$(ofn opera "${USER_PKGS[*]}")" \
514 pcmanfm "A fast and lightweight file manager based in Lxde" "$(ofn pcmanfm "${USER_PKGS[*]}")" \
515 pidgin "Multi-protocol instant messaging client" "$(ofn pidgin "${USER_PKGS[*]}")" \
516 plank "An elegant, simple, and clean dock" "$(ofn plank "${USER_PKGS[*]}")" \
517 qbittorrent "An advanced BitTorrent client" "$(ofn qbittorrent "${USER_PKGS[*]}")" \
518 qpdfview "A tabbed PDF viewer" "$(ofn qpdfview "${USER_PKGS[*]}")" \
519 qt5ct "GUI for managing Qt based application themes, icons, and fonts" "$(ofn qt5ct "${USER_PKGS[*]}")" \
520 qutebrowser "A keyboard-focused vim-like web browser based on Python and PyQt5" "$(ofn qutebrowser "${USER_PKGS[*]}")" \
521 rhythmbox "A Music playback and management application" "$(ofn rhythmbox "${USER_PKGS[*]}")" \
522 rxvt-unicode "A unicode enabled rxvt-clone terminal emulator" "$(ofn rxvt-unicode "${USER_PKGS[*]}")" \
523 sakura "A terminal emulator based on GTK and VTE" "$(ofn sakura "${USER_PKGS[*]}")" \
524 simple-scan "Simple scanning utility" "$(ofn simple-scan "${USER_PKGS[*]}")" \
525 simplescreenrecorder "A feature-rich screen recorder" "$(ofn simplescreenrecorder "${USER_PKGS[*]}")" \
526 steam "A popular game distribution platform by Valve" "$(ofn steam "${USER_PKGS[*]}")" \
527 surf "A simple web browser based on WebKit2/GTK+" "$(ofn surf "${USER_PKGS[*]}")" \
528 terminator "Terminal emulator that supports tabs and grids" "$(ofn terminator "${USER_PKGS[*]}")" \
529 termite "A minimal VTE-based terminal emulator" "$(ofn termite "${USER_PKGS[*]}")" \
530 thunar "A modern file manager for the Xfce Desktop Environment" "$(ofn thunar "${USER_PKGS[*]}")" \
531 thunderbird "Standalone mail and news reader from mozilla" "$(ofn thunderbird "${USER_PKGS[*]}")" \
532 tilda "A GTK based drop down terminal for Linux and Unix" "$(ofn tilda "${USER_PKGS[*]}")" \
533 tilix "A tiling terminal emulator for Linux using GTK+ 3" "$(ofn tilix "${USER_PKGS[*]}")" \
534 transmission-cli "Free BitTorrent client CLI" "$(ofn transmission-cli "${USER_PKGS[*]}")" \
535 transmission-gtk "GTK+ Front end for transmission" "$(ofn transmission-gtk "${USER_PKGS[*]}")" \
536 transmission-qt "Qt Front end for transmission" "$(ofn transmission-qt "${USER_PKGS[*]}")" \
537 ttf-anonymous-pro "A family fixed-width fonts designed with code in mind" "$(ofn ttf-anonymous-pro "${USER_PKGS[*]}")" \
538 ttf-fira-code "Monospaced font with programming ligatures" "$(ofn ttf-fira-code "${USER_PKGS[*]}")" \
539 ttf-font-awesome "Iconic font designed for Bootstrap" "$(ofn ttf-font-awesome "${USER_PKGS[*]}")" \
540 ttf-hack "A hand groomed typeface based on Bitstream Vera Mono" "$(ofn ttf-hack "${USER_PKGS[*]}")" \
541 vlc "A free and open source cross-platform multimedia player" "$(ofn vlc "${USER_PKGS[*]}")" \
542 weechat "Fast, light and extensible IRC client" "$(ofn weechat "${USER_PKGS[*]}")" \
543 xapps "Common library for X-Apps project" "$(ofn xapps "${USER_PKGS[*]}")" \
544 xarchiver "A GTK+ frontend to various command line archivers" "$(ofn xarchiver "${USER_PKGS[*]}")" \
545 xed "A small and lightweight text editor. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
546 xfce4-terminal "A terminal emulator based in the Xfce Desktop Environment" "$(ofn xfce4-terminal "${USER_PKGS[*]}")" \
547 xreader "Document viewer for files like PDF and Postscript. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
548 zathura "Minimalistic document viewer" "$(ofn zathura "${USER_PKGS[*]}")"
550 if [[ $USER_PKGS ]]; then # add any needed PKG_EXT to the list
551 for i in $USER_PKGS; do
552 [[ ${PKG_EXT[$i]} && $USER_PKGS != *"${PKG_EXT[$i]}"* ]] && USER_PKGS+=" ${PKG_EXT[$i]}"
559 ###############################################################################
561 # non-essential partitioning helpers called by the user when using the optional
562 # partition menu and selecting a device to edit
566 no_bg_install || return 0
567 local device choice devhash
568 devhash="$(lsblk -f | base64)"
570 part_device || return 1
575 dlg choice menu "Edit Partitions" "$_part\n\n$(lsblk -no NAME,MODEL,SIZE,TYPE,FSTYPE $device)" \
576 "auto" "Whole device automatic partitioning" \
577 "shrink" "Shrink an existing ext or ntfs partition" \
578 "cfdisk" "Curses based variant of fdisk" \
579 "parted" "GNU partition editor" \
580 "fdisk" "Dialog-driven creation and manipulation of partitions" \
581 "done" "Return to the main menu"
583 if [[ -z $choice || $choice == 'done' ]]; then
585 elif [[ $choice == 'shrink' ]]; then
586 part_shrink "$device"
587 elif [[ $choice == 'auto' ]]; then
588 local root_size txt table boot_fs
589 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"}}')
590 txt="\nWARNING:\n\nALL data on $device will be destroyed and the following partitions will be created\n\n- "
591 if [[ $SYS == 'BIOS' ]]; then
592 table="msdos" boot_fs="ext4"
593 txt+="An $boot_fs boot partition with the boot flag enabled (512M)\n- "
595 table="gpt" boot_fs="fat32"
596 txt+="A $boot_fs efi boot partition (512M)\n- "
598 txt+="An ext4 partition using all remaining space ($root_size)\n\nDo you want to continue?\n"
599 yesno "Auto Partition" "$txt" && part_auto "$device" "$table" "$boot_fs" "$root_size"
605 if [[ $devhash != "$(lsblk -f | base64)" ]]; then
606 msg "Probing Partitions" "\nInforming kernel of partition changes using partprobe\n" 0
607 partprobe > /dev/null 2>&1
608 [[ $choice == 'auto' ]] && return
616 if [[ $IGNORE_DEV ]]; then
617 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk "!/$IGNORE_DEV/"' && /disk|part|lvm|crypt|NAME/')"
619 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk '/disk|part|lvm|crypt|NAME/')"
621 msg "Device Tree" "\n\n$txt\n\n"
626 local device="$1" table="$2" boot_fs="$3" size="$4" dev_info=""
628 msg "Auto Partition" "\nRemoving partitions on $device and setting table to $table\n" 1
630 dev_info="$(parted -s "$device" print)"
633 while read -r PART; do
634 parted -s "$device" rm "$PART" > /dev/null 2>&1
635 done <<< "$(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r)"
637 [[ $(awk '/Table:/ {print $3}' <<< "$dev_info") != "$table" ]] && parted -s "$device" mklabel "$table" > /dev/null 2>&1
639 msg "Auto Partition" "\nCreating a 512M $boot_fs boot partition.\n" 1
640 if [[ $SYS == "BIOS" ]]; then
641 parted -s "$device" mkpart primary "$boot_fs" 1MiB 513MiB > /dev/null 2>&1
643 parted -s "$device" mkpart ESP "$boot_fs" 1MiB 513MiB > /dev/null 2>&1
648 AUTO_BOOT_PART=$(lsblk -lno NAME,TYPE "$device" | awk 'NR==2 {print "/dev/" $1}')
650 if [[ $SYS == "BIOS" ]]; then
651 mkfs.ext4 -q "$AUTO_BOOT_PART" > /dev/null 2>&1
653 mkfs.vfat -F32 "$AUTO_BOOT_PART" > /dev/null 2>&1
656 msg "Auto Partition" "\nCreating a $size ext4 root partition.\n" 0
657 parted -s "$device" mkpart primary ext4 513MiB 100% > /dev/null 2>&1
659 AUTO_ROOT_PART="$(lsblk -lno NAME,TYPE "$device" | awk 'NR==3 {print "/dev/" $1}')"
660 mkfs.ext4 -q "$AUTO_ROOT_PART" > /dev/null 2>&1
662 msg "Auto Partition" "\nProcess complete.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$device")\n"
669 local device="$1" fs=""
671 part_find "${device##*/}[^ ]" || return 1
672 (( COUNT == 1 )) && part="$(awk '{print $1}' <<< "${PARTS[@]}" )"
674 if (( COUNT == 1 )) || dlg part menu "Resize" "\nWhich partition on $device do you want to resize?" $PARTS; then
675 fs=$(lsblk -lno FSTYPE "$part")
678 msg "Resize" "\nGathering device size info.\n" 0
680 end=$(parted -s "$device" unit KiB print | awk '/^\s*'"$num"'/ {print $3}') # part size in KiB
681 devsize=$(parted -s "$device" unit KiB print | awk '/Disk '"${device//\//\\/}"':/ {print $3}') # whole device size in KiB
682 mount "$part" "$MNT" > /dev/null 2>&1; sleep 0.5
683 min=$(df --output=used --block-size=MiB "$part" | awk 'NR == 2 {print int($1) + 256}')
684 max=$(df --output=avail --block-size=MiB "$part" | awk 'NR == 2 {print int($1)}')
687 if dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Resize: $part " --rangebox "$_resize" 17 "$COLUMNS" "$min" "$max" $((max / 2)) 2> $ANS; then
689 size=$((size * 1024))
696 if ntfsresize -fc "$part"; then
697 ntfsresize -ff --size $(( (size * 1024) / 1000 ))k "$part" 2> $ERR # k=10^3 bytes
698 errshow "ntfsresize -f -s $(( (size * 1024) / 1000 ))k $part" || return 1
700 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"
705 e2fsck -f "$part"; sleep 0.5
706 resize2fs -f "$part" ${size}K 2> $ERR # K=2^10 bytes
707 errshow "resize2fs -f $part ${size}K" || return 1
711 parted "$device" resizepart "$num" ${size}KiB || return 1
714 if [[ $devsize == "$end" ]]; then
715 parted -s "$device" mkpart primary ext4 ${size}KiB 100% 2> $ERR
716 errshow "parted -s $device mkpart primary ext4 ${size}KiB 100%" || return 1
718 parted -s "$device" mkpart primary ext4 ${size}KiB ${end}KiB 2> $ERR
719 errshow "parted -s $device mkpart primary ext4 ${size}KiB ${end}KiB" || return 1
721 msg "Resize Complete" "\n$part has been successfully resized to $((size / 1024))M.\n" 1
723 "") msg "No Filesystem" "\nFor unformatted partitions, cfdisk can be used in the partition menu.\n" ;;
724 *) msg "Invalid Filesystem: $fs" "\nResizing only supports ext and ntfs.\n" ;;
729 ###############################################################################
730 # partition management functions
731 # these are helpers for use by other functions to do essential setup/teardown
735 local regexp="$1" err=''
737 # string of partitions as /TYPE/PART SIZE.. eg. /dev/sda1 256G
738 if [[ $IGNORE_DEV ]]; then
739 PARTS="$(lsblk -lno TYPE,NAME,SIZE | awk "/$regexp/"' && !'"/$IGNORE_DEV/"' {sub(/^part/, "/dev/"); sub(/^lvm|^crypt/, "/dev/mapper/"); print $1$2, $3}')"
741 PARTS="$(lsblk -lno TYPE,NAME,SIZE | awk "/$regexp/"' {sub(/^part/, "/dev/"); sub(/^lvm|^crypt/, "/dev/mapper/"); print $1$2 " " $3}')"
744 # ensure we have enough partitions for the system and action were trying to do
745 COUNT=$(wc -l <<< "$PARTS")
747 'part|lvm|crypt') [[ $COUNT -lt 1 || ($SYS == 'UEFI' && $COUNT -lt 2) ]] && err="$_errpart" ;;
748 'part|crypt') (( COUNT < 1 )) && err="$_lvmerr" ;;
749 'part|lvm') (( COUNT < 2 )) && err="$_lukserr" ;;
753 msg "Not Enough Partitions" "$err" 2
762 if [[ $1 == "$MNT/swapfile" && $SWAP_SIZE ]]; then
763 fallocate -l $SWAP_SIZE "$1" 2> $ERR
764 errshow "fallocate -l $SWAP_SIZE $1"
765 chmod 600 "$1" 2> $ERR
766 errshow "chmod 600 $1"
768 mkswap "$1" > /dev/null 2> $ERR
770 swapon "$1" > /dev/null 2> $ERR
777 local part="$1" mountp="${MNT}$2" fs=""
778 fs="$(lsblk -lno FSTYPE "$part")"
781 if [[ $fs && ${FS_OPTS[$fs]} && $part != "$BOOT_PART" && $part != "$AUTO_ROOT_PART" ]] && select_mntopts "$fs"; then
782 mount -o "$MNT_OPTS" "$part" "$mountp" > /dev/null 2>&1
784 mount "$part" "$mountp" > /dev/null 2>&1
787 part_mountconf "$part" "$mountp" || return 1
795 local part="$1" fs="$2" delay="$3"
797 msg "Format" "\nFormatting $part as $fs\n" 0
798 mkfs.$fs ${FS_CMD_FLAGS[$fs]} "$part" > /dev/null 2> $ERR
799 errshow "mkfs.$fs ${FS_CMD_FLAGS[$fs]} "$part"" || return 1
806 if [[ $DEV_COUNT -eq 1 && $SYS_DEVS ]]; then
807 DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
808 elif (( DEV_COUNT > 1 )); then
810 dlg DEVICE menu "Boot Device" "\nSelect the device to use for bootloader install." $SYS_DEVS
812 dlg DEVICE menu "Select Device" "$_device" $SYS_DEVS
814 [[ $DEVICE ]] || return 1
815 elif [[ $DEV_COUNT -lt 1 && ! $1 ]]; then
816 msg "Device Error" "\nNo available devices.\n\nExiting..\n" 2
820 [[ $1 ]] && BOOT_DEV="$DEVICE"
827 BOOT_DEV="${BOOT_PART%[1-9]}"
828 BOOT_PART_NUM="${BOOT_PART: -1}"
829 [[ $BOOT_PART = /dev/nvme* ]] && BOOT_DEV="${BOOT_PART%p[1-9]}"
830 if [[ $SYS == 'UEFI' ]]; then
831 parted -s $BOOT_DEV set $BOOT_PART_NUM esp on > /dev/null 2>&1
833 parted -s $BOOT_DEV set $BOOT_PART_NUM boot on > /dev/null 2>&1
840 local part="$1" devs=""
841 devs="$(lsblk -lno NAME,FSTYPE,TYPE)"
843 # Identify if $part is LUKS+LVM, LVM+LUKS, LVM alone, or LUKS alone
844 if lsblk -lno TYPE "$part" | grep -q 'crypt'; then
846 LUKS_NAME="${part#/dev/mapper/}"
847 for dev in $(awk '/lvm/ && /crypto_LUKS/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
848 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
849 LUKS_DEV="$LUKS_DEV cryptdevice=$dev:$LUKS_NAME"
854 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
855 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
856 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
857 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
861 elif lsblk -lno TYPE "$part" | grep -q 'lvm'; then
863 VNAME="${part#/dev/mapper/}"
864 for dev in $(awk '/crypt/ && /lvm2_member/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
865 if lsblk -lno NAME "$dev" | grep -q "$VNAME"; then
866 LUKS_NAME="${dev/\/dev\/mapper\//}"
870 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
871 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
872 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
873 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
884 if (( COUNT > 0 )); then
885 PARTS="$(sed "/${pt//\//\\/}/d" <<< "$PARTS")"
893 if grep -qw "$1" /proc/mounts; then
894 msg "Mount Success" "\nPartition $1 mounted at $2\n" 1
898 msg "Mount Fail" "\nPartition $1 failed to mount at $2\n" 2
903 ###############################################################################
905 # mount_menu is the entry point which calls all other functions
906 # once finished it returns to the main menu: main()
910 no_bg_install || return 0
913 part_find 'part|lvm|crypt' || { SEL=2; return 1; }
914 [[ $LUKS && $LUKS_PART ]] && part_countdec $LUKS_PART
915 [[ $LVM && $LVM_PARTS ]] && part_countdec $LVM_PARTS
916 select_root_partition || { ROOT_PART=''; return 1; }
917 select_boot_partition || { BOOT_PART=''; return 1; }
918 if [[ $BOOT_PART ]]; then
919 part_mount "$BOOT_PART" "/$BOOTDIR" && SEP_BOOT=true || return 1
922 select_swap || return 1
923 select_extra_partitions || return 1
930 local pts dev size isize
932 while read -r dev size; do # walk partition list and skip ones that are too small/big for swap
933 size_t="${size: -1:1}"
936 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 16) || ($size_t == 'M' && $isize -lt 100) ]] || pts+="$dev $size "
939 dlg SWAP_PART menu "Swap Setup" "\nSelect whether to use a swapfile, swap partition, or none." \
940 "none" "Don't allocate any swap space" \
941 "swapfile" "Allocate $SYS_MEM at /swapfile" \
944 if [[ -z $SWAP_PART || $SWAP_PART == "none" ]]; then
947 elif [[ $SWAP_PART == "swapfile" ]]; then
949 until [[ ${SWAP_SIZE:0:1} =~ [1-9] && ${SWAP_SIZE: -1} =~ (M|G) ]]; do
950 (( 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
951 dlg SWAP_SIZE input "Swap Setup" "$_swapsize" "$SYS_MEM" || { SWAP_PART=''; SWAP_SIZE=''; return 1; }
954 part_swap "$MNT/$SWAP_PART"
955 SWAP_PART="/$SWAP_PART"
956 elif [[ $PARTS == *"$SWAP_PART"* ]]; then
958 part_countdec $SWAP_PART
959 SWAP_SIZE="$(lsblk -lno SIZE $SWAP_PART)"
969 local fs="$1" opts=''
970 local title="${fs^} Mount Options"
972 for i in ${FS_OPTS[$fs]}; do
976 until [[ $MNT_OPTS ]]; do
977 dlg MNT_OPTS check "$title" "$_mount" $opts
978 [[ $MNT_OPTS ]] || return 1
979 MNT_OPTS="${MNT_OPTS// /,}"
980 yesno "$title" "\nConfirm the following options: $MNT_OPTS\n" || MNT_OPTS=''
989 until [[ $EXMNT ]]; do
990 dlg EXMNT input "Extra Mount $part" "$_exmnt" "/" || return 1
991 if [[ ${EXMNT:0:1} != "/" || ${#EXMNT} -le 1 || $EXMNT =~ \ |\' || $EXMNTS == *"$EXMNT"* ]]; then
992 msg "Mountpoint Error" "$_errexpart"
996 msg "Mount Extra" "\nMounting Finished\n\n\nNo extra partitions available to mount, returning to main menu.\n" 2
1002 local part="$1" fs='' cur=''
1003 local txt="\nSelect which filesystem to use for: $part\n\nDefault: ext4"
1004 cur="$(lsblk -lno FSTYPE "$part" 2> /dev/null)"
1006 # bail early if the partition was created in part_auto()
1007 [[ $cur && $part == "$AUTO_ROOT_PART" ]] && return 0
1010 if [[ $cur && $FORMATTED == *"$part"* ]]; then
1011 dlg fs menu "Filesystem" "$txt\nCurrent: $cur" skip - ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1013 dlg fs menu "Filesystem" "$txt" ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1015 [[ $fs == 'skip' ]] && return 0
1016 yesno "Filesystem" "\nFormat $part as $fs?\n" || fs=''
1018 part_format "$part" "$fs" 0
1021 select_boot_partition()
1023 local pts dev size isize ptcount=0
1025 if [[ -z $BOOT_PART ]]; then
1026 if [[ $AUTO_BOOT_PART && -z $LVM && -z $LUKS ]]; then
1027 BOOT_PART="$AUTO_BOOT_PART"
1030 while read -r dev size; do # walk partition list and skip ones that are too small/big for boot
1031 size_t="${size: -1:1}"
1034 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1040 0) msg "EFI Boot Partition" "\nNo partitions available that meet size requirements!!\n\nReturning to the main menu.\n" 2; return 1 ;;
1041 1) msg "EFI Boot Partition" "\nOnly one partition available that meets size requirements.\n" 1; BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")" ;;
1042 *) dlg BOOT_PART menu "EFI Partition" "$_uefi" $pts ;;
1044 [[ $BOOT_PART ]] || return 1
1047 (( ptcount == 0 )) && return 0
1048 if [[ $LUKS && ! $LVM ]]; then
1049 dlg BOOT_PART menu "Boot Partition" "$_biosluks" $pts
1050 [[ $BOOT_PART ]] || return 1
1052 dlg BOOT_PART menu "Boot Partition" "$_bios" "skip" "no separate boot" $pts
1053 [[ -z $BOOT_PART || $BOOT_PART == "skip" ]] && { BOOT_PART=''; return 0; }
1060 if ([[ $SYS == 'BIOS' ]] && grep -q 'ext[34]' <<< "$(fsck -N "$BOOT_PART")") || ([[ $SYS == 'UEFI' ]] && grep -q 'fat' <<< "$(fsck -N "$BOOT_PART")"); then
1061 yesno "Format Boot Partition" "\nIMPORTANT:\n\nThe boot partition $BOOT_PART $_format" "Format $BOOT_PART" "Skip Formatting" 1 || return 0
1065 UEFI) part_format "$BOOT_PART" "vfat" 2 || return 1 ;;
1066 BIOS) part_format "$BOOT_PART" "ext4" 2 || return 1 ;;
1071 select_root_partition()
1073 if [[ -z $ROOT_PART ]]; then
1074 if [[ $AUTO_ROOT_PART && -z $LVM && -z $LUKS ]]; then
1075 ROOT_PART="$AUTO_ROOT_PART"
1076 msg "Mount Menu" "\nUsing partitions created during automatic format.\n" 2
1077 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1078 return 0 # we're done here
1080 local pts dev size isize ptcount=0
1082 # walk partition list and skip ones that are too small for / (root)
1083 while read -r dev size; do
1084 size_t="${size: -1:1}" # size type eg. K, M, G, T
1085 isize=${size:0:-1} # remove trailing size type character
1086 isize=${isize%.*} # remove any decimal (round down)
1087 [[ $size_t =~ [MK] || ($size_t == 'G' && $isize -lt 4) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1090 if (( ptcount == 1 )); then # only one available device
1091 msg "Root Partition (/)" "\nOnly one partition available that meets size requirements.\n" 2
1092 ROOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")"
1094 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
1099 if [[ -z $ROOT_PART ]] || ! select_filesystem "$ROOT_PART" || ! part_mount "$ROOT_PART"; then
1106 select_extra_partitions()
1110 # walk partition list and skip ones that are too small to be usable
1111 while read -r dev size; do
1112 [[ ${size: -1:1} =~ [KM] ]] && part_countdec "$dev"
1115 while (( COUNT > 0 )); do
1117 dlg part menu 'Mount Extra' "$_expart" 'done' 'finish mounting step' $PARTS || break
1118 if [[ $part == 'done' ]]; then
1120 elif select_filesystem "$part" && select_mountpoint && part_mount "$part" "$EXMNT"; then
1121 EXMNTS+="$part: $EXMNT "
1122 [[ $EXMNT == '/usr' && $HOOKS != *usr* ]] && HOOKS+=" usr"
1130 ###############################################################################
1132 # main is the entry point which calls all other install functions, once
1133 # complete it shows a dialog to edit files on the new system before reboot
1138 genfstab -U "$MNT" > "$MNT/etc/fstab" 2> "$ERR" 2>&1
1139 errshow 1 "genfstab -U $MNT > $MNT/etc/fstab"
1140 [[ -f $MNT/swapfile ]] && sed -i "s~${MNT}~~" "$MNT/etc/fstab"
1142 # video driver tearfree configs, MUST be done after package install to support nvidia
1143 install_tearfree_conf "$MNT/etc/X11/xorg.conf.d"
1146 chrun "hwclock --systohc --utc" || chrun "hwclock --systohc --utc --directisa"
1149 chrun "chown -Rf $NEWUSER:users /home/$NEWUSER"
1150 if [[ "$USER_CMD" ]]; then
1151 chrun "$USER_CMD" 2> "$ERR" 2>&1
1152 errshow 0 "$USER_CMD"
1156 dlg choice menu "Finalization" "$_edit" \
1157 finished "exit the installer and reboot" \
1158 keyboard "${EDIT_FILES[keyboard]}" \
1159 console "${EDIT_FILES[console]}" \
1160 locale "${EDIT_FILES[locale]}" \
1161 hostname "${EDIT_FILES[hostname]}" \
1162 sudoers "${EDIT_FILES[sudoers]}" \
1163 mkinitcpio "${EDIT_FILES[mkinitcpio]}" \
1164 fstab "${EDIT_FILES[fstab]}" \
1165 crypttab "${EDIT_FILES[crypttab]}" \
1166 bootloader "${EDIT_FILES[bootloader]}" \
1167 pacman "${EDIT_FILES[pacman]}" \
1168 login "${EDIT_FILES[login]}"
1170 if [[ -z $choice || $choice == 'finished' ]]; then
1171 [[ $DEBUG == true && -r $DBG ]] && ${EDITOR:-vim} "$DBG"
1176 for f in ${EDIT_FILES[$choice]}; do
1177 if [[ -e ${MNT}$f ]]; then
1178 ${EDITOR:-vim} "${MNT}$f"
1180 msg "File Missing" "\nThe file(s) selected do not exist:\n\n${MNT}$f\n"
1191 while kill -0 $BG_PID 2> /dev/null; do
1192 clear; printf "\nA background install process is still running...\n"; sleep 1
1198 rm -rf "$MNT/etc/mkinitcpio-archiso.conf"
1199 find "$MNT/usr/lib/initcpio" -name 'archiso*' -type f -delete
1201 # remove/disable customizations done to airootfs during building
1202 chrun "systemctl disable pacman-init.service choose-mirror.service" > /dev/null 2>&1
1203 rm -f "$MNT/etc/systemd/scripts/choose-mirror"
1204 rm -f "$MNT/etc/systemd/system/"{choose-mirror.service,etc-pacman.d-gnupg.mount,pacman-init.service}
1205 sed -i 's/#\(Storage=\)volatile/\1auto/' "$MNT/etc/systemd/journald.conf"
1206 sed -i 's/#\(HandleSuspendKey=\)ignore/\1suspend/' "$MNT/etc/systemd/logind.conf"
1207 sed -i 's/#\(HandleHibernateKey=\)ignore/\1hibernate/' "$MNT/etc/systemd/logind.conf"
1208 sed -i 's/#\(HandleLidSwitch=\)ignore/\1suspend/' "$MNT/etc/systemd/logind.conf"
1209 find "$MNT/boot" -name '*-ucode.img' -delete
1211 # changing distro name?
1212 [[ $DIST != "ArchLabs" ]] || sed -i "s/ArchLabs/$DIST/g" "$MNT/etc/"{lsb-release,os-release}
1214 # vmlinuz, if this isn't copied the standard kernel may fail mkinitcpio
1215 cp -vf "$RUN/x86_64/vmlinuz" "$MNT/boot/vmlinuz-linux" 2> $ERR 2>&1
1216 errshow 1 "cp -vf $RUN/x86_64/vmlinuz $MNT/boot/vmlinuz-linux"
1218 # copy network settings
1219 [[ -d /etc/netctl ]] && cp -rfv /etc/netctl "$MNT/etc/"
1220 [[ -f /etc/resolv.conf ]] && cp -fv /etc/resolv.conf "$MNT/etc/"
1221 [[ -e /etc/NetworkManager/system-connections ]] && cp -rvf /etc/NetworkManager/system-connections "$MNT/etc/NetworkManager/"
1223 echo "LANG=$MYLOCALE" > "$MNT/etc/locale.conf"
1224 cp -fv "$MNT/etc/locale.conf" "$MNT/etc/default/locale"
1225 sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${MYLOCALE}/${MYLOCALE}/g" "$MNT/etc/locale.gen"
1227 chrun "ln -svf /usr/share/zoneinfo/$ZONE/$SUBZ /etc/localtime"
1229 cat > "$MNT/etc/X11/xorg.conf.d/00-keyboard.conf" <<- EOF
1230 # Use localectl(1) to instruct systemd-localed to update it.
1231 Section "InputClass"
1232 Identifier "system-keyboard"
1233 MatchIsKeyboard "on"
1234 Option "XkbLayout" "$KEYMAP"
1238 cat > "$MNT/etc/default/keyboard" <<- EOF
1239 # KEYBOARD CONFIGURATION FILE
1240 # Consult the keyboard(5) manual page.
1247 printf "KEYMAP=%s\nFONT=%s\n" "$CMAP" "$FONT" > "$MNT/etc/vconsole.conf"
1249 echo "$MYHOST" > "$MNT/etc/hostname"
1250 cat > "$MNT/etc/hosts" <<- EOF
1253 ::1 localhost ip6-localhost ip6-loopback
1254 ff02::1 ip6-allnodes
1255 ff02::2 ip6-allrouters
1261 echo "Installing $BOOTLDR"
1263 if [[ $ROOT_PART == /dev/mapper* ]]; then
1264 ROOT_PART_ID="$ROOT_PART"
1266 local uuid_type="UUID"
1267 [[ $BOOTLDR =~ (systemd-boot|refind-efi|efistub) ]] && uuid_type="PARTUUID"
1268 ROOT_PART_ID="$uuid_type=$(blkid -s $uuid_type -o value $ROOT_PART)"
1271 if [[ $SYS == 'UEFI' ]]; then
1272 # remove our old install and generic BOOT/ dir
1273 echo "Removing conflicting boot directories"
1274 find "$MNT/$BOOTDIR/EFI/" -maxdepth 1 -mindepth 1 -iname "$DIST" -type d -delete -printf "remove %p\n"
1275 find "$MNT/$BOOTDIR/EFI/" -maxdepth 1 -mindepth 1 -iname 'BOOT' -type d -delete -printf "remove %p\n"
1279 chrun "${BCMDS[$BOOTLDR]}" 2> $ERR 2>&1
1280 errshow 1 "${BCMDS[$BOOTLDR]}"
1282 if [[ -d $MNT/hostrun ]]; then
1283 echo "Unmounting chroot directories"
1284 # cleanup the bind mounts we made earlier for the grub-probe module
1285 umount_dir "$MNT/hostrun/"{udev,lvm}
1286 rm -rf "$MNT/hostrun" > /dev/null 2>&1
1289 if [[ $SYS == 'UEFI' ]]; then
1290 # some UEFI firmware requires a generic esp/BOOT/BOOTX64.EFI
1291 mkdir -pv "$MNT/$BOOTDIR/EFI/BOOT"
1293 grub) cp -fv "$MNT/$BOOTDIR/EFI/$DIST/grubx64.efi" "$MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI" ;;
1294 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" ;;
1295 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"
1296 cp -fv "$MNT/$BOOTDIR/EFI/refind/refind_x64.efi" "$MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI" ;;
1305 local groups='audio,video,floppy,log,network,rfkill,scanner,storage,optical,power,wheel'
1306 [[ -e $MNT/etc/X11/xorg.conf.d/20-nvida.conf && -e $MNT/usr/bin/optirun ]] && groups+=',bumblebee'
1308 rm -f "$MNT/root/.zlogin" # remove welcome message
1310 chrun "chpasswd <<< 'root:$ROOT_PASS'" 2> "$ERR" 2>&1
1311 errshow 1 "set root password"
1312 if [[ $MYSHELL != 'zsh' ]]; then # root uses zsh by default
1313 chrun "usermod -s /bin/$MYSHELL root" 2> "$ERR" 2>&1
1314 errshow 1 "usermod -s /bin/$MYSHELL root"
1315 # copy the default mkshrc to /root if it was selected
1316 [[ $MYSHELL == 'mksh' ]] && cp -fv "$MNT/etc/skel/.mkshrc" "$MNT/root/.mkshrc"
1319 echo "Creating new user $NEWUSER and setting password"
1320 chrun "useradd -m -u 1000 -g users -G $groups -s /bin/$MYSHELL $NEWUSER" 2> "$ERR" 2>&1
1321 errshow 1 "useradd -m -u 1000 -g users -G $groups -s /bin/$MYSHELL $NEWUSER"
1322 chrun "chpasswd <<< '$NEWUSER:$USER_PASS'" 2> "$ERR" 2>&1
1323 errshow 1 "set $NEWUSER password"
1325 if [[ $INSTALL_WMS == *dwm* ]];then
1326 install_suckless "/home/$NEWUSER" chroot
1327 [[ $INSTALL_WMS == 'dwm' ]] && rm -rf "$MNT/home/$NEWUSER/.config/xfce4"
1329 [[ $INSTALL_WMS == *jwm* ]] && cp -rf "$MNT/etc/system.jwmrc" "$MNT/home/$NEWUSER/.jwmrc"
1330 [[ $INSTALL_WMS != *bspwm* && $INSTALL_WMS != *openbox* ]] && rm -rf "$MNT/home/$NEWUSER/.config/"{jgmenu,tint2}
1331 [[ $USER_PKGS != *geany* ]] && rm -rf "$MNT/home/$NEWUSER/.config/geany"
1332 [[ $MYSHELL != 'bash' ]] && rm -rf "$MNT/home/$NEWUSER/.bash"*
1333 [[ $MYSHELL != 'zsh' ]] && rm -rf "$MNT/home/$NEWUSER/.z"*
1335 # remove some commands from ~/.xprofile when using KDE or Gnome as the login session
1336 if [[ $LOGIN_WM =~ (startkde|gnome-session) || ($LOGIN_TYPE != 'xinit' && $WM_PKGS =~ (plasma|gnome)) ]]; then
1337 sed -i '/super/d; /nitrogen/d; /compton/d' "$MNT/home/$NEWUSER/.xprofile" "$MNT/root/.xprofile"
1338 elif [[ $LOGIN_WM == 'dwm' ]]; then # and dwm
1339 sed -i '/super/d; /compton/d' "$MNT/home/$NEWUSER/.xprofile" "$MNT/root/.xprofile"
1347 local serv="$MNT/etc/systemd/system/getty@tty1.service.d"
1348 echo "Setting up $LOGIN_TYPE"
1350 ly|sddm|gdm|lightdm)
1351 if [[ $LOGIN_WM == *dwm* ]]; then # dwm doesn't include an xsession file for display managers
1352 mkdir -p "$MNT/usr/share/xsessions"
1353 cat > "$MNT/usr/share/xsessions/dwm.desktop" <<- EOF
1357 Comment=Dynamic Window Manager
1362 rm -rf "$serv" "$MNT/home/$NEWUSER/.xinitrc"
1363 chrun "systemctl enable $LOGIN_TYPE.service" 2> $ERR 2>&1
1364 errshow 1 "systemctl enable $LOGIN_TYPE.service"
1365 ${LOGIN_TYPE}_config
1368 if [[ $INSTALL_WMS ]]; then
1369 sed -i "/exec/ c exec ${LOGIN_WM}" "$MNT/home/$NEWUSER/.xinitrc"
1370 elif [[ -e $MNT/home/$NEWUSER/.xinitrc ]]; then
1371 sed -i '/exec/d' "$MNT/home/$NEWUSER/.xinitrc"
1374 if [[ $AUTOLOGIN ]]; then
1375 sed -i "s/root/${NEWUSER}/g" $serv/autologin.conf
1376 cat > "$MNT/home/$NEWUSER/$LOGINRC" <<- EOF
1377 # automatically run startx when logging in on tty1
1378 [ \$XDG_VTNR -eq 1 ] && exec startx
1390 local inpkg="$PACKAGES $USER_PKGS $AL_BASE_PKGS "
1392 if pacman -Qq archlabs-installer > /dev/null 2>&1; then
1393 rmpkg+="archlabs-installer "
1396 if [[ $MYSHELL == 'zsh' ]]; then
1397 inpkg+="zsh-completions "
1402 if [[ $INSTALL_WMS =~ (openbox|bspwm|i3-gaps|fluxbox) ]]; then
1403 inpkg+="$WM_BASE_PKGS "
1404 elif [[ $INSTALL_WMS == 'dwm' ]]; then # dwm only needs a very limited package set
1405 inpkg+="nitrogen polkit-gnome gnome-keyring dunst "
1408 # update and install crucial packages first to avoid issues
1409 chrun "pacman -Syyu $KERNEL $BASE_PKGS base-devel ${LOGIN_PKGS[$LOGIN_TYPE]} $MYSHELL --noconfirm --needed" 2> $ERR 2>&1
1410 errshow 1 "pacman -Syyu $KERNEL $BASE_PKGS base-devel ${LOGIN_PKGS[$LOGIN_TYPE]} $MYSHELL --noconfirm --needed"
1412 # remove the packages we don't want on the installed system
1413 [[ $rmpkg ]] && chrun "pacman -Rnsc $rmpkg --noconfirm"
1415 # reinstalling iputils fixes the network issue for non-root users
1416 chrun "pacman -S iputils $UCODE --noconfirm"
1418 # install the packages chosen throughout the install
1419 chrun "pacman -S $inpkg --needed --noconfirm" 2> $ERR 2>&1
1420 errshow 1 "pacman -S $inpkg --needed --noconfirm"
1422 # bootloader packages
1423 if [[ $BOOTLDR == 'grub' ]]; then
1424 [[ $SYS == 'UEFI' ]] && local efib="efibootmgr"
1425 chrun "pacman -S os-prober grub $efib --needed --noconfirm" 2> $ERR 2>&1
1426 errshow 1 "pacman -S os-prober grub $efib --needed --noconfirm"
1427 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1428 chrun "pacman -S refind-efi efibootmgr --needed --noconfirm" 2> $ERR 2>&1
1429 errshow 1 "pacman -S refind-efi efibootmgr --needed --noconfirm"
1430 elif [[ $SYS == 'UEFI' ]]; then
1431 chrun "pacman -S efibootmgr --needed --noconfirm" 2> $ERR 2>&1
1432 errshow 1 "pacman -S efibootmgr --needed --noconfirm"
1435 if [[ $VM ]] && dmesg | grep -qi 'vbox'; then
1437 linux) chrun "pacman -S virtualbox-guest-utils virtualbox-guest-modules-arch --needed --noconfirm" ;;
1438 *) chrun "pacman -S virtualbox-guest-utils virtualbox-guest-modules-dkms ${KERNEL}-headers --needed --noconfirm" ;;
1442 # allow members of the wheel group to run commands as root
1443 sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" "$MNT/etc/sudoers"
1450 local dir="$1/suckless"
1452 if [[ $2 == 'chroot' ]]; then
1453 chrun "mkdir -pv '$dir'"
1454 for i in dwm dmenu st; do
1455 if chrun "git clone 'https://git.suckless.org/$i' '$dir/$i'"; then
1456 chrun "cd '$dir/$i' && make PREFIX=/usr install"
1458 printf "failed to clone %s repo\n" "$i"
1463 for i in dwm dmenu st; do
1464 if git clone "https://git.suckless.org/$i" "$dir/$i"; then
1465 cd "$dir/$i" && make PREFIX=/usr install
1467 printf "failed to clone %s repo\n" "$i"
1473 install_mkinitcpio()
1476 [[ $LUKS ]] && add="encrypt"
1477 [[ $LVM ]] && { [[ $add ]] && add+=" lvm2" || add+="lvm2"; }
1478 sed -i "s/block filesystems/block ${add} filesystems ${HOOKS}/g" "$MNT/etc/mkinitcpio.conf"
1479 chrun "mkinitcpio -p $KERNEL" 2> $ERR 2>&1
1480 errshow 1 "mkinitcpio -p $KERNEL"
1483 install_mirrorlist()
1485 if hash reflector > /dev/null 2>&1; then
1486 reflector --verbose --score 80 -l 40 -f 5 --sort rate --save "$1"
1487 elif hash rankmirrors > /dev/null 2>&1; then
1488 echo "Sorting mirrorlist"
1489 local key="access_key=5f29642060ab983b31fdf4c2935d8c56"
1490 ip_add="$(curl -fsSL "http://api.ipstack.com/check&?$key&fields=ip" | python -c "import sys, json; print(json.load(sys.stdin)['ip'])")"
1491 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'])")"
1492 if [[ "$country" ]]; then
1493 if [[ $country =~ (CA|US) ]]; then
1494 # use both CA and US mirrors for CA or US countries
1495 mirror="https://www.archlinux.org/mirrorlist/?country=US&country=CA&use_mirror_status=on"
1496 elif [[ $country =~ (AU|NZ) ]]; then
1497 # use both AU and NZ mirrors for AU or NZ countries
1498 mirror="https://www.archlinux.org/mirrorlist/?country=AU&country=NZ&use_mirror_status=on"
1500 mirror="https://www.archlinux.org/mirrorlist/?country=${country}&use_mirror_status=on"
1502 else # no country code so just grab all mirrors, will be a very slow sort but we don't have other options
1503 mirror="https://www.archlinux.org/mirrorlist/?country=all&use_mirror_status=on"
1505 curl -fsSL "$mirror" | sed -e 's/^#Server/Server/' -e '/^#/d' | rankmirrors -n 6 - > "$1"
1509 install_background()
1511 ( rsync -a /run/archiso/sfs/airootfs/ "$MNT/" && install_mirrorlist "$MNT/etc/pacman.d/mirrorlist" > /dev/null 2>&1 ) &
1513 trap "kill $BG_PID 2> /dev/null" EXIT
1516 install_tearfree_conf()
1521 echo "Virtual machine detected, removing xorg configs"
1522 find "$xpath/" -name '*.conf' -delete -printf "remove %p\n"
1523 elif lspci | grep ' VGA ' | grep -q 'Intel'; then
1524 echo "Creating Intel Tear Free config /etc/X11/xorg.conf.d/20-intel.conf"
1525 cat > "$xpath/20-intel.conf" <<- EOF
1527 Identifier "Intel Graphics"
1529 Option "TearFree" "true"
1532 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
1533 echo "Creating AMD Tear Free config /etc/X11/xorg.conf.d/20-amdgpu.conf"
1534 cat > "$xpath/20-amdgpu.conf" <<- EOF
1536 Identifier "AMD Graphics"
1538 Option "TearFree" "true"
1541 elif lspci | grep ' VGA ' | grep -q 'AMD/ATI.*HD [2-6][0-9]*'; then # older HD 2xxx-6xxx cards must use the radeon driver
1542 echo "Creating Radeon Tear Free config /etc/X11/xorg.conf.d/20-radeon.conf"
1543 cat > "$xpath/20-radeon.conf" <<- EOF
1545 Identifier "AMD Graphics"
1547 Option "TearFree" "on"
1550 elif lspci | grep ' VGA ' | grep -q 'NVIDIA'; then # nvidia cards require a bit of checking for notebook gpus
1551 echo "Trying nvidia driver install"
1552 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
1553 if [[ $xpath == *"$MNT"* ]]; then
1554 chrun "nvidia-installer --bumblebee"
1556 nvidia-installer --bumblebee
1559 if [[ $xpath == *"$MNT"* ]]; then
1560 chrun "nvidia-installer" # unsure which card so try auto detection
1565 if [[ -e $xpath/20-nvidia.conf ]]; then
1566 echo "NVIDIA driver installed"
1567 if [[ $xpath == *"$MNT"* ]]; then
1568 echo "Trying to load the driver for live session"
1571 echo "To enable driver vsync:"
1572 echo -e "\trun nvidia-settings (as root) on first boot\n\tenable 'ForceFullCompositionPipeline' under the advanced settings"
1573 echo -e "\tlastly save the change to your nvida xorg config /etc/X11/xorg.conf.d/20-nvidia.conf"
1574 echo -e "\tand remove everything but the Device and Screen sections from the file"
1576 echo "Unable to install nvidia driver"
1581 if lspci | grep ' VGA ' | grep -q 'Intel\|AMD/ATI'; then
1582 if [[ $xpath == *"$MNT"* ]]; then
1583 sed -i 's/xrender/glx/g' "$MNT/etc/skel/.config/compton.conf"
1585 sed -i 's/xrender/glx/g' /etc/skel/.config/compton.conf
1589 # remove nvidia installer from installed system when not running nvidia gpu
1590 [[ $xpath == *"$MNT"* ]] && rm -rf "$MNT/usr/bin/nvidia-installer" "$MNT/var/lib/nvidia-installer"
1593 ###############################################################################
1594 # display manager config
1595 # these are called based on which DM is chosen after it is installed
1596 # additional config can be handled here, for now only lightdm has one
1615 cat > "$MNT/etc/lightdm/lightdm-gtk-greeter.conf" <<- EOF
1617 default-user-image=/usr/share/icons/ArchLabs-Dark/64x64/places/distributor-logo-archlabs.png
1618 background=/usr/share/backgrounds/archlabs/archlabs.jpg
1619 theme-name=Adwaita-dark
1620 icon-theme-name=Adwaita
1621 font-name=DejaVu Sans Mono 11
1622 position=30%,end 50%,end
1626 ###############################################################################
1628 # prerun_* set up the configs needed before actually running the commands
1629 # setup_* are run after selecting a bootloader and build the command used later
1630 # they can also be used for further user input as these run before control is taken away
1634 EDIT_FILES[bootloader]="/etc/default/grub"
1636 if [[ $SYS == 'BIOS' ]]; then
1637 [[ $BOOT_DEV ]] || { part_device 1 || return 1; }
1638 BCMDS[grub]="grub-install --recheck --force --target=i386-pc $BOOT_DEV"
1640 BCMDS[grub]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1641 grub-install --recheck --force --target=x86_64-efi --efi-directory=/$BOOTDIR --bootloader-id=$DIST"
1642 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1645 BCMDS[grub]="mkdir -p /run/udev /run/lvm &&
1646 mount --bind /hostrun/udev /run/udev &&
1647 mount --bind /hostrun/lvm /run/lvm &&
1649 grub-mkconfig -o /boot/grub/grub.cfg &&
1650 sleep 1 && umount /run/udev /run/lvm"
1657 sed -i "s/GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR=\"${DIST}\"/g; s/GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"\"/g" "$MNT/etc/default/grub"
1659 if [[ $LUKS_DEV ]]; then
1660 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
1661 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"
1664 if [[ $SYS == 'BIOS' && $LVM && -z $SEP_BOOT ]]; then
1665 sed -i "s/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g" "$MNT/etc/default/grub" 2> $ERR 2>&1
1666 errshow 1 "sed -i 's/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g' $MNT/etc/default/grub"
1669 # setup for os-prober module
1670 mkdir -p /run/{lvm,udev} "$MNT/hostrun/"{lvm,udev}
1671 mount --bind /run/lvm "$MNT/hostrun/lvm"
1672 mount --bind /run/udev "$MNT/hostrun/udev"
1679 EDIT_FILES[bootloader]=""
1684 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1685 efibootmgr -v -d $BOOT_DEV -p $BOOT_PART_NUM -c -L '${DIST} Linux' -l /vmlinuz-${KERNEL} \
1686 -u 'root=$ROOT_PART_ID rw $([[ $UCODE ]] && printf 'initrd=\%s.img ' "$UCODE")initrd=\initramfs-${KERNEL}.img'"
1691 if [[ $SYS == 'BIOS' ]]; then
1692 EDIT_FILES[bootloader]="/boot/syslinux/syslinux.cfg"
1694 EDIT_FILES[bootloader]="/boot/EFI/syslinux/syslinux.cfg"
1695 BCMDS[syslinux]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1696 efibootmgr -v -c -d $BOOT_DEV -p $BOOT_PART_NUM -l /EFI/syslinux/syslinux.efi -L $DIST"
1702 local c="$MNT/boot/syslinux"
1703 local s="/usr/lib/syslinux/bios"
1705 if [[ $SYS == 'UEFI' ]]; then
1706 c="$MNT/boot/EFI/syslinux"
1707 s="/usr/lib/syslinux/efi64"
1710 mkdir -pv "$c" 2> $ERR 2>&1
1711 errshow 1 "mkdir -pv $c"
1712 cp -rfv "$s/"* "$c/" 2> $ERR 2>&1
1713 errshow 1 "cp -rfv $s/* $c/"
1714 cp -fv "$RUN/syslinux/splash.png" "$c/" 2> $ERR 2>&1
1715 errshow 0 "cp -fv $RUN/syslinux/splash.png $c/"
1716 cat > "$c/syslinux.cfg" <<- EOF
1718 MENU TITLE $DIST Boot Menu
1719 MENU BACKGROUND splash.png
1723 # see: https://www.syslinux.org/wiki/index.php/Comboot/menu.c32
1732 MENU HELPMSGENDROW 29
1733 MENU COLOR border 30;44 #40ffffff #a0000000 std
1734 MENU COLOR title 1;36;44 #9033ccff #a0000000 std
1735 MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
1736 MENU COLOR unsel 37;44 #50ffffff #a0000000 std
1737 MENU COLOR help 37;40 #c0ffffff #a0000000 std
1738 MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
1739 MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
1740 MENU COLOR msg07 37;40 #90ffffff #a0000000 std
1741 MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
1744 MENU LABEL $DIST Linux
1745 LINUX $d/vmlinuz-$KERNEL
1746 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1747 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL.img
1749 LABEL ${DIST}fallback
1750 MENU LABEL $DIST Linux Fallback
1751 LINUX $d/vmlinuz-$KERNEL
1752 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1753 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL-fallback.img
1760 EDIT_FILES[bootloader]="/boot/refind_linux.conf"
1761 BCMDS[refind-efi]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1; refind-install"
1766 cat > "$MNT/boot/refind_linux.conf" <<- EOF
1767 "$DIST Linux" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1768 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1769 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL.img"
1770 "$DIST Linux Fallback" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1771 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1772 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL-fallback.img"
1774 mkdir -p "$MNT/etc/pacman.d/hooks"
1775 cat > "$MNT/etc/pacman.d/hooks/refind.hook" <<- EOF
1782 Description = Updating rEFInd on ESP
1783 When = PostTransaction
1784 Exec = /usr/bin/refind-install
1788 setup_systemd-boot()
1790 EDIT_FILES[bootloader]="/boot/loader/entries/$DIST.conf"
1791 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1; bootctl --path=/boot install"
1794 prerun_systemd-boot()
1796 mkdir -p "$MNT/boot/loader/entries"
1797 cat > "$MNT/boot/loader/loader.conf" <<- EOF
1802 cat > "$MNT/boot/loader/entries/$DIST.conf" <<- EOF
1804 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1805 initrd /initramfs-$KERNEL.img
1806 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1808 cat > "$MNT/boot/loader/entries/$DIST-fallback.conf" <<- EOF
1809 title $DIST Linux Fallback
1810 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1811 initrd /initramfs-$KERNEL-fallback.img
1812 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1814 mkdir -p "$MNT/etc/pacman.d/hooks"
1815 cat > "$MNT/etc/pacman.d/hooks/systemd-boot.hook" <<- EOF
1822 Description = Updating systemd-boot
1823 When = PostTransaction
1824 Exec = /usr/bin/bootctl update
1826 systemd-machine-id-setup --root="$MNT"
1830 ###############################################################################
1835 no_bg_install || return 1
1839 dlg choice menu "Logical Volume Management" "$_lvmmenu" \
1840 "$_lvmnew" "vgcreate -f, lvcreate -L -n" \
1841 "$_lvmdel" "vgremove -f" \
1842 "$_lvmdelall" "lvrmeove, vgremove, pvremove -f" \
1843 "Back" "Return to the main menu"
1845 "$_lvmnew") lvm_create && break ;;
1846 "$_lvmdel") lvm_delgroup && yesno "$_lvmdel" "$_lvmdelask" && vgremove -f "$DEL_VG" > /dev/null 2>&1 ;;
1847 "$_lvmdelall") lvm_del_all ;;
1858 pv="$(pvs -o pv_name --noheading 2> /dev/null)"
1859 v="$(lvs -o vg_name,lv_name --noheading --separator - 2> /dev/null)"
1860 VGROUP="$(vgs -o vg_name --noheading 2> /dev/null)"
1862 if [[ $VGROUP && $v && $pv ]]; then
1863 msg "LVM Setup" "\nActivating existing logical volume management.\n" 0
1864 modprobe dm-mod > /dev/null 2> $ERR
1865 errshow 'modprobe dm-mod'
1866 vgscan > /dev/null 2>&1
1867 vgchange -ay > /dev/null 2>&1
1873 VGROUP='' LVM_PARTS='' VGROUP_MB=0
1875 lvm_mkgroup || return 1
1876 local txt="\nThe last (or only) logical volume will automatically use all remaining space in the volume group."
1877 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 -
1878 [[ $VOL_COUNT ]] || return 1
1879 lvm_extra_lvs || return 1
1880 lvm_volume_name "$_lvmlvname\nNOTE: This LV will use up all remaining space in the volume group (${VGROUP_MB}MB)" || return 1
1881 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating volume $VNAME from remaining space in $VGROUP\n" 0
1882 lvcreate -l +100%FREE "$VGROUP" -n "$VNAME" > /dev/null 2> $ERR
1883 errshow "lvcreate -l +100%FREE $VGROUP -n $VNAME" || return 1
1884 LVM='logical volume'; sleep 0.5
1885 txt="\nDone, volume: $VGROUP-$VNAME (${VOLUME_SIZE:-${VGROUP_MB}MB}) has been created.\n"
1886 msg "$_lvmnew (LV:$VOL_COUNT)" "$txt\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE $LVM_PARTS)\n"
1892 local txt="${VGROUP}: ${SIZE}$SIZE_UNIT (${VGROUP_MB}MB remaining).$_lvmlvsize"
1896 dlg VOLUME_SIZE input "$_lvmnew (LV:$VOL_COUNT)" "$txt" ''
1897 if [[ -z $VOLUME_SIZE ]]; then
1899 break # allow bailing with escape or an empty choice
1900 elif (( ${VOLUME_SIZE:0:1} == 0 )); then
1901 ERR_SIZE=1 # size values can't begin with '0'
1903 # walk the string and make sure all but the last char are digits
1904 local lv=$((${#VOLUME_SIZE} - 1))
1905 for (( i=0; i<lv; i++ )); do
1906 [[ ${VOLUME_SIZE:$i:1} =~ [0-9] ]] || { ERR_SIZE=1; break; }
1908 if (( ERR_SIZE != 1 )); then
1909 case ${VOLUME_SIZE:$lv:1} in
1910 [mMgG]) local s=${VOLUME_SIZE:0:$lv} m=$((s * 1000))
1911 case ${VOLUME_SIZE:$lv:1} in
1912 [Gg]) (( m >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - m)) ;;
1913 [Mm]) (( ${VOLUME_SIZE:0:$lv} >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - s)) ;;
1920 if (( ERR_SIZE )); then
1921 msg "Invalid Logical Volume Size" "$_lvmerrlvsize"
1934 until [[ $named ]]; do
1935 lvm_partitions || return 1
1936 lvm_group_name || return 1
1937 yesno "$_lvmnew" "\nCreate volume group: $VGROUP\n\nusing these partition(s): $LVM_PARTS\n" && named=true
1940 msg "$_lvmnew" "\nCreating volume group: $VGROUP\n" 0
1941 vgcreate -f "$VGROUP" $LVM_PARTS > /dev/null 2> $ERR
1942 errshow "vgcreate -f $VGROUP $LVM_PARTS" || return 1
1944 SIZE=$(vgdisplay "$VGROUP" | awk '/VG Size/ { gsub(/[^0-9.]/, ""); print int($0) }')
1945 SIZE_UNIT="$(vgdisplay "$VGROUP" | awk '/VG Size/ { print substr($NF, 0, 1) }')"
1947 if [[ $SIZE_UNIT == 'G' ]]; then
1948 VGROUP_MB=$((SIZE * 1000))
1953 msg "$_lvmnew" "\nVolume group $VGROUP (${SIZE}$SIZE_UNIT) successfully created\n"
1959 pv="$(pvs -o pv_name --noheading 2> /dev/null)"
1960 v="$(lvs -o vg_name,lv_name --noheading --separator - 2> /dev/null)"
1961 VGROUP="$(vgs -o vg_name --noheading 2> /dev/null)"
1963 if [[ $VGROUP || $v || $pv ]]; then
1964 if yesno "$_lvmdelall" "$_lvmdelask"; then
1965 for i in $v; do lvremove -f "/dev/mapper/$i" > /dev/null 2>&1; done
1966 for i in $VGROUP; do vgremove -f "$i" > /dev/null 2>&1; done
1967 for i in $pv; do pvremove -f "$i" > /dev/null 2>&1; done
1971 msg "Delete LVM" "\nNo LVMs to remove...\n" 2
1981 for i in $(lvs --noheadings | awk '{print $2}' | uniq); do
1982 VOL_GROUP_LIST+="$i $(vgdisplay "$i" | awk '/VG Size/ {print $3$4}') "
1985 [[ $VOL_GROUP_LIST ]] || { msg "No Groups" "\nNo volume groups found."; return 1; }
1987 dlg DEL_VG menu "Logical Volume Management" "\nSelect volume group to delete.\n\nAll logical volumes within will also be deleted." $VOL_GROUP_LIST
1993 while (( VOL_COUNT > 1 )); do
1994 lvm_volume_name "$_lvmlvname" && lvm_lv_size || return 1
1995 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating a $VOLUME_SIZE volume $VNAME in $VGROUP\n" 0
1996 lvcreate -L "$VOLUME_SIZE" "$VGROUP" -n "$VNAME" > /dev/null 2> $ERR
1997 errshow "lvcreate -L $VOLUME_SIZE $VGROUP -n $VNAME" || return 1
1998 msg "$_lvmnew (LV:$VOL_COUNT)" "\nDone, logical volume (LV) $VNAME ($VOLUME_SIZE) has been created.\n"
2006 part_find 'part|crypt' || return 1
2007 PARTS="$(awk 'NF > 0 {print $0 " off"}' <<< "$PARTS")"
2008 dlg LVM_PARTS check "$_lvmnew" "\nSelect the partition(s) to use for the physical volume (PV)." $PARTS
2015 until [[ $VGROUP ]]; do
2016 dlg VGROUP input "$_lvmnew" "$_lvmvgname" "lvgroup"
2017 if [[ -z $VGROUP ]]; then
2019 elif [[ ${VGROUP:0:1} == "/" || $VGROUP =~ \ |\' ]] || vgdisplay | grep -q "$VGROUP"; then
2020 msg "LVM Name Error" "$_lvmerrvgname"
2030 local txt="$1" default="mainvolume"
2031 (( VOL_COUNT > 1 )) && default="extvolume$VOL_COUNT"
2032 until [[ $VNAME ]]; do
2033 dlg VNAME input "$_lvmnew (LV:$VOL_COUNT)" "\n$txt" "$default"
2034 if [[ -z $VNAME ]]; then
2036 elif [[ ${VNAME:0:1} == "/" || $VNAME =~ \ |\' ]] || lsblk | grep -q "$VNAME"; then
2037 msg "LVM Name Error" "$_lvmerlvname"
2044 ###############################################################################
2050 no_bg_install || return 1
2051 dlg choice menu "LUKS Encryption" "$_luksmenu" \
2052 "$_luksnew" "cryptsetup -q luksFormat" \
2053 "$_luksopen" "cryptsetup open --type luks" \
2054 "$_luksadv" "cryptsetup -q -s -c luksFormat" \
2055 "Back" "Return to the main menu"
2058 "$_luksnew") luks_basic || return 1 ;;
2059 "$_luksopen") luks_open || return 1 ;;
2060 "$_luksadv") luks_advanced || return 1 ;;
2068 modprobe -a dm-mod dm_crypt > /dev/null 2>&1
2070 part_find 'part|crypt|lvm' || return 1
2072 if (( COUNT == 1 )); then
2073 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2075 dlg LUKS_PART menu "$_luksopen" "\nSelect which partition to open." $PARTS
2078 [[ $LUKS_PART ]] || return 1
2080 luks_pass "$_luksopen" || return 1
2081 msg "$_luksopen" "\nOpening encrypted partition: $LUKS_NAME\n\nUsing device/volume: $LUKS_PART\n" 0
2082 cryptsetup open --type luks "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> $ERR
2083 errshow "cryptsetup open --type luks $LUKS_PART $LUKS_NAME" || return 1
2084 LUKS='encrypted'; luks_show
2092 typeset -a ans=(cryptroot) # default name to start
2094 until [[ $LUKS_PASS ]]; do
2096 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " --mixedform "$_luksomenu" 0 0 0 \
2097 "Name:" 1 1 "${ans[0]}" 1 7 "$COLUMNS" 0 0 \
2098 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
2099 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 2> "$ANS" || return 1
2101 mapfile -t ans <"$ANS"
2103 if [[ -z "${ans[0]}" ]]; then
2104 msg "Name Empty" "\nEncrypted device name cannot be empty.\n\nPlease try again.\n" 2
2105 elif [[ -z "${ans[1]}" || "${ans[1]}" != "${ans[2]}" ]]; then
2106 LUKS_NAME="${ans[0]}"
2107 msg "Password Mismatch" "\nThe passwords entered do not match.\n\nPlease try again.\n" 2
2109 LUKS_NAME="${ans[0]}"
2110 LUKS_PASS="${ans[1]}"
2120 msg "$_luksnew" "\nEncrypted partition ready for mounting.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$LUKS_PART")\n\n"
2125 modprobe -a dm-mod dm_crypt > /dev/null 2>&1
2127 part_find 'part|lvm' || return 1
2129 if [[ $AUTO_ROOT_PART ]]; then
2130 LUKS_PART="$AUTO_ROOT_PART"
2131 elif (( COUNT == 1 )); then
2132 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2134 dlg LUKS_PART menu "$_luksnew" "\nSelect the partition you want to encrypt." $PARTS
2137 [[ $LUKS_PART ]] || return 1
2138 luks_pass "$_luksnew"
2143 luks_setup || return 1
2144 msg "$_luksnew" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2145 cryptsetup -q luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2> $ERR
2146 errshow "cryptsetup -q luksFormat $LUKS_PART" || return 1
2147 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> $ERR
2148 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2149 LUKS='encrypted'; luks_show
2157 dlg cipher input "LUKS Encryption" "$_lukskey" "-s 512 -c aes-xts-plain64"
2158 [[ $cipher ]] || return 1
2159 msg "$_luksadv" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2160 cryptsetup -q $cipher luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2> $ERR
2161 errshow "cryptsetup -q $cipher luksFormat $LUKS_PART" || return 1
2162 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> $ERR
2163 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2170 ###############################################################################
2172 # some help avoid repetition and improve usability of some commands
2173 # others are initial setup functions used before reaching the main loop
2177 [[ "$2" == *"$1"* ]] && printf "on" || printf "off"
2182 # cleanup and exit the installer cleanly with exit code $1
2183 local e="$1" # when e is 127 unmount /run/archiso/bootmnt and reboot
2187 if [[ -d $MNT ]]; then
2189 (( e == 127 )) && umount_dir /run/archiso/bootmnt && sleep 0.5 && reboot -f
2196 local var="$1" # assign output from dialog to var
2197 local dlg_t="$2" # dialog type (menu, check, input)
2198 local title="$3" # dialog title
2199 local body="$4" # dialog message
2200 local n=0 # number of items to display for menu and check dialogs
2202 shift 4 # shift off args assigned above
2204 # adjust n when passed a large list
2205 local l=$((LINES - 20))
2206 (( ($# / 2) > l )) && n=$l
2210 menu) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --menu "$body" 0 0 $n "$@" 2> "$ANS" || return 1 ;;
2211 check) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --checklist "$body" 0 0 $n "$@" 2> "$ANS" || return 1 ;;
2214 local def="$1" # assign default value for input
2216 if [[ $1 == 'limit' ]]; then
2217 dialog --backtitle "$DIST Installer - $SYS - v$VER" --max-input 63 --title " $title " --inputbox "$body" 0 0 "$def" 2> "$ANS" || return 1
2219 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --inputbox "$body" 0 0 "$def" 2> "$ANS" || return 1
2223 # if answer file isn't empty read from it into $var
2224 [[ -s "$ANS" ]] && printf -v "$var" "%s" "$(< "$ANS")"
2229 # displays a message dialog
2230 # when more than 2 args the message will disappear after sleep time ($3)
2236 dialog --backtitle "$DIST Installer - $SYS - v$VER" --sleep "$1" --title " $title " --infobox "$body\n" 0 0
2238 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --msgbox "$body\n" 0 0
2246 if ! select_keymap; then
2249 elif ! net_connect; then
2250 msg "Not Connected" "\nRunning live requires an active internet connection to install packages.\n\nExiting..\n" 2
2252 elif (( $(awk '/MemTotal/ {print int($2 / 1024)}' /proc/meminfo) < 2500)); then
2253 msg "Not Enough Memory" "\nLive session requires at least 2.5G of system memory for installing packages.\n\nExiting..\n" 2
2258 echo "Sorting mirrorlist"
2259 mount /run/archiso/cowspace -o remount,size=2G
2260 install_mirrorlist "/etc/pacman.d/mirrorlist"
2261 pacman -Syyu --noconfirm || die 1
2262 rm -rf /var/cache/pacman/pkg/*
2263 pacman -S $BASE_PKGS $AL_BASE_PKGS xorg-xinit --needed --noconfirm || die 1
2264 rm -rf /var/cache/pacman/pkg/*
2266 i3-gaps|openbox|fluxbox|bspwm|awesome|xfce4|jwm) pacman -S "$ses" $WM_BASE_PKGS ${WM_EXT[$ses]} --needed --noconfirm || die 1 ;;
2267 gnome|plasma|cinnamon) pacman -S "$ses" ${WM_EXT[$ses]} --needed --noconfirm || die 1 ;;
2268 dwm) { pacman -S git --needed --noconfirm || die 1; }; install_suckless "/root" nochroot ;;
2270 rm -rf /var/cache/pacman/pkg/*
2271 [[ $VM ]] && dmesg | grep -qi 'vbox' && pacman -S virtualbox-guest-utils virtualbox-guest-modules-arch --needed --noconfirm
2272 pacman -Scc --noconfirm
2273 rm -rf /var/cache/pacman/pkg/*
2274 cp -rfT /etc/skel /root
2275 install_tearfree_conf "/etc/X11/xorg.conf.d"
2277 plasma|gnome|cinnamon) sed -i '/super/d; /nitrogen/d; /compton/d' /root/.xprofile ;;
2278 dwm) sed -i '/super/d; /compton/d' /root/.xprofile ;;
2281 echo -e "pulseaudio &\n(sleep 1; pamixer --unmute --set-volume 50) &" >> /root/.xprofile
2282 sed -i "/exec/ c exec ${WM_SESSIONS[$ses]}" /root/.xinitrc
2283 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]}"
2290 usage: $1 [-hdl] [session]
2293 -h, --help print this message and exit
2294 -l, --live install and setup a live session
2295 -d, --debug enable xtrace and log output to $DBG
2298 i3-gaps - A fork of i3wm with more features including gaps
2299 openbox - A lightweight, powerful, and highly configurable stacking wm
2300 dwm - A dynamic WM for X that manages windows in tiled, floating, or monocle layouts
2301 awesome - A customized Awesome WM session created by @elanapan
2302 bspwm - A tiling wm that represents windows as the leaves of a binary tree
2303 fluxbox - A lightweight and highly-configurable window manager
2304 gnome - A desktop environment that aims to be simple and easy to use
2305 cinnamon - A desktop environment combining traditional desktop with modern effects
2306 plasma - A kde software project currently comprising a full desktop environment
2307 xfce4 - A lightweight and modular desktop environment based on gtk+2/3
2311 set the DIST environment variable before launching the installer eg.
2315 root/boot partition:
2317 set the ROOT_PART and/or BOOT_PART environment variables before launching the installer eg.
2319 ROOT_PART='/dev/sda2' BOOT_PART='/dev/sda1' $1
2323 set the EDITOR environment variable before launching the installer eg.
2333 local title="$1" body="$2" yes='Yes' no='No'
2334 (( $# >= 3 )) && yes="$3"
2335 (( $# >= 4 )) && no="$4"
2337 if (( $# == 5 )); then
2338 dialog --backtitle "$DIST Installer - $SYS - v$VER" --defaultno --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2340 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2346 arch-chroot "$MNT" bash -c "$1"
2351 export PS4='| ${BASH_SOURCE} LINE:${LINENO} FUNC:${FUNCNAME[0]:+ ${FUNCNAME[0]}()} |> '
2361 "\e]P0191919" # #191919
2362 "\e]P1D15355" # #D15355
2363 "\e]P2609960" # #609960
2364 "\e]P3FFCC66" # #FFCC66
2365 "\e]P4255A9B" # #255A9B
2366 "\e]P5AF86C8" # #AF86C8
2367 "\e]P62EC8D3" # #2EC8D3
2368 "\e]P7949494" # #949494
2369 "\e]P8191919" # #191919
2370 "\e]P9D15355" # #D15355
2371 "\e]PA609960" # #609960
2372 "\e]PBFF9157" # #FF9157
2373 "\e]PC4E88CF" # #4E88CF
2374 "\e]PDAF86C8" # #AF86C8
2375 "\e]PE2ec8d3" # #2ec8d3
2376 "\e]PFE1E1E1" # #E1E1E1
2379 [[ $TERM == 'linux' ]] && printf "%b" "${colors[@]}" && clear
2384 [ $? -eq 0 ] && return 0
2386 local fatal=0 err=""
2387 err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
2388 [[ -z $err ]] && err="no error message was found"
2390 (( $1 == 1 )) && { fatal=1; shift; }
2392 local txt="\nCommand: $1\n\n\n\nError: $err\n\n"
2394 if (( fatal )); then
2395 msg "Install Error" "${txt}Errors at this stage are fatal, the install cannot continue.\n"
2396 [[ -r $DBG && $TERM == 'linux' ]] && less "$DBG"
2400 msg "Install Error" "${txt}Errors at this stage are non-fatal and may be fixed or ignored depending on the error.\n"
2408 if (( $1 >= 0 )) && ! grep -qw "$MNT" /proc/mounts; then
2409 msg "Not Mounted" "\nPartition(s) must be mounted first.\n" 2
2411 elif [[ $1 -ge 1 && -z $BOOTLDR ]]; then
2412 msg "No Bootloader" "\nBootloader must be selected first.\n" 2
2414 elif [[ $1 -ge 2 && (-z $NEWUSER || -z $USER_PASS) ]]; then
2415 msg "No User" "\nA user must be created first.\n" 2
2417 elif [[ $1 -ge 3 && -z $CONFIG_DONE ]]; then
2418 msg "Not Configured" "\nSystem configuration must be done first.\n" 2
2421 (( i )) # return code
2426 mount | grep -q 'swap' && swapoff -a
2428 if [[ -d $dir ]] && mount | grep -q "on $dir "; then
2429 if ! umount "$dir" 2> /dev/null; then
2431 umount -f "$dir" 2> /dev/null || umount -l "$dir"
2439 msg "Network Connect" "\nVerifying network connection\n" 0
2440 curl -sIN --connect-timeout 5 'https://www.archlinux.org/' | sed '1q' | grep -q '200'
2445 if chk_connect; then
2447 elif hash nmtui > /dev/null 2>&1; then
2449 if [[ $TERM == 'linux' ]]; then
2450 printf "%b" "\e]P1191919" "\e]P4191919"
2452 printf "%b" "\e]P1D15355" "\e]P4255a9b"
2457 elif hash wifi-menu > /dev/null 2>&1; then
2467 [[ $BG_PID ]] || return 0
2468 msg "Install Running" "\nA background install process is currently running.\n" 2
2474 IGNORE_DEV="$(lsblk -lno NAME,MOUNTPOINT | awk '/\/run\/archiso\/bootmnt/ {sub(/[1-9]/, ""); print $1}')"
2476 if [[ $IGNORE_DEV ]]; then
2477 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ && !'"/$IGNORE_DEV/"' {print "/dev/" $1 " " $2}')"
2479 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ {print "/dev/" $1 " " $2}')"
2482 if [[ -z $SYS_DEVS ]]; then
2483 msg "Device Error" "\nNo available devices...\n\nExiting..\n" 2
2488 while read -r line; do
2490 done <<< "$SYS_DEVS"
2497 # amd-ucode is not needed it's provided by linux-firmware
2498 # elif grep -q 'AuthenticAMD' /proc/cpuinfo; then
2500 elif grep -q 'GenuineIntel' /proc/cpuinfo; then
2504 modprobe -q efivarfs > /dev/null 2>&1
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
2514 ###############################################################################
2517 # enable some nicer colours in the linux console
2520 if (( UID != 0 )); then
2521 msg "Not Root" "\nThis installer must be run as root or using sudo.\n\nExiting..\n" 2
2523 elif ! grep -qwm 1 'lm' /proc/cpuinfo; then
2524 msg "Not x86_64 Architecture" "\nThis installer only supports x86_64 architectures.\n\nExiting..\n" 2
2528 # trap ^C to perform cleanup
2529 trap 'printf "\n^C\n" && die 1' INT
2531 while getopts ":hl:d" OPT; do
2536 if [[ "${!WM_SESSIONS[@]}" =~ $OPTARG ]]; then
2539 echo "error: invalid session for -l, see -h for help"; die 1
2542 \?) echo "error: invalid option: -$OPTARG"; die 1 ;;
2549 msg "Welcome to the $DIST Installer" "$_welcome"
2551 if ! select_keymap; then
2553 elif ! net_connect; then
2554 msg "Not Connected" "\nThis installer requires an active internet connection.\n\nExiting..\n" 2
2561 # vim:fdm=marker:fmr={,}