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 FONT=ter-i16n # font used for the linux console
19 HOOKS=shutdown # additional mkinitcpio HOOKS
20 SEL=0 # currently selected menu item
21 SYS=Unknown # bios type, to be determined: UEFI/BIOS
22 ERR=/tmp/errlog # stderr log used internally by errshow()
23 DBG=/tmp/debuglog # debug log file when passed -d
24 RUN=/run/archiso/bootmnt/arch/boot # path for live system /boot
25 VM="$(dmesg | grep -i hypervisor)" # system running in a virtual machine
26 EXMNTS="" # extra partitions that were mounted, used to verify mountpoint and show user
27 FORMATTED="" # partitions that have been formatted, allows skipping the format step
28 USER_CMD="" # optional command(s) entered by the user to run in the chroot
29 export DIALOGOPTS="--cr-wrap" # dialog environment variable to hold default options, see `man dialog`
31 BASE_PKGS="base xorg xorg-drivers sudo git gvfs gtk3 libmad libmatroska tumbler "
32 BASE_PKGS+="playerctl pulseaudio pulseaudio-alsa pavucontrol pamixer scrot xdg-user-dirs "
33 BASE_PKGS+="ffmpeg gstreamer gst-libav gst-plugins-base gst-plugins-good bash-completion xterm"
35 AL_BASE_PKGS="archlabs-keyring archlabs-icons archlabs-fonts archlabs-themes "
36 AL_BASE_PKGS+="archlabs-baph archlabs-wallpapers archlabs-scripts archlabs-skel-base"
38 WM_BASE_PKGS="arandr nitrogen polkit-gnome network-manager-applet "
39 WM_BASE_PKGS+="volumeicon xclip exo laptop-detect xdotool compton wmctrl feh "
40 WM_BASE_PKGS+="gnome-keyring dunst gsimplecal xfce4-power-manager xfce4-settings"
42 SYS_MEM="$(awk '/MemTotal/ {print int($2 / 1024) "M"}' /proc/meminfo)"
43 LOCALES="$(awk '/\.UTF-8/ {gsub(/# .*|#/, ""); if ($1) {print $1 " - "}}' /etc/locale.gen)"
44 CMAPS="$(find /usr/share/kbd/keymaps -name '*.map.gz' | awk '{gsub(/\.map\.gz|.*\//, ""); print $1 " - "}' | sort)"
46 [[ $LINES ]] || LINES=$(tput lines)
47 [[ $COLUMNS ]] || COLUMNS=$(tput cols)
51 # commands used to install each bootloader, however most get modified during runtime {
53 [refind-efi]='refind-install'
54 [grub]='grub-install --recheck --force' [syslinux]='syslinux-install_update -i -a -m'
55 [efistub]='efibootmgr -v -d /dev/sda -p 1 -c -l' [systemd-boot]='bootctl --path=/boot install'
58 # executable name for each wm/de used in ~/.xinitrc {
59 declare -A WM_SESSIONS=(
60 [dwm]='dwm' [jwm]='jwm' [i3-gaps]='i3' [bspwm]='bspwm' [awesome]='awesome' [plasma]='startkde' [xfce4]='startxfce4'
61 [gnome]='gnome-session' [fluxbox]='startfluxbox' [openbox]='openbox-session' [cinnamon]='cinnamon-session'
64 # packages installed for each wm/de, most are depends of the skel packages {
66 [dwm]='' [jwm]='' [gnome]='' [cinnamon]='gnome-terminal' [plasma]='kdebase-meta'
67 [awesome]='archlabs-skel-awesome' [bspwm]='archlabs-skel-bspwm' [fluxbox]='archlabs-skel-fluxbox'
68 [i3-gaps]='archlabs-skel-i3-gaps' [openbox]='archlabs-skel-openbox' [xfce4]='archlabs-skel-xfce4 xfce4-goodies'
71 # files offered for editing after install is complete {
72 declare -A EDIT_FILES=(
73 [login]='' # login is populated once we know the username and shell
74 [fstab]='/etc/fstab' [sudoers]='/etc/sudoers' [crypttab]='/etc/crypttab' [pacman]='/etc/pacman.conf'
75 [console]='/etc/vconsole.conf' [mkinitcpio]='/etc/mkinitcpio.conf' [hostname]='/etc/hostname /etc/hosts'
76 [bootloader]="/boot/loader/entries/$DIST.conf" # ** based on bootloader
77 [locale]='/etc/locale.conf /etc/default/locale' [keyboard]='/etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard'
80 # mkfs command flags for filesystem formatting {
81 declare -A FS_CMD_FLAGS=(
82 [f2fs]='' [jfs]='-q' [xfs]='-f' [ntfs]='-q' [ext2]='-q' [ext3]='-q' [ext4]='-q' [vfat]='-F32' [nilfs2]='-q' [reiserfs]='-q'
85 # mount options for each filesystem {
87 [vfat]='' [ntfs]='' [ext2]='' [ext3]='' # NA
88 [jfs]='discard errors=continue errors=panic nointegrity'
89 [reiserfs]='acl nolog notail replayonly user_xattr off'
90 [ext4]='discard dealloc nofail noacl relatime noatime nobarrier nodelalloc'
91 [xfs]='discard filestreams ikeep largeio noalign nobarrier norecovery noquota wsync'
92 [nilfs2]='discard nobarrier errors=continue errors=panic order=relaxed order=strict norecovery'
93 [f2fs]='discard fastboot flush_merge data_flush inline_xattr inline_data noinline_data inline_dentry no_heap noacl nobarrier norecovery noextent_cache disable_roll_forward disable_ext_identify'
96 # packages installed for each login option {
97 declare -A LOGIN_PKGS=(
98 [xinit]='xorg-xinit' [ly]='archlabs-ly' [gdm]='gdm' [sddm]='sddm'
99 [lightdm]='lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings accountsservice'
102 # extras installed for user selected packages {
103 # if a package requires additional packages that aren't already dependencies
104 # they can be added here eg. [package]="extra"
106 [vlc]='qt4' [mpd]='mpc' [mupdf]='mupdf-tools'
107 [rxvt-unicode]='urxvt-perls' [zathura]='zathura-pdf-poppler' [noto-fonts]='noto-fonts-emoji' [cairo-dock]='cairo-dock-plug-ins' [qt5ct]='qt5-styleplugins'
108 [vlc]='qt5ct qt5-styleplugins' [qutebrowser]='qt5ct qt5-styleplugins' [qbittorrent]='qt5ct qt5-styleplugins' [transmission-qt]='qt5ct qt5-styleplugins'
109 [bluez]='bluez-libs bluez-utils bluez-tools bluez-plugins bluez-hid2hci' [kdenlive]='kdebase-meta dvdauthor frei0r-plugins breeze breeze-gtk qt5ct qt5-styleplugins'
112 # dialog text variables {
113 # Basics (somewhat in order)
114 _welcome="\nThis will help you get $DIST installed and setup on your system.\n\nIf you are unsure about a section the default option will be listed or\nthe first selected item will be the default.\n\n\nMenu Navigation:\n\n - Select items with the arrow keys or the option number.\n - Use [Space] to toggle check boxes and [Enter] to accept.\n - Switch between fields using [Tab] or the arrow keys.\n - Use [Page Up] and [Page Down] to jump whole pages\n - Press the highlighted key of an option to select it.\n"
115 _keymap="\nPick which keymap to use for the system from the list below\n\nThis is used once a graphical environment is running (Xorg).\n\nSystem default: us"
116 _vconsole="\nSelect the console keymap, the console is the tty shell you reach before starting a graphical environment (Xorg).\n\nIts keymap is seperate from the one used by the graphical environments, though many do use the same such as 'us' English.\n\nSystem default: us"
117 _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."
118 _device="\nSelect a device to use from the list below.\n\nDevices (/dev) are the available drives on the system. /sda, /sdb, /sdc ..."
119 _resize="\nSelect a new filesystem size in MB, a new partition will be created from the free space but will be left unformatted.\nThe lowest size is just enough to fit the currently in use space on the partition while the default is set to split the free space evenly.\n\nUse Tab or the arrow keys move the cursor between the buttons and the value, when the cursor is on the value, you can edit it by:\n\n - left/right cursor movement to select a digit to modify\n - +/- characters to increment/decrement the digit by one\n - 0 through 9 to set the digit to the given value\n\nSome keys are also recognized in all cursor positions:\n\n - Home/End set the value to its maximum or minimum\n - Pageup/Pagedown increment the value so that the slider moves by one column."
120 _mount="\nUse [Space] to toggle mount options from below, press [Enter] when done to confirm selection.\n\nNot selecting any and confirming will run an automatic mount."
121 _warn="\nIMPORTANT:\n\nChoose carefully when editing, formatting, and mounting partitions or your DATA MAY BE LOST.\n\nTo mount a partition without formatting it, select 'skip' when prompted to choose a filesystem during the mounting stage.\nThis can only be used for partitions that already contain a filesystem and cannot be the root (/) partition, it needs to be formatted before install.\n"
122 _part="\nFull device auto partitioning is available for beginners otherwise cfdisk is recommended.\n\n - All systems will require a root partition (8G or greater).\n - UEFI or BIOS using LUKS without LVM require a separate boot partition (100-512M)."
123 _uefi="\nSelect the EFI boot partition (/boot), required for UEFI boot.\n\nIt's usually the first partition on the device, 100-512M, and will be formatted as vfat/fat32 if not already."
124 _bios="\nDo you want to use a separate boot partition? (optional)\n\nIt's usually the first partition on the device, 100-512M, and will be formatted as ext3/4 if not already."
125 _biosluks="\nSelect the boot partition (/boot), required for LUKS.\n\nIt's usually the first partition on the device, 100-512M, and will be formatted as ext3/4 if not already."
126 _format="is already formatted correctly.\n\nFor a clean install, previously existing partitions should be reformatted, however this removes ALL data (bootloaders) on the partition so choose carefully.\n\nDo you want to reformat the partition?\n"
127 _swapsize="\nEnter the size of the swapfile in megabytes (M) or gigabytes (G).\n\neg. 100M will create a 100 megabyte swapfile, while 10G will create a 10 gigabyte swapfile.\n\nFor ease of use and as an example it is filled in to match the size of your system memory (RAM).\n\nMust be greater than 1, contain only whole numbers, and end with either M or G."
128 _expart="\nYou can now choose any additional partitions you want mounted, you'll be asked for a mountpoint after.\n\nSelect 'done' to finish the mounting step and begin unpacking the base system in the background."
129 _exmnt="\nWhere do you want the partition mounted?\n\nEnsure the name begins with a slash (/).\nExamples include: /usr, /home, /var, etc."
130 _user="\nEnter a name and password for the new user account.\n\nThe name must not use capital letters, contain any periods (.), end with a hyphen (-), or include any colons (:)\n\nNOTE: Use [Up], [Down], or [Tab] to switch between fields, and [Enter] to accept."
131 _hostname="\nEnter a hostname for the new system.\n\nA hostname is used to identify systems on the network.\n\nIt's restricted to alphanumeric characters (a-z, A-Z, 0-9).\nIt can contain hyphens (-) BUT NOT at the beggining or end."
132 _locale="\nLocale determines the system language and currency formats.\n\nThe format for locale names is languagecode_COUNTRYCODE\n\neg. en_US is: english United States\n en_GB is: english Great Britain"
133 _timez="\nThe time zone is used to set the system clock.\n\nSelect your country or continent from the list below"
134 _timesubz="\nSelect the nearest city to you or one with the same time zone.\n\nTIP: Pressing the first letter of the city name repeatedly will navigate between entries beggining with that letter."
135 _sessions="\nUse [Space] to toggle available sessions, use [Enter] to accept the selection and continue.\n\nA basic package set will be installed for compatibility and functionality."
136 _login="\nSelect which of your session choices to use for the initial login.\n\nYou can be change this later by editing your ~/.xinitrc"
137 _autologin="\nDo you want autologin enabled for USER?\n\nIf so the following two files will be created (disable autologin by removing them):\n\n - /home/USER/RC (run startx when logging in on tty1)\n - /etc/systemd/system/getty@tty1.service.d/autologin.conf (login USER without password)\n"
138 _packages="\nUse [Space] to move a package into the selected area and press [Enter] to accept the selection.\n\nPackages may be installed by your DE/WM (if any), or for the packages you select."
139 _usercmd="\nEnter command 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"
140 _edit="\nBefore exiting you can select configuration files to review/change.\n\nIf you need to make other changes with the drives still mounted, use Ctrl-z to pause the installer, when finished type 'fg' and [Enter] to resume the installer, if you want to avoid the automatic reboot using Ctrl-c will cleanly exit."
143 _luksnew="Basic LUKS Encryption"
144 _luksadv="Advanced LUKS Encryption"
145 _luksopen="Open Existing LUKS Partition"
146 _luksmenu="\nA seperate boot partition without encryption or logical volume management (LVM) is required (except BIOS systems using grub).\n\nBasic uses the default encryption settings, and is recommended for beginners. Advanced allows cypher and key size parameters to be entered manually."
147 _luksomenu="\nEnter a name and password for the encrypted device.\n\nIt is not necessary to prefix the name with /dev/mapper/,an example has been provided."
148 _lukskey="Once the specified flags have been amended, they will automatically be used with the 'cryptsetup -q luksFormat /dev/...' command.\n\nNOTE: Do not specify any additional flags such as -v (--verbose) or -y (--verify-passphrase)."
151 _lvmmenu="\nLogical volume management (LVM) allows 'virtual' hard drives (volume groups) and partitions (logical volumes) to be created from existing device partitions.\n\nA volume group must be created first, then one or more logical volumes within it.\n\nLVM can also be used with an encrypted partition to create multiple logical volumes (e.g. root and home) within it."
152 _lvmnew="Create Volume Group and Volume(s)"
153 _lvmdel="Delete an Existing Volume Group"
154 _lvmdelall="Delete ALL Volume Group(s) and Volume(s)"
155 _lvmvgname="\nEnter a name for the volume group (VG) being created from the partition(s) selected."
156 _lvmlvname="\nEnter a name for the logical volume (LV) being created.\n\nThis is similar to setting a label for a partition."
157 _lvmlvsize="\nEnter what size you want the logical volume (LV) to be in megabytes (M) or gigabytes (G).\n\neg. 100M will create a 100 megabyte volume, 10G will create a 10 gigabyte volume."
158 _lvmdelask="\nConfirm deletion of volume group(s) and logical volume(s).\n\nDeleting a volume group, will delete all logical volumes within it.\n"
161 _errexpart="\nCannot mount partition due to a problem with the mountpoint.\n\nEnsure it begins with a slash (/) followed by atleast one character.\n"
162 _errpart="\nYou need create the partiton(s) first.\n\n\nBIOS systems require at least one partition (ROOT).\n\nUEFI systems require at least two (ROOT and EFI).\n"
163 _lukserr="\nA minimum of two partitions are required for encryption:\n\n 1. root (/) - standard or LVM.\n 2. boot (/boot) - standard (unless using LVM on BIOS systems).\n"
164 _lvmerr="\nThere are no viable partitions available to use for LVM, a minimum of one is required.\n\nIf LVM is already in use, deactivating it will allow the partition(s) to be used again.\n"
165 _lvmerrvgname="\nInvalid name entered.\n\nThe volume group name may be alpha-numeric, but may not contain spaces, start with a '/', or already be in use.\n"
166 _lvmerlvname="\nInvalid name entered.\n\nThe logical volume (LV) name may be alpha-numeric, but may not contain spaces or be preceded with a '/'\n"
167 _lvmerrlvsize="\nInvalid value Entered.\n\nMust be a numeric value with 'M' (megabytes) or 'G' (gigabytes) at the end.\n\neg. 400M, 10G, 250G, etc...\n\nThe value may also not be equal to or greater than the remaining size of the volume group.\n"
171 ###############################################################################
173 # main is the entry point which calls functions including outside of its block
174 # once those functions finished they always are returned here with the
175 # exception of install_main(), it exits upon completion
179 (( SEL < 13 )) && (( SEL++ ))
181 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Prepare " --default-item $SEL --cancel-label 'Exit' --menu "$_prep" 0 0 0 \
182 1 "Show device tree" \
184 3 "LUKS encryption" \
185 4 "Logical volume management" \
186 5 "* Mount partitions" \
187 6 "* Select bootloader" \
188 7 "* Username and password" \
189 8 "* System configuration" \
190 9 "Select window manager or desktop" \
191 10 "Select additional packages" \
192 11 "Run a command on the installed system" \
193 12 "View configuration and command selections" \
194 13 "* Confirm choices and start the installation" 2> "$ANS"
197 [[ -z $WARN && $SEL =~ (2|5) ]] && { msg "Data Warning" "$_warn"; WARN=true; }
200 2) part_menu || (( SEL-- )) ;;
201 3) luks_menu || (( SEL-- )) ;;
202 4) lvm_menu || (( SEL-- )) ;;
203 5) mount_menu || (( SEL-- )) ;;
204 6) prechecks 0 && { select_boot || (( SEL-- )); } ;;
205 7) prechecks 1 && { select_mkuser || (( SEL-- )); } ;;
206 8) prechecks 2 && { select_config || (( SEL-- )); } ;;
207 9) prechecks 3 && { select_sessions || (( SEL-- )); } ;;
208 10) prechecks 3 && { select_packages || (( SEL-- )); } ;;
209 11) prechecks 3 && select_usercmd ;;
210 12) prechecks 3 && select_show ;;
211 13) prechecks 3 && install_main ;;
212 *) yesno "Exit" "\nUnmount partitions (if any) and exit the installer?\n" && die 0
218 if [[ $SYS == 'BIOS' ]]; then
219 dlg BOOTLDR menu "BIOS Bootloader" "\nSelect which bootloader to use." \
220 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
221 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network" || return 1
223 dlg BOOTLDR menu "UEFI Bootloader" "\nSelect which bootloader to use." \
224 "systemd-boot" "A simple UEFI boot manager which executes configured EFI images" \
225 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
226 "refind-efi" "A UEFI boot manager that aims to be platform neutral and simplify multi-boot" \
227 "efistub" "Boot the kernel image directly (no chainloading support)" \
228 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network (no chainloading support)" || return 1
235 local pkgs="${USER_PKGS// / } ${PACKAGES// / }"
236 [[ $INSTALL_WMS == *dwm* ]] && pkgs="dwm st dmenu $pkgs"
237 pkgs="${pkgs// / }" pkgs="${pkgs# }"
238 msg "Show Configuration" "
239 ---------- PARTITION CONFIGURATION ------------
241 Root Part: $ROOT_PART
242 Boot Part: ${BOOT_PART:-none}
243 Boot Device: ${BOOT_DEV:-none}
244 Swap Part/File: ${SWAP_PART:-none}
245 Swap Size: ${SWAP_SIZE:-none}
246 Extra Mounts: ${EXMNTS:-none}
247 Mkinit Hooks: ${HOOKS:-none}
249 LVM used: ${LVM:-none}
250 LUKS used: ${LUKS:-none}
252 ------------ SYSTEM CONFIGURATION -------------
254 Locale: ${MYLOCALE:-none}
255 Keymap: ${KEYMAP:-none}
256 Hostname: ${MYHOST:-none}
257 Timezone: ${ZONE:-none}/${SUBZ:-none}
259 Chroot cmd: ${USER_CMD:-none}
261 ------------ USER CONFIGURATION ---------------
263 Username: ${NEWUSER:-none}
264 Login Shell: ${MYSHELL:-none}
265 Login Session: ${LOGIN_WM:-none}
266 Autologin: ${AUTOLOGIN:-none}
267 Login Type: ${LOGIN_TYPE:-none}
269 ----------- PACKAGE CONFIGURATION -------------
271 Kernel: ${KERNEL:-none}
272 Bootloader: ${BOOTLDR:-none}
273 Packages: ${pkgs:-none}
279 AUTOLOGIN='' # no autologin unless using xinit
281 dlg LOGIN_TYPE menu "Login Management" "\nSelect what kind of login management to use." \
282 "xinit" "Console login without a display manager" \
283 "ly" "TUI display manager with a ncurses-like interface" \
284 "lightdm" "Lightweight display manager with a gtk greeter" \
285 "gdm" "Gnome display manager" \
286 "sddm" "Simple desktop display manager" || return 1
289 gdm|sddm) EDIT_FILES[login]="" ;;
290 ly) EDIT_FILES[login]="/etc/ly/config.ini" ;;
291 lightdm) EDIT_FILES[login]="/etc/lightdm/lightdm.conf /etc/lightdm/lightdm-gtk-greeter.conf" ;;
292 xinit) EDIT_FILES[login]="/home/$NEWUSER/.xinitrc /home/$NEWUSER/.xprofile"
293 if (( $(wc -w <<< "$INSTALL_WMS") > 1 )); then
294 dlg LOGIN_WM menu "Login Management" "$_login" $LOGIN_CHOICES || return 1
295 LOGIN_WM="${WM_SESSIONS[$LOGIN_WM]}"
297 [[ -z $LOGIN_WM ]] && LOGIN_WM="${WM_SESSIONS[${INSTALL_WMS%% *}]}"
298 yesno "Autologin" "$(sed "s|USER|$NEWUSER|g; s|RC|$LOGINRC|g" <<< "$_autologin")" && AUTOLOGIN=true || AUTOLOGIN=''
308 until [[ $CONFIG_DONE ]]; do
310 0) dlg MYSHELL menu "Shell" "\nChoose which shell to use." \
311 zsh 'A very advanced and programmable command interpreter (shell) for UNIX' \
312 bash 'The GNU Bourne Again shell, standard in many GNU/Linux distributions' \
313 mksh 'The MirBSD Korn Shell - an enhanced version of the public domain ksh' || return 1
315 1) dlg MYHOST input "Hostname" "$_hostname" "${DIST,,}" limit || { i=0; continue; } ;;
316 2) dlg MYLOCALE menu "Locale" "$_locale" $LOCALES || { i=1; continue; } ;;
318 until [[ $ZONE && $SUBZ ]]; do
319 dlg ZONE menu "Timezone" "$_timez" America - Australia - Asia - Atlantic - Africa - Europe - Indian - Pacific - Arctic - Antarctica - || break
320 dlg SUBZ menu "Timezone" "$_timesubz" $(awk '/'"$ZONE"'\// {gsub(/'"$ZONE"'\//, ""); print $3 " - "}' /usr/share/zoneinfo/zone.tab | sort) || continue
322 [[ $ZONE && $SUBZ ]] || { i=2; continue; } ;;
323 4) dlg KERNEL menu "Kernel" "\nChoose which kernel to use." \
324 linux 'Vanilla linux kernel and modules, with a few patches applied' \
325 linux-lts 'Long-term support (LTS) linux kernel and modules' \
326 linux-zen 'A effort of kernel hackers to provide the best kernel for everyday systems' \
327 linux-hardened 'A security-focused linux kernel with hardening patches to mitigate exploits' || { i=3; continue; }
331 (( i++ )) # progress through to the next choice
335 bash) LOGINRC='.bash_profile' ;;
336 zsh) LOGINRC='.zprofile' ;;
337 mksh) LOGINRC='.profile' ;;
348 until [[ $NEWUSER ]]; do
350 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " User " --mixedform "$_user" 0 0 0 \
351 "Username:" 1 1 "${ans[0]}" 1 11 "$COLUMNS" 0 0 \
352 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
353 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 \
354 "--- Root password, if left empty the user password will be used ---" 6 1 '' 6 68 "$COLUMNS" 0 2 \
355 "Password:" 8 1 '' 8 11 "$COLUMNS" 0 1 \
356 "Password2:" 9 1 '' 9 12 "$COLUMNS" 0 1 2> "$ANS" || return 1
358 mapfile -t ans <"$ANS"
360 # root passwords empty, so use the user passwords
361 if [[ -z "${ans[4]}" && -z "${ans[5]}" ]]; then
366 # make sure a username was entered and that the passwords match
367 if [[ -z ${ans[0]} || ${ans[0]} =~ \ |\' || ${ans[0]} =~ [^a-z0-9] ]]; then
368 msg "Invalid Username" "\nInvalid user name.\n\nPlease try again.\n"; u=''
369 elif [[ -z "${ans[1]}" || "${ans[1]}" != "${ans[2]}" ]]; then
370 msg "Password Mismatch" "\nThe user passwords do not match.\n\nPlease try again.\n"
371 elif [[ "${ans[4]}" != "${ans[5]}" ]]; then
372 msg "Password Mismatch" "\nThe root passwords do not match.\n\nPlease try again.\n"
375 USER_PASS="${ans[1]}"
376 ROOT_PASS="${ans[4]}"
384 dlg KEYMAP menu "Keyboard Layout" "$_keymap" \
385 us English cm English gb English au English gh English \
386 za English ng English ca French 'cd' French gn French \
387 tg French fr French de German at German ch German \
388 es Spanish latam Spanish br Portuguese pt Portuguese ma Arabic \
389 sy Arabic ara Arabic ua Ukrainian cz Czech ru Russian \
390 sk Slovak nl Dutch it Italian hu Hungarian cn Chinese \
391 tw Taiwanese vn Vietnamese kr Korean jp Japanese th Thai \
392 la Lao pl Polish se Swedish is Icelandic 'fi' Finnish \
393 dk Danish be Belgian in Indian al Albanian am Armenian \
394 bd Bangla ba Bosnian 'bg' Bulgarian dz Berber mm Burmese \
395 hr Croatian gr Greek il Hebrew ir Persian iq Iraqi \
396 af Afghani fo Faroese ge Georgian ee Estonian kg Kyrgyz \
397 kz Kazakh lt Lithuanian mt Maltese mn Mongolian ro Romanian \
398 no Norwegian rs Serbian si Slovenian tj Tajik lk Sinhala \
399 tr Turkish uz Uzbek ie Irish pk Urdu 'mv' Dhivehi \
400 np Nepali et Amharic sn Wolof ml Bambara tz Swahili \
401 ke Swahili bw Tswana ph Filipino my Malay tm Turkmen \
402 id Indonesian bt Dzongkha lv Latvian md Moldavian mao Maori \
403 by Belarusian az Azerbaijani mk Macedonian kh Khmer epo Esperanto \
404 me Montenegrin || return 1
406 if [[ $CMAPS == *"$KEYMAP"* ]]; then
409 dlg CMAP menu "Console Keymap" "$_vconsole" $CMAPS || return 1
412 if [[ $TERM == 'linux' ]]; then
413 loadkeys "$CMAP" > /dev/null 2>&1
415 setxkbmap "$KEYMAP" > /dev/null 2>&1
423 dlg USER_CMD input "User Command" "$_usercmd" "$USER_CMD" nolimit
429 dlg INSTALL_WMS check "Sessions" "$_sessions\n" \
430 i3-gaps "A fork of i3wm with more features including gaps" "$(ofn i3-gaps "${INSTALL_WMS[*]}")" \
431 openbox "A lightweight, powerful, and highly configurable stacking wm" "$(ofn openbox "${INSTALL_WMS[*]}")" \
432 dwm "A dynamic WM for X that manages windows in tiled, floating, or monocle layouts" "$(ofn dwm "${INSTALL_WMS[*]}")" \
433 bspwm "A tiling wm that represents windows as the leaves of a binary tree" "$(ofn bspwm "${INSTALL_WMS[*]}")" \
434 jwm "A lightweight window manager for Xorg written in C" "$(ofn jwm "${INSTALL_WMS[*]}")" \
435 xfce4 "A lightweight and modular desktop environment based on gtk+2/3" "$(ofn xfce4 "${INSTALL_WMS[*]}")" \
436 awesome "A customized Awesome WM session created by @elanapan" "$(ofn awesome "${INSTALL_WMS[*]}")" \
437 fluxbox "A lightweight and highly-configurable window manager" "$(ofn fluxbox "${INSTALL_WMS[*]}")" \
438 plasma "A kde software project currently comprising a full desktop environment" "$(ofn plasma "${INSTALL_WMS[*]}")" \
439 gnome "A desktop environment that aims to be simple and easy to use" "$(ofn gnome "${INSTALL_WMS[*]}")" \
440 cinnamon "A desktop environment combining traditional desktop with modern effects" "$(ofn cinnamon "${INSTALL_WMS[*]}")"
442 [[ $INSTALL_WMS ]] || return 0
443 WM_PKGS="${INSTALL_WMS/dwm/}"
444 WM_PKGS="${WM_PKGS// / }"
445 WM_PKGS="${WM_PKGS# }"
447 for i in $INSTALL_WMS; do
448 LOGIN_CHOICES+="$i - "
449 [[ ${WM_EXT[$i]} && $WM_PKGS != *"${WM_EXT[$i]}"* ]] && WM_PKGS+=" ${WM_EXT[$i]}"
452 select_login || return 1
454 while IFS=' ' read -r pkg; do
455 [[ $PACKAGES != *"$pkg"* ]] && PACKAGES+=" $pkg"
463 dlg USER_PKGS check " Packages " "$_packages" \
464 abiword "A Fully-featured word processor" "$(ofn abiword "${USER_PKGS[*]}")" \
465 alacritty "A cross-platform, GPU-accelerated terminal emulator" "$(ofn alacritty "${USER_PKGS[*]}")" \
466 atom "An open-source text editor developed by GitHub" "$(ofn atom "${USER_PKGS[*]}")" \
467 audacious "A free and advanced audio player based on GTK+" "$(ofn audacious "${USER_PKGS[*]}")" \
468 audacity "A program that lets you manipulate digital audio waveforms" "$(ofn audacity "${USER_PKGS[*]}")" \
469 blueman "GUI bluetooth device manager" "$(ofn blueman "${USER_PKGS[*]}")" \
470 bluez "Simple CLI based bluetooth support" "$(ofn bluez "${USER_PKGS[*]}")" \
471 cairo-dock "Light eye-candy fully themable animated dock" "$(ofn cairo-dock "${USER_PKGS[*]}")" \
472 calligra "A set of applications for productivity" "$(ofn calligra "${USER_PKGS[*]}")" \
473 chromium "An open-source web browser based on the Blink rendering engine" "$(ofn chromium "${USER_PKGS[*]}")" \
474 clementine "A modern music player and library organizer" "$(ofn clementine "${USER_PKGS[*]}")" \
475 cmus "A small, fast and powerful console music player" "$(ofn cmus "${USER_PKGS[*]}")" \
476 deadbeef "A GTK+ audio player for GNU/Linux" "$(ofn deadbeef "${USER_PKGS[*]}")" \
477 deluge "A BitTorrent client written in python" "$(ofn deluge "${USER_PKGS[*]}")" \
478 emacs "An extensible, customizable, self-documenting real-time display editor" "$(ofn emacs "${USER_PKGS[*]}")" \
479 epiphany "A GNOME web browser based on the WebKit rendering engine" "$(ofn epiphany "${USER_PKGS[*]}")" \
480 evince "A document viewer" "$(ofn evince "${USER_PKGS[*]}")" \
481 evolution "Manage your email, contacts and schedule" "$(ofn evolution "${USER_PKGS[*]}")" \
482 file-roller "Create and modify archives" "$(ofn file-roller "${USER_PKGS[*]}")" \
483 firefox "A popular open-source web browser from Mozilla" "$(ofn firefox "${USER_PKGS[*]}")" \
484 gcolor2 "A simple GTK+2 color selector" "$(ofn gcolor2 "${USER_PKGS[*]}")" \
485 geany "A fast and lightweight IDE" "$(ofn geany "${USER_PKGS[*]}")" \
486 geary "A lightweight email client for the GNOME desktop" "$(ofn geary "${USER_PKGS[*]}")" \
487 gimp "GNU Image Manipulation Program" "$(ofn gimp "${USER_PKGS[*]}")" \
488 gnome-calculator "GNOME Scientific calculator" "$(ofn gnome-calculator "${USER_PKGS[*]}")" \
489 gnome-disk-utility "Disk Management Utility" "$(ofn gnome-disk-utility "${USER_PKGS[*]}")" \
490 gnome-system-monitor "View current processes and monitor system state" "$(ofn gnome-system-monitor "${USER_PKGS[*]}")" \
491 gparted "A GUI frontend for creating and manipulating partition tables" "$(ofn gparted "${USER_PKGS[*]}")" \
492 gpick "Advanced color picker using GTK+ toolkit" "$(ofn gpick "${USER_PKGS[*]}")" \
493 gpicview "Lightweight image viewer" "$(ofn gpicview "${USER_PKGS[*]}")" \
494 guvcview "Capture video from camera devices" "$(ofn guvcview "${USER_PKGS[*]}")" \
495 hexchat "A popular and easy to use graphical IRC client" "$(ofn hexchat "${USER_PKGS[*]}")" \
496 inkscape "Professional vector graphics editor" "$(ofn inkscape "${USER_PKGS[*]}")" \
497 irssi "Modular text mode IRC client" "$(ofn irssi "${USER_PKGS[*]}")" \
498 kdenlive "A popular non-linear video editor for Linux" "$(ofn kdenlive "${USER_PKGS[*]}")" \
499 krita "Edit and paint images" "$(ofn krita "${USER_PKGS[*]}")" \
500 libreoffice-fresh "Full featured office suite" "$(ofn libreoffice-fresh "${USER_PKGS[*]}")" \
501 lollypop "A new music playing application" "$(ofn lollypop "${USER_PKGS[*]}")" \
502 mousepad "A simple text editor" "$(ofn mousepad "${USER_PKGS[*]}")" \
503 mpd "A flexible, powerful, server-side application for playing music" "$(ofn mpd "${USER_PKGS[*]}")" \
504 mpv "A media player based on mplayer" "$(ofn mpv "${USER_PKGS[*]}")" \
505 mupdf "Lightweight PDF and XPS viewer" "$(ofn mupdf "${USER_PKGS[*]}")" \
506 mutt "Small but very powerful text-based mail client" "$(ofn mutt "${USER_PKGS[*]}")" \
507 nautilus "The default file manager for Gnome" "$(ofn nautilus "${USER_PKGS[*]}")" \
508 ncmpcpp "A mpd client and almost exact clone of ncmpc with some new features" "$(ofn ncmpcpp "${USER_PKGS[*]}")" \
509 neovim "A fork of Vim aiming to improve user experience, plugins, and GUIs." "$(ofn neovim "${USER_PKGS[*]}")" \
510 noto-fonts "Google Noto fonts" "$(ofn noto-fonts "${USER_PKGS[*]}")" \
511 noto-fonts-cjk "Google Noto CJK fonts (Chinese, Japanese, Korean)" "$(ofn noto-fonts-cjk "${USER_PKGS[*]}")" \
512 obs-studio "Free opensource streaming/recording software" "$(ofn obs-studio "${USER_PKGS[*]}")" \
513 openshot "An open-source, non-linear video editor for Linux" "$(ofn openshot "${USER_PKGS[*]}")" \
514 opera "A Fast and secure, free of charge web browser from Opera Software" "$(ofn opera "${USER_PKGS[*]}")" \
515 pcmanfm "A fast and lightweight file manager based in Lxde" "$(ofn pcmanfm "${USER_PKGS[*]}")" \
516 pidgin "Multi-protocol instant messaging client" "$(ofn pidgin "${USER_PKGS[*]}")" \
517 plank "An elegant, simple, and clean dock" "$(ofn plank "${USER_PKGS[*]}")" \
518 qbittorrent "An advanced BitTorrent client" "$(ofn qbittorrent "${USER_PKGS[*]}")" \
519 qpdfview "A tabbed PDF viewer" "$(ofn qpdfview "${USER_PKGS[*]}")" \
520 qt5ct "GUI for managing Qt based application themes, icons, and fonts" "$(ofn qt5ct "${USER_PKGS[*]}")" \
521 qutebrowser "A keyboard-focused vim-like web browser based on Python and PyQt5" "$(ofn qutebrowser "${USER_PKGS[*]}")" \
522 rhythmbox "A Music playback and management application" "$(ofn rhythmbox "${USER_PKGS[*]}")" \
523 rxvt-unicode "A unicode enabled rxvt-clone terminal emulator" "$(ofn rxvt-unicode "${USER_PKGS[*]}")" \
524 sakura "A terminal emulator based on GTK and VTE" "$(ofn sakura "${USER_PKGS[*]}")" \
525 simple-scan "Simple scanning utility" "$(ofn simple-scan "${USER_PKGS[*]}")" \
526 simplescreenrecorder "A feature-rich screen recorder" "$(ofn simplescreenrecorder "${USER_PKGS[*]}")" \
527 steam "A popular game distribution platform by Valve" "$(ofn steam "${USER_PKGS[*]}")" \
528 surf "A simple web browser based on WebKit2/GTK+" "$(ofn surf "${USER_PKGS[*]}")" \
529 terminator "Terminal emulator that supports tabs and grids" "$(ofn terminator "${USER_PKGS[*]}")" \
530 termite "A minimal VTE-based terminal emulator" "$(ofn termite "${USER_PKGS[*]}")" \
531 thunar "A modern file manager for the Xfce Desktop Environment" "$(ofn thunar "${USER_PKGS[*]}")" \
532 thunderbird "Standalone mail and news reader from mozilla" "$(ofn thunderbird "${USER_PKGS[*]}")" \
533 tilda "A GTK based drop down terminal for Linux and Unix" "$(ofn tilda "${USER_PKGS[*]}")" \
534 tilix "A tiling terminal emulator for Linux using GTK+ 3" "$(ofn tilix "${USER_PKGS[*]}")" \
535 transmission-cli "Free BitTorrent client CLI" "$(ofn transmission-cli "${USER_PKGS[*]}")" \
536 transmission-gtk "GTK+ Front end for transmission" "$(ofn transmission-gtk "${USER_PKGS[*]}")" \
537 transmission-qt "Qt Front end for transmission" "$(ofn transmission-qt "${USER_PKGS[*]}")" \
538 ttf-anonymous-pro "A family fixed-width fonts designed with code in mind" "$(ofn ttf-anonymous-pro "${USER_PKGS[*]}")" \
539 ttf-fira-code "Monospaced font with programming ligatures" "$(ofn ttf-fira-code "${USER_PKGS[*]}")" \
540 ttf-font-awesome "Iconic font designed for Bootstrap" "$(ofn ttf-font-awesome "${USER_PKGS[*]}")" \
541 ttf-hack "A hand groomed typeface based on Bitstream Vera Mono" "$(ofn ttf-hack "${USER_PKGS[*]}")" \
542 vlc "A free and open source cross-platform multimedia player" "$(ofn vlc "${USER_PKGS[*]}")" \
543 weechat "Fast, light and extensible IRC client" "$(ofn weechat "${USER_PKGS[*]}")" \
544 xapps "Common library for X-Apps project" "$(ofn xapps "${USER_PKGS[*]}")" \
545 xarchiver "A GTK+ frontend to various command line archivers" "$(ofn xarchiver "${USER_PKGS[*]}")" \
546 xed "A small and lightweight text editor. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
547 xfce4-terminal "A terminal emulator based in the Xfce Desktop Environment" "$(ofn xfce4-terminal "${USER_PKGS[*]}")" \
548 xreader "Document viewer for files like PDF and Postscript. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
549 zathura "Minimalistic document viewer" "$(ofn zathura "${USER_PKGS[*]}")"
551 if [[ $USER_PKGS ]]; then # add any needed PKG_EXT to the list
552 for i in $USER_PKGS; do
553 [[ ${PKG_EXT[$i]} && $USER_PKGS != *"${PKG_EXT[$i]}"* ]] && USER_PKGS+=" ${PKG_EXT[$i]}"
560 ###############################################################################
562 # non-essential partitioning helpers called by the user when using the optional
563 # partition menu and selecting a device to edit
567 no_bg_install || return 0
568 local device choice devhash
569 devhash="$(lsblk -f | base64)"
571 part_device || return 1
576 dlg choice menu "Edit Partitions" "$_part\n\n$(lsblk -no NAME,MODEL,SIZE,TYPE,FSTYPE $device)" \
577 "auto" "Whole device automatic partitioning" \
578 "cfdisk" "Curses based variant of fdisk" \
579 "parted" "GNU partition editor" \
580 "fdisk" "Dialog-driven creation and manipulation of partitions" \
581 "done" "Return to the main menu"
582 # "shrink" "Shrink an existing ext or ntfs partition" \
584 if [[ -z $choice || $choice == 'done' ]]; then
586 elif [[ $choice == 'shrink' ]]; then
587 part_shrink "$device"
588 elif [[ $choice == 'auto' ]]; then
589 local root_size txt table boot_fs
590 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"}}')
591 txt="\nWARNING:\n\nALL data on $device will be destroyed and the following partitions will be created\n\n- "
592 if [[ $SYS == 'BIOS' ]]; then
593 table="msdos" boot_fs="ext4"
594 txt+="An $boot_fs boot partition with the boot flag enabled (512M)\n- "
596 table="gpt" boot_fs="fat32"
597 txt+="A $boot_fs efi boot partition (512M)\n- "
599 txt+="An ext4 partition using all remaining space ($root_size)\n\nDo you want to continue?\n"
600 yesno "Auto Partition" "$txt" && part_auto "$device" "$table" "$boot_fs" "$root_size"
606 if [[ $devhash != "$(lsblk -f | base64)" ]]; then
607 msg "Probing Partitions" "\nInforming kernel of partition changes using partprobe\n" 0
608 partprobe > /dev/null 2>&1
609 [[ $choice == 'auto' ]] && return
617 if [[ $IGNORE_DEV ]]; then
618 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk "!/$IGNORE_DEV/"' && /disk|part|lvm|crypt|NAME/')"
620 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk '/disk|part|lvm|crypt|NAME/')"
622 msg "Device Tree" "\n\n$txt\n\n"
627 local device="$1" table="$2" boot_fs="$3" size="$4" dev_info=""
629 msg "Auto Partition" "\nRemoving partitions on $device and setting table to $table\n" 1
631 dev_info="$(parted -s "$device" print 2> /dev/null)"
634 while read -r PART; do
635 parted -s "$device" rm "$PART" > /dev/null 2> "$ERR"
636 errshow 0 "parted -s $device rm $PART" || return 1
637 done <<< "$(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r)"
639 [[ $(awk '/Table:/ {print $3}' <<< "$dev_info") != "$table" ]] && parted -s "$device" mklabel "$table" > /dev/null 2> "$ERR"
641 msg "Auto Partition" "\nCreating a 512M $boot_fs boot partition.\n" 1
642 if [[ $SYS == "BIOS" ]]; then
643 parted -s "$device" mkpart primary "$boot_fs" 1MiB 513MiB > /dev/null 2> "$ERR"
644 errshow 0 "parted -s $device mkpart primary $boot_fs 1MiB 513MiB" || return 1
646 parted -s "$device" mkpart ESP "$boot_fs" 1MiB 513MiB > /dev/null 2> "$ERR"
647 errshow 0 "parted -s $device mkpart ESP $boot_fs 1MiB 513MiB" || return 1
652 AUTO_BOOT_PART=$(lsblk -lno NAME,TYPE "$device" | awk 'NR==2 {print "/dev/" $1}')
654 if [[ $SYS == "BIOS" ]]; then
655 mkfs.ext4 -q "$AUTO_BOOT_PART" > /dev/null 2> "$ERR"
656 errshow 0 "mkfs.ext4 -q $AUTO_BOOT_PART" || return 1
658 mkfs.vfat -F32 "$AUTO_BOOT_PART" > /dev/null 2> "$ERR"
659 errshow 0 "mkfs.vfat -F32 $AUTO_BOOT_PART" || return 1
662 msg "Auto Partition" "\nCreating a $size ext4 root partition.\n" 0
663 parted -s "$device" mkpart primary ext4 513MiB 100% > /dev/null 2> "$ERR"
664 errshow 0 "parted -s $device mkpart primary ext4 513MiB 100%" || return 1
666 AUTO_ROOT_PART="$(lsblk -lno NAME,TYPE "$device" | awk 'NR==3 {print "/dev/" $1}')"
667 mkfs.ext4 -q "$AUTO_ROOT_PART" > /dev/null 2> "$ERR"
668 errshow 0 "mkfs.ext4 -q $AUTO_ROOT_PART" || return 1
670 msg "Auto Partition" "\nProcess complete.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$device")\n"
677 local device="$1" fs=""
679 part_find "${device##*/}[^ ]" || return 1
680 (( COUNT == 1 )) && part="$(awk '{print $1}' <<< "${PARTS[@]}" )"
682 if (( COUNT == 1 )) || dlg part menu "Resize" "\nWhich partition on $device do you want to resize?" $PARTS; then
683 fs=$(lsblk -lno FSTYPE "$part")
686 msg "Resize" "\nGathering device size info.\n" 0
688 end=$(parted -s "$device" unit KiB print | awk '/^\s*'"$num"'/ {print $3}') # part size in KiB
689 devsize=$(parted -s "$device" unit KiB print | awk '/Disk '"${device//\//\\/}"':/ {print $3}') # whole device size in KiB
690 mount "$part" "$MNT" > /dev/null 2>&1; sleep 0.5
691 min=$(df --output=used --block-size=MiB "$part" | awk 'NR == 2 {print int($1) + 256}')
692 max=$(df --output=avail --block-size=MiB "$part" | awk 'NR == 2 {print int($1)}')
695 if dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Resize: $part " --rangebox "$_resize" 17 "$COLUMNS" "$min" "$max" $((max / 2)) 2> $ANS; then
697 size=$((size * 1024))
704 if ntfsresize -fc "$part"; then
705 ntfsresize -ff --size $(( (size * 1024) / 1000 ))k "$part" 2> "$ERR" # k=10^3 bytes
706 errshow "ntfsresize -f -s $(( (size * 1024) / 1000 ))k $part" || return 1
708 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"
713 e2fsck -f "$part"; sleep 0.5
714 resize2fs -f "$part" ${size}K 2> "$ERR" # K=2^10 bytes
715 errshow "resize2fs -f $part ${size}K" || return 1
719 parted "$device" resizepart "$num" ${size}KiB || return 1
722 if [[ $devsize == "$end" ]]; then
723 parted -s "$device" mkpart primary ext4 ${size}KiB 100% 2> "$ERR"
724 errshow "parted -s $device mkpart primary ext4 ${size}KiB 100%" || return 1
726 parted -s "$device" mkpart primary ext4 ${size}KiB ${end}KiB 2> "$ERR"
727 errshow "parted -s $device mkpart primary ext4 ${size}KiB ${end}KiB" || return 1
729 msg "Resize Complete" "\n$part has been successfully resized to $((size / 1024))M.\n" 1
731 "") msg "No Filesystem" "\nFor unformatted partitions, cfdisk can be used in the partition menu.\n" ;;
732 *) msg "Invalid Filesystem: $fs" "\nResizing only supports ext and ntfs.\n" ;;
737 ###############################################################################
738 # partition management functions
739 # these are helpers for use by other functions to do essential setup/teardown
743 local regexp="$1" err=''
744 local pts dev size isize ptcount=0
746 # string of partitions as /TYPE/PART SIZE.. eg. /dev/sda1 256G
747 if [[ $IGNORE_DEV ]]; then
748 PARTS="$(lsblk -lno TYPE,NAME,SIZE | awk "/$regexp/"' && !'"/$IGNORE_DEV/"' {sub(/^part/, "/dev/"); sub(/^lvm|^crypt/, "/dev/mapper/"); print $1$2, $3}')"
750 PARTS="$(lsblk -lno TYPE,NAME,SIZE | awk "/$regexp/"' {sub(/^part/, "/dev/"); sub(/^lvm|^crypt/, "/dev/mapper/"); print $1$2 " " $3}')"
753 # ensure we have enough partitions for the system and action were trying to do
754 COUNT=$(wc -l <<< "$PARTS")
756 while read -r dev size; do # walk partition list and skip ones that are too small
757 [[ $dev && $size ]] || continue
758 size_t="${size: -1:1}"
761 [[ $size_t == 'K' || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
765 'part|lvm|crypt') [[ $ptcount -lt 1 || ($SYS == 'UEFI' && $COUNT -lt 2) ]] && err="$_errpart" ;;
766 'part|crypt') (( ptcount < 1 )) && err="$_lvmerr" ;;
767 'part|lvm') (( ptcount < 2 )) && err="$_lukserr" ;;
771 msg "Not Enough Partitions" "$err" 2
780 if [[ $1 == "$MNT/swapfile" && $SWAP_SIZE ]]; then
781 fallocate -l $SWAP_SIZE "$1" 2> "$ERR"
782 errshow "fallocate -l $SWAP_SIZE $1"
783 chmod 600 "$1" 2> "$ERR"
784 errshow "chmod 600 $1"
786 mkswap "$1" > /dev/null 2> "$ERR"
788 swapon "$1" > /dev/null 2> "$ERR"
795 local part="$1" mountp="${MNT}$2" fs=""
796 fs="$(lsblk -lno FSTYPE "$part")"
799 if [[ $fs && ${FS_OPTS[$fs]} && $part != "$BOOT_PART" && $part != "$AUTO_ROOT_PART" ]] && select_mntopts "$fs"; then
800 mount -o "$MNT_OPTS" "$part" "$mountp" > /dev/null 2>&1
802 mount "$part" "$mountp" > /dev/null 2>&1
805 part_mountconf "$part" "$mountp" || return 1
813 local part="$1" fs="$2" delay="$3"
815 msg "Format" "\nFormatting $part as $fs\n" 0
816 mkfs.$fs ${FS_CMD_FLAGS[$fs]} "$part" > /dev/null 2> "$ERR"
817 errshow "mkfs.$fs ${FS_CMD_FLAGS[$fs]} "$part"" || return 1
824 if [[ $DEV_COUNT -eq 1 && $SYS_DEVS ]]; then
825 DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
826 elif (( DEV_COUNT > 1 )); then
828 dlg DEVICE menu "Boot Device" "\nSelect the device to use for bootloader install." $SYS_DEVS
830 dlg DEVICE menu "Select Device" "$_device" $SYS_DEVS
832 [[ $DEVICE ]] || return 1
833 elif [[ $DEV_COUNT -lt 1 && ! $1 ]]; then
834 msg "Device Error" "\nNo available devices.\n\nExiting..\n" 2
838 [[ $1 ]] && BOOT_DEV="$DEVICE"
845 BOOT_DEV="${BOOT_PART%[1-9]}"
846 BOOT_PART_NUM="${BOOT_PART: -1}"
847 [[ $BOOT_PART = /dev/nvme* ]] && BOOT_DEV="${BOOT_PART%p[1-9]}"
848 if [[ $SYS == 'UEFI' ]]; then
849 parted -s $BOOT_DEV set $BOOT_PART_NUM esp on > /dev/null 2>&1
851 parted -s $BOOT_DEV set $BOOT_PART_NUM boot on > /dev/null 2>&1
858 local part="$1" devs=""
859 devs="$(lsblk -lno NAME,FSTYPE,TYPE)"
861 # Identify if $part is LUKS+LVM, LVM+LUKS, LVM alone, or LUKS alone
862 if lsblk -lno TYPE "$part" | grep -q 'crypt'; then
864 LUKS_NAME="${part#/dev/mapper/}"
865 for dev in $(awk '/lvm/ && /crypto_LUKS/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
866 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
867 LUKS_DEV="$LUKS_DEV cryptdevice=$dev:$LUKS_NAME"
872 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
873 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
874 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
875 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
879 elif lsblk -lno TYPE "$part" | grep -q 'lvm'; then
881 VNAME="${part#/dev/mapper/}"
882 for dev in $(awk '/crypt/ && /lvm2_member/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
883 if lsblk -lno NAME "$dev" | grep -q "$VNAME"; then
884 LUKS_NAME="${dev/\/dev\/mapper\//}"
888 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
889 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
890 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
891 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
902 if (( COUNT > 0 )); then
903 PARTS="$(sed "/${pt//\//\\/}/d" <<< "$PARTS")"
911 if grep -qw "$1" /proc/mounts; then
912 msg "Mount Success" "\nPartition $1 mounted at $2\n" 1
916 msg "Mount Fail" "\nPartition $1 failed to mount at $2\n" 2
921 ###############################################################################
923 # mount_menu is the entry point which calls all other functions
924 # once finished it returns to the main menu: main()
928 msg "Mount Menu" "\nGathering device and partition information.\n" 1
929 no_bg_install || return 0
932 part_find 'part|lvm|crypt' || { SEL=2; return 1; }
933 [[ $LUKS && $LUKS_PART ]] && part_countdec $LUKS_PART
934 [[ $LVM && $LVM_PARTS ]] && part_countdec $LVM_PARTS
935 select_root_partition || { ROOT_PART=''; return 1; }
936 select_boot_partition || { BOOT_PART=''; return 1; }
937 if [[ $BOOT_PART ]]; then
938 part_mount "$BOOT_PART" "/boot" && SEP_BOOT=true || return 1
941 select_swap || return 1
942 select_extra_partitions || return 1
949 local pts dev size isize
951 if (( COUNT )) ; then
952 while read -r dev size; do # walk partition list and skip ones that are too small/big for swap
953 size_t="${size: -1:1}"
956 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 16) || ($size_t == 'M' && $isize -lt 100) ]] || pts+="$dev $size "
960 dlg SWAP_PART menu "Swap Setup" "\nSelect whether to use a swapfile, swap partition, or none." \
961 "none" "Don't allocate any swap space" \
962 "swapfile" "Allocate $SYS_MEM at /swapfile" \
965 if [[ -z $SWAP_PART || $SWAP_PART == "none" ]]; then
968 elif [[ $SWAP_PART == "swapfile" ]]; then
970 until [[ ${SWAP_SIZE:0:1} =~ [1-9] && ${SWAP_SIZE: -1} =~ (M|G) ]]; do
971 (( 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
972 dlg SWAP_SIZE input "Swap Setup" "$_swapsize" "$SYS_MEM" || { SWAP_PART=''; SWAP_SIZE=''; return 1; }
975 part_swap "$MNT/$SWAP_PART"
976 SWAP_PART="/$SWAP_PART"
977 elif [[ $PARTS == *"$SWAP_PART"* ]]; then
979 part_countdec $SWAP_PART
980 SWAP_SIZE="$(lsblk -lno SIZE $SWAP_PART)"
990 local fs="$1" opts=''
991 local title="${fs^} Mount Options"
993 for i in ${FS_OPTS[$fs]}; do
997 until [[ $MNT_OPTS ]]; do
998 dlg MNT_OPTS check "$title" "$_mount" $opts
999 [[ $MNT_OPTS ]] || return 1
1000 MNT_OPTS="${MNT_OPTS// /,}"
1001 yesno "$title" "\nConfirm the following options: $MNT_OPTS\n" || MNT_OPTS=''
1010 until [[ $EXMNT ]]; do
1011 dlg EXMNT input "Extra Mount $part" "$_exmnt" "/" || return 1
1012 if [[ ${EXMNT:0:1} != "/" || ${#EXMNT} -le 1 || $EXMNT =~ \ |\' || $EXMNTS == *"$EXMNT"* ]]; then
1013 msg "Mountpoint Error" "$_errexpart"
1017 msg "Mount Extra" "\nMounting Finished\n\n\nNo extra partitions available to mount, returning to main menu.\n" 2
1023 local part="$1" fs='' cur=''
1024 local txt="\nSelect which filesystem to use for: $part\n\nDefault: ext4"
1025 cur="$(lsblk -lno FSTYPE "$part" 2> /dev/null)"
1027 # bail early if the partition was created in part_auto()
1028 [[ $cur && $part == "$AUTO_ROOT_PART" ]] && return 0
1031 if [[ $cur && $FORMATTED == *"$part"* ]]; then
1032 dlg fs menu "Filesystem" "$txt\nCurrent: $cur" skip - ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1034 dlg fs menu "Filesystem" "$txt" ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1036 [[ $fs == 'skip' ]] && return 0
1037 yesno "Filesystem" "\nFormat $part as $fs?\n" || fs=''
1039 part_format "$part" "$fs" 0
1042 select_boot_partition()
1044 local pts dev size isize ptcount=0
1046 if [[ -z $BOOT_PART ]]; then
1047 if [[ $AUTO_BOOT_PART && -z $LVM && -z $LUKS ]]; then
1048 BOOT_PART="$AUTO_BOOT_PART"
1051 if (( COUNT )); then
1052 while read -r dev size; do # walk partition list and skip ones that are too small/big for boot
1053 size_t="${size: -1:1}"
1056 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1063 0) msg "EFI Boot Partition" "\nNo partitions available that meet size requirements!!\n\nReturning to the main menu.\n" 2; return 1 ;;
1064 1) msg "EFI Boot Partition" "\nOnly one partition available that meets size requirements.\n" 1; BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")" ;;
1065 *) dlg BOOT_PART menu "EFI Partition" "$_uefi" $pts ;;
1067 [[ $BOOT_PART ]] || return 1
1070 if [[ $LUKS && ! $LVM ]]; then
1072 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 ;;
1073 1) msg "Boot Partition" "\nOnly one partition available that meets size requirements.\n" 1; BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")" ;;
1074 *) dlg BOOT_PART menu "Boot Partition" "$_biosluks" $pts ;;
1076 [[ $BOOT_PART ]] || return 1
1078 (( ptcount == 0 )) && return 0
1079 dlg BOOT_PART menu "Boot Partition" "$_bios" "skip" "no separate boot" $pts
1080 [[ -z $BOOT_PART || $BOOT_PART == "skip" ]] && { BOOT_PART=''; return 0; }
1087 if ([[ $SYS == 'BIOS' ]] && grep -q 'ext[34]' <<< "$(fsck -N "$BOOT_PART")") || ([[ $SYS == 'UEFI' ]] && grep -q 'fat' <<< "$(fsck -N "$BOOT_PART")"); then
1088 yesno "Format Boot Partition" "\nIMPORTANT:\n\nThe boot partition $BOOT_PART $_format" "Format $BOOT_PART" "Skip Formatting" 1 || return 0
1092 UEFI) part_format "$BOOT_PART" "vfat" 2 || return 1 ;;
1093 BIOS) part_format "$BOOT_PART" "ext4" 2 || return 1 ;;
1098 select_root_partition()
1100 if [[ -z $ROOT_PART ]]; then
1101 if [[ $AUTO_ROOT_PART && -z $LVM && -z $LUKS ]]; then
1102 ROOT_PART="$AUTO_ROOT_PART"
1103 msg "Mount Menu" "\nUsing partitions created during automatic format.\n" 2
1104 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1105 return 0 # we're done here
1107 local pts dev size isize ptcount=0
1109 # walk partition list and skip ones that are too small for / (root)
1110 while read -r dev size; do
1111 size_t="${size: -1:1}" # size type eg. K, M, G, T
1112 isize=${size:0:-1} # remove trailing size type character
1113 isize=${isize%.*} # remove any decimal (round down)
1114 [[ $size_t =~ [MK] || ($size_t == 'G' && $isize -lt 4) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1117 if (( ptcount == 1 )); then # only one available device
1118 msg "Root Partition (/)" "\nOnly one partition available that meets size requirements.\n" 2
1119 ROOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")"
1121 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
1126 if [[ -z $ROOT_PART ]] || ! select_filesystem "$ROOT_PART" || ! part_mount "$ROOT_PART"; then
1133 select_extra_partitions()
1137 # walk partition list and skip ones that are too small to be usable
1138 if (( COUNT )); then
1139 while read -r dev size; do
1140 [[ ${size: -1:1} =~ [KM] ]] && part_countdec "$dev"
1144 while (( COUNT )); do
1146 dlg part menu 'Mount Extra' "$_expart" 'done' 'finish mounting step' $PARTS || break
1147 if [[ $part == 'done' ]]; then
1149 elif select_filesystem "$part" && select_mountpoint && part_mount "$part" "$EXMNT"; then
1150 EXMNTS+="$part: $EXMNT "
1151 [[ $EXMNT == '/usr' && $HOOKS != *usr* ]] && HOOKS+=" usr"
1159 ###############################################################################
1161 # main is the entry point which calls all other install functions, once
1162 # complete it shows a dialog to edit files on the new system before reboot
1167 genfstab -U "$MNT" > "$MNT/etc/fstab" 2> "$ERR"
1168 errshow 1 "genfstab -U $MNT > $MNT/etc/fstab"
1169 [[ -f $MNT/swapfile ]] && sed -i "s~${MNT}~~" "$MNT/etc/fstab"
1171 # tear free configs, MUST be done after package install for nvidia
1172 [[ $TEARFREE ]] && install_tearfree_conf "$MNT/etc/X11/xorg.conf.d"
1175 chrun "hwclock --systohc --utc" || chrun "hwclock --systohc --utc --directisa"
1178 chrun "chown -Rf $NEWUSER:users /home/$NEWUSER"
1179 if [[ "$USER_CMD" ]]; then
1180 chrun "$USER_CMD" 2> "$ERR" 2>&1
1181 errshow 0 "$USER_CMD"
1185 dlg choice menu "Finalization" "$_edit" \
1186 finished "exit the installer and reboot" \
1187 keyboard "${EDIT_FILES[keyboard]}" \
1188 console "${EDIT_FILES[console]}" \
1189 locale "${EDIT_FILES[locale]}" \
1190 hostname "${EDIT_FILES[hostname]}" \
1191 sudoers "${EDIT_FILES[sudoers]}" \
1192 mkinitcpio "${EDIT_FILES[mkinitcpio]}" \
1193 fstab "${EDIT_FILES[fstab]}" \
1194 crypttab "${EDIT_FILES[crypttab]}" \
1195 bootloader "${EDIT_FILES[bootloader]}" \
1196 pacman "${EDIT_FILES[pacman]}" \
1197 login "${EDIT_FILES[login]}"
1199 if [[ -z $choice || $choice == 'finished' ]]; then
1200 [[ $DEBUG == true && -r $DBG ]] && ${EDITOR:-vim} "$DBG"
1205 for f in ${EDIT_FILES[$choice]}; do
1206 if [[ -e ${MNT}$f ]]; then
1207 ${EDITOR:-vim} "${MNT}$f"
1209 msg "File Missing" "\nThe file(s) selected do not exist:\n\n${MNT}$f\n"
1220 while kill -0 $BG_PID 2> /dev/null; do
1221 clear; printf "\nA background install process is still running...\n"; sleep 1
1227 rm -rf "$MNT/etc/mkinitcpio-archiso.conf"
1228 find "$MNT/usr/lib/initcpio" -name 'archiso*' -type f -delete
1230 # remove/disable customizations done to airootfs during building
1231 chrun "systemctl disable pacman-init.service choose-mirror.service" > /dev/null 2>&1
1232 rm -f "$MNT/etc/systemd/scripts/choose-mirror"
1233 rm -f "$MNT/etc/systemd/system/"{choose-mirror.service,etc-pacman.d-gnupg.mount,pacman-init.service}
1234 sed -i 's/#\(Storage=\)volatile/\1auto/' "$MNT/etc/systemd/journald.conf"
1235 sed -i 's/#\(HandleSuspendKey=\)ignore/\1suspend/' "$MNT/etc/systemd/logind.conf"
1236 sed -i 's/#\(HandleHibernateKey=\)ignore/\1hibernate/' "$MNT/etc/systemd/logind.conf"
1237 sed -i 's/#\(HandleLidSwitch=\)ignore/\1suspend/' "$MNT/etc/systemd/logind.conf"
1238 find "$MNT/boot" -name '*-ucode.img' -delete
1240 # changing distro name?
1241 [[ $DIST != "ArchLabs" ]] || sed -i "s/ArchLabs/$DIST/g" "$MNT/etc/"{lsb-release,os-release}
1243 # vmlinuz, if this isn't copied the standard kernel may fail mkinitcpio
1244 cp -vf "$RUN/x86_64/vmlinuz" "$MNT/boot/vmlinuz-linux" 2> "$ERR" 2>&1
1245 errshow 1 "cp -vf $RUN/x86_64/vmlinuz $MNT/boot/vmlinuz-linux"
1247 # copy network settings
1248 [[ -d /etc/netctl ]] && cp -rfv /etc/netctl "$MNT/etc/"
1249 [[ -f /etc/resolv.conf ]] && cp -fv /etc/resolv.conf "$MNT/etc/"
1250 [[ -e /etc/NetworkManager/system-connections ]] && cp -rvf /etc/NetworkManager/system-connections "$MNT/etc/NetworkManager/"
1252 echo "LANG=$MYLOCALE" > "$MNT/etc/locale.conf"
1253 cp -fv "$MNT/etc/locale.conf" "$MNT/etc/default/locale"
1254 sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${MYLOCALE}/${MYLOCALE}/g" "$MNT/etc/locale.gen"
1256 chrun "ln -svf /usr/share/zoneinfo/$ZONE/$SUBZ /etc/localtime"
1258 cat > "$MNT/etc/X11/xorg.conf.d/00-keyboard.conf" <<- EOF
1259 # Use localectl(1) to instruct systemd-localed to update it.
1260 Section "InputClass"
1261 Identifier "system-keyboard"
1262 MatchIsKeyboard "on"
1263 Option "XkbLayout" "$KEYMAP"
1267 cat > "$MNT/etc/default/keyboard" <<- EOF
1268 # KEYBOARD CONFIGURATION FILE
1269 # Consult the keyboard(5) manual page.
1276 printf "KEYMAP=%s\nFONT=%s\n" "$CMAP" "$FONT" > "$MNT/etc/vconsole.conf"
1278 echo "$MYHOST" > "$MNT/etc/hostname"
1279 cat > "$MNT/etc/hosts" <<- EOF
1282 ::1 localhost ip6-localhost ip6-loopback
1283 ff02::1 ip6-allnodes
1284 ff02::2 ip6-allrouters
1290 echo "Installing $BOOTLDR"
1292 if [[ $ROOT_PART == /dev/mapper* ]]; then
1293 ROOT_PART_ID="$ROOT_PART"
1295 local uuid_type="UUID"
1296 [[ $BOOTLDR =~ (systemd-boot|refind-efi|efistub) ]] && uuid_type="PARTUUID"
1297 ROOT_PART_ID="$uuid_type=$(blkid -s $uuid_type -o value $ROOT_PART)"
1300 if [[ $SYS == 'UEFI' ]]; then
1301 # remove our old install and generic BOOT/ dir
1302 echo "Removing conflicting boot directories"
1303 find "$MNT/boot/EFI/" -maxdepth 1 -mindepth 1 -iname "$DIST" -type d -delete -printf "remove %p\n"
1304 find "$MNT/boot/EFI/" -maxdepth 1 -mindepth 1 -iname 'BOOT' -type d -delete -printf "remove %p\n"
1308 chrun "${BCMDS[$BOOTLDR]}" 2> "$ERR" 2>&1
1309 errshow 1 "${BCMDS[$BOOTLDR]}"
1311 if [[ -d $MNT/hostrun ]]; then
1312 echo "Unmounting chroot directories"
1313 # cleanup the bind mounts we made earlier for the grub-probe module
1314 umount_dir "$MNT/hostrun/"{udev,lvm}
1315 rm -rf "$MNT/hostrun" > /dev/null 2>&1
1318 if [[ $SYS == 'UEFI' ]]; then
1319 # some UEFI firmware requires a generic esp/BOOT/BOOTX64.EFI
1320 mkdir -pv "$MNT/boot/EFI/BOOT"
1322 grub) cp -fv "$MNT/boot/EFI/$DIST/grubx64.efi" "$MNT/boot/EFI/BOOT/BOOTX64.EFI" ;;
1323 syslinux) cp -rf "$MNT/boot/EFI/syslinux/"* "$MNT/boot/EFI/BOOT/" && cp -f "$MNT/boot/EFI/syslinux/syslinux.efi" "$MNT/boot/EFI/BOOT/BOOTX64.EFI" ;;
1324 refind-efi) sed -i '/#extra_kernel_version_strings/ c extra_kernel_version_strings linux-hardened,linux-zen,linux-lts,linux' "$MNT/boot/EFI/refind/refind.conf"
1325 cp -fv "$MNT/boot/EFI/refind/refind_x64.efi" "$MNT/boot/EFI/BOOT/BOOTX64.EFI" ;;
1334 local groups='audio,video,floppy,log,network,rfkill,scanner,storage,optical,power,wheel'
1335 [[ -e $MNT/etc/X11/xorg.conf.d/20-nvida.conf && -e $MNT/usr/bin/optirun ]] && groups+=',bumblebee'
1337 rm -f "$MNT/root/.zlogin" # remove welcome message
1339 chrun "chpasswd <<< 'root:$ROOT_PASS'" 2> "$ERR" 2>&1
1340 errshow 1 "set root password"
1341 if [[ $MYSHELL != 'zsh' ]]; then # root uses zsh by default
1342 chrun "usermod -s /bin/$MYSHELL root" 2> "$ERR" 2>&1
1343 errshow 1 "usermod -s /bin/$MYSHELL root"
1344 # copy the default mkshrc to /root if it was selected
1345 [[ $MYSHELL == 'mksh' ]] && cp -fv "$MNT/etc/skel/.mkshrc" "$MNT/root/.mkshrc"
1348 echo "Creating new user $NEWUSER and setting password"
1349 chrun "useradd -m -u 1000 -g users -G $groups -s /bin/$MYSHELL $NEWUSER" 2> "$ERR" 2>&1
1350 errshow 1 "useradd -m -u 1000 -g users -G $groups -s /bin/$MYSHELL $NEWUSER"
1351 chrun "chpasswd <<< '$NEWUSER:$USER_PASS'" 2> "$ERR" 2>&1
1352 errshow 1 "set $NEWUSER password"
1354 if [[ $INSTALL_WMS == *dwm* ]]; then
1355 install_suckless "/home/$NEWUSER" chroot
1356 [[ $INSTALL_WMS == 'dwm' ]] && rm -rf "$MNT/home/$NEWUSER/.config/xfce4"
1358 [[ $INSTALL_WMS == *jwm* ]] && sed '7,14d; s/xlock -mode blank/i3-lock-fancy -p/g; s/root:1/rofi_run/g' "$MNT/etc/system.jwmrc" > "$MNT/home/$NEWUSER/.jwmrc"
1359 [[ $INSTALL_WMS =~ (bspwm|openbox) ]] || rm -rf "$MNT/home/$NEWUSER/.config/"{jgmenu,tint2}
1360 [[ $USER_PKGS != *geany* ]] && rm -rf "$MNT/home/$NEWUSER/.config/geany"
1361 [[ $MYSHELL != 'bash' ]] && rm -rf "$MNT/home/$NEWUSER/.bash"*
1362 [[ $MYSHELL != 'zsh' ]] && rm -rf "$MNT/home/$NEWUSER/.z"*
1364 # remove some commands from ~/.xprofile when using KDE or Gnome as the login session
1365 if [[ $LOGIN_WM =~ (startkde|gnome-session) || ($LOGIN_TYPE != 'xinit' && $WM_PKGS =~ (plasma|gnome)) ]]; then
1366 sed -i '/super/d; /nitrogen/d; /compton/d' "$MNT/home/$NEWUSER/.xprofile" "$MNT/root/.xprofile"
1367 elif [[ $LOGIN_WM == 'dwm' ]]; then # and dwm
1368 sed -i '/super/d; /compton/d' "$MNT/home/$NEWUSER/.xprofile" "$MNT/root/.xprofile"
1376 local serv="$MNT/etc/systemd/system/getty@tty1.service.d"
1377 echo "Setting up $LOGIN_TYPE"
1379 ly|sddm|gdm|lightdm)
1380 if [[ $LOGIN_WM == *dwm* ]]; then # dwm doesn't include an xsession file for display managers
1381 mkdir -p "$MNT/usr/share/xsessions"
1382 cat > "$MNT/usr/share/xsessions/dwm.desktop" <<- EOF
1386 Comment=Dynamic Window Manager
1391 rm -rf "$serv" "$MNT/home/$NEWUSER/.xinitrc"
1392 chrun "systemctl enable $LOGIN_TYPE.service" 2> "$ERR" 2>&1
1393 errshow 1 "systemctl enable $LOGIN_TYPE.service"
1394 ${LOGIN_TYPE}_config
1397 if [[ $INSTALL_WMS ]]; then
1398 sed -i "/exec/ c exec ${LOGIN_WM}" "$MNT/home/$NEWUSER/.xinitrc"
1399 elif [[ -e $MNT/home/$NEWUSER/.xinitrc ]]; then
1400 sed -i '/exec/d' "$MNT/home/$NEWUSER/.xinitrc"
1403 if [[ $AUTOLOGIN ]]; then
1404 sed -i "s/root/${NEWUSER}/g" $serv/autologin.conf
1405 cat > "$MNT/home/$NEWUSER/$LOGINRC" <<- EOF
1406 # automatically run startx when logging in on tty1
1407 [ \$XDG_VTNR -eq 1 ] && exec startx
1419 local inpkg="$PACKAGES $USER_PKGS $AL_BASE_PKGS "
1421 if pacman -Qq archlabs-installer > /dev/null 2>&1; then
1422 rmpkg+="archlabs-installer "
1425 if [[ $MYSHELL == 'zsh' ]]; then
1426 inpkg+="zsh-completions "
1431 if [[ $INSTALL_WMS =~ (openbox|bspwm|i3-gaps|fluxbox|jwm|awesome) ]]; then
1432 inpkg+="$WM_BASE_PKGS "
1433 elif [[ $INSTALL_WMS == 'dwm' ]]; then # dwm only needs a very limited package set
1434 inpkg+="nitrogen polkit-gnome gnome-keyring dunst "
1437 # update and install crucial packages first to avoid issues
1438 chrun "pacman -Syyu $KERNEL $BASE_PKGS base-devel ${LOGIN_PKGS[$LOGIN_TYPE]} $MYSHELL --noconfirm --needed" 2> "$ERR" 2>&1
1439 errshow 1 "pacman -Syyu $KERNEL $BASE_PKGS base-devel ${LOGIN_PKGS[$LOGIN_TYPE]} $MYSHELL --noconfirm --needed"
1441 # remove the packages we don't want on the installed system
1442 [[ $rmpkg ]] && chrun "pacman -Rnsc $rmpkg --noconfirm"
1444 # reinstalling iputils fixes the network issue for non-root users
1445 chrun "pacman -S iputils $UCODE --noconfirm"
1447 # install the packages chosen throughout the install
1448 chrun "pacman -S $inpkg --needed --noconfirm" 2> "$ERR" 2>&1
1449 errshow 1 "pacman -S $inpkg --needed --noconfirm"
1451 # bootloader packages
1452 if [[ $BOOTLDR == 'grub' ]]; then
1453 [[ $SYS == 'UEFI' ]] && local efib="efibootmgr"
1454 chrun "pacman -S os-prober grub $efib --needed --noconfirm" 2> "$ERR" 2>&1
1455 errshow 1 "pacman -S os-prober grub $efib --needed --noconfirm"
1456 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1457 chrun "pacman -S refind-efi efibootmgr --needed --noconfirm" 2> "$ERR" 2>&1
1458 errshow 1 "pacman -S refind-efi efibootmgr --needed --noconfirm"
1459 elif [[ $SYS == 'UEFI' ]]; then
1460 chrun "pacman -S efibootmgr --needed --noconfirm" 2> "$ERR" 2>&1
1461 errshow 1 "pacman -S efibootmgr --needed --noconfirm"
1464 if [[ $VM ]] && dmesg | grep -qi 'vbox'; then
1466 linux) chrun "pacman -S virtualbox-guest-utils virtualbox-guest-modules-arch --needed --noconfirm" ;;
1467 *) chrun "pacman -S virtualbox-guest-utils virtualbox-guest-modules-dkms ${KERNEL}-headers --needed --noconfirm" ;;
1471 # allow members of the wheel group to run commands as root
1472 sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" "$MNT/etc/sudoers"
1479 local dir="$1/suckless"
1482 if [[ $1 == 'chroot' ]]; then
1483 chrun "mkdir -pv '$dir'"
1484 for i in dwm dmenu st; do
1485 if chrun "git clone 'https://git.suckless.org/$i' '$dir/$i'"; then
1486 chrun "cd '$dir/$i' && make PREFIX=/usr install"
1488 printf "failed to clone %s repo\n" "$i"
1493 for i in dwm dmenu st; do
1494 if git clone "https://git.suckless.org/$i" "$dir/$i"; then
1495 cd "$dir/$i" && make PREFIX=/usr install
1497 printf "failed to clone %s repo\n" "$i"
1503 install_mkinitcpio()
1506 [[ $LUKS ]] && add="encrypt"
1507 [[ $LVM ]] && { [[ $add ]] && add+=" lvm2" || add+="lvm2"; }
1508 sed -i "s/block filesystems/block ${add} filesystems ${HOOKS}/g" "$MNT/etc/mkinitcpio.conf"
1509 chrun "mkinitcpio -p $KERNEL" 2> "$ERR" 2>&1
1510 errshow 1 "mkinitcpio -p $KERNEL"
1513 install_mirrorlist()
1515 if hash reflector > /dev/null 2>&1; then
1516 reflector --verbose --score 80 -l 40 -f 5 --sort rate --save "$1"
1517 elif hash rankmirrors > /dev/null 2>&1; then
1518 echo "Sorting mirrorlist"
1519 local key="access_key=5f29642060ab983b31fdf4c2935d8c56"
1520 ip_add="$(curl -fsSL "http://api.ipstack.com/check&?$key&fields=ip" | python -c "import sys, json; print(json.load(sys.stdin)['ip'])")"
1521 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'])")"
1522 if [[ "$country" ]]; then
1523 if [[ $country =~ (CA|US) ]]; then
1524 # use both CA and US mirrors for CA or US countries
1525 mirror="https://www.archlinux.org/mirrorlist/?country=US&country=CA&use_mirror_status=on"
1526 elif [[ $country =~ (AU|NZ) ]]; then
1527 # use both AU and NZ mirrors for AU or NZ countries
1528 mirror="https://www.archlinux.org/mirrorlist/?country=AU&country=NZ&use_mirror_status=on"
1530 mirror="https://www.archlinux.org/mirrorlist/?country=${country}&use_mirror_status=on"
1532 else # no country code so just grab all mirrors, will be a very slow sort but we don't have other options
1533 mirror="https://www.archlinux.org/mirrorlist/?country=all&use_mirror_status=on"
1535 curl -fsSL "$mirror" | sed -e 's/^#Server/Server/' -e '/^#/d' | rankmirrors -n 6 - > "$1"
1539 install_background()
1541 ( rsync -a /run/archiso/sfs/airootfs/ "$MNT/" && install_mirrorlist "$MNT/etc/pacman.d/mirrorlist" > /dev/null 2>&1 ) &
1543 trap "kill $BG_PID 2> /dev/null" EXIT
1546 install_tearfree_conf()
1551 echo "Virtual machine detected, removing xorg configs"
1552 find "$xpath/" -name '*.conf' -delete -printf "remove %p\n"
1553 elif lspci | grep ' VGA ' | grep -q 'Intel'; then
1554 echo "Creating Intel Tear Free config /etc/X11/xorg.conf.d/20-intel.conf"
1555 cat > "$xpath/20-intel.conf" <<- EOF
1557 Identifier "Intel Graphics"
1559 Option "TearFree" "true"
1562 cat "$xpath/20-intel.conf"
1563 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
1564 echo "Creating AMD Tear Free config /etc/X11/xorg.conf.d/20-amdgpu.conf"
1565 cat > "$xpath/20-amdgpu.conf" <<- EOF
1567 Identifier "AMD Graphics"
1569 Option "TearFree" "true"
1572 cat "$xpath/20-amdgpu.conf"
1573 elif lspci | grep ' VGA ' | grep -q 'AMD/ATI.*HD [2-6][0-9]*'; then # older HD 2xxx-6xxx cards must use the radeon driver
1574 echo "Creating Radeon Tear Free config /etc/X11/xorg.conf.d/20-radeon.conf"
1575 cat > "$xpath/20-radeon.conf" <<- EOF
1577 Identifier "AMD Graphics"
1579 Option "TearFree" "on"
1582 cat "$xpath/20-radeon.conf"
1583 elif lspci | grep ' VGA ' | grep -q 'NVIDIA'; then # nvidia cards require a bit of checking for notebook gpus
1584 echo "Trying nvidia driver install"
1585 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
1586 if [[ $xpath == *"$MNT"* ]]; then
1587 chrun "nvidia-installer --bumblebee"
1589 nvidia-installer --bumblebee
1592 if [[ $xpath == *"$MNT"* ]]; then
1593 chrun "nvidia-installer" # unsure which card so try auto detection
1598 if [[ -e $xpath/20-nvidia.conf ]]; then
1599 cat "$xpath/20-radeon.conf"
1601 echo "NVIDIA driver installed"
1602 if [[ $xpath == *"$MNT"* ]]; then
1603 echo "Trying to load the driver for live session"
1606 echo "To enable driver vsync:"
1607 echo -e "\trun nvidia-settings (as root) on first boot\n\tenable 'ForceFullCompositionPipeline' under the advanced settings"
1608 echo -e "\tlastly save the change to your nvida xorg config /etc/X11/xorg.conf.d/20-nvidia.conf"
1609 echo -e "\tand remove everything but the Device and Screen sections from the file"
1611 echo "Unable to install nvidia driver"
1616 if lspci | grep ' VGA ' | grep -q 'Intel\|AMD/ATI'; then
1617 if [[ $xpath == *"$MNT"* ]]; then
1618 sed -i 's/xrender/glx/g' "$MNT/etc/skel/.config/compton.conf"
1620 sed -i 's/xrender/glx/g' /etc/skel/.config/compton.conf
1624 # remove nvidia installer from installed system when not running nvidia gpu
1625 [[ $xpath == *"$MNT"* ]] && rm -rf "$MNT/usr/bin/nvidia-installer" "$MNT/var/lib/nvidia-installer"
1628 ###############################################################################
1629 # display manager config
1630 # these are called based on which DM is chosen after it is installed
1631 # additional config can be handled here, for now only lightdm has one
1650 cat > "$MNT/etc/lightdm/lightdm-gtk-greeter.conf" <<- EOF
1652 default-user-image=/usr/share/icons/ArchLabs-Dark/64x64/places/distributor-logo-archlabs.png
1653 background=/usr/share/backgrounds/archlabs/archlabs.jpg
1654 theme-name=Adwaita-dark
1655 icon-theme-name=Adwaita
1656 font-name=DejaVu Sans Mono 11
1657 position=30%,end 50%,end
1661 ###############################################################################
1663 # prerun_* set up the configs needed before actually running the commands
1664 # setup_* are run after selecting a bootloader and build the command used later
1665 # they can also be used for further user input as these run before control is taken away
1669 EDIT_FILES[bootloader]="/etc/default/grub"
1671 if [[ $SYS == 'BIOS' ]]; then
1672 [[ $BOOT_DEV ]] || { part_device 1 || return 1; }
1673 BCMDS[grub]="grub-install --recheck --force --target=i386-pc $BOOT_DEV"
1675 BCMDS[grub]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1676 grub-install --recheck --force --target=x86_64-efi --efi-directory=/boot --bootloader-id=$DIST"
1677 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1680 BCMDS[grub]="mkdir -p /run/udev /run/lvm &&
1681 mount --bind /hostrun/udev /run/udev &&
1682 mount --bind /hostrun/lvm /run/lvm &&
1684 grub-mkconfig -o /boot/grub/grub.cfg &&
1685 sleep 1 && umount /run/udev /run/lvm"
1692 sed -i "s/GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR=\"${DIST}\"/g; s/GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"\"/g" "$MNT/etc/default/grub"
1694 if [[ $LUKS_DEV ]]; then
1695 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
1696 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"
1699 if [[ $SYS == 'BIOS' && $LVM && -z $SEP_BOOT ]]; then
1700 sed -i "s/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g" "$MNT/etc/default/grub" 2> "$ERR" 2>&1
1701 errshow 1 "sed -i 's/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g' $MNT/etc/default/grub"
1704 # setup for os-prober module
1705 mkdir -p /run/{lvm,udev} "$MNT/hostrun/"{lvm,udev}
1706 mount --bind /run/lvm "$MNT/hostrun/lvm"
1707 mount --bind /run/udev "$MNT/hostrun/udev"
1714 EDIT_FILES[bootloader]=""
1719 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1720 efibootmgr -v -d $BOOT_DEV -p $BOOT_PART_NUM -c -L '${DIST} Linux' -l /vmlinuz-${KERNEL} \
1721 -u 'root=$ROOT_PART_ID rw $([[ $UCODE ]] && printf 'initrd=\%s.img ' "$UCODE")initrd=\initramfs-${KERNEL}.img'"
1726 if [[ $SYS == 'BIOS' ]]; then
1727 EDIT_FILES[bootloader]="/boot/syslinux/syslinux.cfg"
1729 EDIT_FILES[bootloader]="/boot/EFI/syslinux/syslinux.cfg"
1730 BCMDS[syslinux]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1731 efibootmgr -v -c -d $BOOT_DEV -p $BOOT_PART_NUM -l /EFI/syslinux/syslinux.efi -L $DIST"
1737 local c="$MNT/boot/syslinux"
1738 local s="/usr/lib/syslinux/bios"
1740 if [[ $SYS == 'UEFI' ]]; then
1741 c="$MNT/boot/EFI/syslinux"
1742 s="/usr/lib/syslinux/efi64"
1745 mkdir -pv "$c" 2> "$ERR" 2>&1
1746 errshow 1 "mkdir -pv $c"
1747 cp -rfv "$s/"* "$c/" 2> "$ERR" 2>&1
1748 errshow 1 "cp -rfv $s/* $c/"
1749 cp -fv "$RUN/syslinux/splash.png" "$c/" 2> "$ERR" 2>&1
1750 errshow 0 "cp -fv $RUN/syslinux/splash.png $c/"
1751 cat > "$c/syslinux.cfg" <<- EOF
1753 MENU TITLE $DIST Boot Menu
1754 MENU BACKGROUND splash.png
1758 # see: https://www.syslinux.org/wiki/index.php/Comboot/menu.c32
1767 MENU HELPMSGENDROW 29
1768 MENU COLOR border 30;44 #40ffffff #a0000000 std
1769 MENU COLOR title 1;36;44 #9033ccff #a0000000 std
1770 MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
1771 MENU COLOR unsel 37;44 #50ffffff #a0000000 std
1772 MENU COLOR help 37;40 #c0ffffff #a0000000 std
1773 MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
1774 MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
1775 MENU COLOR msg07 37;40 #90ffffff #a0000000 std
1776 MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
1779 MENU LABEL $DIST Linux
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.img
1784 LABEL ${DIST}fallback
1785 MENU LABEL $DIST Linux Fallback
1786 LINUX $d/vmlinuz-$KERNEL
1787 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1788 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL-fallback.img
1795 EDIT_FILES[bootloader]="/boot/refind_linux.conf"
1796 BCMDS[refind-efi]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1; refind-install"
1801 cat > "$MNT/boot/refind_linux.conf" <<- EOF
1802 "$DIST Linux" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1803 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1804 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL.img"
1805 "$DIST Linux Fallback" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1806 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1807 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL-fallback.img"
1809 mkdir -p "$MNT/etc/pacman.d/hooks"
1810 cat > "$MNT/etc/pacman.d/hooks/refind.hook" <<- EOF
1817 Description = Updating rEFInd on ESP
1818 When = PostTransaction
1819 Exec = /usr/bin/refind-install
1823 setup_systemd-boot()
1825 EDIT_FILES[bootloader]="/boot/loader/entries/$DIST.conf"
1826 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1; bootctl --path=/boot install"
1829 prerun_systemd-boot()
1831 mkdir -p "$MNT/boot/loader/entries"
1832 cat > "$MNT/boot/loader/loader.conf" <<- EOF
1837 cat > "$MNT/boot/loader/entries/$DIST.conf" <<- EOF
1839 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1840 initrd /initramfs-$KERNEL.img
1841 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1843 cat > "$MNT/boot/loader/entries/$DIST-fallback.conf" <<- EOF
1844 title $DIST Linux Fallback
1845 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1846 initrd /initramfs-$KERNEL-fallback.img
1847 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1849 mkdir -p "$MNT/etc/pacman.d/hooks"
1850 cat > "$MNT/etc/pacman.d/hooks/systemd-boot.hook" <<- EOF
1857 Description = Updating systemd-boot
1858 When = PostTransaction
1859 Exec = /usr/bin/bootctl update
1861 systemd-machine-id-setup --root="$MNT"
1865 ###############################################################################
1870 no_bg_install || return 1
1874 dlg choice menu "Logical Volume Management" "$_lvmmenu" \
1875 "$_lvmnew" "vgcreate -f, lvcreate -L -n" \
1876 "$_lvmdel" "vgremove -f" \
1877 "$_lvmdelall" "lvrmeove, vgremove, pvremove -f" \
1878 "Back" "Return to the main menu"
1880 "$_lvmnew") lvm_create && break ;;
1881 "$_lvmdel") lvm_delgroup && yesno "$_lvmdel" "$_lvmdelask" && vgremove -f "$DEL_VG" > /dev/null 2>&1 ;;
1882 "$_lvmdelall") lvm_del_all ;;
1892 if [[ $(vgs -o vg_name --noheading 2> /dev/null) ]]; then
1893 if [[ $(lvs -o vg_name,lv_name --noheading --separator - 2> /dev/null) && $(pvs -o pv_name --noheading 2> /dev/null) ]]; then
1894 msg "LVM Setup" "\nActivating existing logical volume management.\n" 0
1895 modprobe dm-mod > /dev/null 2> "$ERR"
1896 errshow 'modprobe dm-mod'
1897 vgscan > /dev/null 2>&1
1898 vgchange -ay > /dev/null 2>&1
1905 VGROUP='' LVM_PARTS='' VGROUP_MB=0
1907 lvm_mkgroup || return 1
1908 local txt="\nThe last (or only) logical volume will automatically use all remaining space in the volume group."
1909 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 -
1910 [[ $VOL_COUNT ]] || return 1
1911 lvm_extra_lvs || return 1
1912 lvm_volume_name "$_lvmlvname\nNOTE: This LV will use up all remaining space in the volume group (${VGROUP_MB}MB)" || return 1
1913 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating volume $VNAME from remaining space in $VGROUP\n" 0
1914 lvcreate -l +100%FREE "$VGROUP" -n "$VNAME" > /dev/null 2> "$ERR"
1915 errshow "lvcreate -l +100%FREE $VGROUP -n $VNAME" || return 1
1916 LVM='logical volume'; sleep 0.5
1917 txt="\nDone, volume: $VGROUP-$VNAME (${VOLUME_SIZE:-${VGROUP_MB}MB}) has been created.\n"
1918 msg "$_lvmnew (LV:$VOL_COUNT)" "$txt\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE $LVM_PARTS)\n"
1924 local txt="${VGROUP}: ${SIZE}$SIZE_UNIT (${VGROUP_MB}MB remaining).$_lvmlvsize"
1928 dlg VOLUME_SIZE input "$_lvmnew (LV:$VOL_COUNT)" "$txt" ''
1929 if [[ -z $VOLUME_SIZE ]]; then
1931 break # allow bailing with escape or an empty choice
1932 elif (( ${VOLUME_SIZE:0:1} == 0 )); then
1933 ERR_SIZE=1 # size values can't begin with '0'
1935 # walk the string and make sure all but the last char are digits
1936 local lv=$((${#VOLUME_SIZE} - 1))
1937 for (( i=0; i<lv; i++ )); do
1938 [[ ${VOLUME_SIZE:$i:1} =~ [0-9] ]] || { ERR_SIZE=1; break; }
1940 if (( ERR_SIZE != 1 )); then
1941 case ${VOLUME_SIZE:$lv:1} in
1942 [mMgG]) local s=${VOLUME_SIZE:0:$lv} m=$((s * 1000))
1943 case ${VOLUME_SIZE:$lv:1} in
1944 [Gg]) (( m >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - m)) ;;
1945 [Mm]) (( ${VOLUME_SIZE:0:$lv} >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - s)) ;;
1952 if (( ERR_SIZE )); then
1953 msg "Invalid Logical Volume Size" "$_lvmerrlvsize"
1966 until [[ $named ]]; do
1967 lvm_partitions || return 1
1968 lvm_group_name || return 1
1969 yesno "$_lvmnew" "\nCreate volume group: $VGROUP\n\nusing these partition(s): $LVM_PARTS\n" && named=true
1972 msg "$_lvmnew" "\nCreating volume group: $VGROUP\n" 0
1973 vgcreate -f "$VGROUP" $LVM_PARTS > /dev/null 2> "$ERR"
1974 errshow "vgcreate -f $VGROUP $LVM_PARTS" || return 1
1976 SIZE=$(vgdisplay "$VGROUP" | awk '/VG Size/ { gsub(/[^0-9.]/, ""); print int($0) }')
1977 SIZE_UNIT="$(vgdisplay "$VGROUP" | awk '/VG Size/ { print substr($NF, 0, 1) }')"
1979 if [[ $SIZE_UNIT == 'G' ]]; then
1980 VGROUP_MB=$((SIZE * 1000))
1985 msg "$_lvmnew" "\nVolume group $VGROUP (${SIZE}$SIZE_UNIT) successfully created\n"
1991 pv="$(pvs -o pv_name --noheading 2> /dev/null)"
1992 v="$(lvs -o vg_name,lv_name --noheading --separator - 2> /dev/null)"
1993 VGROUP="$(vgs -o vg_name --noheading 2> /dev/null)"
1995 if [[ $VGROUP || $v || $pv ]]; then
1996 if yesno "$_lvmdelall" "$_lvmdelask"; then
1997 for i in $v; do lvremove -f "/dev/mapper/$i" > /dev/null 2>&1; done
1998 for i in $VGROUP; do vgremove -f "$i" > /dev/null 2>&1; done
1999 for i in $pv; do pvremove -f "$i" > /dev/null 2>&1; done
2003 msg "Delete LVM" "\nNo LVMs to remove...\n" 2
2013 for i in $(lvs --noheadings | awk '{print $2}' | uniq); do
2014 VOL_GROUP_LIST+="$i $(vgdisplay "$i" | awk '/VG Size/ {print $3$4}') "
2017 [[ $VOL_GROUP_LIST ]] || { msg "No Groups" "\nNo volume groups found."; return 1; }
2019 dlg DEL_VG menu "Logical Volume Management" "\nSelect volume group to delete.\n\nAll logical volumes within will also be deleted." $VOL_GROUP_LIST
2025 while (( VOL_COUNT > 1 )); do
2026 lvm_volume_name "$_lvmlvname" && lvm_lv_size || return 1
2027 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating a $VOLUME_SIZE volume $VNAME in $VGROUP\n" 0
2028 lvcreate -L "$VOLUME_SIZE" "$VGROUP" -n "$VNAME" > /dev/null 2> "$ERR"
2029 errshow "lvcreate -L $VOLUME_SIZE $VGROUP -n $VNAME" || return 1
2030 msg "$_lvmnew (LV:$VOL_COUNT)" "\nDone, logical volume (LV) $VNAME ($VOLUME_SIZE) has been created.\n"
2038 part_find 'part|crypt' || return 1
2039 PARTS="$(awk 'NF > 0 {print $0 " off"}' <<< "$PARTS")"
2040 dlg LVM_PARTS check "$_lvmnew" "\nSelect the partition(s) to use for the physical volume (PV)." $PARTS
2047 until [[ $VGROUP ]]; do
2048 dlg VGROUP input "$_lvmnew" "$_lvmvgname" "lvgroup"
2049 if [[ -z $VGROUP ]]; then
2051 elif [[ ${VGROUP:0:1} == "/" || $VGROUP =~ \ |\' ]] || vgdisplay | grep -q "$VGROUP"; then
2052 msg "LVM Name Error" "$_lvmerrvgname"
2062 local txt="$1" default="mainvolume"
2063 (( VOL_COUNT > 1 )) && default="extvolume$VOL_COUNT"
2064 until [[ $VNAME ]]; do
2065 dlg VNAME input "$_lvmnew (LV:$VOL_COUNT)" "\n$txt" "$default"
2066 if [[ -z $VNAME ]]; then
2068 elif [[ ${VNAME:0:1} == "/" || $VNAME =~ \ |\' ]] || lsblk | grep -q "$VNAME"; then
2069 msg "LVM Name Error" "$_lvmerlvname"
2076 ###############################################################################
2082 no_bg_install || return 1
2083 dlg choice menu "LUKS Encryption" "$_luksmenu" \
2084 "$_luksnew" "cryptsetup -q luksFormat" \
2085 "$_luksopen" "cryptsetup open --type luks" \
2086 "$_luksadv" "cryptsetup -q -s -c luksFormat" \
2087 "Back" "Return to the main menu"
2090 "$_luksnew") luks_basic || return 1 ;;
2091 "$_luksopen") luks_open || return 1 ;;
2092 "$_luksadv") luks_advanced || return 1 ;;
2100 modprobe -a dm-mod dm_crypt > /dev/null 2>&1
2102 part_find 'part|crypt|lvm' || return 1
2104 if (( COUNT == 1 )); then
2105 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2107 dlg LUKS_PART menu "$_luksopen" "\nSelect which partition to open." $PARTS
2110 [[ $LUKS_PART ]] || return 1
2112 luks_pass "$_luksopen" || return 1
2113 msg "$_luksopen" "\nOpening encrypted partition: $LUKS_NAME\n\nUsing device/volume: $LUKS_PART\n" 0
2114 cryptsetup open --type luks "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> "$ERR"
2115 errshow "cryptsetup open --type luks $LUKS_PART $LUKS_NAME" || return 1
2116 LUKS='encrypted'; luks_show
2124 typeset -a ans=(cryptroot) # default name to start
2126 until [[ $LUKS_PASS ]]; do
2128 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " --mixedform "$_luksomenu" 0 0 0 \
2129 "Name:" 1 1 "${ans[0]}" 1 7 "$COLUMNS" 0 0 \
2130 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
2131 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 2> "$ANS" || return 1
2133 mapfile -t ans <"$ANS"
2135 if [[ -z "${ans[0]}" ]]; then
2136 msg "Name Empty" "\nEncrypted device name cannot be empty.\n\nPlease try again.\n" 2
2137 elif [[ -z "${ans[1]}" || "${ans[1]}" != "${ans[2]}" ]]; then
2138 LUKS_NAME="${ans[0]}"
2139 msg "Password Mismatch" "\nThe passwords entered do not match.\n\nPlease try again.\n" 2
2141 LUKS_NAME="${ans[0]}"
2142 LUKS_PASS="${ans[1]}"
2152 msg "$_luksnew" "\nEncrypted partition ready for mounting.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$LUKS_PART")\n\n"
2157 modprobe -a dm-mod dm_crypt > /dev/null 2>&1
2159 part_find 'part|lvm' || return 1
2161 if [[ $AUTO_ROOT_PART ]]; then
2162 LUKS_PART="$AUTO_ROOT_PART"
2163 elif (( COUNT == 1 )); then
2164 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2166 dlg LUKS_PART menu "$_luksnew" "\nSelect the partition you want to encrypt." $PARTS
2169 [[ $LUKS_PART ]] || return 1
2170 luks_pass "$_luksnew"
2175 luks_setup || return 1
2176 msg "$_luksnew" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2177 cryptsetup -q luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2> "$ERR"
2178 errshow "cryptsetup -q luksFormat $LUKS_PART" || return 1
2179 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> "$ERR"
2180 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2181 LUKS='encrypted'; luks_show
2189 dlg cipher input "LUKS Encryption" "$_lukskey" "-s 512 -c aes-xts-plain64"
2190 [[ $cipher ]] || return 1
2191 msg "$_luksadv" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2192 cryptsetup -q $cipher luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2> "$ERR"
2193 errshow "cryptsetup -q $cipher luksFormat $LUKS_PART" || return 1
2194 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> "$ERR"
2195 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2202 ###############################################################################
2204 # some help avoid repetition and improve usability of some commands
2205 # others are initial setup functions used before reaching the main loop
2209 [[ "$2" == *"$1"* ]] && printf "on" || printf "off"
2214 # cleanup and exit the installer cleanly with exit code $1
2215 local e="$1" # when e is 127 unmount /run/archiso/bootmnt and reboot
2219 if [[ -d $MNT ]]; then
2221 (( e == 127 )) && umount_dir /run/archiso/bootmnt && sleep 0.5 && reboot -f
2228 local var="$1" # assign output from dialog to var
2229 local dlg_t="$2" # dialog type (menu, check, input)
2230 local title="$3" # dialog title
2231 local body="$4" # dialog message
2232 local n=0 # number of items to display for menu and check dialogs
2234 shift 4 # shift off args assigned above
2236 # adjust n when passed a large list
2237 local l=$((LINES - 20))
2238 (( ($# / 2) > l )) && n=$l
2242 menu) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --menu "$body" 0 0 $n "$@" 2> "$ANS" || return 1 ;;
2243 check) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --checklist "$body" 0 0 $n "$@" 2> "$ANS" || return 1 ;;
2246 local def="$1" # assign default value for input
2248 if [[ $1 == 'limit' ]]; then
2249 dialog --backtitle "$DIST Installer - $SYS - v$VER" --max-input 63 --title " $title " --inputbox "$body" 0 0 "$def" 2> "$ANS" || return 1
2251 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --inputbox "$body" 0 0 "$def" 2> "$ANS" || return 1
2255 # if answer file isn't empty read from it into $var
2256 [[ -s "$ANS" ]] && printf -v "$var" "%s" "$(< "$ANS")"
2261 # displays a message dialog
2262 # when more than 2 args the message will disappear after sleep time ($3)
2268 dialog --backtitle "$DIST Installer - $SYS - v$VER" --sleep "$1" --title " $title " --infobox "$body\n" 0 0
2270 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --msgbox "$body\n" 0 0
2278 if ! select_keymap; then
2281 elif ! net_connect; then
2282 msg "Not Connected" "\nRunning live requires an active internet connection to install packages.\n\nExiting..\n" 2
2284 elif (( $(awk '/MemTotal/ {print int($2 / 1024)}' /proc/meminfo) < 2500)); then
2285 msg "Not Enough Memory" "\nLive session requires at least 2.5G of system memory for installing packages.\n\nExiting..\n" 2
2290 echo "Sorting mirrorlist"
2291 mount /run/archiso/cowspace -o remount,size=2G
2292 install_mirrorlist "/etc/pacman.d/mirrorlist"
2293 pacman -Syyu --noconfirm || die 1
2294 rm -rf /var/cache/pacman/pkg/*
2295 pacman -S $BASE_PKGS $AL_BASE_PKGS xorg-xinit --needed --noconfirm || die 1
2296 rm -rf /var/cache/pacman/pkg/*
2298 i3-gaps|openbox|fluxbox|bspwm|awesome|xfce4|jwm) pacman -S "$ses" $WM_BASE_PKGS ${WM_EXT[$ses]} --needed --noconfirm || die 1 ;;
2299 gnome|plasma|cinnamon) pacman -S "$ses" ${WM_EXT[$ses]} --needed --noconfirm || die 1 ;;
2300 dwm) { pacman -S git --needed --noconfirm || die 1; }; install_suckless "/root" nochroot ;;
2302 rm -rf /var/cache/pacman/pkg/*
2303 [[ $VM ]] && dmesg | grep -qi 'vbox' && pacman -S virtualbox-guest-utils virtualbox-guest-modules-arch --needed --noconfirm
2304 pacman -Scc --noconfirm
2305 rm -rf /var/cache/pacman/pkg/*
2306 cp -rfT /etc/skel /root
2307 [[ $TEARFREE ]] && install_tearfree_conf "/etc/X11/xorg.conf.d"
2309 plasma|gnome|cinnamon) sed -i '/super/d; /nitrogen/d; /compton/d' /root/.xprofile ;;
2310 dwm) sed -i '/super/d; /compton/d' /root/.xprofile ;;
2313 echo -e "pulseaudio &\n(sleep 1; pamixer --unmute --set-volume 50) &" >> /root/.xprofile
2314 sed -i "/exec/ c exec ${WM_SESSIONS[$ses]}" /root/.xinitrc
2315 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]}"
2322 usage: $1 [-hdl] [session]
2325 -h, --help print this message and exit
2326 -l, --live install and setup a live session
2327 -d, --debug enable xtrace and log output to $DBG
2328 -t, --tearfree install and setup drivers for nvidia or tearfree xorg configs for other vendors
2329 if you experience boot issues with this option you can remove
2330 /etc/X11/xorg.conf.d/20-*.conf
2333 i3-gaps - A fork of i3wm with more features including gaps
2334 openbox - A lightweight, powerful, and highly configurable stacking wm
2335 dwm - A dynamic WM for X that manages windows in tiled, floating, or monocle layouts
2336 awesome - A customized Awesome WM session created by @elanapan
2337 bspwm - A tiling wm that represents windows as the leaves of a binary tree
2338 fluxbox - A lightweight and highly-configurable window manager
2339 gnome - A desktop environment that aims to be simple and easy to use
2340 cinnamon - A desktop environment combining traditional desktop with modern effects
2341 plasma - A kde software project currently comprising a full desktop environment
2342 xfce4 - A lightweight and modular desktop environment based on gtk+2/3
2346 set the DIST environment variable before launching the installer eg.
2350 root/boot partition:
2352 set the ROOT_PART and/or BOOT_PART environment variables before launching the installer eg.
2354 ROOT_PART='/dev/sda2' BOOT_PART='/dev/sda1' $1
2358 set the EDITOR environment variable before launching the installer eg.
2368 local title="$1" body="$2" yes='Yes' no='No'
2369 (( $# >= 3 )) && yes="$3"
2370 (( $# >= 4 )) && no="$4"
2372 if (( $# == 5 )); then
2373 dialog --backtitle "$DIST Installer - $SYS - v$VER" --defaultno --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2375 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2381 arch-chroot "$MNT" bash -c "$1"
2386 export PS4='| ${BASH_SOURCE} LINE:${LINENO} FUNC:${FUNCNAME[0]:+ ${FUNCNAME[0]}()} |> '
2396 "\e]P0191919" # #191919
2397 "\e]P1D15355" # #D15355
2398 "\e]P2609960" # #609960
2399 "\e]P3FFCC66" # #FFCC66
2400 "\e]P4255A9B" # #255A9B
2401 "\e]P5AF86C8" # #AF86C8
2402 "\e]P62EC8D3" # #2EC8D3
2403 "\e]P7949494" # #949494
2404 "\e]P8191919" # #191919
2405 "\e]P9D15355" # #D15355
2406 "\e]PA609960" # #609960
2407 "\e]PBFF9157" # #FF9157
2408 "\e]PC4E88CF" # #4E88CF
2409 "\e]PDAF86C8" # #AF86C8
2410 "\e]PE2ec8d3" # #2ec8d3
2411 "\e]PFE1E1E1" # #E1E1E1
2414 [[ $TERM == 'linux' ]] && printf "%b" "${colors[@]}" && clear
2419 [ $? -eq 0 ] && return 0
2421 local fatal=0 err=""
2422 err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
2423 [[ -z $err ]] && err="no error message was found"
2425 (( $1 == 1 )) && { fatal=1; shift; }
2427 local txt="\nCommand: $1\n\n\n\nError: $err\n\n"
2429 if (( fatal )); then
2430 msg "Install Error" "${txt}Errors at this stage are fatal, the install cannot continue.\n"
2431 [[ -r $DBG && $TERM == 'linux' ]] && less "$DBG"
2435 msg "Install Error" "${txt}Errors at this stage are non-fatal and may be fixed or ignored depending on the error.\n"
2443 if (( $1 >= 0 )) && ! grep -qw "$MNT" /proc/mounts; then
2444 msg "Not Mounted" "\nPartition(s) must be mounted first.\n" 2
2446 elif [[ $1 -ge 1 && -z $BOOTLDR ]]; then
2447 msg "No Bootloader" "\nBootloader must be selected first.\n" 2
2449 elif [[ $1 -ge 2 && (-z $NEWUSER || -z $USER_PASS) ]]; then
2450 msg "No User" "\nA user must be created first.\n" 2
2452 elif [[ $1 -ge 3 && -z $CONFIG_DONE ]]; then
2453 msg "Not Configured" "\nSystem configuration must be done first.\n" 2
2456 (( i )) # return code
2461 mount | grep -q 'swap' && swapoff -a
2463 if [[ -d $dir ]] && mount | grep -q "on $dir "; then
2464 if ! umount "$dir" 2> /dev/null; then
2466 umount -f "$dir" 2> /dev/null || umount -l "$dir"
2474 msg "Network Connect" "\nVerifying network connection\n" 0
2475 curl -sIN --connect-timeout 5 'https://www.archlinux.org/' | sed '1q' | grep -q '200'
2480 if chk_connect; then
2482 elif hash nmtui > /dev/null 2>&1; then
2484 if [[ $TERM == 'linux' ]]; then
2485 printf "%b" "\e]P1191919" "\e]P4191919"
2487 printf "%b" "\e]P1D15355" "\e]P4255a9b"
2492 elif hash wifi-menu > /dev/null 2>&1; then
2502 [[ $BG_PID ]] || return 0
2503 msg "Install Running" "\nA background install process is currently running.\n" 2
2509 IGNORE_DEV="$(lsblk -lno NAME,MOUNTPOINT | awk '/\/run\/archiso\/bootmnt/ {sub(/[1-9]/, ""); print $1}')"
2511 if [[ $IGNORE_DEV ]]; then
2512 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ && !'"/$IGNORE_DEV/"' {print "/dev/" $1 " " $2}')"
2514 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ {print "/dev/" $1 " " $2}')"
2517 if [[ -z $SYS_DEVS ]]; then
2518 msg "Device Error" "\nNo available devices...\n\nExiting..\n" 2
2523 while read -r line; do
2525 done <<< "$SYS_DEVS"
2532 # amd-ucode is not needed it's provided by linux-firmware
2533 # elif grep -q 'AuthenticAMD' /proc/cpuinfo; then
2535 elif grep -q 'GenuineIntel' /proc/cpuinfo; then
2539 modprobe -q efivarfs > /dev/null 2>&1
2541 if [[ -d /sys/firmware/efi/efivars ]]; then
2543 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars
2549 ###############################################################################
2552 # enable some nicer colours in the linux console
2555 if (( UID != 0 )); then
2556 msg "Not Root" "\nThis installer must be run as root or using sudo.\n\nExiting..\n" 2
2558 elif ! grep -qwm 1 'lm' /proc/cpuinfo; then
2559 msg "Not x86_64 Architecture" "\nThis installer only supports x86_64 architectures.\n\nExiting..\n" 2
2563 # trap ^C to perform cleanup
2564 trap 'printf "\n^C\n" && die 1' INT
2566 while getopts ":htl:d" OPT; do
2572 if [[ "${!WM_SESSIONS[@]}" =~ $OPTARG ]]; then
2575 echo "error: invalid session for -l, see -h for help"; die 1
2578 \?) echo "error: invalid option: -$OPTARG"; die 1 ;;
2585 msg "Welcome to the $DIST Installer" "$_welcome"
2587 if ! select_keymap; then
2589 elif ! net_connect; then
2590 msg "Not Connected" "\nThis installer requires an active internet connection.\n\nExiting..\n" 2
2597 # vim:fdm=marker:fmr={,}