3 # This program is free software, provided under the GNU GPL
4 # Written by Nathaniel Maia for use in Archlabs
5 # Some ideas and code reworked from other resources
6 # AIF, Calamares, and the Arch Wiki.. Credit where credit is due
8 # check for syntax errors
15 : ${DIST=ArchLabs} # distro name if not set
16 MNT=/mnt # installation root mountpoint
17 ANS=/tmp/ans # dialog answer output file
18 BOOTDIR=boot # location to mount boot partition
19 FONT=ter-i16n # font used for the linux console
20 HOOKS=shutdown # additional mkinitcpio HOOKS
21 SEL=0 # currently selected menu item
22 SYS=Unknown # bios type, to be determined: UEFI/BIOS
23 ERR=/tmp/errlog # stderr log used internally by errshow()
24 DBG=/tmp/debuglog # debug log file when passed -d
25 RUN=/run/archiso/bootmnt/arch/boot # path for live system /boot
26 VM="$(dmesg | grep -i hypervisor)" # system running in a virtual machine
27 EXMNTS="" # extra partitions that were mounted, used to verify mountpoint and show user
28 FORMATTED="" # partitions that have been formatted, allows skipping the format step
29 USER_CMD="" # optional command(s) entered by the user to run in the chroot
30 export DIALOGOPTS="--cr-wrap" # dialog environment variable to hold default options, see `man dialog`
32 BASE_PKGS="base xorg xorg-drivers sudo git gvfs gtk3 libmad libmatroska tumbler "
33 BASE_PKGS+="playerctl pulseaudio pulseaudio-alsa pavucontrol pamixer scrot xdg-user-dirs "
34 BASE_PKGS+="ffmpeg gstreamer gst-libav gst-plugins-base gst-plugins-good bash-completion xterm"
36 AL_BASE_PKGS="archlabs-keyring archlabs-icons archlabs-fonts archlabs-themes "
37 AL_BASE_PKGS+="archlabs-baph archlabs-wallpapers archlabs-scripts archlabs-skel-base"
39 WM_BASE_PKGS="arandr nitrogen polkit-gnome network-manager-applet "
40 WM_BASE_PKGS+="volumeicon xclip exo laptop-detect xdotool compton wmctrl feh "
41 WM_BASE_PKGS+="gnome-keyring dunst gsimplecal xfce4-power-manager xfce4-settings"
43 SYS_MEM="$(awk '/MemTotal/ {print int($2 / 1024) "M"}' /proc/meminfo)"
44 LOCALES="$(awk '/\.UTF-8/ {gsub(/# .*|#/, ""); if ($1) {print $1 " - "}}' /etc/locale.gen)"
45 CMAPS="$(find /usr/share/kbd/keymaps -name '*.map.gz' | awk '{gsub(/\.map\.gz|.*\//, ""); print $1 " - "}' | sort)"
47 [[ $LINES ]] || LINES=$(tput lines)
48 [[ $COLUMNS ]] || COLUMNS=$(tput cols)
52 # commands used to install each bootloader, however most get modified during runtime {
54 [refind-efi]='refind-install'
55 [grub]='grub-install --recheck --force' [syslinux]='syslinux-install_update -i -a -m'
56 [efistub]='efibootmgr -v -d /dev/sda -p 1 -c -l' [systemd-boot]='bootctl --path=/boot install'
59 # executable name for each wm/de used in ~/.xinitrc {
60 declare -A WM_SESSIONS=(
61 [dwm]='dwm' [jwm]='jwm' [i3-gaps]='i3' [bspwm]='bspwm' [awesome]='awesome' [plasma]='startkde' [xfce4]='startxfce4'
62 [gnome]='gnome-session' [fluxbox]='startfluxbox' [openbox]='openbox-session' [cinnamon]='cinnamon-session'
65 # packages installed for each wm/de, most are depends of the skel packages {
67 [dwm]='' [jwm]='' [gnome]='' [cinnamon]='gnome-terminal' [plasma]='kdebase-meta'
68 [awesome]='archlabs-skel-awesome' [bspwm]='archlabs-skel-bspwm' [fluxbox]='archlabs-skel-fluxbox'
69 [i3-gaps]='archlabs-skel-i3-gaps' [openbox]='archlabs-skel-openbox' [xfce4]='archlabs-skel-xfce4 xfce4-goodies'
72 # files offered for editing after install is complete {
73 declare -A EDIT_FILES=(
74 [login]='' # login is populated once we know the username and shell
75 [fstab]='/etc/fstab' [sudoers]='/etc/sudoers' [crypttab]='/etc/crypttab' [pacman]='/etc/pacman.conf'
76 [console]='/etc/vconsole.conf' [mkinitcpio]='/etc/mkinitcpio.conf' [hostname]='/etc/hostname /etc/hosts'
77 [bootloader]="/boot/loader/entries/$DIST.conf" # ** based on bootloader
78 [locale]='/etc/locale.conf /etc/default/locale' [keyboard]='/etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard'
81 # mkfs command flags for filesystem formatting {
82 declare -A FS_CMD_FLAGS=(
83 [f2fs]='' [jfs]='-q' [xfs]='-f' [ntfs]='-q' [ext2]='-q' [ext3]='-q' [ext4]='-q' [vfat]='-F32' [nilfs2]='-q' [reiserfs]='-q'
86 # mount options for each filesystem {
88 [vfat]='' [ntfs]='' [ext2]='' [ext3]='' # NA
89 [jfs]='discard errors=continue errors=panic nointegrity'
90 [reiserfs]='acl nolog notail replayonly user_xattr off'
91 [ext4]='discard dealloc nofail noacl relatime noatime nobarrier nodelalloc'
92 [xfs]='discard filestreams ikeep largeio noalign nobarrier norecovery noquota wsync'
93 [nilfs2]='discard nobarrier errors=continue errors=panic order=relaxed order=strict norecovery'
94 [f2fs]='discard fastboot flush_merge data_flush inline_xattr inline_data noinline_data inline_dentry no_heap noacl nobarrier norecovery noextent_cache disable_roll_forward disable_ext_identify'
97 # packages installed for each login option {
98 declare -A LOGIN_PKGS=(
99 [xinit]='xorg-xinit' [ly]='archlabs-ly' [gdm]='gdm' [sddm]='sddm'
100 [lightdm]='lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings accountsservice'
103 # extras installed for user selected packages {
104 # if a package requires additional packages that aren't already dependencies
105 # they can be added here eg. [package]="extra"
107 [vlc]='qt4' [mpd]='mpc' [mupdf]='mupdf-tools'
108 [rxvt-unicode]='urxvt-perls' [zathura]='zathura-pdf-poppler' [noto-fonts]='noto-fonts-emoji' [cairo-dock]='cairo-dock-plug-ins' [qt5ct]='qt5-styleplugins'
109 [vlc]='qt5ct qt5-styleplugins' [qutebrowser]='qt5ct qt5-styleplugins' [qbittorrent]='qt5ct qt5-styleplugins' [transmission-qt]='qt5ct qt5-styleplugins'
110 [bluez]='bluez-libs bluez-utils bluez-tools bluez-plugins bluez-hid2hci' [kdenlive]='kdebase-meta dvdauthor frei0r-plugins breeze breeze-gtk qt5ct qt5-styleplugins'
113 # dialog text variables {
114 # Basics (somewhat in order)
115 _welcome="\nThis will help you get $DIST installed and setup on your system.\n\nIf you are unsure about a section the default option will be listed or\nthe first selected item will be the default.\n\n\nMenu Navigation:\n\n - Select items with the arrow keys or the option number.\n - Use [Space] to toggle check boxes and [Enter] to accept.\n - Switch between fields using [Tab] or the arrow keys.\n - Use [Page Up] and [Page Down] to jump whole pages\n - Press the highlighted key of an option to select it.\n"
116 _keymap="\nPick which keymap to use for the system from the list below\n\nThis is used once a graphical environment is running (Xorg).\n\nSystem default: us"
117 _vconsole="\nSelect the console keymap, the console is the tty shell you reach before starting a graphical environment (Xorg).\n\nIts keymap is seperate from the one used by the graphical environments, though many do use the same such as 'us' English.\n\nSystem default: us"
118 _prep="\nThis is the installer main menu, once a step is complete you will return here.\n\nOn successful completion of a step the cursor will be advanced to the next step\nOn failure the cursor will be placed on the step required to advance (when possible).\n\nSteps beginning with an asterix (*) are required.\n\nOnce you're happy with the choices and the required steps are complete, selecting the final step will begin the install."
119 _device="\nSelect a device to use from the list below.\n\nDevices (/dev) are the available drives on the system. /sda, /sdb, /sdc ..."
120 _resize="\nSelect a new filesystem size in MB, a new partition will be created from the free space but will be left unformatted.\nThe lowest size is just enough to fit the currently in use space on the partition while the default is set to split the free space evenly.\n\nUse Tab or the arrow keys move the cursor between the buttons and the value, when the cursor is on the value, you can edit it by:\n\n - left/right cursor movement to select a digit to modify\n - +/- characters to increment/decrement the digit by one\n - 0 through 9 to set the digit to the given value\n\nSome keys are also recognized in all cursor positions:\n\n - Home/End set the value to its maximum or minimum\n - Pageup/Pagedown increment the value so that the slider moves by one column."
121 _mount="\nUse [Space] to toggle mount options from below, press [Enter] when done to confirm selection.\n\nNot selecting any and confirming will run an automatic mount."
122 _warn="\nIMPORTANT:\n\nChoose carefully when editing, formatting, and mounting partitions or your DATA MAY BE LOST.\n\nTo mount a partition without formatting it, select 'skip' when prompted to choose a filesystem during the mounting stage.\nThis can only be used for partitions that already contain a filesystem and cannot be the root (/) partition, it needs to be formatted before install.\n"
123 _part="\nFull device auto partitioning is available for beginners otherwise cfdisk is recommended.\n\n - All systems will require a root partition (8G or greater).\n - UEFI or BIOS using LUKS without LVM require a separate boot partition (100-512M)."
124 _uefi="\nSelect the EFI boot partition (/boot), required for UEFI boot.\n\nIt's usually the first partition on the device, 100-512M, and will be formatted as vfat/fat32 if not already."
125 _bios="\nDo you want to use a separate boot partition? (optional)\n\nIt's usually the first partition on the device, 100-512M, and will be formatted as ext3/4 if not already."
126 _biosluks="\nSelect the boot partition (/boot), required for LUKS.\n\nIt's usually the first partition on the device, 100-512M, and will be formatted as ext3/4 if not already."
127 _format="is already formatted correctly.\n\nFor a clean install, previously existing partitions should be reformatted, however this removes ALL data (bootloaders) on the partition so choose carefully.\n\nDo you want to reformat the partition?\n"
128 _swapsize="\nEnter the size of the swapfile in megabytes (M) or gigabytes (G).\n\neg. 100M will create a 100 megabyte swapfile, while 10G will create a 10 gigabyte swapfile.\n\nFor ease of use and as an example it is filled in to match the size of your system memory (RAM).\n\nMust be greater than 1, contain only whole numbers, and end with either M or G."
129 _expart="\nYou can now choose any additional partitions you want mounted, you'll be asked for a mountpoint after.\n\nSelect 'done' to finish the mounting step and begin unpacking the base system in the background."
130 _exmnt="\nWhere do you want the partition mounted?\n\nEnsure the name begins with a slash (/).\nExamples include: /usr, /home, /var, etc."
131 _user="\nEnter a name and password for the new user account.\n\nThe name must not use capital letters, contain any periods (.), end with a hyphen (-), or include any colons (:)\n\nNOTE: Use [Up], [Down], or [Tab] to switch between fields, and [Enter] to accept."
132 _hostname="\nEnter a hostname for the new system.\n\nA hostname is used to identify systems on the network.\n\nIt's restricted to alphanumeric characters (a-z, A-Z, 0-9).\nIt can contain hyphens (-) BUT NOT at the beggining or end."
133 _locale="\nLocale determines the system language and currency formats.\n\nThe format for locale names is languagecode_COUNTRYCODE\n\neg. en_US is: english United States\n en_GB is: english Great Britain"
134 _timez="\nThe time zone is used to set the system clock.\n\nSelect your country or continent from the list below"
135 _timesubz="\nSelect the nearest city to you or one with the same time zone.\n\nTIP: Pressing the first letter of the city name repeatedly will navigate between entries beggining with that letter."
136 _sessions="\nUse [Space] to toggle available sessions, use [Enter] to accept the selection and continue.\n\nA basic package set will be installed for compatibility and functionality."
137 _login="\nSelect which of your session choices to use for the initial login.\n\nYou can be change this later by editing your ~/.xinitrc"
138 _autologin="\nDo you want autologin enabled for USER?\n\nIf so the following two files will be created (disable autologin by removing them):\n\n - /home/USER/RC (run startx when logging in on tty1)\n - /etc/systemd/system/getty@tty1.service.d/autologin.conf (login USER without password)\n"
139 _packages="\nUse [Space] to move a package into the selected area and press [Enter] to accept the selection.\n\nPackages may be installed by your DE/WM (if any), or for the packages you select."
140 _usercmd="\nEnter command to be run in the newly installed system (chroot) below.\n\nAn example use case would be installing packages or editing files not offered in the menus.\n\nBecause the command will be run in a chroot not every command will function correctly, additionally the command will not be sanity checked, it's your system so exercise caution.\n\nMore than one command may be run using standard bash syntax.\n"
141 _edit="\nBefore exiting you can select configuration files to review/change.\n\nIf you need to make other changes with the drives still mounted, use Ctrl-z to pause the installer, when finished type 'fg' and [Enter] to resume the installer, if you want to avoid the automatic reboot using Ctrl-c will cleanly exit."
144 _luksnew="Basic LUKS Encryption"
145 _luksadv="Advanced LUKS Encryption"
146 _luksopen="Open Existing LUKS Partition"
147 _luksmenu="\nA seperate boot partition without encryption or logical volume management (LVM) is required (except BIOS systems using grub).\n\nBasic uses the default encryption settings, and is recommended for beginners. Advanced allows cypher and key size parameters to be entered manually."
148 _luksomenu="\nEnter a name and password for the encrypted device.\n\nIt is not necessary to prefix the name with /dev/mapper/,an example has been provided."
149 _lukskey="Once the specified flags have been amended, they will automatically be used with the 'cryptsetup -q luksFormat /dev/...' command.\n\nNOTE: Do not specify any additional flags such as -v (--verbose) or -y (--verify-passphrase)."
152 _lvmmenu="\nLogical volume management (LVM) allows 'virtual' hard drives (volume groups) and partitions (logical volumes) to be created from existing device partitions.\n\nA volume group must be created first, then one or more logical volumes within it.\n\nLVM can also be used with an encrypted partition to create multiple logical volumes (e.g. root and home) within it."
153 _lvmnew="Create Volume Group and Volume(s)"
154 _lvmdel="Delete an Existing Volume Group"
155 _lvmdelall="Delete ALL Volume Group(s) and Volume(s)"
156 _lvmvgname="\nEnter a name for the volume group (VG) being created from the partition(s) selected."
157 _lvmlvname="\nEnter a name for the logical volume (LV) being created.\n\nThis is similar to setting a label for a partition."
158 _lvmlvsize="\nEnter what size you want the logical volume (LV) to be in megabytes (M) or gigabytes (G).\n\neg. 100M will create a 100 megabyte volume, 10G will create a 10 gigabyte volume."
159 _lvmdelask="\nConfirm deletion of volume group(s) and logical volume(s).\n\nDeleting a volume group, will delete all logical volumes within it.\n"
162 _errexpart="\nCannot mount partition due to a problem with the mountpoint.\n\nEnsure it begins with a slash (/) followed by atleast one character.\n"
163 _errpart="\nYou need create the partiton(s) first.\n\n\nBIOS systems require at least one partition (ROOT).\n\nUEFI systems require at least two (ROOT and EFI).\n"
164 _lukserr="\nA minimum of two partitions are required for encryption:\n\n 1. root (/) - standard or LVM.\n 2. boot (/boot) - standard (unless using LVM on BIOS systems).\n"
165 _lvmerr="\nThere are no viable partitions available to use for LVM, a minimum of one is required.\n\nIf LVM is already in use, deactivating it will allow the partition(s) to be used again.\n"
166 _lvmerrvgname="\nInvalid name entered.\n\nThe volume group name may be alpha-numeric, but may not contain spaces, start with a '/', or already be in use.\n"
167 _lvmerlvname="\nInvalid name entered.\n\nThe logical volume (LV) name may be alpha-numeric, but may not contain spaces or be preceded with a '/'\n"
168 _lvmerrlvsize="\nInvalid value Entered.\n\nMust be a numeric value with 'M' (megabytes) or 'G' (gigabytes) at the end.\n\neg. 400M, 10G, 250G, etc...\n\nThe value may also not be equal to or greater than the remaining size of the volume group.\n"
172 ###############################################################################
174 # main is the entry point which calls functions including outside of its block
175 # once those functions finished they always are returned here with the
176 # exception of install_main(), it exits upon completion
180 (( SEL < 13 )) && (( SEL++ ))
182 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Prepare " --default-item $SEL --cancel-label 'Exit' --menu "$_prep" 0 0 0 \
183 1 "Show device tree" \
185 3 "LUKS encryption" \
186 4 "Logical volume management" \
187 5 "* Mount partitions" \
188 6 "* Select bootloader" \
189 7 "* Username and password" \
190 8 "* System configuration" \
191 9 "Select window manager or desktop" \
192 10 "Select additional packages" \
193 11 "Run a command on the installed system" \
194 12 "View configuration and command selections" \
195 13 "* Confirm choices and start the installation" 2> "$ANS"
198 [[ -z $WARN && $SEL =~ (2|5) ]] && { msg "Data Warning" "$_warn"; WARN=true; }
201 2) part_menu || (( SEL-- )) ;;
202 3) luks_menu || (( SEL-- )) ;;
203 4) lvm_menu || (( SEL-- )) ;;
204 5) mount_menu || (( SEL-- )) ;;
205 6) prechecks 0 && { select_boot || (( SEL-- )); } ;;
206 7) prechecks 1 && { select_mkuser || (( SEL-- )); } ;;
207 8) prechecks 2 && { select_config || (( SEL-- )); } ;;
208 9) prechecks 3 && { select_sessions || (( SEL-- )); } ;;
209 10) prechecks 3 && { select_packages || (( SEL-- )); } ;;
210 11) prechecks 3 && select_usercmd ;;
211 12) prechecks 3 && select_show ;;
212 13) prechecks 3 && install_main ;;
213 *) yesno "Exit" "\nUnmount partitions (if any) and exit the installer?\n" && die 0
219 if [[ $SYS == 'BIOS' ]]; then
220 dlg BOOTLDR menu "BIOS Bootloader" "\nSelect which bootloader to use." \
221 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
222 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network" || return 1
224 dlg BOOTLDR menu "UEFI Bootloader" "\nSelect which bootloader to use." \
225 "systemd-boot" "A simple UEFI boot manager which executes configured EFI images" \
226 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
227 "refind-efi" "A UEFI boot manager that aims to be platform neutral and simplify multi-boot" \
228 "efistub" "Boot the kernel image directly (no chainloading support)" \
229 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network (no chainloading support)" || return 1
236 local pkgs="${USER_PKGS// / } ${PACKAGES// / }"
237 [[ $INSTALL_WMS == *dwm* ]] && pkgs="dwm st dmenu $pkgs"
238 pkgs="${pkgs// / }" pkgs="${pkgs# }"
239 msg "Show Configuration" "
240 ---------- PARTITION CONFIGURATION ------------
242 Root Part: $ROOT_PART
243 Boot Part: ${BOOT_PART:-none}
244 Boot Device: ${BOOT_DEV:-none}
245 Swap Part/File: ${SWAP_PART:-none}
246 Swap Size: ${SWAP_SIZE:-none}
247 Extra Mounts: ${EXMNTS:-none}
248 Mkinit Hooks: ${HOOKS:-none}
250 LVM used: ${LVM:-none}
251 LUKS used: ${LUKS:-none}
253 ------------ SYSTEM CONFIGURATION -------------
255 Locale: ${MYLOCALE:-none}
256 Keymap: ${KEYMAP:-none}
257 Hostname: ${MYHOST:-none}
258 Timezone: ${ZONE:-none}/${SUBZ:-none}
260 Chroot cmd: ${USER_CMD:-none}
262 ------------ USER CONFIGURATION ---------------
264 Username: ${NEWUSER:-none}
265 Login Shell: ${MYSHELL:-none}
266 Login Session: ${LOGIN_WM:-none}
267 Autologin: ${AUTOLOGIN:-none}
268 Login Type: ${LOGIN_TYPE:-none}
270 ----------- PACKAGE CONFIGURATION -------------
272 Kernel: ${KERNEL:-none}
273 Bootloader: ${BOOTLDR:-none}
274 Packages: ${pkgs:-none}
280 AUTOLOGIN='' # no autologin unless using xinit
282 dlg LOGIN_TYPE menu "Login Management" "\nSelect what kind of login management to use." \
283 "xinit" "Console login without a display manager" \
284 "ly" "TUI display manager with a ncurses-like interface" \
285 "lightdm" "Lightweight display manager with a gtk greeter" \
286 "gdm" "Gnome display manager" \
287 "sddm" "Simple desktop display manager" || return 1
290 gdm|sddm) EDIT_FILES[login]="" ;;
291 ly) EDIT_FILES[login]="/etc/ly/config.ini" ;;
292 lightdm) EDIT_FILES[login]="/etc/lightdm/lightdm.conf /etc/lightdm/lightdm-gtk-greeter.conf" ;;
293 xinit) EDIT_FILES[login]="/home/$NEWUSER/.xinitrc /home/$NEWUSER/.xprofile"
294 if (( $(wc -w <<< "$INSTALL_WMS") > 1 )); then
295 dlg LOGIN_WM menu "Login Management" "$_login" $LOGIN_CHOICES || return 1
296 LOGIN_WM="${WM_SESSIONS[$LOGIN_WM]}"
298 [[ -z $LOGIN_WM ]] && LOGIN_WM="${WM_SESSIONS[${INSTALL_WMS%% *}]}"
299 yesno "Autologin" "$(sed "s|USER|$NEWUSER|g; s|RC|$LOGINRC|g" <<< "$_autologin")" && AUTOLOGIN=true || AUTOLOGIN=''
309 until [[ $CONFIG_DONE ]]; do
311 0) dlg MYSHELL menu "Shell" "\nChoose which shell to use." \
312 zsh 'A very advanced and programmable command interpreter (shell) for UNIX' \
313 bash 'The GNU Bourne Again shell, standard in many GNU/Linux distributions' \
314 mksh 'The MirBSD Korn Shell - an enhanced version of the public domain ksh' || return 1
316 1) dlg MYHOST input "Hostname" "$_hostname" "${DIST,,}" limit || { i=0; continue; } ;;
317 2) dlg MYLOCALE menu "Locale" "$_locale" $LOCALES || { i=1; continue; } ;;
319 until [[ $ZONE && $SUBZ ]]; do
320 dlg ZONE menu "Timezone" "$_timez" America - Australia - Asia - Atlantic - Africa - Europe - Indian - Pacific - Arctic - Antarctica - || break
321 dlg SUBZ menu "Timezone" "$_timesubz" $(awk '/'"$ZONE"'\// {gsub(/'"$ZONE"'\//, ""); print $3 " - "}' /usr/share/zoneinfo/zone.tab | sort) || continue
323 [[ $ZONE && $SUBZ ]] || { i=2; continue; } ;;
324 4) dlg KERNEL menu "Kernel" "\nChoose which kernel to use." \
325 linux 'Vanilla linux kernel and modules, with a few patches applied' \
326 linux-lts 'Long-term support (LTS) linux kernel and modules' \
327 linux-zen 'A effort of kernel hackers to provide the best kernel for everyday systems' \
328 linux-hardened 'A security-focused linux kernel with hardening patches to mitigate exploits' || { i=3; continue; }
332 (( i++ )) # progress through to the next choice
336 bash) LOGINRC='.bash_profile' ;;
337 zsh) LOGINRC='.zprofile' ;;
338 mksh) LOGINRC='.profile' ;;
349 until [[ $NEWUSER ]]; do
351 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " User " --mixedform "$_user" 0 0 0 \
352 "Username:" 1 1 "${ans[0]}" 1 11 "$COLUMNS" 0 0 \
353 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
354 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 \
355 "--- Root password, if left empty the user password will be used ---" 6 1 '' 6 68 "$COLUMNS" 0 2 \
356 "Password:" 8 1 '' 8 11 "$COLUMNS" 0 1 \
357 "Password2:" 9 1 '' 9 12 "$COLUMNS" 0 1 2> "$ANS" || return 1
359 mapfile -t ans <"$ANS"
361 # root passwords empty, so use the user passwords
362 if [[ -z "${ans[4]}" && -z "${ans[5]}" ]]; then
367 # make sure a username was entered and that the passwords match
368 if [[ -z ${ans[0]} || ${ans[0]} =~ \ |\' || ${ans[0]} =~ [^a-z0-9] ]]; then
369 msg "Invalid Username" "\nInvalid user name.\n\nPlease try again.\n"; u=''
370 elif [[ -z "${ans[1]}" || "${ans[1]}" != "${ans[2]}" ]]; then
371 msg "Password Mismatch" "\nThe user passwords do not match.\n\nPlease try again.\n"
372 elif [[ "${ans[4]}" != "${ans[5]}" ]]; then
373 msg "Password Mismatch" "\nThe root passwords do not match.\n\nPlease try again.\n"
376 USER_PASS="${ans[1]}"
377 ROOT_PASS="${ans[4]}"
385 dlg KEYMAP menu "Keyboard Layout" "$_keymap" \
386 us English cm English gb English au English gh English \
387 za English ng English ca French 'cd' French gn French \
388 tg French fr French de German at German ch German \
389 es Spanish latam Spanish br Portuguese pt Portuguese ma Arabic \
390 sy Arabic ara Arabic ua Ukrainian cz Czech ru Russian \
391 sk Slovak nl Dutch it Italian hu Hungarian cn Chinese \
392 tw Taiwanese vn Vietnamese kr Korean jp Japanese th Thai \
393 la Lao pl Polish se Swedish is Icelandic 'fi' Finnish \
394 dk Danish be Belgian in Indian al Albanian am Armenian \
395 bd Bangla ba Bosnian 'bg' Bulgarian dz Berber mm Burmese \
396 hr Croatian gr Greek il Hebrew ir Persian iq Iraqi \
397 af Afghani fo Faroese ge Georgian ee Estonian kg Kyrgyz \
398 kz Kazakh lt Lithuanian mt Maltese mn Mongolian ro Romanian \
399 no Norwegian rs Serbian si Slovenian tj Tajik lk Sinhala \
400 tr Turkish uz Uzbek ie Irish pk Urdu 'mv' Dhivehi \
401 np Nepali et Amharic sn Wolof ml Bambara tz Swahili \
402 ke Swahili bw Tswana ph Filipino my Malay tm Turkmen \
403 id Indonesian bt Dzongkha lv Latvian md Moldavian mao Maori \
404 by Belarusian az Azerbaijani mk Macedonian kh Khmer epo Esperanto \
405 me Montenegrin || return 1
407 if [[ $CMAPS == *"$KEYMAP"* ]]; then
410 dlg CMAP menu "Console Keymap" "$_vconsole" $CMAPS || return 1
413 if [[ $TERM == 'linux' ]]; then
414 loadkeys "$CMAP" > /dev/null 2>&1
416 setxkbmap "$KEYMAP" > /dev/null 2>&1
424 dlg USER_CMD input "User Command" "$_usercmd" "$USER_CMD" nolimit
430 dlg INSTALL_WMS check "Sessions" "$_sessions\n" \
431 i3-gaps "A fork of i3wm with more features including gaps" "$(ofn i3-gaps "${INSTALL_WMS[*]}")" \
432 openbox "A lightweight, powerful, and highly configurable stacking wm" "$(ofn openbox "${INSTALL_WMS[*]}")" \
433 dwm "A dynamic WM for X that manages windows in tiled, floating, or monocle layouts" "$(ofn dwm "${INSTALL_WMS[*]}")" \
434 bspwm "A tiling wm that represents windows as the leaves of a binary tree" "$(ofn bspwm "${INSTALL_WMS[*]}")" \
435 jwm "A lightweight window manager for Xorg written in C" "$(ofn jwm "${INSTALL_WMS[*]}")" \
436 xfce4 "A lightweight and modular desktop environment based on gtk+2/3" "$(ofn xfce4 "${INSTALL_WMS[*]}")" \
437 awesome "A customized Awesome WM session created by @elanapan" "$(ofn awesome "${INSTALL_WMS[*]}")" \
438 fluxbox "A lightweight and highly-configurable window manager" "$(ofn fluxbox "${INSTALL_WMS[*]}")" \
439 plasma "A kde software project currently comprising a full desktop environment" "$(ofn plasma "${INSTALL_WMS[*]}")" \
440 gnome "A desktop environment that aims to be simple and easy to use" "$(ofn gnome "${INSTALL_WMS[*]}")" \
441 cinnamon "A desktop environment combining traditional desktop with modern effects" "$(ofn cinnamon "${INSTALL_WMS[*]}")"
443 [[ $INSTALL_WMS ]] || return 0
444 WM_PKGS="${INSTALL_WMS/dwm/}"
445 WM_PKGS="${WM_PKGS// / }"
446 WM_PKGS="${WM_PKGS# }"
448 for i in $INSTALL_WMS; do
449 LOGIN_CHOICES+="$i - "
450 [[ ${WM_EXT[$i]} && $WM_PKGS != *"${WM_EXT[$i]}"* ]] && WM_PKGS+=" ${WM_EXT[$i]}"
453 select_login || return 1
455 while IFS=' ' read -r pkg; do
456 [[ $PACKAGES != *"$pkg"* ]] && PACKAGES+=" $pkg"
464 dlg USER_PKGS check " Packages " "$_packages" \
465 abiword "A Fully-featured word processor" "$(ofn abiword "${USER_PKGS[*]}")" \
466 alacritty "A cross-platform, GPU-accelerated terminal emulator" "$(ofn alacritty "${USER_PKGS[*]}")" \
467 atom "An open-source text editor developed by GitHub" "$(ofn atom "${USER_PKGS[*]}")" \
468 audacious "A free and advanced audio player based on GTK+" "$(ofn audacious "${USER_PKGS[*]}")" \
469 audacity "A program that lets you manipulate digital audio waveforms" "$(ofn audacity "${USER_PKGS[*]}")" \
470 blueman "GUI bluetooth device manager" "$(ofn blueman "${USER_PKGS[*]}")" \
471 bluez "Simple CLI based bluetooth support" "$(ofn bluez "${USER_PKGS[*]}")" \
472 cairo-dock "Light eye-candy fully themable animated dock" "$(ofn cairo-dock "${USER_PKGS[*]}")" \
473 calligra "A set of applications for productivity" "$(ofn calligra "${USER_PKGS[*]}")" \
474 chromium "An open-source web browser based on the Blink rendering engine" "$(ofn chromium "${USER_PKGS[*]}")" \
475 clementine "A modern music player and library organizer" "$(ofn clementine "${USER_PKGS[*]}")" \
476 cmus "A small, fast and powerful console music player" "$(ofn cmus "${USER_PKGS[*]}")" \
477 deadbeef "A GTK+ audio player for GNU/Linux" "$(ofn deadbeef "${USER_PKGS[*]}")" \
478 deluge "A BitTorrent client written in python" "$(ofn deluge "${USER_PKGS[*]}")" \
479 emacs "An extensible, customizable, self-documenting real-time display editor" "$(ofn emacs "${USER_PKGS[*]}")" \
480 epiphany "A GNOME web browser based on the WebKit rendering engine" "$(ofn epiphany "${USER_PKGS[*]}")" \
481 evince "A document viewer" "$(ofn evince "${USER_PKGS[*]}")" \
482 evolution "Manage your email, contacts and schedule" "$(ofn evolution "${USER_PKGS[*]}")" \
483 file-roller "Create and modify archives" "$(ofn file-roller "${USER_PKGS[*]}")" \
484 firefox "A popular open-source web browser from Mozilla" "$(ofn firefox "${USER_PKGS[*]}")" \
485 gcolor2 "A simple GTK+2 color selector" "$(ofn gcolor2 "${USER_PKGS[*]}")" \
486 geany "A fast and lightweight IDE" "$(ofn geany "${USER_PKGS[*]}")" \
487 geary "A lightweight email client for the GNOME desktop" "$(ofn geary "${USER_PKGS[*]}")" \
488 gimp "GNU Image Manipulation Program" "$(ofn gimp "${USER_PKGS[*]}")" \
489 gnome-calculator "GNOME Scientific calculator" "$(ofn gnome-calculator "${USER_PKGS[*]}")" \
490 gnome-disk-utility "Disk Management Utility" "$(ofn gnome-disk-utility "${USER_PKGS[*]}")" \
491 gnome-system-monitor "View current processes and monitor system state" "$(ofn gnome-system-monitor "${USER_PKGS[*]}")" \
492 gparted "A GUI frontend for creating and manipulating partition tables" "$(ofn gparted "${USER_PKGS[*]}")" \
493 gpick "Advanced color picker using GTK+ toolkit" "$(ofn gpick "${USER_PKGS[*]}")" \
494 gpicview "Lightweight image viewer" "$(ofn gpicview "${USER_PKGS[*]}")" \
495 guvcview "Capture video from camera devices" "$(ofn guvcview "${USER_PKGS[*]}")" \
496 hexchat "A popular and easy to use graphical IRC client" "$(ofn hexchat "${USER_PKGS[*]}")" \
497 inkscape "Professional vector graphics editor" "$(ofn inkscape "${USER_PKGS[*]}")" \
498 irssi "Modular text mode IRC client" "$(ofn irssi "${USER_PKGS[*]}")" \
499 kdenlive "A popular non-linear video editor for Linux" "$(ofn kdenlive "${USER_PKGS[*]}")" \
500 krita "Edit and paint images" "$(ofn krita "${USER_PKGS[*]}")" \
501 libreoffice-fresh "Full featured office suite" "$(ofn libreoffice-fresh "${USER_PKGS[*]}")" \
502 lollypop "A new music playing application" "$(ofn lollypop "${USER_PKGS[*]}")" \
503 mousepad "A simple text editor" "$(ofn mousepad "${USER_PKGS[*]}")" \
504 mpd "A flexible, powerful, server-side application for playing music" "$(ofn mpd "${USER_PKGS[*]}")" \
505 mpv "A media player based on mplayer" "$(ofn mpv "${USER_PKGS[*]}")" \
506 mupdf "Lightweight PDF and XPS viewer" "$(ofn mupdf "${USER_PKGS[*]}")" \
507 mutt "Small but very powerful text-based mail client" "$(ofn mutt "${USER_PKGS[*]}")" \
508 nautilus "The default file manager for Gnome" "$(ofn nautilus "${USER_PKGS[*]}")" \
509 ncmpcpp "A mpd client and almost exact clone of ncmpc with some new features" "$(ofn ncmpcpp "${USER_PKGS[*]}")" \
510 neovim "A fork of Vim aiming to improve user experience, plugins, and GUIs." "$(ofn neovim "${USER_PKGS[*]}")" \
511 noto-fonts "Google Noto fonts" "$(ofn noto-fonts "${USER_PKGS[*]}")" \
512 noto-fonts-cjk "Google Noto CJK fonts (Chinese, Japanese, Korean)" "$(ofn noto-fonts-cjk "${USER_PKGS[*]}")" \
513 obs-studio "Free opensource streaming/recording software" "$(ofn obs-studio "${USER_PKGS[*]}")" \
514 openshot "An open-source, non-linear video editor for Linux" "$(ofn openshot "${USER_PKGS[*]}")" \
515 opera "A Fast and secure, free of charge web browser from Opera Software" "$(ofn opera "${USER_PKGS[*]}")" \
516 pcmanfm "A fast and lightweight file manager based in Lxde" "$(ofn pcmanfm "${USER_PKGS[*]}")" \
517 pidgin "Multi-protocol instant messaging client" "$(ofn pidgin "${USER_PKGS[*]}")" \
518 plank "An elegant, simple, and clean dock" "$(ofn plank "${USER_PKGS[*]}")" \
519 qbittorrent "An advanced BitTorrent client" "$(ofn qbittorrent "${USER_PKGS[*]}")" \
520 qpdfview "A tabbed PDF viewer" "$(ofn qpdfview "${USER_PKGS[*]}")" \
521 qt5ct "GUI for managing Qt based application themes, icons, and fonts" "$(ofn qt5ct "${USER_PKGS[*]}")" \
522 qutebrowser "A keyboard-focused vim-like web browser based on Python and PyQt5" "$(ofn qutebrowser "${USER_PKGS[*]}")" \
523 rhythmbox "A Music playback and management application" "$(ofn rhythmbox "${USER_PKGS[*]}")" \
524 rxvt-unicode "A unicode enabled rxvt-clone terminal emulator" "$(ofn rxvt-unicode "${USER_PKGS[*]}")" \
525 sakura "A terminal emulator based on GTK and VTE" "$(ofn sakura "${USER_PKGS[*]}")" \
526 simple-scan "Simple scanning utility" "$(ofn simple-scan "${USER_PKGS[*]}")" \
527 simplescreenrecorder "A feature-rich screen recorder" "$(ofn simplescreenrecorder "${USER_PKGS[*]}")" \
528 steam "A popular game distribution platform by Valve" "$(ofn steam "${USER_PKGS[*]}")" \
529 surf "A simple web browser based on WebKit2/GTK+" "$(ofn surf "${USER_PKGS[*]}")" \
530 terminator "Terminal emulator that supports tabs and grids" "$(ofn terminator "${USER_PKGS[*]}")" \
531 termite "A minimal VTE-based terminal emulator" "$(ofn termite "${USER_PKGS[*]}")" \
532 thunar "A modern file manager for the Xfce Desktop Environment" "$(ofn thunar "${USER_PKGS[*]}")" \
533 thunderbird "Standalone mail and news reader from mozilla" "$(ofn thunderbird "${USER_PKGS[*]}")" \
534 tilda "A GTK based drop down terminal for Linux and Unix" "$(ofn tilda "${USER_PKGS[*]}")" \
535 tilix "A tiling terminal emulator for Linux using GTK+ 3" "$(ofn tilix "${USER_PKGS[*]}")" \
536 transmission-cli "Free BitTorrent client CLI" "$(ofn transmission-cli "${USER_PKGS[*]}")" \
537 transmission-gtk "GTK+ Front end for transmission" "$(ofn transmission-gtk "${USER_PKGS[*]}")" \
538 transmission-qt "Qt Front end for transmission" "$(ofn transmission-qt "${USER_PKGS[*]}")" \
539 ttf-anonymous-pro "A family fixed-width fonts designed with code in mind" "$(ofn ttf-anonymous-pro "${USER_PKGS[*]}")" \
540 ttf-fira-code "Monospaced font with programming ligatures" "$(ofn ttf-fira-code "${USER_PKGS[*]}")" \
541 ttf-font-awesome "Iconic font designed for Bootstrap" "$(ofn ttf-font-awesome "${USER_PKGS[*]}")" \
542 ttf-hack "A hand groomed typeface based on Bitstream Vera Mono" "$(ofn ttf-hack "${USER_PKGS[*]}")" \
543 vlc "A free and open source cross-platform multimedia player" "$(ofn vlc "${USER_PKGS[*]}")" \
544 weechat "Fast, light and extensible IRC client" "$(ofn weechat "${USER_PKGS[*]}")" \
545 xapps "Common library for X-Apps project" "$(ofn xapps "${USER_PKGS[*]}")" \
546 xarchiver "A GTK+ frontend to various command line archivers" "$(ofn xarchiver "${USER_PKGS[*]}")" \
547 xed "A small and lightweight text editor. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
548 xfce4-terminal "A terminal emulator based in the Xfce Desktop Environment" "$(ofn xfce4-terminal "${USER_PKGS[*]}")" \
549 xreader "Document viewer for files like PDF and Postscript. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
550 zathura "Minimalistic document viewer" "$(ofn zathura "${USER_PKGS[*]}")"
552 if [[ $USER_PKGS ]]; then # add any needed PKG_EXT to the list
553 for i in $USER_PKGS; do
554 [[ ${PKG_EXT[$i]} && $USER_PKGS != *"${PKG_EXT[$i]}"* ]] && USER_PKGS+=" ${PKG_EXT[$i]}"
561 ###############################################################################
563 # non-essential partitioning helpers called by the user when using the optional
564 # partition menu and selecting a device to edit
568 no_bg_install || return 0
569 local device choice devhash
570 devhash="$(lsblk -f | base64)"
572 part_device || return 1
577 dlg choice menu "Edit Partitions" "$_part\n\n$(lsblk -no NAME,MODEL,SIZE,TYPE,FSTYPE $device)" \
578 "auto" "Whole device automatic partitioning" \
579 "cfdisk" "Curses based variant of fdisk" \
580 "parted" "GNU partition editor" \
581 "fdisk" "Dialog-driven creation and manipulation of partitions" \
582 "done" "Return to the main menu"
583 # "shrink" "Shrink an existing ext or ntfs partition" \
585 if [[ -z $choice || $choice == 'done' ]]; then
587 elif [[ $choice == 'shrink' ]]; then
588 part_shrink "$device"
589 elif [[ $choice == 'auto' ]]; then
590 local root_size txt table boot_fs
591 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"}}')
592 txt="\nWARNING:\n\nALL data on $device will be destroyed and the following partitions will be created\n\n- "
593 if [[ $SYS == 'BIOS' ]]; then
594 table="msdos" boot_fs="ext4"
595 txt+="An $boot_fs boot partition with the boot flag enabled (512M)\n- "
597 table="gpt" boot_fs="fat32"
598 txt+="A $boot_fs efi boot partition (512M)\n- "
600 txt+="An ext4 partition using all remaining space ($root_size)\n\nDo you want to continue?\n"
601 yesno "Auto Partition" "$txt" && part_auto "$device" "$table" "$boot_fs" "$root_size"
607 if [[ $devhash != "$(lsblk -f | base64)" ]]; then
608 msg "Probing Partitions" "\nInforming kernel of partition changes using partprobe\n" 0
609 partprobe > /dev/null 2>&1
610 [[ $choice == 'auto' ]] && return
618 if [[ $IGNORE_DEV ]]; then
619 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk "!/$IGNORE_DEV/"' && /disk|part|lvm|crypt|NAME/')"
621 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk '/disk|part|lvm|crypt|NAME/')"
623 msg "Device Tree" "\n\n$txt\n\n"
628 local device="$1" table="$2" boot_fs="$3" size="$4" dev_info=""
630 msg "Auto Partition" "\nRemoving partitions on $device and setting table to $table\n" 1
632 dev_info="$(parted -s "$device" print 2> /dev/null)"
635 while read -r PART; do
636 parted -s "$device" rm "$PART" > /dev/null 2> "$ERR"
637 errshow 0 "parted -s $device rm $PART" || return 1
638 done <<< "$(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r)"
640 [[ $(awk '/Table:/ {print $3}' <<< "$dev_info") != "$table" ]] && parted -s "$device" mklabel "$table" > /dev/null 2> "$ERR"
642 msg "Auto Partition" "\nCreating a 512M $boot_fs boot partition.\n" 1
643 if [[ $SYS == "BIOS" ]]; then
644 parted -s "$device" mkpart primary "$boot_fs" 1MiB 513MiB > /dev/null 2> "$ERR"
645 errshow 0 "parted -s $device mkpart primary $boot_fs 1MiB 513MiB" || return 1
647 parted -s "$device" mkpart ESP "$boot_fs" 1MiB 513MiB > /dev/null 2> "$ERR"
648 errshow 0 "parted -s $device mkpart ESP $boot_fs 1MiB 513MiB" || return 1
653 AUTO_BOOT_PART=$(lsblk -lno NAME,TYPE "$device" | awk 'NR==2 {print "/dev/" $1}')
655 if [[ $SYS == "BIOS" ]]; then
656 mkfs.ext4 -q "$AUTO_BOOT_PART" > /dev/null 2> "$ERR"
657 errshow 0 "mkfs.ext4 -q $AUTO_BOOT_PART" || return 1
659 mkfs.vfat -F32 "$AUTO_BOOT_PART" > /dev/null 2> "$ERR"
660 errshow 0 "mkfs.vfat -F32 $AUTO_BOOT_PART" || return 1
663 msg "Auto Partition" "\nCreating a $size ext4 root partition.\n" 0
664 parted -s "$device" mkpart primary ext4 513MiB 100% > /dev/null 2> "$ERR"
665 errshow 0 "parted -s $device mkpart primary ext4 513MiB 100%" || return 1
667 AUTO_ROOT_PART="$(lsblk -lno NAME,TYPE "$device" | awk 'NR==3 {print "/dev/" $1}')"
668 mkfs.ext4 -q "$AUTO_ROOT_PART" > /dev/null 2> "$ERR"
669 errshow 0 "mkfs.ext4 -q $AUTO_ROOT_PART" || return 1
671 msg "Auto Partition" "\nProcess complete.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$device")\n"
678 local device="$1" fs=""
680 part_find "${device##*/}[^ ]" || return 1
681 (( COUNT == 1 )) && part="$(awk '{print $1}' <<< "${PARTS[@]}" )"
683 if (( COUNT == 1 )) || dlg part menu "Resize" "\nWhich partition on $device do you want to resize?" $PARTS; then
684 fs=$(lsblk -lno FSTYPE "$part")
687 msg "Resize" "\nGathering device size info.\n" 0
689 end=$(parted -s "$device" unit KiB print | awk '/^\s*'"$num"'/ {print $3}') # part size in KiB
690 devsize=$(parted -s "$device" unit KiB print | awk '/Disk '"${device//\//\\/}"':/ {print $3}') # whole device size in KiB
691 mount "$part" "$MNT" > /dev/null 2>&1; sleep 0.5
692 min=$(df --output=used --block-size=MiB "$part" | awk 'NR == 2 {print int($1) + 256}')
693 max=$(df --output=avail --block-size=MiB "$part" | awk 'NR == 2 {print int($1)}')
696 if dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Resize: $part " --rangebox "$_resize" 17 "$COLUMNS" "$min" "$max" $((max / 2)) 2> $ANS; then
698 size=$((size * 1024))
705 if ntfsresize -fc "$part"; then
706 ntfsresize -ff --size $(( (size * 1024) / 1000 ))k "$part" 2> "$ERR" # k=10^3 bytes
707 errshow "ntfsresize -f -s $(( (size * 1024) / 1000 ))k $part" || return 1
709 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"
714 e2fsck -f "$part"; sleep 0.5
715 resize2fs -f "$part" ${size}K 2> "$ERR" # K=2^10 bytes
716 errshow "resize2fs -f $part ${size}K" || return 1
720 parted "$device" resizepart "$num" ${size}KiB || return 1
723 if [[ $devsize == "$end" ]]; then
724 parted -s "$device" mkpart primary ext4 ${size}KiB 100% 2> "$ERR"
725 errshow "parted -s $device mkpart primary ext4 ${size}KiB 100%" || return 1
727 parted -s "$device" mkpart primary ext4 ${size}KiB ${end}KiB 2> "$ERR"
728 errshow "parted -s $device mkpart primary ext4 ${size}KiB ${end}KiB" || return 1
730 msg "Resize Complete" "\n$part has been successfully resized to $((size / 1024))M.\n" 1
732 "") msg "No Filesystem" "\nFor unformatted partitions, cfdisk can be used in the partition menu.\n" ;;
733 *) msg "Invalid Filesystem: $fs" "\nResizing only supports ext and ntfs.\n" ;;
738 ###############################################################################
739 # partition management functions
740 # these are helpers for use by other functions to do essential setup/teardown
744 local regexp="$1" err=''
745 local pts dev size isize ptcount=0
747 # string of partitions as /TYPE/PART SIZE.. eg. /dev/sda1 256G
748 if [[ $IGNORE_DEV ]]; then
749 PARTS="$(lsblk -lno TYPE,NAME,SIZE | awk "/$regexp/"' && !'"/$IGNORE_DEV/"' {sub(/^part/, "/dev/"); sub(/^lvm|^crypt/, "/dev/mapper/"); print $1$2, $3}')"
751 PARTS="$(lsblk -lno TYPE,NAME,SIZE | awk "/$regexp/"' {sub(/^part/, "/dev/"); sub(/^lvm|^crypt/, "/dev/mapper/"); print $1$2 " " $3}')"
754 # ensure we have enough partitions for the system and action were trying to do
755 COUNT=$(wc -l <<< "$PARTS")
757 while read -r dev size; do # walk partition list and skip ones that are too small
758 [[ $dev && $size ]] || continue
759 size_t="${size: -1:1}"
762 [[ $size_t == 'K' || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
766 'part|lvm|crypt') [[ $ptcount -lt 1 || ($SYS == 'UEFI' && $COUNT -lt 2) ]] && err="$_errpart" ;;
767 'part|crypt') (( ptcount < 1 )) && err="$_lvmerr" ;;
768 'part|lvm') (( ptcount < 2 )) && err="$_lukserr" ;;
772 msg "Not Enough Partitions" "$err" 2
781 if [[ $1 == "$MNT/swapfile" && $SWAP_SIZE ]]; then
782 fallocate -l $SWAP_SIZE "$1" 2> "$ERR"
783 errshow "fallocate -l $SWAP_SIZE $1"
784 chmod 600 "$1" 2> "$ERR"
785 errshow "chmod 600 $1"
787 mkswap "$1" > /dev/null 2> "$ERR"
789 swapon "$1" > /dev/null 2> "$ERR"
796 local part="$1" mountp="${MNT}$2" fs=""
797 fs="$(lsblk -lno FSTYPE "$part")"
800 if [[ $fs && ${FS_OPTS[$fs]} && $part != "$BOOT_PART" && $part != "$AUTO_ROOT_PART" ]] && select_mntopts "$fs"; then
801 mount -o "$MNT_OPTS" "$part" "$mountp" > /dev/null 2>&1
803 mount "$part" "$mountp" > /dev/null 2>&1
806 part_mountconf "$part" "$mountp" || return 1
814 local part="$1" fs="$2" delay="$3"
816 msg "Format" "\nFormatting $part as $fs\n" 0
817 mkfs.$fs ${FS_CMD_FLAGS[$fs]} "$part" > /dev/null 2> "$ERR"
818 errshow "mkfs.$fs ${FS_CMD_FLAGS[$fs]} "$part"" || return 1
825 if [[ $DEV_COUNT -eq 1 && $SYS_DEVS ]]; then
826 DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
827 elif (( DEV_COUNT > 1 )); then
829 dlg DEVICE menu "Boot Device" "\nSelect the device to use for bootloader install." $SYS_DEVS
831 dlg DEVICE menu "Select Device" "$_device" $SYS_DEVS
833 [[ $DEVICE ]] || return 1
834 elif [[ $DEV_COUNT -lt 1 && ! $1 ]]; then
835 msg "Device Error" "\nNo available devices.\n\nExiting..\n" 2
839 [[ $1 ]] && BOOT_DEV="$DEVICE"
846 BOOT_DEV="${BOOT_PART%[1-9]}"
847 BOOT_PART_NUM="${BOOT_PART: -1}"
848 [[ $BOOT_PART = /dev/nvme* ]] && BOOT_DEV="${BOOT_PART%p[1-9]}"
849 if [[ $SYS == 'UEFI' ]]; then
850 parted -s $BOOT_DEV set $BOOT_PART_NUM esp on > /dev/null 2>&1
852 parted -s $BOOT_DEV set $BOOT_PART_NUM boot on > /dev/null 2>&1
859 local part="$1" devs=""
860 devs="$(lsblk -lno NAME,FSTYPE,TYPE)"
862 # Identify if $part is LUKS+LVM, LVM+LUKS, LVM alone, or LUKS alone
863 if lsblk -lno TYPE "$part" | grep -q 'crypt'; then
865 LUKS_NAME="${part#/dev/mapper/}"
866 for dev in $(awk '/lvm/ && /crypto_LUKS/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
867 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
868 LUKS_DEV="$LUKS_DEV cryptdevice=$dev:$LUKS_NAME"
873 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
874 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
875 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
876 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
880 elif lsblk -lno TYPE "$part" | grep -q 'lvm'; then
882 VNAME="${part#/dev/mapper/}"
883 for dev in $(awk '/crypt/ && /lvm2_member/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
884 if lsblk -lno NAME "$dev" | grep -q "$VNAME"; then
885 LUKS_NAME="${dev/\/dev\/mapper\//}"
889 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
890 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
891 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
892 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
903 if (( COUNT > 0 )); then
904 PARTS="$(sed "/${pt//\//\\/}/d" <<< "$PARTS")"
912 if grep -qw "$1" /proc/mounts; then
913 msg "Mount Success" "\nPartition $1 mounted at $2\n" 1
917 msg "Mount Fail" "\nPartition $1 failed to mount at $2\n" 2
922 ###############################################################################
924 # mount_menu is the entry point which calls all other functions
925 # once finished it returns to the main menu: main()
929 msg "Mount Menu" "\nGathering device and partition information.\n" 0
930 no_bg_install || return 0
933 part_find 'part|lvm|crypt' || { SEL=2; return 1; }
934 [[ $LUKS && $LUKS_PART ]] && part_countdec $LUKS_PART
935 [[ $LVM && $LVM_PARTS ]] && part_countdec $LVM_PARTS
936 select_root_partition || { ROOT_PART=''; return 1; }
937 select_boot_partition || { BOOT_PART=''; return 1; }
938 if [[ $BOOT_PART ]]; then
939 part_mount "$BOOT_PART" "/$BOOTDIR" && SEP_BOOT=true || return 1
942 select_swap || return 1
943 select_extra_partitions || return 1
950 local pts dev size isize
952 if (( COUNT )) ; then
953 while read -r dev size; do # walk partition list and skip ones that are too small/big for swap
954 size_t="${size: -1:1}"
957 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 16) || ($size_t == 'M' && $isize -lt 100) ]] || pts+="$dev $size "
961 dlg SWAP_PART menu "Swap Setup" "\nSelect whether to use a swapfile, swap partition, or none." \
962 "none" "Don't allocate any swap space" \
963 "swapfile" "Allocate $SYS_MEM at /swapfile" \
966 if [[ -z $SWAP_PART || $SWAP_PART == "none" ]]; then
969 elif [[ $SWAP_PART == "swapfile" ]]; then
971 until [[ ${SWAP_SIZE:0:1} =~ [1-9] && ${SWAP_SIZE: -1} =~ (M|G) ]]; do
972 (( 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
973 dlg SWAP_SIZE input "Swap Setup" "$_swapsize" "$SYS_MEM" || { SWAP_PART=''; SWAP_SIZE=''; return 1; }
976 part_swap "$MNT/$SWAP_PART"
977 SWAP_PART="/$SWAP_PART"
978 elif [[ $PARTS == *"$SWAP_PART"* ]]; then
980 part_countdec $SWAP_PART
981 SWAP_SIZE="$(lsblk -lno SIZE $SWAP_PART)"
991 local fs="$1" opts=''
992 local title="${fs^} Mount Options"
994 for i in ${FS_OPTS[$fs]}; do
998 until [[ $MNT_OPTS ]]; do
999 dlg MNT_OPTS check "$title" "$_mount" $opts
1000 [[ $MNT_OPTS ]] || return 1
1001 MNT_OPTS="${MNT_OPTS// /,}"
1002 yesno "$title" "\nConfirm the following options: $MNT_OPTS\n" || MNT_OPTS=''
1011 until [[ $EXMNT ]]; do
1012 dlg EXMNT input "Extra Mount $part" "$_exmnt" "/" || return 1
1013 if [[ ${EXMNT:0:1} != "/" || ${#EXMNT} -le 1 || $EXMNT =~ \ |\' || $EXMNTS == *"$EXMNT"* ]]; then
1014 msg "Mountpoint Error" "$_errexpart"
1018 msg "Mount Extra" "\nMounting Finished\n\n\nNo extra partitions available to mount, returning to main menu.\n" 2
1024 local part="$1" fs='' cur=''
1025 local txt="\nSelect which filesystem to use for: $part\n\nDefault: ext4"
1026 cur="$(lsblk -lno FSTYPE "$part" 2> /dev/null)"
1028 # bail early if the partition was created in part_auto()
1029 [[ $cur && $part == "$AUTO_ROOT_PART" ]] && return 0
1032 if [[ $cur && $FORMATTED == *"$part"* ]]; then
1033 dlg fs menu "Filesystem" "$txt\nCurrent: $cur" skip - ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1035 dlg fs menu "Filesystem" "$txt" ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1037 [[ $fs == 'skip' ]] && return 0
1038 yesno "Filesystem" "\nFormat $part as $fs?\n" || fs=''
1040 part_format "$part" "$fs" 0
1043 select_boot_partition()
1045 local pts dev size isize ptcount=0
1047 if [[ -z $BOOT_PART ]]; then
1048 if [[ $AUTO_BOOT_PART && -z $LVM && -z $LUKS ]]; then
1049 BOOT_PART="$AUTO_BOOT_PART"
1052 if (( COUNT )); then
1053 while read -r dev size; do # walk partition list and skip ones that are too small/big for boot
1054 size_t="${size: -1:1}"
1057 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1064 0) msg "EFI Boot Partition" "\nNo partitions available that meet size requirements!!\n\nReturning to the main menu.\n" 2; return 1 ;;
1065 1) msg "EFI Boot Partition" "\nOnly one partition available that meets size requirements.\n" 1; BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")" ;;
1066 *) dlg BOOT_PART menu "EFI Partition" "$_uefi" $pts ;;
1068 [[ $BOOT_PART ]] || return 1
1071 if [[ $LUKS && ! $LVM ]]; then
1073 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 ;;
1074 1) msg "Boot Partition" "\nOnly one partition available that meets size requirements.\n" 1; BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")" ;;
1075 *) dlg BOOT_PART menu "Boot Partition" "$_biosluks" $pts ;;
1077 [[ $BOOT_PART ]] || return 1
1079 (( ptcount == 0 )) && return 0
1080 dlg BOOT_PART menu "Boot Partition" "$_bios" "skip" "no separate boot" $pts
1081 [[ -z $BOOT_PART || $BOOT_PART == "skip" ]] && { BOOT_PART=''; return 0; }
1088 if ([[ $SYS == 'BIOS' ]] && grep -q 'ext[34]' <<< "$(fsck -N "$BOOT_PART")") || ([[ $SYS == 'UEFI' ]] && grep -q 'fat' <<< "$(fsck -N "$BOOT_PART")"); then
1089 yesno "Format Boot Partition" "\nIMPORTANT:\n\nThe boot partition $BOOT_PART $_format" "Format $BOOT_PART" "Skip Formatting" 1 || return 0
1093 UEFI) part_format "$BOOT_PART" "vfat" 2 || return 1 ;;
1094 BIOS) part_format "$BOOT_PART" "ext4" 2 || return 1 ;;
1099 select_root_partition()
1101 if [[ -z $ROOT_PART ]]; then
1102 if [[ $AUTO_ROOT_PART && -z $LVM && -z $LUKS ]]; then
1103 ROOT_PART="$AUTO_ROOT_PART"
1104 msg "Mount Menu" "\nUsing partitions created during automatic format.\n" 2
1105 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1106 return 0 # we're done here
1108 local pts dev size isize ptcount=0
1110 # walk partition list and skip ones that are too small for / (root)
1111 while read -r dev size; do
1112 size_t="${size: -1:1}" # size type eg. K, M, G, T
1113 isize=${size:0:-1} # remove trailing size type character
1114 isize=${isize%.*} # remove any decimal (round down)
1115 [[ $size_t =~ [MK] || ($size_t == 'G' && $isize -lt 4) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1118 if (( ptcount == 1 )); then # only one available device
1119 msg "Root Partition (/)" "\nOnly one partition available that meets size requirements.\n" 2
1120 ROOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")"
1122 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
1127 if [[ -z $ROOT_PART ]] || ! select_filesystem "$ROOT_PART" || ! part_mount "$ROOT_PART"; then
1134 select_extra_partitions()
1138 # walk partition list and skip ones that are too small to be usable
1139 if (( COUNT )); then
1140 while read -r dev size; do
1141 [[ ${size: -1:1} =~ [KM] ]] && part_countdec "$dev"
1145 while (( COUNT )); do
1147 dlg part menu 'Mount Extra' "$_expart" 'done' 'finish mounting step' $PARTS || break
1148 if [[ $part == 'done' ]]; then
1150 elif select_filesystem "$part" && select_mountpoint && part_mount "$part" "$EXMNT"; then
1151 EXMNTS+="$part: $EXMNT "
1152 [[ $EXMNT == '/usr' && $HOOKS != *usr* ]] && HOOKS+=" usr"
1160 ###############################################################################
1162 # main is the entry point which calls all other install functions, once
1163 # complete it shows a dialog to edit files on the new system before reboot
1168 genfstab -U "$MNT" > "$MNT/etc/fstab" 2> "$ERR"
1169 errshow 1 "genfstab -U $MNT > $MNT/etc/fstab"
1170 [[ -f $MNT/swapfile ]] && sed -i "s~${MNT}~~" "$MNT/etc/fstab"
1172 # tear free configs, MUST be done after package install for nvidia
1173 [[ $TEARFREE ]] && install_tearfree_conf "$MNT/etc/X11/xorg.conf.d"
1176 chrun "hwclock --systohc --utc" || chrun "hwclock --systohc --utc --directisa"
1179 chrun "chown -Rf $NEWUSER:users /home/$NEWUSER"
1180 if [[ "$USER_CMD" ]]; then
1181 chrun "$USER_CMD" 2> "$ERR" 2>&1
1182 errshow 0 "$USER_CMD"
1186 dlg choice menu "Finalization" "$_edit" \
1187 finished "exit the installer and reboot" \
1188 keyboard "${EDIT_FILES[keyboard]}" \
1189 console "${EDIT_FILES[console]}" \
1190 locale "${EDIT_FILES[locale]}" \
1191 hostname "${EDIT_FILES[hostname]}" \
1192 sudoers "${EDIT_FILES[sudoers]}" \
1193 mkinitcpio "${EDIT_FILES[mkinitcpio]}" \
1194 fstab "${EDIT_FILES[fstab]}" \
1195 crypttab "${EDIT_FILES[crypttab]}" \
1196 bootloader "${EDIT_FILES[bootloader]}" \
1197 pacman "${EDIT_FILES[pacman]}" \
1198 login "${EDIT_FILES[login]}"
1200 if [[ -z $choice || $choice == 'finished' ]]; then
1201 [[ $DEBUG == true && -r $DBG ]] && ${EDITOR:-vim} "$DBG"
1206 for f in ${EDIT_FILES[$choice]}; do
1207 if [[ -e ${MNT}$f ]]; then
1208 ${EDITOR:-vim} "${MNT}$f"
1210 msg "File Missing" "\nThe file(s) selected do not exist:\n\n${MNT}$f\n"
1221 while kill -0 $BG_PID 2> /dev/null; do
1222 clear; printf "\nA background install process is still running...\n"; sleep 1
1228 rm -rf "$MNT/etc/mkinitcpio-archiso.conf"
1229 find "$MNT/usr/lib/initcpio" -name 'archiso*' -type f -delete
1231 # remove/disable customizations done to airootfs during building
1232 chrun "systemctl disable pacman-init.service choose-mirror.service" > /dev/null 2>&1
1233 rm -f "$MNT/etc/systemd/scripts/choose-mirror"
1234 rm -f "$MNT/etc/systemd/system/"{choose-mirror.service,etc-pacman.d-gnupg.mount,pacman-init.service}
1235 sed -i 's/#\(Storage=\)volatile/\1auto/' "$MNT/etc/systemd/journald.conf"
1236 sed -i 's/#\(HandleSuspendKey=\)ignore/\1suspend/' "$MNT/etc/systemd/logind.conf"
1237 sed -i 's/#\(HandleHibernateKey=\)ignore/\1hibernate/' "$MNT/etc/systemd/logind.conf"
1238 sed -i 's/#\(HandleLidSwitch=\)ignore/\1suspend/' "$MNT/etc/systemd/logind.conf"
1239 find "$MNT/boot" -name '*-ucode.img' -delete
1241 # changing distro name?
1242 [[ $DIST != "ArchLabs" ]] || sed -i "s/ArchLabs/$DIST/g" "$MNT/etc/"{lsb-release,os-release}
1244 # vmlinuz, if this isn't copied the standard kernel may fail mkinitcpio
1245 cp -vf "$RUN/x86_64/vmlinuz" "$MNT/boot/vmlinuz-linux" 2> "$ERR" 2>&1
1246 errshow 1 "cp -vf $RUN/x86_64/vmlinuz $MNT/boot/vmlinuz-linux"
1248 # copy network settings
1249 [[ -d /etc/netctl ]] && cp -rfv /etc/netctl "$MNT/etc/"
1250 [[ -f /etc/resolv.conf ]] && cp -fv /etc/resolv.conf "$MNT/etc/"
1251 [[ -e /etc/NetworkManager/system-connections ]] && cp -rvf /etc/NetworkManager/system-connections "$MNT/etc/NetworkManager/"
1253 echo "LANG=$MYLOCALE" > "$MNT/etc/locale.conf"
1254 cp -fv "$MNT/etc/locale.conf" "$MNT/etc/default/locale"
1255 sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${MYLOCALE}/${MYLOCALE}/g" "$MNT/etc/locale.gen"
1257 chrun "ln -svf /usr/share/zoneinfo/$ZONE/$SUBZ /etc/localtime"
1259 cat > "$MNT/etc/X11/xorg.conf.d/00-keyboard.conf" <<- EOF
1260 # Use localectl(1) to instruct systemd-localed to update it.
1261 Section "InputClass"
1262 Identifier "system-keyboard"
1263 MatchIsKeyboard "on"
1264 Option "XkbLayout" "$KEYMAP"
1268 cat > "$MNT/etc/default/keyboard" <<- EOF
1269 # KEYBOARD CONFIGURATION FILE
1270 # Consult the keyboard(5) manual page.
1277 printf "KEYMAP=%s\nFONT=%s\n" "$CMAP" "$FONT" > "$MNT/etc/vconsole.conf"
1279 echo "$MYHOST" > "$MNT/etc/hostname"
1280 cat > "$MNT/etc/hosts" <<- EOF
1283 ::1 localhost ip6-localhost ip6-loopback
1284 ff02::1 ip6-allnodes
1285 ff02::2 ip6-allrouters
1291 echo "Installing $BOOTLDR"
1293 if [[ $ROOT_PART == /dev/mapper* ]]; then
1294 ROOT_PART_ID="$ROOT_PART"
1296 local uuid_type="UUID"
1297 [[ $BOOTLDR =~ (systemd-boot|refind-efi|efistub) ]] && uuid_type="PARTUUID"
1298 ROOT_PART_ID="$uuid_type=$(blkid -s $uuid_type -o value $ROOT_PART)"
1301 if [[ $SYS == 'UEFI' ]]; then
1302 # remove our old install and generic BOOT/ dir
1303 echo "Removing conflicting boot directories"
1304 find "$MNT/$BOOTDIR/EFI/" -maxdepth 1 -mindepth 1 -iname "$DIST" -type d -delete -printf "remove %p\n"
1305 find "$MNT/$BOOTDIR/EFI/" -maxdepth 1 -mindepth 1 -iname 'BOOT' -type d -delete -printf "remove %p\n"
1309 chrun "${BCMDS[$BOOTLDR]}" 2> "$ERR" 2>&1
1310 errshow 1 "${BCMDS[$BOOTLDR]}"
1312 if [[ -d $MNT/hostrun ]]; then
1313 echo "Unmounting chroot directories"
1314 # cleanup the bind mounts we made earlier for the grub-probe module
1315 umount_dir "$MNT/hostrun/"{udev,lvm}
1316 rm -rf "$MNT/hostrun" > /dev/null 2>&1
1319 if [[ $SYS == 'UEFI' ]]; then
1320 # some UEFI firmware requires a generic esp/BOOT/BOOTX64.EFI
1321 mkdir -pv "$MNT/$BOOTDIR/EFI/BOOT"
1323 grub) cp -fv "$MNT/$BOOTDIR/EFI/$DIST/grubx64.efi" "$MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI" ;;
1324 syslinux) cp -rf "$MNT/$BOOTDIR/EFI/syslinux/"* "$MNT/$BOOTDIR/EFI/BOOT/" && cp -f "$MNT/$BOOTDIR/EFI/syslinux/syslinux.efi" "$MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI" ;;
1325 refind-efi) sed -i '/#extra_kernel_version_strings/ c extra_kernel_version_strings linux-hardened,linux-zen,linux-lts,linux' "$MNT/$BOOTDIR/EFI/refind/refind.conf"
1326 cp -fv "$MNT/$BOOTDIR/EFI/refind/refind_x64.efi" "$MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI" ;;
1335 local groups='audio,video,floppy,log,network,rfkill,scanner,storage,optical,power,wheel'
1336 [[ -e $MNT/etc/X11/xorg.conf.d/20-nvida.conf && -e $MNT/usr/bin/optirun ]] && groups+=',bumblebee'
1338 rm -f "$MNT/root/.zlogin" # remove welcome message
1340 chrun "chpasswd <<< 'root:$ROOT_PASS'" 2> "$ERR" 2>&1
1341 errshow 1 "set root password"
1342 if [[ $MYSHELL != 'zsh' ]]; then # root uses zsh by default
1343 chrun "usermod -s /bin/$MYSHELL root" 2> "$ERR" 2>&1
1344 errshow 1 "usermod -s /bin/$MYSHELL root"
1345 # copy the default mkshrc to /root if it was selected
1346 [[ $MYSHELL == 'mksh' ]] && cp -fv "$MNT/etc/skel/.mkshrc" "$MNT/root/.mkshrc"
1349 echo "Creating new user $NEWUSER and setting password"
1350 chrun "useradd -m -u 1000 -g users -G $groups -s /bin/$MYSHELL $NEWUSER" 2> "$ERR" 2>&1
1351 errshow 1 "useradd -m -u 1000 -g users -G $groups -s /bin/$MYSHELL $NEWUSER"
1352 chrun "chpasswd <<< '$NEWUSER:$USER_PASS'" 2> "$ERR" 2>&1
1353 errshow 1 "set $NEWUSER password"
1355 if [[ $INSTALL_WMS == *dwm* ]]; then
1356 install_suckless "/home/$NEWUSER" chroot
1357 [[ $INSTALL_WMS == 'dwm' ]] && rm -rf "$MNT/home/$NEWUSER/.config/xfce4"
1359 [[ $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"
1360 [[ $INSTALL_WMS =~ (bspwm|openbox) ]] || rm -rf "$MNT/home/$NEWUSER/.config/"{jgmenu,tint2}
1361 [[ $USER_PKGS != *geany* ]] && rm -rf "$MNT/home/$NEWUSER/.config/geany"
1362 [[ $MYSHELL != 'bash' ]] && rm -rf "$MNT/home/$NEWUSER/.bash"*
1363 [[ $MYSHELL != 'zsh' ]] && rm -rf "$MNT/home/$NEWUSER/.z"*
1365 # remove some commands from ~/.xprofile when using KDE or Gnome as the login session
1366 if [[ $LOGIN_WM =~ (startkde|gnome-session) || ($LOGIN_TYPE != 'xinit' && $WM_PKGS =~ (plasma|gnome)) ]]; then
1367 sed -i '/super/d; /nitrogen/d; /compton/d' "$MNT/home/$NEWUSER/.xprofile" "$MNT/root/.xprofile"
1368 elif [[ $LOGIN_WM == 'dwm' ]]; then # and dwm
1369 sed -i '/super/d; /compton/d' "$MNT/home/$NEWUSER/.xprofile" "$MNT/root/.xprofile"
1377 local serv="$MNT/etc/systemd/system/getty@tty1.service.d"
1378 echo "Setting up $LOGIN_TYPE"
1380 ly|sddm|gdm|lightdm)
1381 if [[ $LOGIN_WM == *dwm* ]]; then # dwm doesn't include an xsession file for display managers
1382 mkdir -p "$MNT/usr/share/xsessions"
1383 cat > "$MNT/usr/share/xsessions/dwm.desktop" <<- EOF
1387 Comment=Dynamic Window Manager
1392 rm -rf "$serv" "$MNT/home/$NEWUSER/.xinitrc"
1393 chrun "systemctl enable $LOGIN_TYPE.service" 2> "$ERR" 2>&1
1394 errshow 1 "systemctl enable $LOGIN_TYPE.service"
1395 ${LOGIN_TYPE}_config
1398 if [[ $INSTALL_WMS ]]; then
1399 sed -i "/exec/ c exec ${LOGIN_WM}" "$MNT/home/$NEWUSER/.xinitrc"
1400 elif [[ -e $MNT/home/$NEWUSER/.xinitrc ]]; then
1401 sed -i '/exec/d' "$MNT/home/$NEWUSER/.xinitrc"
1404 if [[ $AUTOLOGIN ]]; then
1405 sed -i "s/root/${NEWUSER}/g" $serv/autologin.conf
1406 cat > "$MNT/home/$NEWUSER/$LOGINRC" <<- EOF
1407 # automatically run startx when logging in on tty1
1408 [ \$XDG_VTNR -eq 1 ] && exec startx
1420 local inpkg="$PACKAGES $USER_PKGS $AL_BASE_PKGS "
1422 if pacman -Qq archlabs-installer > /dev/null 2>&1; then
1423 rmpkg+="archlabs-installer "
1426 if [[ $MYSHELL == 'zsh' ]]; then
1427 inpkg+="zsh-completions "
1432 if [[ $INSTALL_WMS =~ (openbox|bspwm|i3-gaps|fluxbox|jwm|awesome) ]]; then
1433 inpkg+="$WM_BASE_PKGS "
1434 elif [[ $INSTALL_WMS == 'dwm' ]]; then # dwm only needs a very limited package set
1435 inpkg+="nitrogen polkit-gnome gnome-keyring dunst "
1438 # update and install crucial packages first to avoid issues
1439 chrun "pacman -Syyu $KERNEL $BASE_PKGS base-devel ${LOGIN_PKGS[$LOGIN_TYPE]} $MYSHELL --noconfirm --needed" 2> "$ERR" 2>&1
1440 errshow 1 "pacman -Syyu $KERNEL $BASE_PKGS base-devel ${LOGIN_PKGS[$LOGIN_TYPE]} $MYSHELL --noconfirm --needed"
1442 # remove the packages we don't want on the installed system
1443 [[ $rmpkg ]] && chrun "pacman -Rnsc $rmpkg --noconfirm"
1445 # reinstalling iputils fixes the network issue for non-root users
1446 chrun "pacman -S iputils $UCODE --noconfirm"
1448 # install the packages chosen throughout the install
1449 chrun "pacman -S $inpkg --needed --noconfirm" 2> "$ERR" 2>&1
1450 errshow 1 "pacman -S $inpkg --needed --noconfirm"
1452 # bootloader packages
1453 if [[ $BOOTLDR == 'grub' ]]; then
1454 [[ $SYS == 'UEFI' ]] && local efib="efibootmgr"
1455 chrun "pacman -S os-prober grub $efib --needed --noconfirm" 2> "$ERR" 2>&1
1456 errshow 1 "pacman -S os-prober grub $efib --needed --noconfirm"
1457 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1458 chrun "pacman -S refind-efi efibootmgr --needed --noconfirm" 2> "$ERR" 2>&1
1459 errshow 1 "pacman -S refind-efi efibootmgr --needed --noconfirm"
1460 elif [[ $SYS == 'UEFI' ]]; then
1461 chrun "pacman -S efibootmgr --needed --noconfirm" 2> "$ERR" 2>&1
1462 errshow 1 "pacman -S efibootmgr --needed --noconfirm"
1465 if [[ $VM ]] && dmesg | grep -qi 'vbox'; then
1467 linux) chrun "pacman -S virtualbox-guest-utils virtualbox-guest-modules-arch --needed --noconfirm" ;;
1468 *) chrun "pacman -S virtualbox-guest-utils virtualbox-guest-modules-dkms ${KERNEL}-headers --needed --noconfirm" ;;
1472 # allow members of the wheel group to run commands as root
1473 sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" "$MNT/etc/sudoers"
1480 local dir="$1/suckless"
1483 if [[ $1 == 'chroot' ]]; then
1484 chrun "mkdir -pv '$dir'"
1485 for i in dwm dmenu st; do
1486 if chrun "git clone 'https://git.suckless.org/$i' '$dir/$i'"; then
1487 chrun "cd '$dir/$i' && make PREFIX=/usr install"
1489 printf "failed to clone %s repo\n" "$i"
1494 for i in dwm dmenu st; do
1495 if git clone "https://git.suckless.org/$i" "$dir/$i"; then
1496 cd "$dir/$i" && make PREFIX=/usr install
1498 printf "failed to clone %s repo\n" "$i"
1504 install_mkinitcpio()
1507 [[ $LUKS ]] && add="encrypt"
1508 [[ $LVM ]] && { [[ $add ]] && add+=" lvm2" || add+="lvm2"; }
1509 sed -i "s/block filesystems/block ${add} filesystems ${HOOKS}/g" "$MNT/etc/mkinitcpio.conf"
1510 chrun "mkinitcpio -p $KERNEL" 2> "$ERR" 2>&1
1511 errshow 1 "mkinitcpio -p $KERNEL"
1514 install_mirrorlist()
1516 if hash reflector > /dev/null 2>&1; then
1517 reflector --verbose --score 80 -l 40 -f 5 --sort rate --save "$1"
1518 elif hash rankmirrors > /dev/null 2>&1; then
1519 echo "Sorting mirrorlist"
1520 local key="access_key=5f29642060ab983b31fdf4c2935d8c56"
1521 ip_add="$(curl -fsSL "http://api.ipstack.com/check&?$key&fields=ip" | python -c "import sys, json; print(json.load(sys.stdin)['ip'])")"
1522 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'])")"
1523 if [[ "$country" ]]; then
1524 if [[ $country =~ (CA|US) ]]; then
1525 # use both CA and US mirrors for CA or US countries
1526 mirror="https://www.archlinux.org/mirrorlist/?country=US&country=CA&use_mirror_status=on"
1527 elif [[ $country =~ (AU|NZ) ]]; then
1528 # use both AU and NZ mirrors for AU or NZ countries
1529 mirror="https://www.archlinux.org/mirrorlist/?country=AU&country=NZ&use_mirror_status=on"
1531 mirror="https://www.archlinux.org/mirrorlist/?country=${country}&use_mirror_status=on"
1533 else # no country code so just grab all mirrors, will be a very slow sort but we don't have other options
1534 mirror="https://www.archlinux.org/mirrorlist/?country=all&use_mirror_status=on"
1536 curl -fsSL "$mirror" | sed -e 's/^#Server/Server/' -e '/^#/d' | rankmirrors -n 6 - > "$1"
1540 install_background()
1542 ( rsync -a /run/archiso/sfs/airootfs/ "$MNT/" && install_mirrorlist "$MNT/etc/pacman.d/mirrorlist" > /dev/null 2>&1 ) &
1544 trap "kill $BG_PID 2> /dev/null" EXIT
1547 install_tearfree_conf()
1552 echo "Virtual machine detected, removing xorg configs"
1553 find "$xpath/" -name '*.conf' -delete -printf "remove %p\n"
1554 elif lspci | grep ' VGA ' | grep -q 'Intel'; then
1555 echo "Creating Intel Tear Free config /etc/X11/xorg.conf.d/20-intel.conf"
1556 cat > "$xpath/20-intel.conf" <<- EOF
1558 Identifier "Intel Graphics"
1560 Option "TearFree" "true"
1563 cat "$xpath/20-intel.conf"
1564 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
1565 echo "Creating AMD Tear Free config /etc/X11/xorg.conf.d/20-amdgpu.conf"
1566 cat > "$xpath/20-amdgpu.conf" <<- EOF
1568 Identifier "AMD Graphics"
1570 Option "TearFree" "true"
1573 cat "$xpath/20-amdgpu.conf"
1574 elif lspci | grep ' VGA ' | grep -q 'AMD/ATI.*HD [2-6][0-9]*'; then # older HD 2xxx-6xxx cards must use the radeon driver
1575 echo "Creating Radeon Tear Free config /etc/X11/xorg.conf.d/20-radeon.conf"
1576 cat > "$xpath/20-radeon.conf" <<- EOF
1578 Identifier "AMD Graphics"
1580 Option "TearFree" "on"
1583 cat "$xpath/20-radeon.conf"
1584 elif lspci | grep ' VGA ' | grep -q 'NVIDIA'; then # nvidia cards require a bit of checking for notebook gpus
1585 echo "Trying nvidia driver install"
1586 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
1587 if [[ $xpath == *"$MNT"* ]]; then
1588 chrun "nvidia-installer --bumblebee"
1590 nvidia-installer --bumblebee
1593 if [[ $xpath == *"$MNT"* ]]; then
1594 chrun "nvidia-installer" # unsure which card so try auto detection
1599 if [[ -e $xpath/20-nvidia.conf ]]; then
1600 cat "$xpath/20-radeon.conf"
1602 echo "NVIDIA driver installed"
1603 if [[ $xpath == *"$MNT"* ]]; then
1604 echo "Trying to load the driver for live session"
1607 echo "To enable driver vsync:"
1608 echo -e "\trun nvidia-settings (as root) on first boot\n\tenable 'ForceFullCompositionPipeline' under the advanced settings"
1609 echo -e "\tlastly save the change to your nvida xorg config /etc/X11/xorg.conf.d/20-nvidia.conf"
1610 echo -e "\tand remove everything but the Device and Screen sections from the file"
1612 echo "Unable to install nvidia driver"
1617 if lspci | grep ' VGA ' | grep -q 'Intel\|AMD/ATI'; then
1618 if [[ $xpath == *"$MNT"* ]]; then
1619 sed -i 's/xrender/glx/g' "$MNT/etc/skel/.config/compton.conf"
1621 sed -i 's/xrender/glx/g' /etc/skel/.config/compton.conf
1625 # remove nvidia installer from installed system when not running nvidia gpu
1626 [[ $xpath == *"$MNT"* ]] && rm -rf "$MNT/usr/bin/nvidia-installer" "$MNT/var/lib/nvidia-installer"
1629 ###############################################################################
1630 # display manager config
1631 # these are called based on which DM is chosen after it is installed
1632 # additional config can be handled here, for now only lightdm has one
1651 cat > "$MNT/etc/lightdm/lightdm-gtk-greeter.conf" <<- EOF
1653 default-user-image=/usr/share/icons/ArchLabs-Dark/64x64/places/distributor-logo-archlabs.png
1654 background=/usr/share/backgrounds/archlabs/archlabs.jpg
1655 theme-name=Adwaita-dark
1656 icon-theme-name=Adwaita
1657 font-name=DejaVu Sans Mono 11
1658 position=30%,end 50%,end
1662 ###############################################################################
1664 # prerun_* set up the configs needed before actually running the commands
1665 # setup_* are run after selecting a bootloader and build the command used later
1666 # they can also be used for further user input as these run before control is taken away
1670 EDIT_FILES[bootloader]="/etc/default/grub"
1672 if [[ $SYS == 'BIOS' ]]; then
1673 [[ $BOOT_DEV ]] || { part_device 1 || return 1; }
1674 BCMDS[grub]="grub-install --recheck --force --target=i386-pc $BOOT_DEV"
1676 BCMDS[grub]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1677 grub-install --recheck --force --target=x86_64-efi --efi-directory=/$BOOTDIR --bootloader-id=$DIST"
1678 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1681 BCMDS[grub]="mkdir -p /run/udev /run/lvm &&
1682 mount --bind /hostrun/udev /run/udev &&
1683 mount --bind /hostrun/lvm /run/lvm &&
1685 grub-mkconfig -o /boot/grub/grub.cfg &&
1686 sleep 1 && umount /run/udev /run/lvm"
1693 sed -i "s/GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR=\"${DIST}\"/g; s/GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"\"/g" "$MNT/etc/default/grub"
1695 if [[ $LUKS_DEV ]]; then
1696 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
1697 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"
1700 if [[ $SYS == 'BIOS' && $LVM && -z $SEP_BOOT ]]; then
1701 sed -i "s/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g" "$MNT/etc/default/grub" 2> "$ERR" 2>&1
1702 errshow 1 "sed -i 's/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g' $MNT/etc/default/grub"
1705 # setup for os-prober module
1706 mkdir -p /run/{lvm,udev} "$MNT/hostrun/"{lvm,udev}
1707 mount --bind /run/lvm "$MNT/hostrun/lvm"
1708 mount --bind /run/udev "$MNT/hostrun/udev"
1715 EDIT_FILES[bootloader]=""
1720 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1721 efibootmgr -v -d $BOOT_DEV -p $BOOT_PART_NUM -c -L '${DIST} Linux' -l /vmlinuz-${KERNEL} \
1722 -u 'root=$ROOT_PART_ID rw $([[ $UCODE ]] && printf 'initrd=\%s.img ' "$UCODE")initrd=\initramfs-${KERNEL}.img'"
1727 if [[ $SYS == 'BIOS' ]]; then
1728 EDIT_FILES[bootloader]="/boot/syslinux/syslinux.cfg"
1730 EDIT_FILES[bootloader]="/boot/EFI/syslinux/syslinux.cfg"
1731 BCMDS[syslinux]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1
1732 efibootmgr -v -c -d $BOOT_DEV -p $BOOT_PART_NUM -l /EFI/syslinux/syslinux.efi -L $DIST"
1738 local c="$MNT/boot/syslinux"
1739 local s="/usr/lib/syslinux/bios"
1741 if [[ $SYS == 'UEFI' ]]; then
1742 c="$MNT/boot/EFI/syslinux"
1743 s="/usr/lib/syslinux/efi64"
1746 mkdir -pv "$c" 2> "$ERR" 2>&1
1747 errshow 1 "mkdir -pv $c"
1748 cp -rfv "$s/"* "$c/" 2> "$ERR" 2>&1
1749 errshow 1 "cp -rfv $s/* $c/"
1750 cp -fv "$RUN/syslinux/splash.png" "$c/" 2> "$ERR" 2>&1
1751 errshow 0 "cp -fv $RUN/syslinux/splash.png $c/"
1752 cat > "$c/syslinux.cfg" <<- EOF
1754 MENU TITLE $DIST Boot Menu
1755 MENU BACKGROUND splash.png
1759 # see: https://www.syslinux.org/wiki/index.php/Comboot/menu.c32
1768 MENU HELPMSGENDROW 29
1769 MENU COLOR border 30;44 #40ffffff #a0000000 std
1770 MENU COLOR title 1;36;44 #9033ccff #a0000000 std
1771 MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
1772 MENU COLOR unsel 37;44 #50ffffff #a0000000 std
1773 MENU COLOR help 37;40 #c0ffffff #a0000000 std
1774 MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
1775 MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
1776 MENU COLOR msg07 37;40 #90ffffff #a0000000 std
1777 MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
1780 MENU LABEL $DIST Linux
1781 LINUX $d/vmlinuz-$KERNEL
1782 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1783 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL.img
1785 LABEL ${DIST}fallback
1786 MENU LABEL $DIST Linux Fallback
1787 LINUX $d/vmlinuz-$KERNEL
1788 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1789 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL-fallback.img
1796 EDIT_FILES[bootloader]="/boot/refind_linux.conf"
1797 BCMDS[refind-efi]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1; refind-install"
1802 cat > "$MNT/boot/refind_linux.conf" <<- EOF
1803 "$DIST Linux" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1804 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1805 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL.img"
1806 "$DIST Linux Fallback" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1807 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1808 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL-fallback.img"
1810 mkdir -p "$MNT/etc/pacman.d/hooks"
1811 cat > "$MNT/etc/pacman.d/hooks/refind.hook" <<- EOF
1818 Description = Updating rEFInd on ESP
1819 When = PostTransaction
1820 Exec = /usr/bin/refind-install
1824 setup_systemd-boot()
1826 EDIT_FILES[bootloader]="/boot/loader/entries/$DIST.conf"
1827 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars > /dev/null 2>&1; bootctl --path=/boot install"
1830 prerun_systemd-boot()
1832 mkdir -p "$MNT/boot/loader/entries"
1833 cat > "$MNT/boot/loader/loader.conf" <<- EOF
1838 cat > "$MNT/boot/loader/entries/$DIST.conf" <<- EOF
1840 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1841 initrd /initramfs-$KERNEL.img
1842 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1844 cat > "$MNT/boot/loader/entries/$DIST-fallback.conf" <<- EOF
1845 title $DIST Linux Fallback
1846 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1847 initrd /initramfs-$KERNEL-fallback.img
1848 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1850 mkdir -p "$MNT/etc/pacman.d/hooks"
1851 cat > "$MNT/etc/pacman.d/hooks/systemd-boot.hook" <<- EOF
1858 Description = Updating systemd-boot
1859 When = PostTransaction
1860 Exec = /usr/bin/bootctl update
1862 systemd-machine-id-setup --root="$MNT"
1866 ###############################################################################
1871 no_bg_install || return 1
1875 dlg choice menu "Logical Volume Management" "$_lvmmenu" \
1876 "$_lvmnew" "vgcreate -f, lvcreate -L -n" \
1877 "$_lvmdel" "vgremove -f" \
1878 "$_lvmdelall" "lvrmeove, vgremove, pvremove -f" \
1879 "Back" "Return to the main menu"
1881 "$_lvmnew") lvm_create && break ;;
1882 "$_lvmdel") lvm_delgroup && yesno "$_lvmdel" "$_lvmdelask" && vgremove -f "$DEL_VG" > /dev/null 2>&1 ;;
1883 "$_lvmdelall") lvm_del_all ;;
1893 if [[ $(vgs -o vg_name --noheading 2> /dev/null) ]]; then
1894 if [[ $(lvs -o vg_name,lv_name --noheading --separator - 2> /dev/null) && $(pvs -o pv_name --noheading 2> /dev/null) ]]; then
1895 msg "LVM Setup" "\nActivating existing logical volume management.\n" 0
1896 modprobe dm-mod > /dev/null 2> "$ERR"
1897 errshow 'modprobe dm-mod'
1898 vgscan > /dev/null 2>&1
1899 vgchange -ay > /dev/null 2>&1
1906 VGROUP='' LVM_PARTS='' VGROUP_MB=0
1908 lvm_mkgroup || return 1
1909 local txt="\nThe last (or only) logical volume will automatically use all remaining space in the volume group."
1910 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 -
1911 [[ $VOL_COUNT ]] || return 1
1912 lvm_extra_lvs || return 1
1913 lvm_volume_name "$_lvmlvname\nNOTE: This LV will use up all remaining space in the volume group (${VGROUP_MB}MB)" || return 1
1914 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating volume $VNAME from remaining space in $VGROUP\n" 0
1915 lvcreate -l +100%FREE "$VGROUP" -n "$VNAME" > /dev/null 2> "$ERR"
1916 errshow "lvcreate -l +100%FREE $VGROUP -n $VNAME" || return 1
1917 LVM='logical volume'; sleep 0.5
1918 txt="\nDone, volume: $VGROUP-$VNAME (${VOLUME_SIZE:-${VGROUP_MB}MB}) has been created.\n"
1919 msg "$_lvmnew (LV:$VOL_COUNT)" "$txt\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE $LVM_PARTS)\n"
1925 local txt="${VGROUP}: ${SIZE}$SIZE_UNIT (${VGROUP_MB}MB remaining).$_lvmlvsize"
1929 dlg VOLUME_SIZE input "$_lvmnew (LV:$VOL_COUNT)" "$txt" ''
1930 if [[ -z $VOLUME_SIZE ]]; then
1932 break # allow bailing with escape or an empty choice
1933 elif (( ${VOLUME_SIZE:0:1} == 0 )); then
1934 ERR_SIZE=1 # size values can't begin with '0'
1936 # walk the string and make sure all but the last char are digits
1937 local lv=$((${#VOLUME_SIZE} - 1))
1938 for (( i=0; i<lv; i++ )); do
1939 [[ ${VOLUME_SIZE:$i:1} =~ [0-9] ]] || { ERR_SIZE=1; break; }
1941 if (( ERR_SIZE != 1 )); then
1942 case ${VOLUME_SIZE:$lv:1} in
1943 [mMgG]) local s=${VOLUME_SIZE:0:$lv} m=$((s * 1000))
1944 case ${VOLUME_SIZE:$lv:1} in
1945 [Gg]) (( m >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - m)) ;;
1946 [Mm]) (( ${VOLUME_SIZE:0:$lv} >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - s)) ;;
1953 if (( ERR_SIZE )); then
1954 msg "Invalid Logical Volume Size" "$_lvmerrlvsize"
1967 until [[ $named ]]; do
1968 lvm_partitions || return 1
1969 lvm_group_name || return 1
1970 yesno "$_lvmnew" "\nCreate volume group: $VGROUP\n\nusing these partition(s): $LVM_PARTS\n" && named=true
1973 msg "$_lvmnew" "\nCreating volume group: $VGROUP\n" 0
1974 vgcreate -f "$VGROUP" $LVM_PARTS > /dev/null 2> "$ERR"
1975 errshow "vgcreate -f $VGROUP $LVM_PARTS" || return 1
1977 SIZE=$(vgdisplay "$VGROUP" | awk '/VG Size/ { gsub(/[^0-9.]/, ""); print int($0) }')
1978 SIZE_UNIT="$(vgdisplay "$VGROUP" | awk '/VG Size/ { print substr($NF, 0, 1) }')"
1980 if [[ $SIZE_UNIT == 'G' ]]; then
1981 VGROUP_MB=$((SIZE * 1000))
1986 msg "$_lvmnew" "\nVolume group $VGROUP (${SIZE}$SIZE_UNIT) successfully created\n"
1992 pv="$(pvs -o pv_name --noheading 2> /dev/null)"
1993 v="$(lvs -o vg_name,lv_name --noheading --separator - 2> /dev/null)"
1994 VGROUP="$(vgs -o vg_name --noheading 2> /dev/null)"
1996 if [[ $VGROUP || $v || $pv ]]; then
1997 if yesno "$_lvmdelall" "$_lvmdelask"; then
1998 for i in $v; do lvremove -f "/dev/mapper/$i" > /dev/null 2>&1; done
1999 for i in $VGROUP; do vgremove -f "$i" > /dev/null 2>&1; done
2000 for i in $pv; do pvremove -f "$i" > /dev/null 2>&1; done
2004 msg "Delete LVM" "\nNo LVMs to remove...\n" 2
2014 for i in $(lvs --noheadings | awk '{print $2}' | uniq); do
2015 VOL_GROUP_LIST+="$i $(vgdisplay "$i" | awk '/VG Size/ {print $3$4}') "
2018 [[ $VOL_GROUP_LIST ]] || { msg "No Groups" "\nNo volume groups found."; return 1; }
2020 dlg DEL_VG menu "Logical Volume Management" "\nSelect volume group to delete.\n\nAll logical volumes within will also be deleted." $VOL_GROUP_LIST
2026 while (( VOL_COUNT > 1 )); do
2027 lvm_volume_name "$_lvmlvname" && lvm_lv_size || return 1
2028 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating a $VOLUME_SIZE volume $VNAME in $VGROUP\n" 0
2029 lvcreate -L "$VOLUME_SIZE" "$VGROUP" -n "$VNAME" > /dev/null 2> "$ERR"
2030 errshow "lvcreate -L $VOLUME_SIZE $VGROUP -n $VNAME" || return 1
2031 msg "$_lvmnew (LV:$VOL_COUNT)" "\nDone, logical volume (LV) $VNAME ($VOLUME_SIZE) has been created.\n"
2039 part_find 'part|crypt' || return 1
2040 PARTS="$(awk 'NF > 0 {print $0 " off"}' <<< "$PARTS")"
2041 dlg LVM_PARTS check "$_lvmnew" "\nSelect the partition(s) to use for the physical volume (PV)." $PARTS
2048 until [[ $VGROUP ]]; do
2049 dlg VGROUP input "$_lvmnew" "$_lvmvgname" "lvgroup"
2050 if [[ -z $VGROUP ]]; then
2052 elif [[ ${VGROUP:0:1} == "/" || $VGROUP =~ \ |\' ]] || vgdisplay | grep -q "$VGROUP"; then
2053 msg "LVM Name Error" "$_lvmerrvgname"
2063 local txt="$1" default="mainvolume"
2064 (( VOL_COUNT > 1 )) && default="extvolume$VOL_COUNT"
2065 until [[ $VNAME ]]; do
2066 dlg VNAME input "$_lvmnew (LV:$VOL_COUNT)" "\n$txt" "$default"
2067 if [[ -z $VNAME ]]; then
2069 elif [[ ${VNAME:0:1} == "/" || $VNAME =~ \ |\' ]] || lsblk | grep -q "$VNAME"; then
2070 msg "LVM Name Error" "$_lvmerlvname"
2077 ###############################################################################
2083 no_bg_install || return 1
2084 dlg choice menu "LUKS Encryption" "$_luksmenu" \
2085 "$_luksnew" "cryptsetup -q luksFormat" \
2086 "$_luksopen" "cryptsetup open --type luks" \
2087 "$_luksadv" "cryptsetup -q -s -c luksFormat" \
2088 "Back" "Return to the main menu"
2091 "$_luksnew") luks_basic || return 1 ;;
2092 "$_luksopen") luks_open || return 1 ;;
2093 "$_luksadv") luks_advanced || return 1 ;;
2101 modprobe -a dm-mod dm_crypt > /dev/null 2>&1
2103 part_find 'part|crypt|lvm' || return 1
2105 if (( COUNT == 1 )); then
2106 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2108 dlg LUKS_PART menu "$_luksopen" "\nSelect which partition to open." $PARTS
2111 [[ $LUKS_PART ]] || return 1
2113 luks_pass "$_luksopen" || return 1
2114 msg "$_luksopen" "\nOpening encrypted partition: $LUKS_NAME\n\nUsing device/volume: $LUKS_PART\n" 0
2115 cryptsetup open --type luks "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> "$ERR"
2116 errshow "cryptsetup open --type luks $LUKS_PART $LUKS_NAME" || return 1
2117 LUKS='encrypted'; luks_show
2125 typeset -a ans=(cryptroot) # default name to start
2127 until [[ $LUKS_PASS ]]; do
2129 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " --mixedform "$_luksomenu" 0 0 0 \
2130 "Name:" 1 1 "${ans[0]}" 1 7 "$COLUMNS" 0 0 \
2131 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
2132 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 2> "$ANS" || return 1
2134 mapfile -t ans <"$ANS"
2136 if [[ -z "${ans[0]}" ]]; then
2137 msg "Name Empty" "\nEncrypted device name cannot be empty.\n\nPlease try again.\n" 2
2138 elif [[ -z "${ans[1]}" || "${ans[1]}" != "${ans[2]}" ]]; then
2139 LUKS_NAME="${ans[0]}"
2140 msg "Password Mismatch" "\nThe passwords entered do not match.\n\nPlease try again.\n" 2
2142 LUKS_NAME="${ans[0]}"
2143 LUKS_PASS="${ans[1]}"
2153 msg "$_luksnew" "\nEncrypted partition ready for mounting.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$LUKS_PART")\n\n"
2158 modprobe -a dm-mod dm_crypt > /dev/null 2>&1
2160 part_find 'part|lvm' || return 1
2162 if [[ $AUTO_ROOT_PART ]]; then
2163 LUKS_PART="$AUTO_ROOT_PART"
2164 elif (( COUNT == 1 )); then
2165 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2167 dlg LUKS_PART menu "$_luksnew" "\nSelect the partition you want to encrypt." $PARTS
2170 [[ $LUKS_PART ]] || return 1
2171 luks_pass "$_luksnew"
2176 luks_setup || return 1
2177 msg "$_luksnew" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2178 cryptsetup -q luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2> "$ERR"
2179 errshow "cryptsetup -q luksFormat $LUKS_PART" || return 1
2180 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> "$ERR"
2181 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2182 LUKS='encrypted'; luks_show
2190 dlg cipher input "LUKS Encryption" "$_lukskey" "-s 512 -c aes-xts-plain64"
2191 [[ $cipher ]] || return 1
2192 msg "$_luksadv" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2193 cryptsetup -q $cipher luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2> "$ERR"
2194 errshow "cryptsetup -q $cipher luksFormat $LUKS_PART" || return 1
2195 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2> "$ERR"
2196 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2203 ###############################################################################
2205 # some help avoid repetition and improve usability of some commands
2206 # others are initial setup functions used before reaching the main loop
2210 [[ "$2" == *"$1"* ]] && printf "on" || printf "off"
2215 # cleanup and exit the installer cleanly with exit code $1
2216 local e="$1" # when e is 127 unmount /run/archiso/bootmnt and reboot
2220 if [[ -d $MNT ]]; then
2222 (( e == 127 )) && umount_dir /run/archiso/bootmnt && sleep 0.5 && reboot -f
2229 local var="$1" # assign output from dialog to var
2230 local dlg_t="$2" # dialog type (menu, check, input)
2231 local title="$3" # dialog title
2232 local body="$4" # dialog message
2233 local n=0 # number of items to display for menu and check dialogs
2235 shift 4 # shift off args assigned above
2237 # adjust n when passed a large list
2238 local l=$((LINES - 20))
2239 (( ($# / 2) > l )) && n=$l
2243 menu) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --menu "$body" 0 0 $n "$@" 2> "$ANS" || return 1 ;;
2244 check) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --checklist "$body" 0 0 $n "$@" 2> "$ANS" || return 1 ;;
2247 local def="$1" # assign default value for input
2249 if [[ $1 == 'limit' ]]; then
2250 dialog --backtitle "$DIST Installer - $SYS - v$VER" --max-input 63 --title " $title " --inputbox "$body" 0 0 "$def" 2> "$ANS" || return 1
2252 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --inputbox "$body" 0 0 "$def" 2> "$ANS" || return 1
2256 # if answer file isn't empty read from it into $var
2257 [[ -s "$ANS" ]] && printf -v "$var" "%s" "$(< "$ANS")"
2262 # displays a message dialog
2263 # when more than 2 args the message will disappear after sleep time ($3)
2269 dialog --backtitle "$DIST Installer - $SYS - v$VER" --sleep "$1" --title " $title " --infobox "$body\n" 0 0
2271 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --msgbox "$body\n" 0 0
2279 if ! select_keymap; then
2282 elif ! net_connect; then
2283 msg "Not Connected" "\nRunning live requires an active internet connection to install packages.\n\nExiting..\n" 2
2285 elif (( $(awk '/MemTotal/ {print int($2 / 1024)}' /proc/meminfo) < 2500)); then
2286 msg "Not Enough Memory" "\nLive session requires at least 2.5G of system memory for installing packages.\n\nExiting..\n" 2
2291 echo "Sorting mirrorlist"
2292 mount /run/archiso/cowspace -o remount,size=2G
2293 install_mirrorlist "/etc/pacman.d/mirrorlist"
2294 pacman -Syyu --noconfirm || die 1
2295 rm -rf /var/cache/pacman/pkg/*
2296 pacman -S $BASE_PKGS $AL_BASE_PKGS xorg-xinit --needed --noconfirm || die 1
2297 rm -rf /var/cache/pacman/pkg/*
2299 i3-gaps|openbox|fluxbox|bspwm|awesome|xfce4|jwm) pacman -S "$ses" $WM_BASE_PKGS ${WM_EXT[$ses]} --needed --noconfirm || die 1 ;;
2300 gnome|plasma|cinnamon) pacman -S "$ses" ${WM_EXT[$ses]} --needed --noconfirm || die 1 ;;
2301 dwm) { pacman -S git --needed --noconfirm || die 1; }; install_suckless "/root" nochroot ;;
2303 rm -rf /var/cache/pacman/pkg/*
2304 [[ $VM ]] && dmesg | grep -qi 'vbox' && pacman -S virtualbox-guest-utils virtualbox-guest-modules-arch --needed --noconfirm
2305 pacman -Scc --noconfirm
2306 rm -rf /var/cache/pacman/pkg/*
2307 cp -rfT /etc/skel /root
2308 [[ $TEARFREE ]] && install_tearfree_conf "/etc/X11/xorg.conf.d"
2310 plasma|gnome|cinnamon) sed -i '/super/d; /nitrogen/d; /compton/d' /root/.xprofile ;;
2311 dwm) sed -i '/super/d; /compton/d' /root/.xprofile ;;
2314 echo -e "pulseaudio &\n(sleep 1; pamixer --unmute --set-volume 50) &" >> /root/.xprofile
2315 sed -i "/exec/ c exec ${WM_SESSIONS[$ses]}" /root/.xinitrc
2316 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]}"
2323 usage: $1 [-hdl] [session]
2326 -h, --help print this message and exit
2327 -l, --live install and setup a live session
2328 -d, --debug enable xtrace and log output to $DBG
2329 -t, --tearfree install and setup drivers for nvidia or tearfree xorg configs for other vendors
2330 if you experience boot issues with this option you can remove
2331 /etc/X11/xorg.conf.d/20-*.conf
2334 i3-gaps - A fork of i3wm with more features including gaps
2335 openbox - A lightweight, powerful, and highly configurable stacking wm
2336 dwm - A dynamic WM for X that manages windows in tiled, floating, or monocle layouts
2337 awesome - A customized Awesome WM session created by @elanapan
2338 bspwm - A tiling wm that represents windows as the leaves of a binary tree
2339 fluxbox - A lightweight and highly-configurable window manager
2340 gnome - A desktop environment that aims to be simple and easy to use
2341 cinnamon - A desktop environment combining traditional desktop with modern effects
2342 plasma - A kde software project currently comprising a full desktop environment
2343 xfce4 - A lightweight and modular desktop environment based on gtk+2/3
2347 set the DIST environment variable before launching the installer eg.
2351 root/boot partition:
2353 set the ROOT_PART and/or BOOT_PART environment variables before launching the installer eg.
2355 ROOT_PART='/dev/sda2' BOOT_PART='/dev/sda1' $1
2359 set the EDITOR environment variable before launching the installer eg.
2369 local title="$1" body="$2" yes='Yes' no='No'
2370 (( $# >= 3 )) && yes="$3"
2371 (( $# >= 4 )) && no="$4"
2373 if (( $# == 5 )); then
2374 dialog --backtitle "$DIST Installer - $SYS - v$VER" --defaultno --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2376 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2382 arch-chroot "$MNT" bash -c "$1"
2387 export PS4='| ${BASH_SOURCE} LINE:${LINENO} FUNC:${FUNCNAME[0]:+ ${FUNCNAME[0]}()} |> '
2397 "\e]P0191919" # #191919
2398 "\e]P1D15355" # #D15355
2399 "\e]P2609960" # #609960
2400 "\e]P3FFCC66" # #FFCC66
2401 "\e]P4255A9B" # #255A9B
2402 "\e]P5AF86C8" # #AF86C8
2403 "\e]P62EC8D3" # #2EC8D3
2404 "\e]P7949494" # #949494
2405 "\e]P8191919" # #191919
2406 "\e]P9D15355" # #D15355
2407 "\e]PA609960" # #609960
2408 "\e]PBFF9157" # #FF9157
2409 "\e]PC4E88CF" # #4E88CF
2410 "\e]PDAF86C8" # #AF86C8
2411 "\e]PE2ec8d3" # #2ec8d3
2412 "\e]PFE1E1E1" # #E1E1E1
2415 [[ $TERM == 'linux' ]] && printf "%b" "${colors[@]}" && clear
2420 [ $? -eq 0 ] && return 0
2422 local fatal=0 err=""
2423 err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
2424 [[ -z $err ]] && err="no error message was found"
2426 (( $1 == 1 )) && { fatal=1; shift; }
2428 local txt="\nCommand: $1\n\n\n\nError: $err\n\n"
2430 if (( fatal )); then
2431 msg "Install Error" "${txt}Errors at this stage are fatal, the install cannot continue.\n"
2432 [[ -r $DBG && $TERM == 'linux' ]] && less "$DBG"
2436 msg "Install Error" "${txt}Errors at this stage are non-fatal and may be fixed or ignored depending on the error.\n"
2444 if (( $1 >= 0 )) && ! grep -qw "$MNT" /proc/mounts; then
2445 msg "Not Mounted" "\nPartition(s) must be mounted first.\n" 2
2447 elif [[ $1 -ge 1 && -z $BOOTLDR ]]; then
2448 msg "No Bootloader" "\nBootloader must be selected first.\n" 2
2450 elif [[ $1 -ge 2 && (-z $NEWUSER || -z $USER_PASS) ]]; then
2451 msg "No User" "\nA user must be created first.\n" 2
2453 elif [[ $1 -ge 3 && -z $CONFIG_DONE ]]; then
2454 msg "Not Configured" "\nSystem configuration must be done first.\n" 2
2457 (( i )) # return code
2462 mount | grep -q 'swap' && swapoff -a
2464 if [[ -d $dir ]] && mount | grep -q "on $dir "; then
2465 if ! umount "$dir" 2> /dev/null; then
2467 umount -f "$dir" 2> /dev/null || umount -l "$dir"
2475 msg "Network Connect" "\nVerifying network connection\n" 0
2476 curl -sIN --connect-timeout 5 'https://www.archlinux.org/' | sed '1q' | grep -q '200'
2481 if chk_connect; then
2483 elif hash nmtui > /dev/null 2>&1; then
2485 if [[ $TERM == 'linux' ]]; then
2486 printf "%b" "\e]P1191919" "\e]P4191919"
2488 printf "%b" "\e]P1D15355" "\e]P4255a9b"
2493 elif hash wifi-menu > /dev/null 2>&1; then
2503 [[ $BG_PID ]] || return 0
2504 msg "Install Running" "\nA background install process is currently running.\n" 2
2510 IGNORE_DEV="$(lsblk -lno NAME,MOUNTPOINT | awk '/\/run\/archiso\/bootmnt/ {sub(/[1-9]/, ""); print $1}')"
2512 if [[ $IGNORE_DEV ]]; then
2513 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ && !'"/$IGNORE_DEV/"' {print "/dev/" $1 " " $2}')"
2515 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ {print "/dev/" $1 " " $2}')"
2518 if [[ -z $SYS_DEVS ]]; then
2519 msg "Device Error" "\nNo available devices...\n\nExiting..\n" 2
2524 while read -r line; do
2526 done <<< "$SYS_DEVS"
2533 # amd-ucode is not needed it's provided by linux-firmware
2534 # elif grep -q 'AuthenticAMD' /proc/cpuinfo; then
2536 elif grep -q 'GenuineIntel' /proc/cpuinfo; then
2540 modprobe -q efivarfs > /dev/null 2>&1
2542 if [[ -d /sys/firmware/efi/efivars ]]; then
2544 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars
2550 ###############################################################################
2553 # enable some nicer colours in the linux console
2556 if (( UID != 0 )); then
2557 msg "Not Root" "\nThis installer must be run as root or using sudo.\n\nExiting..\n" 2
2559 elif ! grep -qwm 1 'lm' /proc/cpuinfo; then
2560 msg "Not x86_64 Architecture" "\nThis installer only supports x86_64 architectures.\n\nExiting..\n" 2
2564 # trap ^C to perform cleanup
2565 trap 'printf "\n^C\n" && die 1' INT
2567 while getopts ":htl:d" OPT; do
2573 if [[ "${!WM_SESSIONS[@]}" =~ $OPTARG ]]; then
2576 echo "error: invalid session for -l, see -h for help"; die 1
2579 \?) echo "error: invalid option: -$OPTARG"; die 1 ;;
2586 msg "Welcome to the $DIST Installer" "$_welcome"
2588 if ! select_keymap; then
2590 elif ! net_connect; then
2591 msg "Not Connected" "\nThis installer requires an active internet connection.\n\nExiting..\n" 2
2598 # vim:fdm=marker:fmr={,}