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 TEARFREE="" # whether to install xorg configs and nvidia drivers
28 EXMNTS="" # extra partitions that were mounted, used to verify mountpoint and show user
29 FORMATTED="" # partitions that have been formatted, allows skipping the format step
30 USER_CMD="" # optional command(s) entered by the user to run in the chroot
31 export DIALOGOPTS="--cr-wrap" # dialog environment variable to hold default options, see `man dialog`
33 BASE_PKGS="base xorg xorg-drivers sudo git gvfs gtk3 libmad libmatroska tumbler "
34 BASE_PKGS+="playerctl pulseaudio pulseaudio-alsa pavucontrol pamixer scrot xdg-user-dirs "
35 BASE_PKGS+="ffmpeg gstreamer gst-libav gst-plugins-base gst-plugins-good bash-completion xterm"
37 AL_BASE_PKGS="archlabs-keyring archlabs-icons archlabs-fonts archlabs-themes "
38 AL_BASE_PKGS+="archlabs-baph archlabs-wallpapers archlabs-scripts archlabs-skel-base"
40 WM_BASE_PKGS="arandr nitrogen polkit-gnome network-manager-applet "
41 WM_BASE_PKGS+="volumeicon xclip exo laptop-detect xdotool compton wmctrl feh "
42 WM_BASE_PKGS+="gnome-keyring dunst gsimplecal xfce4-power-manager xfce4-settings"
44 SYS_MEM="$(awk '/MemTotal/ {print int($2 / 1024) "M"}' /proc/meminfo)"
45 LOCALES="$(awk '/\.UTF-8/ {gsub(/# .*|#/, ""); if ($1) {print $1 " - "}}' /etc/locale.gen)"
46 CMAPS="$(find /usr/share/kbd/keymaps -name '*.map.gz' | awk '{gsub(/\.map\.gz|.*\//, ""); print $1 " - "}' | sort)"
48 [[ $LINES ]] || LINES=$(tput lines)
49 [[ $COLUMNS ]] || COLUMNS=$(tput cols)
53 # commands used to install each bootloader, however most get modified during runtime {
55 [refind-efi]='refind-install'
56 [grub]='grub-install --recheck --force' [syslinux]='syslinux-install_update -i -a -m'
57 [efistub]='efibootmgr -v -d /dev/sda -p 1 -c -l' [systemd-boot]='bootctl --path=/boot install'
60 # executable name for each wm/de used in ~/.xinitrc {
61 declare -A WM_SESSIONS=(
62 [dwm]='dwm' [jwm]='jwm' [i3-gaps]='i3' [bspwm]='bspwm' [awesome]='awesome' [plasma]='startkde' [xfce4]='startxfce4'
63 [gnome]='gnome-session' [fluxbox]='startfluxbox' [openbox]='openbox-session' [cinnamon]='cinnamon-session'
66 # packages installed for each wm/de, most are depends of the skel packages {
68 [dwm]='' [jwm]='' [gnome]='' [cinnamon]='gnome-terminal' [plasma]='kdebase-meta'
69 [awesome]='archlabs-skel-awesome' [bspwm]='archlabs-skel-bspwm' [fluxbox]='archlabs-skel-fluxbox'
70 [i3-gaps]='archlabs-skel-i3-gaps' [openbox]='archlabs-skel-openbox' [xfce4]='archlabs-skel-xfce4 xfce4-goodies'
73 # files offered for editing after install is complete {
74 declare -A EDIT_FILES=(
75 [login]='' # login is populated once we know the username and shell
76 [fstab]='/etc/fstab' [sudoers]='/etc/sudoers' [crypttab]='/etc/crypttab' [pacman]='/etc/pacman.conf'
77 [console]='/etc/vconsole.conf' [mkinitcpio]='/etc/mkinitcpio.conf' [hostname]='/etc/hostname /etc/hosts'
78 [bootloader]="/boot/loader/entries/$DIST.conf" # ** based on bootloader
79 [locale]='/etc/locale.conf /etc/default/locale' [keyboard]='/etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard'
82 # mkfs command flags for filesystem formatting {
83 declare -A FS_CMD_FLAGS=(
84 [f2fs]='' [jfs]='-q' [xfs]='-f' [ntfs]='-q' [ext2]='-q' [ext3]='-q' [ext4]='-q' [vfat]='-F32' [nilfs2]='-q' [reiserfs]='-q'
87 # mount options for each filesystem {
89 [vfat]='' [ntfs]='' [ext2]='' [ext3]='' # NA
90 [jfs]='discard errors=continue errors=panic nointegrity'
91 [reiserfs]='acl nolog notail replayonly user_xattr off'
92 [ext4]='discard dealloc nofail noacl relatime noatime nobarrier nodelalloc'
93 [xfs]='discard filestreams ikeep largeio noalign nobarrier norecovery noquota wsync'
94 [nilfs2]='discard nobarrier errors=continue errors=panic order=relaxed order=strict norecovery'
95 [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'
98 # packages installed for each login option {
99 declare -A LOGIN_PKGS=(
100 [xinit]='xorg-xinit' [ly]='archlabs-ly' [gdm]='gdm' [sddm]='sddm'
101 [lightdm]='lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings accountsservice'
104 # extras installed for user selected packages {
105 # if a package requires additional packages that aren't already dependencies
106 # they can be added here eg. [package]="extra"
108 [vlc]='qt4' [mpd]='mpc' [mupdf]='mupdf-tools'
109 [rxvt-unicode]='urxvt-perls' [zathura]='zathura-pdf-poppler' [noto-fonts]='noto-fonts-emoji' [cairo-dock]='cairo-dock-plug-ins' [qt5ct]='qt5-styleplugins'
110 [vlc]='qt5ct qt5-styleplugins' [qutebrowser]='qt5ct qt5-styleplugins' [qbittorrent]='qt5ct qt5-styleplugins' [transmission-qt]='qt5ct qt5-styleplugins'
111 [bluez]='bluez-libs bluez-utils bluez-tools bluez-plugins bluez-hid2hci' [kdenlive]='kdebase-meta dvdauthor frei0r-plugins breeze breeze-gtk qt5ct qt5-styleplugins'
114 # dialog text variables {
115 # Basics (somewhat in order)
116 _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"
117 _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"
118 _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"
119 _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."
120 _device="\nSelect a device to use from the list below.\n\nDevices (/dev) are the available drives on the system. /sda, /sdb, /sdc ..."
121 _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."
122 _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."
123 _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"
124 _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)."
125 _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."
126 _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."
127 _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."
128 _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"
129 _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."
130 _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."
131 _exmnt="\nWhere do you want the partition mounted?\n\nEnsure the name begins with a slash (/).\nExamples include: /usr, /home, /var, etc."
132 _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."
133 _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."
134 _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"
135 _timez="\nThe time zone is used to set the system clock.\n\nSelect your country or continent from the list below"
136 _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."
137 _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."
138 _login="\nSelect which of your session choices to use for the initial login.\n\nYou can be change this later by editing your ~/.xinitrc"
139 _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"
140 _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."
141 _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"
142 _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."
145 _luksnew="Basic LUKS Encryption"
146 _luksadv="Advanced LUKS Encryption"
147 _luksopen="Open Existing LUKS Partition"
148 _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."
149 _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."
150 _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)."
153 _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."
154 _lvmnew="Create Volume Group and Volume(s)"
155 _lvmdel="Delete an Existing Volume Group"
156 _lvmdelall="Delete ALL Volume Group(s) and Volume(s)"
157 _lvmvgname="\nEnter a name for the volume group (VG) being created from the partition(s) selected."
158 _lvmlvname="\nEnter a name for the logical volume (LV) being created.\n\nThis is similar to setting a label for a partition."
159 _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."
160 _lvmdelask="\nConfirm deletion of volume group(s) and logical volume(s).\n\nDeleting a volume group, will delete all logical volumes within it.\n"
163 _errexpart="\nCannot mount partition due to a problem with the mountpoint.\n\nEnsure it begins with a slash (/) followed by atleast one character.\n"
164 _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"
165 _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"
166 _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"
167 _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"
168 _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"
169 _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"
173 ###############################################################################
175 # main is the entry point which calls functions including outside of its block
176 # once those functions finished they always are returned here with the
177 # exception of install_main(), it exits upon completion
181 (( SEL < 13 )) && (( SEL++ ))
183 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Prepare " --default-item $SEL --cancel-label 'Exit' --menu "$_prep" 0 0 0 \
184 1 "Show device tree" \
186 3 "LUKS encryption" \
187 4 "Logical volume management" \
188 5 "* Mount partitions" \
189 6 "* Select bootloader" \
190 7 "* Username and password" \
191 8 "* System configuration" \
192 9 "Select window manager or desktop" \
193 10 "Select additional packages" \
194 11 "Run a command on the installed system" \
195 12 "View configuration and command selections" \
196 13 "* Confirm choices and start the installation" 2> "$ANS"
199 [[ -z $WARN && $SEL =~ (2|5) ]] && { msg "Data Warning" "$_warn"; WARN=true; }
202 2) part_menu || (( SEL-- )) ;;
203 3) luks_menu || (( SEL-- )) ;;
204 4) lvm_menu || (( SEL-- )) ;;
205 5) mount_menu || (( SEL-- )) ;;
206 6) prechecks 0 && { select_boot || (( SEL-- )); } ;;
207 7) prechecks 1 && { select_mkuser || (( SEL-- )); } ;;
208 8) prechecks 2 && { select_config || (( SEL-- )); } ;;
209 9) prechecks 3 && { select_sessions || (( SEL-- )); } ;;
210 10) prechecks 3 && { select_packages || (( SEL-- )); } ;;
211 11) prechecks 3 && select_usercmd ;;
212 12) prechecks 3 && select_show ;;
213 13) prechecks 3 && install_main ;;
214 *) yesno "Exit" "\nUnmount partitions (if any) and exit the installer?\n" && die 0
220 if [[ $SYS == 'BIOS' ]]; then
221 dlg BOOTLDR menu "BIOS Bootloader" "\nSelect which bootloader to use." \
222 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
223 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network" || return 1
225 dlg BOOTLDR menu "UEFI Bootloader" "\nSelect which bootloader to use." \
226 "systemd-boot" "A simple UEFI boot manager which executes configured EFI images" \
227 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
228 "refind-efi" "A UEFI boot manager that aims to be platform neutral and simplify multi-boot" \
229 "efistub" "Boot the kernel image directly (no chainloading support)" \
230 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network (no chainloading support)" || return 1
237 local pkgs="${USER_PKGS// / } ${PACKAGES// / }"
238 [[ $INSTALL_WMS == *dwm* ]] && pkgs="dwm st dmenu $pkgs"
239 pkgs="${pkgs// / }" pkgs="${pkgs# }"
240 msg "Show Configuration" "
241 ---------- PARTITION CONFIGURATION ------------
243 Root Part: $ROOT_PART
244 Boot Part: ${BOOT_PART:-none}
245 Boot Device: ${BOOT_DEV:-none}
246 Swap Part/File: ${SWAP_PART:-none}
247 Swap Size: ${SWAP_SIZE:-none}
248 Extra Mounts: ${EXMNTS:-none}
249 Mkinit Hooks: ${HOOKS:-none}
251 LVM used: ${LVM:-none}
252 LUKS used: ${LUKS:-none}
254 ------------ SYSTEM CONFIGURATION -------------
256 Locale: ${MYLOCALE:-none}
257 Keymap: ${KEYMAP:-none}
258 Hostname: ${MYHOST:-none}
259 Timezone: ${ZONE:-none}/${SUBZ:-none}
261 Chroot cmd: ${USER_CMD:-none}
263 ------------ USER CONFIGURATION ---------------
265 Username: ${NEWUSER:-none}
266 Login Shell: ${MYSHELL:-none}
267 Login Session: ${LOGIN_WM:-none}
268 Autologin: ${AUTOLOGIN:-none}
269 Login Type: ${LOGIN_TYPE:-none}
271 ----------- PACKAGE CONFIGURATION -------------
273 Kernel: ${KERNEL:-none}
274 Bootloader: ${BOOTLDR:-none}
275 Packages: ${pkgs:-none}
281 AUTOLOGIN='' # no autologin unless using xinit
283 dlg LOGIN_TYPE menu "Login Management" "\nSelect what kind of login management to use." \
284 "xinit" "Console login without a display manager" \
285 "ly" "TUI display manager with a ncurses-like interface" \
286 "lightdm" "Lightweight display manager with a gtk greeter" \
287 "gdm" "Gnome display manager" \
288 "sddm" "Simple desktop display manager" || return 1
291 gdm|sddm) EDIT_FILES[login]="" ;;
292 ly) EDIT_FILES[login]="/etc/ly/config.ini" ;;
293 lightdm) EDIT_FILES[login]="/etc/lightdm/lightdm.conf /etc/lightdm/lightdm-gtk-greeter.conf" ;;
294 xinit) EDIT_FILES[login]="/home/$NEWUSER/.xinitrc /home/$NEWUSER/.xprofile"
295 if (( $(wc -w <<< "$INSTALL_WMS") > 1 )); then
296 dlg LOGIN_WM menu "Login Management" "$_login" $LOGIN_CHOICES || return 1
297 LOGIN_WM="${WM_SESSIONS[$LOGIN_WM]}"
299 [[ -z $LOGIN_WM ]] && LOGIN_WM="${WM_SESSIONS[${INSTALL_WMS%% *}]}"
300 yesno "Autologin" "$(sed "s|USER|$NEWUSER|g; s|RC|$LOGINRC|g" <<< "$_autologin")" && AUTOLOGIN=true || AUTOLOGIN=''
310 until [[ $CONFIG_DONE ]]; do
312 0) dlg MYSHELL menu "Shell" "\nChoose which shell to use." \
313 zsh 'A very advanced and programmable command interpreter (shell) for UNIX' \
314 bash 'The GNU Bourne Again shell, standard in many GNU/Linux distributions' \
315 mksh 'The MirBSD Korn Shell - an enhanced version of the public domain ksh' || return 1
317 1) dlg MYHOST input "Hostname" "$_hostname" "${DIST,,}" limit || { i=0; continue; } ;;
318 2) dlg MYLOCALE menu "Locale" "$_locale" $LOCALES || { i=1; continue; } ;;
320 until [[ $ZONE && $SUBZ ]]; do
321 dlg ZONE menu "Timezone" "$_timez" America - Australia - Asia - Atlantic - Africa - Europe - Indian - Pacific - Arctic - Antarctica - || break
322 dlg SUBZ menu "Timezone" "$_timesubz" $(awk '/'"$ZONE"'\// {gsub(/'"$ZONE"'\//, ""); print $3 " - "}' /usr/share/zoneinfo/zone.tab | sort) || continue
324 [[ $ZONE && $SUBZ ]] || { i=2; continue; } ;;
325 4) dlg KERNEL menu "Kernel" "\nChoose which kernel to use." \
326 linux 'Vanilla linux kernel and modules, with a few patches applied' \
327 linux-lts 'Long-term support (LTS) linux kernel and modules' \
328 linux-zen 'A effort of kernel hackers to provide the best kernel for everyday systems' \
329 linux-hardened 'A security-focused linux kernel with hardening patches to mitigate exploits' || { i=3; continue; }
333 (( i++ )) # progress through to the next choice
337 bash) LOGINRC='.bash_profile' ;;
338 zsh) LOGINRC='.zprofile' ;;
339 mksh) LOGINRC='.profile' ;;
350 until [[ $NEWUSER ]]; do
352 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " User " --mixedform "$_user" 0 0 0 \
353 "Username:" 1 1 "${ans[0]}" 1 11 "$COLUMNS" 0 0 \
354 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
355 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 \
356 "--- Root password, if left empty the user password will be used ---" 6 1 '' 6 68 "$COLUMNS" 0 2 \
357 "Password:" 8 1 '' 8 11 "$COLUMNS" 0 1 \
358 "Password2:" 9 1 '' 9 12 "$COLUMNS" 0 1 2> "$ANS" || return 1
360 mapfile -t ans <"$ANS"
362 # root passwords empty, so use the user passwords
363 if [[ -z "${ans[4]}" && -z "${ans[5]}" ]]; then
368 # make sure a username was entered and that the passwords match
369 if [[ -z ${ans[0]} || ${ans[0]} =~ \ |\' || ${ans[0]} =~ [^a-z0-9] ]]; then
370 msg "Invalid Username" "\nInvalid user name.\n\nPlease try again.\n"; u=''
371 elif [[ -z "${ans[1]}" || "${ans[1]}" != "${ans[2]}" ]]; then
372 msg "Password Mismatch" "\nThe user passwords do not match.\n\nPlease try again.\n"
373 elif [[ "${ans[4]}" != "${ans[5]}" ]]; then
374 msg "Password Mismatch" "\nThe root passwords do not match.\n\nPlease try again.\n"
377 USER_PASS="${ans[1]}"
378 ROOT_PASS="${ans[4]}"
386 dlg KEYMAP menu "Keyboard Layout" "$_keymap" \
387 us English cm English gb English au English gh English \
388 za English ng English ca French 'cd' French gn French \
389 tg French fr French de German at German ch German \
390 es Spanish latam Spanish br Portuguese pt Portuguese ma Arabic \
391 sy Arabic ara Arabic ua Ukrainian cz Czech ru Russian \
392 sk Slovak nl Dutch it Italian hu Hungarian cn Chinese \
393 tw Taiwanese vn Vietnamese kr Korean jp Japanese th Thai \
394 la Lao pl Polish se Swedish is Icelandic 'fi' Finnish \
395 dk Danish be Belgian in Indian al Albanian am Armenian \
396 bd Bangla ba Bosnian 'bg' Bulgarian dz Berber mm Burmese \
397 hr Croatian gr Greek il Hebrew ir Persian iq Iraqi \
398 af Afghani fo Faroese ge Georgian ee Estonian kg Kyrgyz \
399 kz Kazakh lt Lithuanian mt Maltese mn Mongolian ro Romanian \
400 no Norwegian rs Serbian si Slovenian tj Tajik lk Sinhala \
401 tr Turkish uz Uzbek ie Irish pk Urdu 'mv' Dhivehi \
402 np Nepali et Amharic sn Wolof ml Bambara tz Swahili \
403 ke Swahili bw Tswana ph Filipino my Malay tm Turkmen \
404 id Indonesian bt Dzongkha lv Latvian md Moldavian mao Maori \
405 by Belarusian az Azerbaijani mk Macedonian kh Khmer epo Esperanto \
406 me Montenegrin || return 1
408 if [[ $CMAPS == *"$KEYMAP"* ]]; then
411 dlg CMAP menu "Console Keymap" "$_vconsole" $CMAPS || return 1
414 if [[ $TERM == 'linux' ]]; then
415 loadkeys "$CMAP" > /dev/null 2>&1
417 setxkbmap "$KEYMAP" > /dev/null 2>&1
425 dlg USER_CMD input "User Command" "$_usercmd" "$USER_CMD" nolimit
431 dlg INSTALL_WMS check "Sessions" "$_sessions\n" \
432 i3-gaps "A fork of i3wm with more features including gaps" "$(ofn i3-gaps "${INSTALL_WMS[*]}")" \
433 openbox "A lightweight, powerful, and highly configurable stacking wm" "$(ofn openbox "${INSTALL_WMS[*]}")" \
434 dwm "A dynamic WM for X that manages windows in tiled, floating, or monocle layouts" "$(ofn dwm "${INSTALL_WMS[*]}")" \
435 bspwm "A tiling wm that represents windows as the leaves of a binary tree" "$(ofn bspwm "${INSTALL_WMS[*]}")" \
436 jwm "A lightweight window manager for Xorg written in C" "$(ofn jwm "${INSTALL_WMS[*]}")" \
437 xfce4 "A lightweight and modular desktop environment based on gtk+2/3" "$(ofn xfce4 "${INSTALL_WMS[*]}")" \
438 awesome "A customized Awesome WM session created by @elanapan" "$(ofn awesome "${INSTALL_WMS[*]}")" \
439 fluxbox "A lightweight and highly-configurable window manager" "$(ofn fluxbox "${INSTALL_WMS[*]}")" \
440 plasma "A kde software project currently comprising a full desktop environment" "$(ofn plasma "${INSTALL_WMS[*]}")" \
441 gnome "A desktop environment that aims to be simple and easy to use" "$(ofn gnome "${INSTALL_WMS[*]}")" \
442 cinnamon "A desktop environment combining traditional desktop with modern effects" "$(ofn cinnamon "${INSTALL_WMS[*]}")"
444 [[ $INSTALL_WMS ]] || return 0
445 WM_PKGS="${INSTALL_WMS/dwm/}"
446 WM_PKGS="${WM_PKGS// / }"
447 WM_PKGS="${WM_PKGS# }"
449 for i in $INSTALL_WMS; do
450 LOGIN_CHOICES+="$i - "
451 [[ ${WM_EXT[$i]} && $WM_PKGS != *"${WM_EXT[$i]}"* ]] && WM_PKGS+=" ${WM_EXT[$i]}"
454 select_login || return 1
456 while IFS=' ' read -r pkg; do
457 [[ $PACKAGES != *"$pkg"* ]] && PACKAGES+=" $pkg"
465 dlg USER_PKGS check " Packages " "$_packages" \
466 abiword "A Fully-featured word processor" "$(ofn abiword "${USER_PKGS[*]}")" \
467 alacritty "A cross-platform, GPU-accelerated terminal emulator" "$(ofn alacritty "${USER_PKGS[*]}")" \
468 atom "An open-source text editor developed by GitHub" "$(ofn atom "${USER_PKGS[*]}")" \
469 audacious "A free and advanced audio player based on GTK+" "$(ofn audacious "${USER_PKGS[*]}")" \
470 audacity "A program that lets you manipulate digital audio waveforms" "$(ofn audacity "${USER_PKGS[*]}")" \
471 blueman "GUI bluetooth device manager" "$(ofn blueman "${USER_PKGS[*]}")" \
472 bluez "Simple CLI based bluetooth support" "$(ofn bluez "${USER_PKGS[*]}")" \
473 cairo-dock "Light eye-candy fully themable animated dock" "$(ofn cairo-dock "${USER_PKGS[*]}")" \
474 calligra "A set of applications for productivity" "$(ofn calligra "${USER_PKGS[*]}")" \
475 chromium "An open-source web browser based on the Blink rendering engine" "$(ofn chromium "${USER_PKGS[*]}")" \
476 clementine "A modern music player and library organizer" "$(ofn clementine "${USER_PKGS[*]}")" \
477 cmus "A small, fast and powerful console music player" "$(ofn cmus "${USER_PKGS[*]}")" \
478 deadbeef "A GTK+ audio player for GNU/Linux" "$(ofn deadbeef "${USER_PKGS[*]}")" \
479 deluge "A BitTorrent client written in python" "$(ofn deluge "${USER_PKGS[*]}")" \
480 emacs "An extensible, customizable, self-documenting real-time display editor" "$(ofn emacs "${USER_PKGS[*]}")" \
481 epiphany "A GNOME web browser based on the WebKit rendering engine" "$(ofn epiphany "${USER_PKGS[*]}")" \
482 evince "A document viewer" "$(ofn evince "${USER_PKGS[*]}")" \
483 evolution "Manage your email, contacts and schedule" "$(ofn evolution "${USER_PKGS[*]}")" \
484 file-roller "Create and modify archives" "$(ofn file-roller "${USER_PKGS[*]}")" \
485 firefox "A popular open-source web browser from Mozilla" "$(ofn firefox "${USER_PKGS[*]}")" \
486 gcolor2 "A simple GTK+2 color selector" "$(ofn gcolor2 "${USER_PKGS[*]}")" \
487 geany "A fast and lightweight IDE" "$(ofn geany "${USER_PKGS[*]}")" \
488 geary "A lightweight email client for the GNOME desktop" "$(ofn geary "${USER_PKGS[*]}")" \
489 gimp "GNU Image Manipulation Program" "$(ofn gimp "${USER_PKGS[*]}")" \
490 gnome-calculator "GNOME Scientific calculator" "$(ofn gnome-calculator "${USER_PKGS[*]}")" \
491 gnome-disk-utility "Disk Management Utility" "$(ofn gnome-disk-utility "${USER_PKGS[*]}")" \
492 gnome-system-monitor "View current processes and monitor system state" "$(ofn gnome-system-monitor "${USER_PKGS[*]}")" \
493 gparted "A GUI frontend for creating and manipulating partition tables" "$(ofn gparted "${USER_PKGS[*]}")" \
494 gpick "Advanced color picker using GTK+ toolkit" "$(ofn gpick "${USER_PKGS[*]}")" \
495 gpicview "Lightweight image viewer" "$(ofn gpicview "${USER_PKGS[*]}")" \
496 guvcview "Capture video from camera devices" "$(ofn guvcview "${USER_PKGS[*]}")" \
497 hexchat "A popular and easy to use graphical IRC client" "$(ofn hexchat "${USER_PKGS[*]}")" \
498 inkscape "Professional vector graphics editor" "$(ofn inkscape "${USER_PKGS[*]}")" \
499 irssi "Modular text mode IRC client" "$(ofn irssi "${USER_PKGS[*]}")" \
500 kdenlive "A popular non-linear video editor for Linux" "$(ofn kdenlive "${USER_PKGS[*]}")" \
501 krita "Edit and paint images" "$(ofn krita "${USER_PKGS[*]}")" \
502 libreoffice-fresh "Full featured office suite" "$(ofn libreoffice-fresh "${USER_PKGS[*]}")" \
503 lollypop "A new music playing application" "$(ofn lollypop "${USER_PKGS[*]}")" \
504 mousepad "A simple text editor" "$(ofn mousepad "${USER_PKGS[*]}")" \
505 mpd "A flexible, powerful, server-side application for playing music" "$(ofn mpd "${USER_PKGS[*]}")" \
506 mpv "A media player based on mplayer" "$(ofn mpv "${USER_PKGS[*]}")" \
507 mupdf "Lightweight PDF and XPS viewer" "$(ofn mupdf "${USER_PKGS[*]}")" \
508 mutt "Small but very powerful text-based mail client" "$(ofn mutt "${USER_PKGS[*]}")" \
509 nautilus "The default file manager for Gnome" "$(ofn nautilus "${USER_PKGS[*]}")" \
510 ncmpcpp "A mpd client and almost exact clone of ncmpc with some new features" "$(ofn ncmpcpp "${USER_PKGS[*]}")" \
511 neovim "A fork of Vim aiming to improve user experience, plugins, and GUIs." "$(ofn neovim "${USER_PKGS[*]}")" \
512 noto-fonts "Google Noto fonts" "$(ofn noto-fonts "${USER_PKGS[*]}")" \
513 noto-fonts-cjk "Google Noto CJK fonts (Chinese, Japanese, Korean)" "$(ofn noto-fonts-cjk "${USER_PKGS[*]}")" \
514 obs-studio "Free opensource streaming/recording software" "$(ofn obs-studio "${USER_PKGS[*]}")" \
515 openshot "An open-source, non-linear video editor for Linux" "$(ofn openshot "${USER_PKGS[*]}")" \
516 opera "A Fast and secure, free of charge web browser from Opera Software" "$(ofn opera "${USER_PKGS[*]}")" \
517 pcmanfm "A fast and lightweight file manager based in Lxde" "$(ofn pcmanfm "${USER_PKGS[*]}")" \
518 pidgin "Multi-protocol instant messaging client" "$(ofn pidgin "${USER_PKGS[*]}")" \
519 plank "An elegant, simple, and clean dock" "$(ofn plank "${USER_PKGS[*]}")" \
520 qbittorrent "An advanced BitTorrent client" "$(ofn qbittorrent "${USER_PKGS[*]}")" \
521 qpdfview "A tabbed PDF viewer" "$(ofn qpdfview "${USER_PKGS[*]}")" \
522 qt5ct "GUI for managing Qt based application themes, icons, and fonts" "$(ofn qt5ct "${USER_PKGS[*]}")" \
523 qutebrowser "A keyboard-focused vim-like web browser based on Python and PyQt5" "$(ofn qutebrowser "${USER_PKGS[*]}")" \
524 rhythmbox "A Music playback and management application" "$(ofn rhythmbox "${USER_PKGS[*]}")" \
525 rxvt-unicode "A unicode enabled rxvt-clone terminal emulator" "$(ofn rxvt-unicode "${USER_PKGS[*]}")" \
526 sakura "A terminal emulator based on GTK and VTE" "$(ofn sakura "${USER_PKGS[*]}")" \
527 simple-scan "Simple scanning utility" "$(ofn simple-scan "${USER_PKGS[*]}")" \
528 simplescreenrecorder "A feature-rich screen recorder" "$(ofn simplescreenrecorder "${USER_PKGS[*]}")" \
529 steam "A popular game distribution platform by Valve" "$(ofn steam "${USER_PKGS[*]}")" \
530 surf "A simple web browser based on WebKit2/GTK+" "$(ofn surf "${USER_PKGS[*]}")" \
531 terminator "Terminal emulator that supports tabs and grids" "$(ofn terminator "${USER_PKGS[*]}")" \
532 termite "A minimal VTE-based terminal emulator" "$(ofn termite "${USER_PKGS[*]}")" \
533 thunar "A modern file manager for the Xfce Desktop Environment" "$(ofn thunar "${USER_PKGS[*]}")" \
534 thunderbird "Standalone mail and news reader from mozilla" "$(ofn thunderbird "${USER_PKGS[*]}")" \
535 tilda "A GTK based drop down terminal for Linux and Unix" "$(ofn tilda "${USER_PKGS[*]}")" \
536 tilix "A tiling terminal emulator for Linux using GTK+ 3" "$(ofn tilix "${USER_PKGS[*]}")" \
537 transmission-cli "Free BitTorrent client CLI" "$(ofn transmission-cli "${USER_PKGS[*]}")" \
538 transmission-gtk "GTK+ Front end for transmission" "$(ofn transmission-gtk "${USER_PKGS[*]}")" \
539 transmission-qt "Qt Front end for transmission" "$(ofn transmission-qt "${USER_PKGS[*]}")" \
540 ttf-anonymous-pro "A family fixed-width fonts designed with code in mind" "$(ofn ttf-anonymous-pro "${USER_PKGS[*]}")" \
541 ttf-fira-code "Monospaced font with programming ligatures" "$(ofn ttf-fira-code "${USER_PKGS[*]}")" \
542 ttf-font-awesome "Iconic font designed for Bootstrap" "$(ofn ttf-font-awesome "${USER_PKGS[*]}")" \
543 ttf-hack "A hand groomed typeface based on Bitstream Vera Mono" "$(ofn ttf-hack "${USER_PKGS[*]}")" \
544 vlc "A free and open source cross-platform multimedia player" "$(ofn vlc "${USER_PKGS[*]}")" \
545 weechat "Fast, light and extensible IRC client" "$(ofn weechat "${USER_PKGS[*]}")" \
546 xapps "Common library for X-Apps project" "$(ofn xapps "${USER_PKGS[*]}")" \
547 xarchiver "A GTK+ frontend to various command line archivers" "$(ofn xarchiver "${USER_PKGS[*]}")" \
548 xed "A small and lightweight text editor. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
549 xfce4-terminal "A terminal emulator based in the Xfce Desktop Environment" "$(ofn xfce4-terminal "${USER_PKGS[*]}")" \
550 xreader "Document viewer for files like PDF and Postscript. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
551 zathura "Minimalistic document viewer" "$(ofn zathura "${USER_PKGS[*]}")"
553 if [[ $USER_PKGS ]]; then # add any needed PKG_EXT to the list
554 for i in $USER_PKGS; do
555 [[ ${PKG_EXT[$i]} && $USER_PKGS != *"${PKG_EXT[$i]}"* ]] && USER_PKGS+=" ${PKG_EXT[$i]}"
562 ###############################################################################
564 # non-essential partitioning helpers called by the user when using the optional
565 # partition menu and selecting a device to edit
569 no_bg_install || return 0
570 local device choice devhash
571 devhash="$(lsblk -f | base64)"
573 part_device || return 1
578 dlg choice menu "Edit Partitions" "$_part\n\n$(lsblk -no NAME,MODEL,SIZE,TYPE,FSTYPE $device)" \
579 "auto" "Whole device automatic partitioning" \
580 "cfdisk" "Curses based variant of fdisk" \
581 "parted" "GNU partition editor" \
582 "fdisk" "Dialog-driven creation and manipulation of partitions" \
583 "done" "Return to the main menu"
584 # "shrink" "Shrink an existing ext or ntfs partition" \
586 if [[ -z $choice || $choice == 'done' ]]; then
588 elif [[ $choice == 'shrink' ]]; then
589 part_shrink "$device"
590 elif [[ $choice == 'auto' ]]; then
591 local root_size txt table boot_fs
592 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"}}')
593 txt="\nWARNING:\n\nALL data on $device will be destroyed and the following partitions will be created\n\n- "
594 if [[ $SYS == 'BIOS' ]]; then
595 table="msdos" boot_fs="ext4"
596 txt+="An $boot_fs boot partition with the boot flag enabled (512M)\n- "
598 table="gpt" boot_fs="fat32"
599 txt+="A $boot_fs efi boot partition (512M)\n- "
601 txt+="An ext4 partition using all remaining space ($root_size)\n\nDo you want to continue?\n"
602 yesno "Auto Partition" "$txt" && part_auto "$device" "$table" "$boot_fs" "$root_size"
608 if [[ $devhash != "$(lsblk -f | base64)" ]]; then
609 msg "Probing Partitions" "\nInforming kernel of partition changes using partprobe\n" 0
610 partprobe > /dev/null 2>&1
611 [[ $choice == 'auto' ]] && return
619 if [[ $IGNORE_DEV ]]; then
620 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk "!/$IGNORE_DEV/"' && /disk|part|lvm|crypt|NAME/')"
622 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk '/disk|part|lvm|crypt|NAME/')"
624 msg "Device Tree" "\n\n$txt\n\n"
629 local device="$1" table="$2" boot_fs="$3" size="$4" dev_info=""
631 msg "Auto Partition" "\nRemoving partitions on $device and setting table to $table\n" 1
633 dev_info="$(parted -s "$device" print)"
636 while read -r PART; do
637 parted -s "$device" rm "$PART" > /dev/null 2>&1
638 done <<< "$(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r)"
640 [[ $(awk '/Table:/ {print $3}' <<< "$dev_info") != "$table" ]] && parted -s "$device" mklabel "$table" > /dev/null 2>&1
642 msg "Auto Partition" "\nCreating a 512M $boot_fs boot partition.\n" 1
643 if [[ $SYS == "BIOS" ]]; then
644 parted -s "$device" mkpart primary "$boot_fs" 1MiB 513MiB > /dev/null 2>&1
646 parted -s "$device" mkpart ESP "$boot_fs" 1MiB 513MiB > /dev/null 2>&1
651 AUTO_BOOT_PART=$(lsblk -lno NAME,TYPE "$device" | awk 'NR==2 {print "/dev/" $1}')
653 if [[ $SYS == "BIOS" ]]; then
654 mkfs.ext4 -q "$AUTO_BOOT_PART" > /dev/null 2>&1
656 mkfs.vfat -F32 "$AUTO_BOOT_PART" > /dev/null 2>&1
659 msg "Auto Partition" "\nCreating a $size ext4 root partition.\n" 0
660 parted -s "$device" mkpart primary ext4 513MiB 100% > /dev/null 2>&1
662 AUTO_ROOT_PART="$(lsblk -lno NAME,TYPE "$device" | awk 'NR==3 {print "/dev/" $1}')"
663 mkfs.ext4 -q "$AUTO_ROOT_PART" > /dev/null 2>&1
665 msg "Auto Partition" "\nProcess complete.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$device")\n"
672 local device="$1" fs=""
674 part_find "${device##*/}[^ ]" || return 1
675 (( COUNT == 1 )) && part="$(awk '{print $1}' <<< "${PARTS[@]}" )"
677 if (( COUNT == 1 )) || dlg part menu "Resize" "\nWhich partition on $device do you want to resize?" $PARTS; then
678 fs=$(lsblk -lno FSTYPE "$part")
681 msg "Resize" "\nGathering device size info.\n" 0
683 end=$(parted -s "$device" unit KiB print | awk '/^\s*'"$num"'/ {print $3}') # part size in KiB
684 devsize=$(parted -s "$device" unit KiB print | awk '/Disk '"${device//\//\\/}"':/ {print $3}') # whole device size in KiB
685 mount "$part" "$MNT" > /dev/null 2>&1; sleep 0.5
686 min=$(df --output=used --block-size=MiB "$part" | awk 'NR == 2 {print int($1) + 256}')
687 max=$(df --output=avail --block-size=MiB "$part" | awk 'NR == 2 {print int($1)}')
690 if dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Resize: $part " --rangebox "$_resize" 17 "$COLUMNS" "$min" "$max" $((max / 2)) 2> $ANS; then
692 size=$((size * 1024))
699 if ntfsresize -fc "$part"; then
700 ntfsresize -ff --size $(( (size * 1024) / 1000 ))k "$part" 2> "$ERR" # k=10^3 bytes
701 errshow "ntfsresize -f -s $(( (size * 1024) / 1000 ))k $part" || return 1
703 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"
708 e2fsck -f "$part"; sleep 0.5
709 resize2fs -f "$part" ${size}K 2> "$ERR" # K=2^10 bytes
710 errshow "resize2fs -f $part ${size}K" || return 1
714 parted "$device" resizepart "$num" ${size}KiB || return 1
717 if [[ $devsize == "$end" ]]; then
718 parted -s "$device" mkpart primary ext4 ${size}KiB 100% 2> "$ERR"
719 errshow "parted -s $device mkpart primary ext4 ${size}KiB 100%" || return 1
721 parted -s "$device" mkpart primary ext4 ${size}KiB ${end}KiB 2> "$ERR"
722 errshow "parted -s $device mkpart primary ext4 ${size}KiB ${end}KiB" || return 1
724 msg "Resize Complete" "\n$part has been successfully resized to $((size / 1024))M.\n" 1
726 "") msg "No Filesystem" "\nFor unformatted partitions, cfdisk can be used in the partition menu.\n" ;;
727 *) msg "Invalid Filesystem: $fs" "\nResizing only supports ext and ntfs.\n" ;;
732 ###############################################################################
733 # partition management functions
734 # these are helpers for use by other functions to do essential setup/teardown
738 local regexp="$1" err=''
739 local pts dev size isize ptcount=0
741 # string of partitions as /TYPE/PART SIZE.. eg. /dev/sda1 256G
742 if [[ $IGNORE_DEV ]]; then
743 PARTS="$(lsblk -lno TYPE,NAME,SIZE | awk "/$regexp/"' && !'"/$IGNORE_DEV/"' {sub(/^part/, "/dev/"); sub(/^lvm|^crypt/, "/dev/mapper/"); print $1$2, $3}')"
745 PARTS="$(lsblk -lno TYPE,NAME,SIZE | awk "/$regexp/"' {sub(/^part/, "/dev/"); sub(/^lvm|^crypt/, "/dev/mapper/"); print $1$2 " " $3}')"
748 # ensure we have enough partitions for the system and action were trying to do
749 COUNT=$(wc -l <<< "$PARTS")
751 while read -r dev size; do # walk partition list and skip ones that are too small
752 [[ $dev && $size ]] || continue
753 size_t="${size: -1:1}"
756 [[ $size_t == 'K' || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
760 'part|lvm|crypt') [[ $ptcount -lt 1 || ($SYS == 'UEFI' && $COUNT -lt 2) ]] && err="$_errpart" ;;
761 'part|crypt') (( ptcount < 1 )) && err="$_lvmerr" ;;
762 'part|lvm') (( ptcount < 2 )) && err="$_lukserr" ;;
766 msg "Not Enough Partitions" "$err" 2
775 if [[ $1 == "$MNT/swapfile" && $SWAP_SIZE ]]; then
776 fallocate -l $SWAP_SIZE "$1" 2> "$ERR"
777 errshow "fallocate -l $SWAP_SIZE $1"
778 chmod 600 "$1" 2> "$ERR"
779 errshow "chmod 600 $1"
781 mkswap "$1" > /dev/null 2> "$ERR"
783 swapon "$1" > /dev/null 2> "$ERR"
790 local part="$1" mountp="${MNT}$2" fs=""
791 fs="$(lsblk -lno FSTYPE "$part")"
794 if [[ $fs && ${FS_OPTS[$fs]} && $part != "$BOOT_PART" && $part != "$AUTO_ROOT_PART" ]] && select_mntopts "$fs"; then
795 mount -o "$MNT_OPTS" "$part" "$mountp" > /dev/null 2>&1
797 mount "$part" "$mountp" > /dev/null 2>&1
800 part_mountconf "$part" "$mountp" || return 1
808 local part="$1" fs="$2" delay="$3"
810 msg "Format" "\nFormatting $part as $fs\n" 0
811 mkfs.$fs ${FS_CMD_FLAGS[$fs]} "$part" > /dev/null 2> "$ERR"
812 errshow "mkfs.$fs ${FS_CMD_FLAGS[$fs]} "$part"" || return 1
819 if [[ $DEV_COUNT -eq 1 && $SYS_DEVS ]]; then
820 DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
821 elif (( DEV_COUNT > 1 )); then
823 dlg DEVICE menu "Boot Device" "\nSelect the device to use for bootloader install." $SYS_DEVS
825 dlg DEVICE menu "Select Device" "$_device" $SYS_DEVS
827 [[ $DEVICE ]] || return 1
828 elif [[ $DEV_COUNT -lt 1 && ! $1 ]]; then
829 msg "Device Error" "\nNo available devices.\n\nExiting..\n" 2
833 [[ $1 ]] && BOOT_DEV="$DEVICE"
840 BOOT_DEV="${BOOT_PART%[1-9]}"
841 BOOT_PART_NUM="${BOOT_PART: -1}"
842 [[ $BOOT_PART = /dev/nvme* ]] && BOOT_DEV="${BOOT_PART%p[1-9]}"
843 if [[ $SYS == 'UEFI' ]]; then
844 parted -s $BOOT_DEV set $BOOT_PART_NUM esp on > /dev/null 2>&1
846 parted -s $BOOT_DEV set $BOOT_PART_NUM boot on > /dev/null 2>&1
853 local part="$1" devs=""
854 devs="$(lsblk -lno NAME,FSTYPE,TYPE)"
856 # Identify if $part is LUKS+LVM, LVM+LUKS, LVM alone, or LUKS alone
857 if lsblk -lno TYPE "$part" | grep -q 'crypt'; then
859 LUKS_NAME="${part#/dev/mapper/}"
860 for dev in $(awk '/lvm/ && /crypto_LUKS/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
861 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
862 LUKS_DEV="$LUKS_DEV cryptdevice=$dev:$LUKS_NAME"
867 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
868 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
869 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
870 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
874 elif lsblk -lno TYPE "$part" | grep -q 'lvm'; then
876 VNAME="${part#/dev/mapper/}"
877 for dev in $(awk '/crypt/ && /lvm2_member/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
878 if lsblk -lno NAME "$dev" | grep -q "$VNAME"; then
879 LUKS_NAME="${dev/\/dev\/mapper\//}"
883 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
884 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
885 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
886 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
897 if (( COUNT > 0 )); then
898 PARTS="$(sed "/${pt//\//\\/}/d" <<< "$PARTS")"
906 if grep -qw "$1" /proc/mounts; then
907 msg "Mount Success" "\nPartition $1 mounted at $2\n" 1
911 msg "Mount Fail" "\nPartition $1 failed to mount at $2\n" 2
916 ###############################################################################
918 # mount_menu is the entry point which calls all other functions
919 # once finished it returns to the main menu: main()
923 msg "Mount Menu" "\nGathering device and partition information.\n" 0
924 no_bg_install || return 0
927 part_find 'part|lvm|crypt' || { SEL=2; return 1; }
928 [[ $LUKS && $LUKS_PART ]] && part_countdec $LUKS_PART
929 [[ $LVM && $LVM_PARTS ]] && part_countdec $LVM_PARTS
930 select_root_partition || { ROOT_PART=''; return 1; }
931 select_boot_partition || { BOOT_PART=''; return 1; }
932 if [[ $BOOT_PART ]]; then
933 part_mount "$BOOT_PART" "/$BOOTDIR" && SEP_BOOT=true || return 1
936 select_swap || return 1
937 select_extra_partitions || return 1
944 local pts dev size isize
946 if (( COUNT )) ; then
947 while read -r dev size; do # walk partition list and skip ones that are too small/big for swap
948 size_t="${size: -1:1}"
951 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 16) || ($size_t == 'M' && $isize -lt 100) ]] || pts+="$dev $size "
955 dlg SWAP_PART menu "Swap Setup" "\nSelect whether to use a swapfile, swap partition, or none." \
956 "none" "Don't allocate any swap space" \
957 "swapfile" "Allocate $SYS_MEM at /swapfile" \
960 if [[ -z $SWAP_PART || $SWAP_PART == "none" ]]; then
963 elif [[ $SWAP_PART == "swapfile" ]]; then
965 until [[ ${SWAP_SIZE:0:1} =~ [1-9] && ${SWAP_SIZE: -1} =~ (M|G) ]]; do
966 (( 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
967 dlg SWAP_SIZE input "Swap Setup" "$_swapsize" "$SYS_MEM" || { SWAP_PART=''; SWAP_SIZE=''; return 1; }
970 part_swap "$MNT/$SWAP_PART"
971 SWAP_PART="/$SWAP_PART"
972 elif [[ $PARTS == *"$SWAP_PART"* ]]; then
974 part_countdec $SWAP_PART
975 SWAP_SIZE="$(lsblk -lno SIZE $SWAP_PART)"
985 local fs="$1" opts=''
986 local title="${fs^} Mount Options"
988 for i in ${FS_OPTS[$fs]}; do
992 until [[ $MNT_OPTS ]]; do
993 dlg MNT_OPTS check "$title" "$_mount" $opts
994 [[ $MNT_OPTS ]] || return 1
995 MNT_OPTS="${MNT_OPTS// /,}"
996 yesno "$title" "\nConfirm the following options: $MNT_OPTS\n" || MNT_OPTS=''
1005 until [[ $EXMNT ]]; do
1006 dlg EXMNT input "Extra Mount $part" "$_exmnt" "/" || return 1
1007 if [[ ${EXMNT:0:1} != "/" || ${#EXMNT} -le 1 || $EXMNT =~ \ |\' || $EXMNTS == *"$EXMNT"* ]]; then
1008 msg "Mountpoint Error" "$_errexpart"
1012 msg "Mount Extra" "\nMounting Finished\n\n\nNo extra partitions available to mount, returning to main menu.\n" 2
1018 local part="$1" fs='' cur=''
1019 local txt="\nSelect which filesystem to use for: $part\n\nDefault: ext4"
1020 cur="$(lsblk -lno FSTYPE "$part" 2> /dev/null)"
1022 # bail early if the partition was created in part_auto()
1023 [[ $cur && $part == "$AUTO_ROOT_PART" ]] && return 0
1026 if [[ $cur && $FORMATTED == *"$part"* ]]; then
1027 dlg fs menu "Filesystem" "$txt\nCurrent: $cur" skip - ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1029 dlg fs menu "Filesystem" "$txt" ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1031 [[ $fs == 'skip' ]] && return 0
1032 yesno "Filesystem" "\nFormat $part as $fs?\n" || fs=''
1034 part_format "$part" "$fs" 0
1037 select_boot_partition()
1039 local pts dev size isize ptcount=0
1041 if [[ -z $BOOT_PART ]]; then
1042 if [[ $AUTO_BOOT_PART && -z $LVM && -z $LUKS ]]; then
1043 BOOT_PART="$AUTO_BOOT_PART"
1046 if (( COUNT )); then
1047 while read -r dev size; do # walk partition list and skip ones that are too small/big for boot
1048 size_t="${size: -1:1}"
1051 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1058 0) msg "EFI Boot Partition" "\nNo partitions available that meet size requirements!!\n\nReturning to the main menu.\n" 2; return 1 ;;
1059 1) msg "EFI Boot Partition" "\nOnly one partition available that meets size requirements.\n" 1; BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")" ;;
1060 *) dlg BOOT_PART menu "EFI Partition" "$_uefi" $pts ;;
1062 [[ $BOOT_PART ]] || return 1
1065 if [[ $LUKS && ! $LVM ]]; then
1067 0) msg "Boot Partition" "\nLUKS without LVM requires a separate boot partition.\nNo partitions available that meet size requirements!!\n\nReturning to the main menu.\n" 2; return 1 ;;
1068 1) msg "Boot Partition" "\nOnly one partition available that meets size requirements.\n" 1; BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")" ;;
1069 *) dlg BOOT_PART menu "Boot Partition" "$_biosluks" $pts ;;
1071 [[ $BOOT_PART ]] || return 1
1073 (( ptcount == 0 )) && return 0
1074 dlg BOOT_PART menu "Boot Partition" "$_bios" "skip" "no separate boot" $pts
1075 [[ -z $BOOT_PART || $BOOT_PART == "skip" ]] && { BOOT_PART=''; return 0; }
1082 if ([[ $SYS == 'BIOS' ]] && grep -q 'ext[34]' <<< "$(fsck -N "$BOOT_PART")") || ([[ $SYS == 'UEFI' ]] && grep -q 'fat' <<< "$(fsck -N "$BOOT_PART")"); then
1083 yesno "Format Boot Partition" "\nIMPORTANT:\n\nThe boot partition $BOOT_PART $_format" "Format $BOOT_PART" "Skip Formatting" 1 || return 0
1087 UEFI) part_format "$BOOT_PART" "vfat" 2 || return 1 ;;
1088 BIOS) part_format "$BOOT_PART" "ext4" 2 || return 1 ;;
1093 select_root_partition()
1095 if [[ -z $ROOT_PART ]]; then
1096 if [[ $AUTO_ROOT_PART && -z $LVM && -z $LUKS ]]; then
1097 ROOT_PART="$AUTO_ROOT_PART"
1098 msg "Mount Menu" "\nUsing partitions created during automatic format.\n" 2
1099 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1100 return 0 # we're done here
1102 local pts dev size isize ptcount=0
1104 # walk partition list and skip ones that are too small for / (root)
1105 while read -r dev size; do
1106 size_t="${size: -1:1}" # size type eg. K, M, G, T
1107 isize=${size:0:-1} # remove trailing size type character
1108 isize=${isize%.*} # remove any decimal (round down)
1109 [[ $size_t =~ [MK] || ($size_t == 'G' && $isize -lt 4) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1112 if (( ptcount == 1 )); then # only one available device
1113 msg "Root Partition (/)" "\nOnly one partition available that meets size requirements.\n" 2
1114 ROOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")"
1116 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
1121 if [[ -z $ROOT_PART ]] || ! select_filesystem "$ROOT_PART" || ! part_mount "$ROOT_PART"; then
1128 select_extra_partitions()
1132 # walk partition list and skip ones that are too small to be usable
1133 if (( COUNT )); then
1134 while read -r dev size; do
1135 [[ ${size: -1:1} =~ [KM] ]] && part_countdec "$dev"
1139 while (( COUNT > 0 )); do
1141 dlg part menu 'Mount Extra' "$_expart" 'done' 'finish mounting step' $PARTS || break
1142 if [[ $part == 'done' ]]; then
1144 elif select_filesystem "$part" && select_mountpoint && part_mount "$part" "$EXMNT"; then
1145 EXMNTS+="$part: $EXMNT "
1146 [[ $EXMNT == '/usr' && $HOOKS != *usr* ]] && HOOKS+=" usr"
1154 ###############################################################################
1156 # main is the entry point which calls all other install functions, once
1157 # complete it shows a dialog to edit files on the new system before reboot
1162 genfstab -U "$MNT" > "$MNT/etc/fstab" 2> "$ERR"
1163 errshow 1 "genfstab -U $MNT > $MNT/etc/fstab"
1164 [[ -f $MNT/swapfile ]] && sed -i "s~${MNT}~~" "$MNT/etc/fstab"
1166 # tear free configs, MUST be done after package install for nvidia
1167 [[ $TEARFREE ]] && install_tearfree_conf "$MNT/etc/X11/xorg.conf.d"
1170 chrun "hwclock --systohc --utc" || chrun "hwclock --systohc --utc --directisa"
1173 chrun "chown -Rf $NEWUSER:users /home/$NEWUSER"
1174 if [[ "$USER_CMD" ]]; then
1175 chrun "$USER_CMD" 2> "$ERR" 2>&1
1176 errshow 0 "$USER_CMD"
1180 dlg choice menu "Finalization" "$_edit" \
1181 finished "exit the installer and reboot" \
1182 keyboard "${EDIT_FILES[keyboard]}" \
1183 console "${EDIT_FILES[console]}" \
1184 locale "${EDIT_FILES[locale]}" \
1185 hostname "${EDIT_FILES[hostname]}" \
1186 sudoers "${EDIT_FILES[sudoers]}" \
1187 mkinitcpio "${EDIT_FILES[mkinitcpio]}" \
1188 fstab "${EDIT_FILES[fstab]}" \
1189 crypttab "${EDIT_FILES[crypttab]}" \
1190 bootloader "${EDIT_FILES[bootloader]}" \
1191 pacman "${EDIT_FILES[pacman]}" \
1192 login "${EDIT_FILES[login]}"
1194 if [[ -z $choice || $choice == 'finished' ]]; then
1195 [[ $DEBUG == true && -r $DBG ]] && ${EDITOR:-vim} "$DBG"
1200 for f in ${EDIT_FILES[$choice]}; do
1201 if [[ -e ${MNT}$f ]]; then
1202 ${EDITOR:-vim} "${MNT}$f"
1204 msg "File Missing" "\nThe file(s) selected do not exist:\n\n${MNT}$f\n"
1215 while kill -0 $BG_PID 2> /dev/null; do
1216 clear; printf "\nA background install process is still running...\n"; sleep 1
1222 rm -rf "$MNT/etc/mkinitcpio-archiso.conf"
1223 find "$MNT/usr/lib/initcpio" -name 'archiso*' -type f -delete
1225 # remove/disable customizations done to airootfs during building
1226 chrun "systemctl disable pacman-init.service choose-mirror.service" > /dev/null 2>&1
1227 rm -f "$MNT/etc/systemd/scripts/choose-mirror"
1228 rm -f "$MNT/etc/systemd/system/"{choose-mirror.service,etc-pacman.d-gnupg.mount,pacman-init.service}
1229 sed -i 's/#\(Storage=\)volatile/\1auto/' "$MNT/etc/systemd/journald.conf"
1230 sed -i 's/#\(HandleSuspendKey=\)ignore/\1suspend/' "$MNT/etc/systemd/logind.conf"
1231 sed -i 's/#\(HandleHibernateKey=\)ignore/\1hibernate/' "$MNT/etc/systemd/logind.conf"
1232 sed -i 's/#\(HandleLidSwitch=\)ignore/\1suspend/' "$MNT/etc/systemd/logind.conf"
1233 find "$MNT/boot" -name '*-ucode.img' -delete
1235 # changing distro name?
1236 [[ $DIST != "ArchLabs" ]] || sed -i "s/ArchLabs/$DIST/g" "$MNT/etc/"{lsb-release,os-release}
1238 # vmlinuz, if this isn't copied the standard kernel may fail mkinitcpio
1239 cp -vf "$RUN/x86_64/vmlinuz" "$MNT/boot/vmlinuz-linux" 2> "$ERR" 2>&1
1240 errshow 1 "cp -vf $RUN/x86_64/vmlinuz $MNT/boot/vmlinuz-linux"
1242 # copy network settings
1243 [[ -d /etc/netctl ]] && cp -rfv /etc/netctl "$MNT/etc/"
1244 [[ -f /etc/resolv.conf ]] && cp -fv /etc/resolv.conf "$MNT/etc/"
1245 [[ -e /etc/NetworkManager/system-connections ]] && cp -rvf /etc/NetworkManager/system-connections "$MNT/etc/NetworkManager/"
1247 echo "LANG=$MYLOCALE" > "$MNT/etc/locale.conf"
1248 cp -fv "$MNT/etc/locale.conf" "$MNT/etc/default/locale"
1249 sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${MYLOCALE}/${MYLOCALE}/g" "$MNT/etc/locale.gen"
1251 chrun "ln -svf /usr/share/zoneinfo/$ZONE/$SUBZ /etc/localtime"
1253 cat > "$MNT/etc/X11/xorg.conf.d/00-keyboard.conf" <<- EOF
1254 # Use localectl(1) to instruct systemd-localed to update it.
1255 Section "InputClass"
1256 Identifier "system-keyboard"
1257 MatchIsKeyboard "on"
1258 Option "XkbLayout" "$KEYMAP"
1262 cat > "$MNT/etc/default/keyboard" <<- EOF
1263 # KEYBOARD CONFIGURATION FILE
1264 # Consult the keyboard(5) manual page.
1271 printf "KEYMAP=%s\nFONT=%s\n" "$CMAP" "$FONT" > "$MNT/etc/vconsole.conf"
1273 echo "$MYHOST" > "$MNT/etc/hostname"
1274 cat > "$MNT/etc/hosts" <<- EOF
1277 ::1 localhost ip6-localhost ip6-loopback
1278 ff02::1 ip6-allnodes
1279 ff02::2 ip6-allrouters
1285 echo "Installing $BOOTLDR"
1287 if [[ $ROOT_PART == /dev/mapper* ]]; then
1288 ROOT_PART_ID="$ROOT_PART"
1290 local uuid_type="UUID"
1291 [[ $BOOTLDR =~ (systemd-boot|refind-efi|efistub) ]] && uuid_type="PARTUUID"
1292 ROOT_PART_ID="$uuid_type=$(blkid -s $uuid_type -o value $ROOT_PART)"
1295 if [[ $SYS == 'UEFI' ]]; then
1296 # remove our old install and generic BOOT/ dir
1297 echo "Removing conflicting boot directories"
1298 find "$MNT/$BOOTDIR/EFI/" -maxdepth 1 -mindepth 1 -iname "$DIST" -type d -delete -printf "remove %p\n"
1299 find "$MNT/$BOOTDIR/EFI/" -maxdepth 1 -mindepth 1 -iname 'BOOT' -type d -delete -printf "remove %p\n"
1303 chrun "${BCMDS[$BOOTLDR]}" 2> "$ERR" 2>&1
1304 errshow 1 "${BCMDS[$BOOTLDR]}"
1306 if [[ -d $MNT/hostrun ]]; then
1307 echo "Unmounting chroot directories"
1308 # cleanup the bind mounts we made earlier for the grub-probe module
1309 umount_dir "$MNT/hostrun/"{udev,lvm}
1310 rm -rf "$MNT/hostrun" > /dev/null 2>&1
1313 if [[ $SYS == 'UEFI' ]]; then
1314 # some UEFI firmware requires a generic esp/BOOT/BOOTX64.EFI
1315 mkdir -pv "$MNT/$BOOTDIR/EFI/BOOT"
1317 grub) cp -fv "$MNT/$BOOTDIR/EFI/$DIST/grubx64.efi" "$MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI" ;;
1318 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" ;;
1319 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"
1320 cp -fv "$MNT/$BOOTDIR/EFI/refind/refind_x64.efi" "$MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI" ;;
1329 local groups='audio,video,floppy,log,network,rfkill,scanner,storage,optical,power,wheel'
1330 [[ -e $MNT/etc/X11/xorg.conf.d/20-nvida.conf && -e $MNT/usr/bin/optirun ]] && groups+=',bumblebee'
1332 rm -f "$MNT/root/.zlogin" # remove welcome message
1334 chrun "chpasswd <<< 'root:$ROOT_PASS'" 2> "$ERR" 2>&1
1335 errshow 1 "set root password"
1336 if [[ $MYSHELL != 'zsh' ]]; then # root uses zsh by default
1337 chrun "usermod -s /bin/$MYSHELL root" 2> "$ERR" 2>&1
1338 errshow 1 "usermod -s /bin/$MYSHELL root"
1339 # copy the default mkshrc to /root if it was selected
1340 [[ $MYSHELL == 'mksh' ]] && cp -fv "$MNT/etc/skel/.mkshrc" "$MNT/root/.mkshrc"
1343 echo "Creating new user $NEWUSER and setting password"
1344 chrun "useradd -m -u 1000 -g users -G $groups -s /bin/$MYSHELL $NEWUSER" 2> "$ERR" 2>&1
1345 errshow 1 "useradd -m -u 1000 -g users -G $groups -s /bin/$MYSHELL $NEWUSER"
1346 chrun "chpasswd <<< '$NEWUSER:$USER_PASS'" 2> "$ERR" 2>&1
1347 errshow 1 "set $NEWUSER password"
1349 if [[ $INSTALL_WMS == *dwm* ]];then
1350 install_suckless "/home/$NEWUSER" chroot
1351 [[ $INSTALL_WMS == 'dwm' ]] && rm -rf "$MNT/home/$NEWUSER/.config/xfce4"
1353 [[ $INSTALL_WMS == *jwm* ]] && cp -rf "$MNT/etc/system.jwmrc" "$MNT/home/$NEWUSER/.jwmrc"
1354 [[ $INSTALL_WMS != *bspwm* && $INSTALL_WMS != *openbox* ]] && rm -rf "$MNT/home/$NEWUSER/.config/"{jgmenu,tint2}
1355 [[ $USER_PKGS != *geany* ]] && rm -rf "$MNT/home/$NEWUSER/.config/geany"
1356 [[ $MYSHELL != 'bash' ]] && rm -rf "$MNT/home/$NEWUSER/.bash"*
1357 [[ $MYSHELL != 'zsh' ]] && rm -rf "$MNT/home/$NEWUSER/.z"*
1359 # remove some commands from ~/.xprofile when using KDE or Gnome as the login session
1360 if [[ $LOGIN_WM =~ (startkde|gnome-session) || ($LOGIN_TYPE != 'xinit' && $WM_PKGS =~ (plasma|gnome)) ]]; then
1361 sed -i '/super/d; /nitrogen/d; /compton/d' "$MNT/home/$NEWUSER/.xprofile" "$MNT/root/.xprofile"
1362 elif [[ $LOGIN_WM == 'dwm' ]]; then # and dwm
1363 sed -i '/super/d; /compton/d' "$MNT/home/$NEWUSER/.xprofile" "$MNT/root/.xprofile"
1371 local serv="$MNT/etc/systemd/system/getty@tty1.service.d"
1372 echo "Setting up $LOGIN_TYPE"
1374 ly|sddm|gdm|lightdm)
1375 if [[ $LOGIN_WM == *dwm* ]]; then # dwm doesn't include an xsession file for display managers
1376 mkdir -p "$MNT/usr/share/xsessions"
1377 cat > "$MNT/usr/share/xsessions/dwm.desktop" <<- EOF
1381 Comment=Dynamic Window Manager
1386 rm -rf "$serv" "$MNT/home/$NEWUSER/.xinitrc"
1387 chrun "systemctl enable $LOGIN_TYPE.service" 2> "$ERR" 2>&1
1388 errshow 1 "systemctl enable $LOGIN_TYPE.service"
1389 ${LOGIN_TYPE}_config
1392 if [[ $INSTALL_WMS ]]; then
1393 sed -i "/exec/ c exec ${LOGIN_WM}" "$MNT/home/$NEWUSER/.xinitrc"
1394 elif [[ -e $MNT/home/$NEWUSER/.xinitrc ]]; then
1395 sed -i '/exec/d' "$MNT/home/$NEWUSER/.xinitrc"
1398 if [[ $AUTOLOGIN ]]; then
1399 sed -i "s/root/${NEWUSER}/g" $serv/autologin.conf
1400 cat > "$MNT/home/$NEWUSER/$LOGINRC" <<- EOF
1401 # automatically run startx when logging in on tty1
1402 [ \$XDG_VTNR -eq 1 ] && exec startx
1414 local inpkg="$PACKAGES $USER_PKGS $AL_BASE_PKGS "
1416 if pacman -Qq archlabs-installer > /dev/null 2>&1; then
1417 rmpkg+="archlabs-installer "
1420 if [[ $MYSHELL == 'zsh' ]]; then
1421 inpkg+="zsh-completions "
1426 if [[ $INSTALL_WMS =~ (openbox|bspwm|i3-gaps|fluxbox) ]]; then
1427 inpkg+="$WM_BASE_PKGS "
1428 elif [[ $INSTALL_WMS == 'dwm' ]]; then # dwm only needs a very limited package set
1429 inpkg+="nitrogen polkit-gnome gnome-keyring dunst "
1432 # update and install crucial packages first to avoid issues
1433 chrun "pacman -Syyu $KERNEL $BASE_PKGS base-devel ${LOGIN_PKGS[$LOGIN_TYPE]} $MYSHELL --noconfirm --needed" 2> "$ERR" 2>&1
1434 errshow 1 "pacman -Syyu $KERNEL $BASE_PKGS base-devel ${LOGIN_PKGS[$LOGIN_TYPE]} $MYSHELL --noconfirm --needed"
1436 # remove the packages we don't want on the installed system
1437 [[ $rmpkg ]] && chrun "pacman -Rnsc $rmpkg --noconfirm"
1439 # reinstalling iputils fixes the network issue for non-root users
1440 chrun "pacman -S iputils $UCODE --noconfirm"
1442 # install the packages chosen throughout the install
1443 chrun "pacman -S $inpkg --needed --noconfirm" 2> "$ERR" 2>&1
1444 errshow 1 "pacman -S $inpkg --needed --noconfirm"
1446 # bootloader packages
1447 if [[ $BOOTLDR == 'grub' ]]; then
1448 [[ $SYS == 'UEFI' ]] && local efib="efibootmgr"
1449 chrun "pacman -S os-prober grub $efib --needed --noconfirm" 2> "$ERR" 2>&1
1450 errshow 1 "pacman -S os-prober grub $efib --needed --noconfirm"
1451 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1452 chrun "pacman -S refind-efi efibootmgr --needed --noconfirm" 2> "$ERR" 2>&1
1453 errshow 1 "pacman -S refind-efi efibootmgr --needed --noconfirm"
1454 elif [[ $SYS == 'UEFI' ]]; then
1455 chrun "pacman -S efibootmgr --needed --noconfirm" 2> "$ERR" 2>&1
1456 errshow 1 "pacman -S efibootmgr --needed --noconfirm"
1459 if [[ $VM ]] && dmesg | grep -qi 'vbox'; then
1461 linux) chrun "pacman -S virtualbox-guest-utils virtualbox-guest-modules-arch --needed --noconfirm" ;;
1462 *) chrun "pacman -S virtualbox-guest-utils virtualbox-guest-modules-dkms ${KERNEL}-headers --needed --noconfirm" ;;
1466 # allow members of the wheel group to run commands as root
1467 sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" "$MNT/etc/sudoers"
1474 local dir="$1/suckless"
1476 if [[ $2 == 'chroot' ]]; then
1477 chrun "mkdir -pv '$dir'"
1478 for i in dwm dmenu st; do
1479 if chrun "git clone 'https://git.suckless.org/$i' '$dir/$i'"; then
1480 chrun "cd '$dir/$i' && make PREFIX=/usr install"
1482 printf "failed to clone %s repo\n" "$i"
1487 for i in dwm dmenu st; do
1488 if git clone "https://git.suckless.org/$i" "$dir/$i"; then
1489 cd "$dir/$i" && make PREFIX=/usr install
1491 printf "failed to clone %s repo\n" "$i"
1497 install_mkinitcpio()
1500 [[ $LUKS ]] && add="encrypt"
1501 [[ $LVM ]] && { [[ $add ]] && add+=" lvm2" || add+="lvm2"; }
1502 sed -i "s/block filesystems/block ${add} filesystems ${HOOKS}/g" "$MNT/etc/mkinitcpio.conf"
1503 chrun "mkinitcpio -p $KERNEL" 2> "$ERR" 2>&1
1504 errshow 1 "mkinitcpio -p $KERNEL"
1507 install_mirrorlist()
1509 if hash reflector > /dev/null 2>&1; then
1510 reflector --verbose --score 80 -l 40 -f 5 --sort rate --save "$1"
1511 elif hash rankmirrors > /dev/null 2>&1; then
1512 echo "Sorting mirrorlist"
1513 local key="access_key=5f29642060ab983b31fdf4c2935d8c56"
1514 ip_add="$(curl -fsSL "http://api.ipstack.com/check&?$key&fields=ip" | python -c "import sys, json; print(json.load(sys.stdin)['ip'])")"
1515 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'])")"
1516 if [[ "$country" ]]; then
1517 if [[ $country =~ (CA|US) ]]; then
1518 # use both CA and US mirrors for CA or US countries
1519 mirror="https://www.archlinux.org/mirrorlist/?country=US&country=CA&use_mirror_status=on"
1520 elif [[ $country =~ (AU|NZ) ]]; then
1521 # use both AU and NZ mirrors for AU or NZ countries
1522 mirror="https://www.archlinux.org/mirrorlist/?country=AU&country=NZ&use_mirror_status=on"
1524 mirror="https://www.archlinux.org/mirrorlist/?country=${country}&use_mirror_status=on"
1526 else # no country code so just grab all mirrors, will be a very slow sort but we don't have other options
1527 mirror="https://www.archlinux.org/mirrorlist/?country=all&use_mirror_status=on"
1529 curl -fsSL "$mirror" | sed -e 's/^#Server/Server/' -e '/^#/d' | rankmirrors -n 6 - > "$1"
1533 install_background()
1535 ( rsync -a /run/archiso/sfs/airootfs/ "$MNT/" && install_mirrorlist "$MNT/etc/pacman.d/mirrorlist" > /dev/null 2>&1 ) &
1537 trap "kill $BG_PID 2> /dev/null" EXIT
1540 install_tearfree_conf()
1545 echo "Virtual machine detected, removing xorg configs"
1546 find "$xpath/" -name '*.conf' -delete -printf "remove %p\n"
1547 elif lspci | grep ' VGA ' | grep -q 'Intel'; then
1548 echo "Creating Intel Tear Free config /etc/X11/xorg.conf.d/20-intel.conf"
1549 cat > "$xpath/20-intel.conf" <<- EOF
1551 Identifier "Intel Graphics"
1553 Option "TearFree" "true"
1556 cat "$xpath/20-intel.conf"
1557 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
1558 echo "Creating AMD Tear Free config /etc/X11/xorg.conf.d/20-amdgpu.conf"
1559 cat > "$xpath/20-amdgpu.conf" <<- EOF
1561 Identifier "AMD Graphics"
1563 Option "TearFree" "true"
1566 cat "$xpath/20-amdgpu.conf"
1567 elif lspci | grep ' VGA ' | grep -q 'AMD/ATI.*HD [2-6][0-9]*'; then # older HD 2xxx-6xxx cards must use the radeon driver
1568 echo "Creating Radeon Tear Free config /etc/X11/xorg.conf.d/20-radeon.conf"
1569 cat > "$xpath/20-radeon.conf" <<- EOF
1571 Identifier "AMD Graphics"
1573 Option "TearFree" "on"
1576 cat "$xpath/20-radeon.conf"
1577 elif lspci | grep ' VGA ' | grep -q 'NVIDIA'; then # nvidia cards require a bit of checking for notebook gpus
1578 echo "Trying nvidia driver install"
1579 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
1580 if [[ $xpath == *"$MNT"* ]]; then
1581 chrun "nvidia-installer --bumblebee"
1583 nvidia-installer --bumblebee
1586 if [[ $xpath == *"$MNT"* ]]; then
1587 chrun "nvidia-installer" # unsure which card so try auto detection
1592 if [[ -e $xpath/20-nvidia.conf ]]; then
1593 cat "$xpath/20-radeon.conf"
1595 echo "NVIDIA driver installed"
1596 if [[ $xpath == *"$MNT"* ]]; then
1597 echo "Trying to load the driver for live session"
1600 echo "To enable driver vsync:"
1601 echo -e "\trun nvidia-settings (as root) on first boot\n\tenable 'ForceFullCompositionPipeline' under the advanced settings"
1602 echo -e "\tlastly save the change to your nvida xorg config /etc/X11/xorg.conf.d/20-nvidia.conf"
1603 echo -e "\tand remove everything but the Device and Screen sections from the file"
1605 echo "Unable to install nvidia driver"
1610 if lspci | grep ' VGA ' | grep -q 'Intel\|AMD/ATI'; then
1611 if [[ $xpath == *"$MNT"* ]]; then
1612 sed -i 's/xrender/glx/g' "$MNT/etc/skel/.config/compton.conf"
1614 sed -i 's/xrender/glx/g' /etc/skel/.config/compton.conf
1618 # remove nvidia installer from installed system when not running nvidia gpu
1619 [[ $xpath == *"$MNT"* ]] && rm -rf "$MNT/usr/bin/nvidia-installer" "$MNT/var/lib/nvidia-installer"
1622 ###############################################################################
1623 # display manager config
1624 # these are called based on which DM is chosen after it is installed
1625 # additional config can be handled here, for now only lightdm has one
1644 cat > "$MNT/etc/lightdm/lightdm-gtk-greeter.conf" <<- EOF
1646 default-user-image=/usr/share/icons/ArchLabs-Dark/64x64/places/distributor-logo-archlabs.png
1647 background=/usr/share/backgrounds/archlabs/archlabs.jpg
1648 theme-name=Adwaita-dark
1649 icon-theme-name=Adwaita
1650 font-name=DejaVu Sans Mono 11
1651 position=30%,end 50%,end
1655 ###############################################################################
1657 # prerun_* set up the configs needed before actually running the commands
1658 # setup_* are run after selecting a bootloader and build the command used later
1659 # they can also be used for further user input as these run before control is taken away
1663 EDIT_FILES[bootloader]="/etc/default/grub"
1665 if [[ $SYS == 'BIOS' ]]; then
1666 [[ $BOOT_DEV ]] || { part_device 1 || return 1; }
1667 BCMDS[grub]="grub-install --recheck --force --target=i386-pc $BOOT_DEV"
1669 BCMDS[grub]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1670 grub-install --recheck --force --target=x86_64-efi --efi-directory=/$BOOTDIR --bootloader-id=$DIST"
1671 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1674 BCMDS[grub]="mkdir -p /run/udev /run/lvm &&
1675 mount --bind /hostrun/udev /run/udev &&
1676 mount --bind /hostrun/lvm /run/lvm &&
1678 grub-mkconfig -o /boot/grub/grub.cfg &&
1679 sleep 1 && umount /run/udev /run/lvm"
1686 sed -i "s/GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR=\"${DIST}\"/g; s/GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"\"/g" "$MNT/etc/default/grub"
1688 if [[ $LUKS_DEV ]]; then
1689 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
1690 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"
1693 if [[ $SYS == 'BIOS' && $LVM && -z $SEP_BOOT ]]; then
1694 sed -i "s/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g" "$MNT/etc/default/grub" 2> "$ERR" 2>&1
1695 errshow 1 "sed -i 's/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g' $MNT/etc/default/grub"
1698 # setup for os-prober module
1699 mkdir -p /run/{lvm,udev} "$MNT/hostrun/"{lvm,udev}
1700 mount --bind /run/lvm "$MNT/hostrun/lvm"
1701 mount --bind /run/udev "$MNT/hostrun/udev"
1708 EDIT_FILES[bootloader]=""
1713 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1714 efibootmgr -v -d $BOOT_DEV -p $BOOT_PART_NUM -c -L '${DIST} Linux' -l /vmlinuz-${KERNEL} \
1715 -u 'root=$ROOT_PART_ID rw $([[ $UCODE ]] && printf 'initrd=\%s.img ' "$UCODE")initrd=\initramfs-${KERNEL}.img'"
1720 if [[ $SYS == 'BIOS' ]]; then
1721 EDIT_FILES[bootloader]="/boot/syslinux/syslinux.cfg"
1723 EDIT_FILES[bootloader]="/boot/EFI/syslinux/syslinux.cfg"
1724 BCMDS[syslinux]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1725 efibootmgr -v -c -d $BOOT_DEV -p $BOOT_PART_NUM -l /EFI/syslinux/syslinux.efi -L $DIST"
1731 local c="$MNT/boot/syslinux"
1732 local s="/usr/lib/syslinux/bios"
1734 if [[ $SYS == 'UEFI' ]]; then
1735 c="$MNT/boot/EFI/syslinux"
1736 s="/usr/lib/syslinux/efi64"
1739 mkdir -pv "$c" 2> "$ERR" 2>&1
1740 errshow 1 "mkdir -pv $c"
1741 cp -rfv "$s/"* "$c/" 2> "$ERR" 2>&1
1742 errshow 1 "cp -rfv $s/* $c/"
1743 cp -fv "$RUN/syslinux/splash.png" "$c/" 2> "$ERR" 2>&1
1744 errshow 0 "cp -fv $RUN/syslinux/splash.png $c/"
1745 cat > "$c/syslinux.cfg" <<- EOF
1747 MENU TITLE $DIST Boot Menu
1748 MENU BACKGROUND splash.png
1752 # see: https://www.syslinux.org/wiki/index.php/Comboot/menu.c32
1761 MENU HELPMSGENDROW 29
1762 MENU COLOR border 30;44 #40ffffff #a0000000 std
1763 MENU COLOR title 1;36;44 #9033ccff #a0000000 std
1764 MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
1765 MENU COLOR unsel 37;44 #50ffffff #a0000000 std
1766 MENU COLOR help 37;40 #c0ffffff #a0000000 std
1767 MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
1768 MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
1769 MENU COLOR msg07 37;40 #90ffffff #a0000000 std
1770 MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
1773 MENU LABEL $DIST Linux
1774 LINUX $d/vmlinuz-$KERNEL
1775 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1776 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL.img
1778 LABEL ${DIST}fallback
1779 MENU LABEL $DIST Linux Fallback
1780 LINUX $d/vmlinuz-$KERNEL
1781 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1782 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL-fallback.img
1789 EDIT_FILES[bootloader]="/boot/refind_linux.conf"
1790 BCMDS[refind-efi]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1; refind-install"
1795 cat > "$MNT/boot/refind_linux.conf" <<- EOF
1796 "$DIST Linux" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1797 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1798 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL.img"
1799 "$DIST Linux Fallback" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1800 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1801 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL-fallback.img"
1803 mkdir -p "$MNT/etc/pacman.d/hooks"
1804 cat > "$MNT/etc/pacman.d/hooks/refind.hook" <<- EOF
1811 Description = Updating rEFInd on ESP
1812 When = PostTransaction
1813 Exec = /usr/bin/refind-install
1817 setup_systemd-boot()
1819 EDIT_FILES[bootloader]="/boot/loader/entries/$DIST.conf"
1820 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1; bootctl --path=/boot install"
1823 prerun_systemd-boot()
1825 mkdir -p "$MNT/boot/loader/entries"
1826 cat > "$MNT/boot/loader/loader.conf" <<- EOF
1831 cat > "$MNT/boot/loader/entries/$DIST.conf" <<- EOF
1833 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1834 initrd /initramfs-$KERNEL.img
1835 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1837 cat > "$MNT/boot/loader/entries/$DIST-fallback.conf" <<- EOF
1838 title $DIST Linux Fallback
1839 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1840 initrd /initramfs-$KERNEL-fallback.img
1841 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1843 mkdir -p "$MNT/etc/pacman.d/hooks"
1844 cat > "$MNT/etc/pacman.d/hooks/systemd-boot.hook" <<- EOF
1851 Description = Updating systemd-boot
1852 When = PostTransaction
1853 Exec = /usr/bin/bootctl update
1855 systemd-machine-id-setup --root="$MNT"
1859 ###############################################################################
1864 no_bg_install || return 1
1868 dlg choice menu "Logical Volume Management" "$_lvmmenu" \
1869 "$_lvmnew" "vgcreate -f, lvcreate -L -n" \
1870 "$_lvmdel" "vgremove -f" \
1871 "$_lvmdelall" "lvrmeove, vgremove, pvremove -f" \
1872 "Back" "Return to the main menu"
1874 "$_lvmnew") lvm_create && break ;;
1875 "$_lvmdel") lvm_delgroup && yesno "$_lvmdel" "$_lvmdelask" && vgremove -f "$DEL_VG" > /dev/null 2>&1 ;;
1876 "$_lvmdelall") lvm_del_all ;;
1886 if [[ $(vgs -o vg_name --noheading 2> /dev/null) ]]; then
1887 if [[ $(lvs -o vg_name,lv_name --noheading --separator - 2> /dev/null) && $(pvs -o pv_name --noheading 2> /dev/null) ]]; then
1888 msg "LVM Setup" "\nActivating existing logical volume management.\n" 0
1889 modprobe dm-mod > /dev/null 2> "$ERR"
1890 errshow 'modprobe dm-mod'
1891 vgscan > /dev/null 2>&1
1892 vgchange -ay > /dev/null 2>&1
1899 VGROUP='' LVM_PARTS='' VGROUP_MB=0
1901 lvm_mkgroup || return 1
1902 local txt="\nThe last (or only) logical volume will automatically use all remaining space in the volume group."
1903 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 -
1904 [[ $VOL_COUNT ]] || return 1
1905 lvm_extra_lvs || return 1
1906 lvm_volume_name "$_lvmlvname\nNOTE: This LV will use up all remaining space in the volume group (${VGROUP_MB}MB)" || return 1
1907 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating volume $VNAME from remaining space in $VGROUP\n" 0
1908 lvcreate -l +100%FREE "$VGROUP" -n "$VNAME" > /dev/null 2> "$ERR"
1909 errshow "lvcreate -l +100%FREE $VGROUP -n $VNAME" || return 1
1910 LVM='logical volume'; sleep 0.5
1911 txt="\nDone, volume: $VGROUP-$VNAME (${VOLUME_SIZE:-${VGROUP_MB}MB}) has been created.\n"
1912 msg "$_lvmnew (LV:$VOL_COUNT)" "$txt\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE $LVM_PARTS)\n"
1918 local txt="${VGROUP}: ${SIZE}$SIZE_UNIT (${VGROUP_MB}MB remaining).$_lvmlvsize"
1922 dlg VOLUME_SIZE input "$_lvmnew (LV:$VOL_COUNT)" "$txt" ''
1923 if [[ -z $VOLUME_SIZE ]]; then
1925 break # allow bailing with escape or an empty choice
1926 elif (( ${VOLUME_SIZE:0:1} == 0 )); then
1927 ERR_SIZE=1 # size values can't begin with '0'
1929 # walk the string and make sure all but the last char are digits
1930 local lv=$((${#VOLUME_SIZE} - 1))
1931 for (( i=0; i<lv; i++ )); do
1932 [[ ${VOLUME_SIZE:$i:1} =~ [0-9] ]] || { ERR_SIZE=1; break; }
1934 if (( ERR_SIZE != 1 )); then
1935 case ${VOLUME_SIZE:$lv:1} in
1936 [mMgG]) local s=${VOLUME_SIZE:0:$lv} m=$((s * 1000))
1937 case ${VOLUME_SIZE:$lv:1} in
1938 [Gg]) (( m >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - m)) ;;
1939 [Mm]) (( ${VOLUME_SIZE:0:$lv} >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - s)) ;;
1946 if (( ERR_SIZE )); then
1947 msg "Invalid Logical Volume Size" "$_lvmerrlvsize"
1960 until [[ $named ]]; do
1961 lvm_partitions || return 1
1962 lvm_group_name || return 1
1963 yesno "$_lvmnew" "\nCreate volume group: $VGROUP\n\nusing these partition(s): $LVM_PARTS\n" && named=true
1966 msg "$_lvmnew" "\nCreating volume group: $VGROUP\n" 0
1967 vgcreate -f "$VGROUP" $LVM_PARTS > /dev/null 2> "$ERR"
1968 errshow "vgcreate -f $VGROUP $LVM_PARTS" || return 1
1970 SIZE=$(vgdisplay "$VGROUP" | awk '/VG Size/ { gsub(/[^0-9.]/, ""); print int($0) }')
1971 SIZE_UNIT="$(vgdisplay "$VGROUP" | awk '/VG Size/ { print substr($NF, 0, 1) }')"
1973 if [[ $SIZE_UNIT == 'G' ]]; then
1974 VGROUP_MB=$((SIZE * 1000))
1979 msg "$_lvmnew" "\nVolume group $VGROUP (${SIZE}$SIZE_UNIT) successfully created\n"
1985 pv="$(pvs -o pv_name --noheading 2> /dev/null)"
1986 v="$(lvs -o vg_name,lv_name --noheading --separator - 2> /dev/null)"
1987 VGROUP="$(vgs -o vg_name --noheading 2> /dev/null)"
1989 if [[ $VGROUP || $v || $pv ]]; then
1990 if yesno "$_lvmdelall" "$_lvmdelask"; then
1991 for i in $v; do lvremove -f "/dev/mapper/$i" > /dev/null 2>&1; done
1992 for i in $VGROUP; do vgremove -f "$i" > /dev/null 2>&1; done
1993 for i in $pv; do pvremove -f "$i" > /dev/null 2>&1; done
1997 msg "Delete LVM" "\nNo LVMs to remove...\n" 2
2007 for i in $(lvs --noheadings | awk '{print $2}' | uniq); do
2008 VOL_GROUP_LIST+="$i $(vgdisplay "$i" | awk '/VG Size/ {print $3$4}') "
2011 [[ $VOL_GROUP_LIST ]] || { msg "No Groups" "\nNo volume groups found."; return 1; }
2013 dlg DEL_VG menu "Logical Volume Management" "\nSelect volume group to delete.\n\nAll logical volumes within will also be deleted." $VOL_GROUP_LIST
2019 while (( VOL_COUNT > 1 )); do
2020 lvm_volume_name "$_lvmlvname" && lvm_lv_size || return 1
2021 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating a $VOLUME_SIZE volume $VNAME in $VGROUP\n" 0
2022 lvcreate -L "$VOLUME_SIZE" "$VGROUP" -n "$VNAME" > /dev/null 2> "$ERR"
2023 errshow "lvcreate -L $VOLUME_SIZE $VGROUP -n $VNAME" || return 1
2024 msg "$_lvmnew (LV:$VOL_COUNT)" "\nDone, logical volume (LV) $VNAME ($VOLUME_SIZE) has been created.\n"
2032 part_find 'part|crypt' || return 1
2033 PARTS="$(awk 'NF > 0 {print $0 " off"}' <<< "$PARTS")"
2034 dlg LVM_PARTS check "$_lvmnew" "\nSelect the partition(s) to use for the physical volume (PV)." $PARTS
2041 until [[ $VGROUP ]]; do
2042 dlg VGROUP input "$_lvmnew" "$_lvmvgname" "lvgroup"
2043 if [[ -z $VGROUP ]]; then
2045 elif [[ ${VGROUP:0:1} == "/" || $VGROUP =~ \ |\' ]] || vgdisplay | grep -q "$VGROUP"; then
2046 msg "LVM Name Error" "$_lvmerrvgname"
2056 local txt="$1" default="mainvolume"
2057 (( VOL_COUNT > 1 )) && default="extvolume$VOL_COUNT"
2058 until [[ $VNAME ]]; do
2059 dlg VNAME input "$_lvmnew (LV:$VOL_COUNT)" "\n$txt" "$default"
2060 if [[ -z $VNAME ]]; then
2062 elif [[ ${VNAME:0:1} == "/" || $VNAME =~ \ |\' ]] || lsblk | grep -q "$VNAME"; then
2063 msg "LVM Name Error" "$_lvmerlvname"
2070 ###############################################################################
2076 no_bg_install || return 1
2077 dlg choice menu "LUKS Encryption" "$_luksmenu" \
2078 "$_luksnew" "cryptsetup -q luksFormat" \
2079 "$_luksopen" "cryptsetup open --type luks" \
2080 "$_luksadv" "cryptsetup -q -s -c luksFormat" \
2081 "Back" "Return to the main menu"
2084 "$_luksnew") luks_basic || return 1 ;;
2085 "$_luksopen") luks_open || return 1 ;;
2086 "$_luksadv") luks_advanced || return 1 ;;
2094 modprobe -a dm-mod dm_crypt > /dev/null 2>&1
2096 part_find 'part|crypt|lvm' || return 1
2098 if (( COUNT == 1 )); then
2099 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2101 dlg LUKS_PART menu "$_luksopen" "\nSelect which partition to open." $PARTS
2104 [[ $LUKS_PART ]] || return 1
2106 luks_pass "$_luksopen" || return 1
2107 msg "$_luksopen" "\nOpening encrypted partition: $LUKS_NAME\n\nUsing device/volume: $LUKS_PART\n" 0
2108 cryptsetup open --type luks "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> "$ERR"
2109 errshow "cryptsetup open --type luks $LUKS_PART $LUKS_NAME" || return 1
2110 LUKS='encrypted'; luks_show
2118 typeset -a ans=(cryptroot) # default name to start
2120 until [[ $LUKS_PASS ]]; do
2122 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " --mixedform "$_luksomenu" 0 0 0 \
2123 "Name:" 1 1 "${ans[0]}" 1 7 "$COLUMNS" 0 0 \
2124 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
2125 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 2> "$ANS" || return 1
2127 mapfile -t ans <"$ANS"
2129 if [[ -z "${ans[0]}" ]]; then
2130 msg "Name Empty" "\nEncrypted device name cannot be empty.\n\nPlease try again.\n" 2
2131 elif [[ -z "${ans[1]}" || "${ans[1]}" != "${ans[2]}" ]]; then
2132 LUKS_NAME="${ans[0]}"
2133 msg "Password Mismatch" "\nThe passwords entered do not match.\n\nPlease try again.\n" 2
2135 LUKS_NAME="${ans[0]}"
2136 LUKS_PASS="${ans[1]}"
2146 msg "$_luksnew" "\nEncrypted partition ready for mounting.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$LUKS_PART")\n\n"
2151 modprobe -a dm-mod dm_crypt > /dev/null 2>&1
2153 part_find 'part|lvm' || return 1
2155 if [[ $AUTO_ROOT_PART ]]; then
2156 LUKS_PART="$AUTO_ROOT_PART"
2157 elif (( COUNT == 1 )); then
2158 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2160 dlg LUKS_PART menu "$_luksnew" "\nSelect the partition you want to encrypt." $PARTS
2163 [[ $LUKS_PART ]] || return 1
2164 luks_pass "$_luksnew"
2169 luks_setup || return 1
2170 msg "$_luksnew" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2171 cryptsetup -q luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2> "$ERR"
2172 errshow "cryptsetup -q luksFormat $LUKS_PART" || return 1
2173 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> "$ERR"
2174 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2175 LUKS='encrypted'; luks_show
2183 dlg cipher input "LUKS Encryption" "$_lukskey" "-s 512 -c aes-xts-plain64"
2184 [[ $cipher ]] || return 1
2185 msg "$_luksadv" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2186 cryptsetup -q $cipher luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2> "$ERR"
2187 errshow "cryptsetup -q $cipher luksFormat $LUKS_PART" || return 1
2188 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> "$ERR"
2189 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2196 ###############################################################################
2198 # some help avoid repetition and improve usability of some commands
2199 # others are initial setup functions used before reaching the main loop
2203 [[ "$2" == *"$1"* ]] && printf "on" || printf "off"
2208 # cleanup and exit the installer cleanly with exit code $1
2209 local e="$1" # when e is 127 unmount /run/archiso/bootmnt and reboot
2213 if [[ -d $MNT ]]; then
2215 (( e == 127 )) && umount_dir /run/archiso/bootmnt && sleep 0.5 && reboot -f
2222 local var="$1" # assign output from dialog to var
2223 local dlg_t="$2" # dialog type (menu, check, input)
2224 local title="$3" # dialog title
2225 local body="$4" # dialog message
2226 local n=0 # number of items to display for menu and check dialogs
2228 shift 4 # shift off args assigned above
2230 # adjust n when passed a large list
2231 local l=$((LINES - 20))
2232 (( ($# / 2) > l )) && n=$l
2236 menu) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --menu "$body" 0 0 $n "$@" 2> "$ANS" || return 1 ;;
2237 check) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --checklist "$body" 0 0 $n "$@" 2> "$ANS" || return 1 ;;
2240 local def="$1" # assign default value for input
2242 if [[ $1 == 'limit' ]]; then
2243 dialog --backtitle "$DIST Installer - $SYS - v$VER" --max-input 63 --title " $title " --inputbox "$body" 0 0 "$def" 2> "$ANS" || return 1
2245 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --inputbox "$body" 0 0 "$def" 2> "$ANS" || return 1
2249 # if answer file isn't empty read from it into $var
2250 [[ -s "$ANS" ]] && printf -v "$var" "%s" "$(< "$ANS")"
2255 # displays a message dialog
2256 # when more than 2 args the message will disappear after sleep time ($3)
2262 dialog --backtitle "$DIST Installer - $SYS - v$VER" --sleep "$1" --title " $title " --infobox "$body\n" 0 0
2264 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --msgbox "$body\n" 0 0
2272 if ! select_keymap; then
2275 elif ! net_connect; then
2276 msg "Not Connected" "\nRunning live requires an active internet connection to install packages.\n\nExiting..\n" 2
2278 elif (( $(awk '/MemTotal/ {print int($2 / 1024)}' /proc/meminfo) < 2500)); then
2279 msg "Not Enough Memory" "\nLive session requires at least 2.5G of system memory for installing packages.\n\nExiting..\n" 2
2284 echo "Sorting mirrorlist"
2285 mount /run/archiso/cowspace -o remount,size=2G
2286 install_mirrorlist "/etc/pacman.d/mirrorlist"
2287 pacman -Syyu --noconfirm || die 1
2288 rm -rf /var/cache/pacman/pkg/*
2289 pacman -S $BASE_PKGS $AL_BASE_PKGS xorg-xinit --needed --noconfirm || die 1
2290 rm -rf /var/cache/pacman/pkg/*
2292 i3-gaps|openbox|fluxbox|bspwm|awesome|xfce4|jwm) pacman -S "$ses" $WM_BASE_PKGS ${WM_EXT[$ses]} --needed --noconfirm || die 1 ;;
2293 gnome|plasma|cinnamon) pacman -S "$ses" ${WM_EXT[$ses]} --needed --noconfirm || die 1 ;;
2294 dwm) { pacman -S git --needed --noconfirm || die 1; }; install_suckless "/root" nochroot ;;
2296 rm -rf /var/cache/pacman/pkg/*
2297 [[ $VM ]] && dmesg | grep -qi 'vbox' && pacman -S virtualbox-guest-utils virtualbox-guest-modules-arch --needed --noconfirm
2298 pacman -Scc --noconfirm
2299 rm -rf /var/cache/pacman/pkg/*
2300 cp -rfT /etc/skel /root
2301 [[ $TEARFREE ]] && install_tearfree_conf "/etc/X11/xorg.conf.d"
2303 plasma|gnome|cinnamon) sed -i '/super/d; /nitrogen/d; /compton/d' /root/.xprofile ;;
2304 dwm) sed -i '/super/d; /compton/d' /root/.xprofile ;;
2307 echo -e "pulseaudio &\n(sleep 1; pamixer --unmute --set-volume 50) &" >> /root/.xprofile
2308 sed -i "/exec/ c exec ${WM_SESSIONS[$ses]}" /root/.xinitrc
2309 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]}"
2316 usage: $1 [-hdl] [session]
2319 -h, --help print this message and exit
2320 -l, --live install and setup a live session
2321 -d, --debug enable xtrace and log output to $DBG
2322 -t, --tearfree install and setup drivers for nvidia or tearfree xorg configs for other vendors
2323 if you experience boot issues with this option you can remove
2324 /etc/X11/xorg.conf.d/20-*.conf
2327 i3-gaps - A fork of i3wm with more features including gaps
2328 openbox - A lightweight, powerful, and highly configurable stacking wm
2329 dwm - A dynamic WM for X that manages windows in tiled, floating, or monocle layouts
2330 awesome - A customized Awesome WM session created by @elanapan
2331 bspwm - A tiling wm that represents windows as the leaves of a binary tree
2332 fluxbox - A lightweight and highly-configurable window manager
2333 gnome - A desktop environment that aims to be simple and easy to use
2334 cinnamon - A desktop environment combining traditional desktop with modern effects
2335 plasma - A kde software project currently comprising a full desktop environment
2336 xfce4 - A lightweight and modular desktop environment based on gtk+2/3
2340 set the DIST environment variable before launching the installer eg.
2344 root/boot partition:
2346 set the ROOT_PART and/or BOOT_PART environment variables before launching the installer eg.
2348 ROOT_PART='/dev/sda2' BOOT_PART='/dev/sda1' $1
2352 set the EDITOR environment variable before launching the installer eg.
2362 local title="$1" body="$2" yes='Yes' no='No'
2363 (( $# >= 3 )) && yes="$3"
2364 (( $# >= 4 )) && no="$4"
2366 if (( $# == 5 )); then
2367 dialog --backtitle "$DIST Installer - $SYS - v$VER" --defaultno --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2369 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2375 arch-chroot "$MNT" bash -c "$1"
2380 export PS4='| ${BASH_SOURCE} LINE:${LINENO} FUNC:${FUNCNAME[0]:+ ${FUNCNAME[0]}()} |> '
2390 "\e]P0191919" # #191919
2391 "\e]P1D15355" # #D15355
2392 "\e]P2609960" # #609960
2393 "\e]P3FFCC66" # #FFCC66
2394 "\e]P4255A9B" # #255A9B
2395 "\e]P5AF86C8" # #AF86C8
2396 "\e]P62EC8D3" # #2EC8D3
2397 "\e]P7949494" # #949494
2398 "\e]P8191919" # #191919
2399 "\e]P9D15355" # #D15355
2400 "\e]PA609960" # #609960
2401 "\e]PBFF9157" # #FF9157
2402 "\e]PC4E88CF" # #4E88CF
2403 "\e]PDAF86C8" # #AF86C8
2404 "\e]PE2ec8d3" # #2ec8d3
2405 "\e]PFE1E1E1" # #E1E1E1
2408 [[ $TERM == 'linux' ]] && printf "%b" "${colors[@]}" && clear
2413 [ $? -eq 0 ] && return 0
2415 local fatal=0 err=""
2416 err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
2417 [[ -z $err ]] && err="no error message was found"
2419 (( $1 == 1 )) && { fatal=1; shift; }
2421 local txt="\nCommand: $1\n\n\n\nError: $err\n\n"
2423 if (( fatal )); then
2424 msg "Install Error" "${txt}Errors at this stage are fatal, the install cannot continue.\n"
2425 [[ -r $DBG && $TERM == 'linux' ]] && less "$DBG"
2429 msg "Install Error" "${txt}Errors at this stage are non-fatal and may be fixed or ignored depending on the error.\n"
2437 if (( $1 >= 0 )) && ! grep -qw "$MNT" /proc/mounts; then
2438 msg "Not Mounted" "\nPartition(s) must be mounted first.\n" 2
2440 elif [[ $1 -ge 1 && -z $BOOTLDR ]]; then
2441 msg "No Bootloader" "\nBootloader must be selected first.\n" 2
2443 elif [[ $1 -ge 2 && (-z $NEWUSER || -z $USER_PASS) ]]; then
2444 msg "No User" "\nA user must be created first.\n" 2
2446 elif [[ $1 -ge 3 && -z $CONFIG_DONE ]]; then
2447 msg "Not Configured" "\nSystem configuration must be done first.\n" 2
2450 (( i )) # return code
2455 mount | grep -q 'swap' && swapoff -a
2457 if [[ -d $dir ]] && mount | grep -q "on $dir "; then
2458 if ! umount "$dir" 2> /dev/null; then
2460 umount -f "$dir" 2> /dev/null || umount -l "$dir"
2468 msg "Network Connect" "\nVerifying network connection\n" 0
2469 curl -sIN --connect-timeout 5 'https://www.archlinux.org/' | sed '1q' | grep -q '200'
2474 if chk_connect; then
2476 elif hash nmtui > /dev/null 2>&1; then
2478 if [[ $TERM == 'linux' ]]; then
2479 printf "%b" "\e]P1191919" "\e]P4191919"
2481 printf "%b" "\e]P1D15355" "\e]P4255a9b"
2486 elif hash wifi-menu > /dev/null 2>&1; then
2496 [[ $BG_PID ]] || return 0
2497 msg "Install Running" "\nA background install process is currently running.\n" 2
2503 IGNORE_DEV="$(lsblk -lno NAME,MOUNTPOINT | awk '/\/run\/archiso\/bootmnt/ {sub(/[1-9]/, ""); print $1}')"
2505 if [[ $IGNORE_DEV ]]; then
2506 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ && !'"/$IGNORE_DEV/"' {print "/dev/" $1 " " $2}')"
2508 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ {print "/dev/" $1 " " $2}')"
2511 if [[ -z $SYS_DEVS ]]; then
2512 msg "Device Error" "\nNo available devices...\n\nExiting..\n" 2
2517 while read -r line; do
2519 done <<< "$SYS_DEVS"
2526 # amd-ucode is not needed it's provided by linux-firmware
2527 # elif grep -q 'AuthenticAMD' /proc/cpuinfo; then
2529 elif grep -q 'GenuineIntel' /proc/cpuinfo; then
2533 modprobe -q efivarfs > /dev/null 2>&1
2535 if [[ -d /sys/firmware/efi/efivars ]]; then
2537 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars
2543 ###############################################################################
2546 # enable some nicer colours in the linux console
2549 if (( UID != 0 )); then
2550 msg "Not Root" "\nThis installer must be run as root or using sudo.\n\nExiting..\n" 2
2552 elif ! grep -qwm 1 'lm' /proc/cpuinfo; then
2553 msg "Not x86_64 Architecture" "\nThis installer only supports x86_64 architectures.\n\nExiting..\n" 2
2557 # trap ^C to perform cleanup
2558 trap 'printf "\n^C\n" && die 1' INT
2560 while getopts ":htl:d" OPT; do
2566 if [[ "${!WM_SESSIONS[@]}" =~ $OPTARG ]]; then
2569 echo "error: invalid session for -l, see -h for help"; die 1
2572 \?) echo "error: invalid option: -$OPTARG"; die 1 ;;
2579 msg "Welcome to the $DIST Installer" "$_welcome"
2581 if ! select_keymap; then
2583 elif ! net_connect; then
2584 msg "Not Connected" "\nThis installer requires an active internet connection.\n\nExiting..\n" 2
2591 # vim:fdm=marker:fmr={,}