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, Cnichi, Calamares, Arch Wiki.. Credit where credit is due
8 VER="2.0.50" # installer version
9 DIST="ArchLabs" # linux distributor
10 MNT="/mnt" # install mountpoint
11 ANS="/tmp/ans" # dialog answer file
13 # ------------------------------------------------------ #
14 # When manually mounting your partitions, you need
15 # to set these values to avoid using the mount menu.
16 # ------------------------------------------------------ #
18 # root partition, eg. /dev/sda2
21 # boot partition, required on UEFI eg. /dev/sda1
24 # boot device, used for some bootloaders eg. /dev/sda
27 # bootloader to use, can be:
28 # UEFI: grub, syslinux, efistub, systemd-boot, refind-efi
29 # BIOS: grub, syslinux
32 # directory to mount the boot partition (if any) for most bootloaders
33 # this will need to be 'boot' however a popular one for grub is 'boot/efi'
36 # ------------------------------------------------------ #
38 # bulk default values {
40 # these values will be selected during the install, it is not recommended
41 # to edit them here unless you know what you're doing.
43 UCODE='' # cpu microcode (if any), can be: amd-ucode, intel-ucode
44 KERNEL='' # linux kernel, can be: linux, linux-lts, linux-zen, or linux-hardened
45 MYSHELL='' # full path for the shell, eg. /usr/bin/zsh
47 SWAP_PART='' # swap partition or file path
48 SWAP_SIZE='' # swap size, only used when creating a swapfile
50 EXMNT='' # holder for additional partitions while mounting
51 EXMNTS='' # when an extra partition is mounted append it's info
53 FONT="ter-i16n" # font used for the linux console
54 HOOKS="shutdown" # list of additional HOOKS to add in /etc/mkinitcpio.conf
56 LOGIN_TYPE='' # login manager can be: lightdm, xinit
57 LOGIN_WM='' # default login session to be placed in ~/.xinitrc
58 LOGINRC='' # login shell rc file, eg. .zprofile, .bash_profile, .profile
60 INSTALL_WMS='' # space separated list of chosen wm/de
62 WM_PKGS='' # full list of packages added during wm/de choice (not user edited)
63 PACKAGES='' # list of all packages to install including WM_PKGS (not user edited)
64 USER_PKGS='' # packages selected by the user during install
66 NEWUSER='' # username for the new user
67 USER_PASS='' # new user's password
68 ROOT_PASS='' # root password
70 LUKS='' # empty when not using encryption
71 LUKS_DEV='' # boot parameter string for LUKS
72 LUKS_PART='' # partition used for encryption
73 LUKS_PASS='' # encryption password
74 LUKS_UUID='' # encrypted partition UUID
75 LUKS_NAME='' # name used for encryption
77 LVM='' # empty when not using lvm
78 LVM_PARTS='' # partitions used for volume group
79 VGROUP_MB=0 # available space in volume group
81 WARN='' # issued mounting/partitioning warning
82 SEP_BOOT='' # separate boot partition for BIOS
83 AUTOLOGIN='' # enable autologin for xinit
84 CONFIG_DONE='' # basic configuration is finished
85 BROADCOM_WL='' # fixes for broadcom cards eg. BCM4352
87 FORMATTED='' # partitions we formatted and should allow skipping
88 AUTO_ROOT_PART='' # root value from auto partition
89 AUTO_BOOT_PART='' # boot value from auto partition
91 # iso base, pacstrap when running the installer from a stock arch iso
92 ISO_BASE="b43-firmware b43-fwcutter broadcom-wl clonezilla dhclient dhcpcd ethtool wpa_supplicant "
93 ISO_BASE+="exfat-utils f2fs-tools gptfdisk vim hdparm ipw2100-fw ipw2200-fw nfs-utils nilfs-utils ntfs-3g "
94 ISO_BASE+="pacman-contrib parted rsync sdparm smartmontools wget wireless_tools wpa_actiond xl2tpd dialog parted "
95 ISO_BASE+="alsa-firmware alsa-lib alsa-plugins pulseaudio pulseaudio-alsa networkmanager w3m htop wireless-regdb "
96 ISO_BASE+="lm_sensors lsb-release p7zip pamixer reflector unrar ranger terminus-font ttf-dejavu archlabs-keyring"
98 # archlabs base packages
99 AL_BASE_PKGS="archlabs-skel-base archlabs-fonts archlabs-themes archlabs-dARK archlabs-icons archlabs-wallpapers archlabs-scripts"
101 # baseline (usually installed in the background)
102 BASE_PKGS="base-devel xorg xorg-drivers xorg-xinit sudo git gvfs gtk3 gtk-engines gtk-engine-murrine pavucontrol tumbler "
103 BASE_PKGS+="playerctl ffmpeg gstreamer libmad libmatroska gst-libav gst-plugins-base gst-plugins-good scrot"
105 # extras for window managers
106 WM_BASE_PKGS="arandr archlabs-networkmanager-dmenu xdg-user-dirs nitrogen polkit-gnome volumeicon xclip exo "
107 WM_BASE_PKGS+="xdotool compton wmctrl gnome-keyring dunst feh gsimplecal xfce4-power-manager xfce4-settings laptop-detect"
110 SEL=0 # currently selected menu item
111 ERR="/tmp/errlog" # error log used internally
112 DBG="/tmp/debuglog" # debug log when passed -d
113 RUN="/run/archiso/bootmnt/arch/boot" # path for live /boot
114 VM="$(dmesg | grep -i "hypervisor")" # is the system a vm
117 export DIALOGOPTS="--cr-wrap"
121 # giant ugly variable container :P {
123 # RAM in the system in MB
124 SYS_MEM="$(awk '/MemTotal/ {print int($2 / 1024) "M"}' /proc/meminfo)"
126 # locales from /etc/locale.gen
127 LOCALES="$(awk '/\.UTF-8/ {gsub(/# .*|#/, ""); if ($1) {print $1 " - "}}' /etc/locale.gen)"
129 # linux console keyboard mappings
130 CMAPS="$(find /usr/share/kbd/keymaps -name '*.map.gz' | awk '{gsub(/\.map\.gz|.*\//, ""); print $1 " - "}' | sort)"
132 # terminal size definitions
133 [[ $LINES ]] || LINES=$(tput lines)
134 [[ $COLUMNS ]] || COLUMNS=$(tput cols)
140 # commands used to install each bootloader (most get modified during runtime) {
142 [refind-efi]='refind-install' # minor modification
143 [grub]='grub-install --recheck --force' # heavily modified
144 [syslinux]='syslinux-install_update -i -a -m' # modified on UEFI
145 [efistub]='efibootmgr -v -d /dev/sda -p 1 -c -l' # heavily modified
146 [systemd-boot]='bootctl --path=/boot install' # not modified
149 # executable name for each wm/de {
150 declare -A WM_SESSIONS=(
157 [gnome]='gnome-session'
158 [fluxbox]='startfluxbox'
159 [openbox]='openbox-session'
160 [cinnamon]='cinnamon-session'
163 # packages installed for each wm/de, most are depends of the skel packages {
168 [plasma]='kdebase-meta' # base plasma application set
169 [bspwm]='' # see deps of bspwm-skel
170 [fluxbox]='' # see deps of fluxbox-skel
171 [i3-gaps]='' # see deps of i3-gaps-skel
172 [openbox]='' # see deps of openbox-skel
173 [xfce4]='xfce4-goodies' # see deps of xfce4-skel
176 # files that can be edited after install is complete {
177 declare -A EDIT_FILES=(
178 [login]='' # login is populated once we know the username and shell
180 [sudoers]='/etc/sudoers'
181 [crypttab]='/etc/crypttab'
182 [pacman]='/etc/pacman.conf'
183 [console]='/etc/vconsole.conf'
184 [mkinitcpio]='/etc/mkinitcpio.conf'
185 [hostname]='/etc/hostname /etc/hosts'
186 [bootloader]="/boot/loader/entries/$DIST.conf"
187 [locale]='/etc/locale.conf /etc/default/locale'
188 [keyboard]='/etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard'
191 # mkfs command for filesystem formatting {
196 [ntfs]='mkfs.ntfs -q'
197 [ext2]='mkfs.ext2 -q'
198 [ext3]='mkfs.ext3 -q'
199 [ext4]='mkfs.ext4 -q'
200 [vfat]='mkfs.vfat -F32'
201 [nilfs2]='mkfs.nilfs2 -q'
202 [reiserfs]='mkfs.reiserfs -q'
205 # mount options for each filesystem (if any) {
211 [jfs]='discard errors=continue errors=panic nointegrity'
212 [reiserfs]='acl nolog notail replayonly user_xattr off'
213 [ext4]='discard dealloc nofail noacl relatime noatime nobarrier nodelalloc'
214 [xfs]='discard filestreams ikeep largeio noalign nobarrier norecovery noquota wsync'
215 [nilfs2]='discard nobarrier errors=continue errors=panic order=relaxed order=strict norecovery'
216 [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'
219 # PKG_EXT: if you add a package to $PACKAGES in any dialog {
220 # and it uses/requires some additional packages,
221 # you can add them here to keep it simple: [package]="extra"
222 # duplicates are not added
226 [mupdf]='mupdf-tools'
227 [qt5ct]='qt5-styleplugins'
228 [vlc]='qt5ct qt5-styleplugins'
229 [zathura]='zathura-pdf-poppler'
230 [noto-fonts]='noto-fonts-emoji'
231 [cairo-dock]='cairo-dock-plug-ins'
232 [qutebrowser]='qt5ct qt5-styleplugins'
233 [qbittorrent]='qt5ct qt5-styleplugins'
234 [transmission-qt]='qt5ct qt5-styleplugins'
235 [kdenlive]='kdebase-meta dvdauthor frei0r-plugins breeze breeze-gtk qt5ct qt5-styleplugins'
243 # Basics (somewhat in order)
244 _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"
245 _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"
246 _device="\nSelect a device to use from the list below.\n\nDevices (/dev) are the available drives on the system. /sda, /sdb, /sdc ..."
247 _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."
248 _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."
249 _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"
250 _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 (and BIOS using LUKS without LVM) require a separate boot partition (100-512M)."
251 _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."
252 _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."
253 _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."
254 _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"
255 _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."
256 _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."
257 _exmnt="\nWhere do you want the partition mounted?\n\nEnsure the name begins with a slash (/).\nExamples include: /usr, /home, /var, etc."
258 _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 the [Up] and [Down] arrows to switch between input fields, [Tab] to toggle between input fields and the buttons, and [Enter] to accept."
259 _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."
260 _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"
261 _timez="\nThe time zone is used to set the system clock.\n\nSelect your country or continent from the list below"
262 _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."
263 _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."
264 _login="\nSelect which of your session choices to use for the initial login.\n\nYou can be change this later by editing your ~/.xinitrc"
265 _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."
266 _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] or Ctrl-z again to resume the installer, if you want to avoid the automatic reboot using Ctrl-c will cleanly exit."
269 _luksnew="Basic LUKS Encryption"
270 _luksadv="Advanced LUKS Encryption"
271 _luksopen="Open Existing LUKS Partition"
272 _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."
273 _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."
274 _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)."
277 _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."
278 _lvmnew="Create Volume Group and Volume(s)"
279 _lvmdel="Delete an Existing Volume Group"
280 _lvmdelall="Delete ALL Volume Group(s) and Volume(s)"
281 _lvmvgname="\nEnter a name for the volume group (VG) being created from the partition(s) selected."
282 _lvmlvname="\nEnter a name for the logical volume (LV) being created.\n\nThis is similar to setting a label for a partition."
283 _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."
284 _lvmdelask="\nConfirm deletion of volume group(s) and logical volume(s).\n\nDeleting a volume group, will delete all logical volumes within it.\n"
287 _errexpart="\nCannot mount partition due to a problem with the mountpoint.\n\nEnsure it begins with a slash (/) followed by atleast one character.\n"
288 _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"
289 _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"
290 _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"
291 _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"
292 _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"
293 _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"
299 ###############################################################################
304 (( SEL < 12 )) && (( SEL++ ))
306 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Prepare " --default-item $SEL --cancel-label 'Exit' --menu "$_prep" 0 0 0 \
307 1 "Device tree (optional)" \
308 2 "Partitioning (optional)" \
309 3 "LUKS setup (optional)" \
310 4 "LVM setup (optional)" \
311 5 "Mount partitions" \
312 6 "System bootloader" \
313 7 "User and password" \
314 8 "System configuration" \
315 9 "Select WM/DE (optional)" \
316 10 "Select Packages (optional)" \
317 11 "View configuration (optional)" \
318 12 "Start the installation" 2>"$ANS"
321 [[ -z $WARN && $SEL =~ (2|5) ]] && { msg "Data Warning" "$_warn"; WARN=true; }
324 2) part_menu || (( SEL-- )) ;;
325 3) luks_menu || (( SEL-- )) ;;
326 4) lvm_menu || (( SEL-- )) ;;
327 5) select_menu || (( SEL-- )) ;;
328 6) prechecks 0 && { select_boot || (( SEL-- )); } ;;
329 7) prechecks 1 && { select_mkuser || (( SEL-- )); } ;;
330 8) prechecks 2 && { select_config || (( SEL-- )); } ;;
331 9) prechecks 3 && { select_sessions || (( SEL-- )); } ;;
332 10) prechecks 3 && { select_packages || (( SEL-- )); } ;;
333 11) prechecks 3 && select_show ;;
334 12) prechecks 3 && install_main ;;
335 *) yesno "Exit" "\nUnmount partitions (if any) and exit the installer?\n" && die 0
341 if [[ $SYS == 'BIOS' ]]; then
342 dlg BOOTLDR menu "BIOS Bootloader" "\nSelect which bootloader to use." \
343 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
344 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network" || return 1
346 dlg BOOTLDR menu "UEFI Bootloader" "\nSelect which bootloader to use." \
347 "systemd-boot" "A simple UEFI boot manager which executes configured EFI images" \
348 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
349 "refind-efi" "A UEFI boot manager that aims to be platform neutral and simplify multi-boot" \
350 "efistub" "Boot the kernel image directly (no chainloading support)" \
351 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network (no chainloading support)" || return 1
359 local cmd="${BCMDS[$BOOTLDR]}"
360 local pkgs="${USER_PKGS// / } ${PACKAGES// / }"
361 [[ $BOOT_PART ]] && mnt="/$BOOTDIR"
362 [[ $INSTALL_WMS == *dwm* ]] && pkgs="dwm st dmenu $pkgs"
364 msg "Show Configuration" "
366 ---------- PARTITION CONFIGURATION ------------
368 Root: ${ROOT_PART:-none}
369 Boot: ${BOOT_PART:-${BOOT_DEV:-none}}
371 Swap: ${SWAP_PART:-none}
372 Size: ${SWAP_SIZE:-none}
377 Extra: ${EXMNTS:-${EXMNT:-none}}
378 Hooks: ${HOOKS:-none}
381 ---------- BOOTLOADER CONFIGURATION -----------
383 Bootloader: ${BOOTLDR:-none}
384 Mountpoint: ${mnt:-none}
385 Command: ${cmd:-none}
388 ------------ SYSTEM CONFIGURATION -------------
390 Locale: ${MYLOCALE:-none}
391 Keymap: ${KEYMAP:-none}
392 Hostname: ${MYHOST:-none}
393 Timezone: ${ZONE:-none}/${SUBZ:-none}
396 ------------ USER CONFIGURATION --------------
398 User: ${NEWUSER:-none}
399 Shell: ${MYSHELL:-none}
400 Session: ${LOGIN_WM:-none}
401 Autologin: ${AUTOLOGIN:-none}
402 Login Method: ${LOGIN_TYPE:-none}
405 ------------ PACKAGES AND MIRRORS -------------
407 Kernel: ${KERNEL:-none}
408 Sessions: ${INSTALL_WMS:-none}
409 Packages: $(print4 "${pkgs:-none}")
415 if [[ -z $LOGIN_TYPE ]]; then
416 dlg LOGIN_TYPE menu "Login Management" "\nSelect what kind of login management to use." \
417 "xinit" "Console login without a display manager" \
418 "lightdm" "Lightweight display manager with a gtk greeter" || return 1
421 if [[ $LOGIN_TYPE == 'lightdm' ]]; then
423 LOGIN_PKGS="lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings accountsservice"
424 EDIT_FILES[login]="/etc/lightdm/lightdm.conf /etc/lightdm/lightdm-gtk-greeter.conf"
426 if (( WM_NUM == 1 )); then
427 LOGIN_WM="${WM_SESSIONS[$INSTALL_WMS]}"
429 dlg LOGIN_WM menu "Login Management" "$_login" $LOGIN_CHOICES || return 1
430 LOGIN_WM="${WM_SESSIONS[$LOGIN_WM]}"
433 local txt="\nDo you want autologin enabled for $NEWUSER?\n\n"
434 txt+="If so the following two files will be created (disable autologin by removing them):\n\n"
435 txt+="- /home/$NEWUSER/$LOGINRC (run startx when logging in on tty1)\n"
436 txt+="- /etc/systemd/system/getty@tty1.service.d/autologin.conf (login $NEWUSER without password)\n"
437 yesno "Autologin" "$txt" && AUTOLOGIN=true || AUTOLOGIN=''
438 LOGIN_PKGS="xorg-xinit"
439 EDIT_FILES[login]="/home/$NEWUSER/.xinitrc /home/$NEWUSER/.xprofile"
448 until [[ $CONFIG_DONE ]]; do
451 dlg MYSHELL menu "Shell" "\nChoose which shell to use." \
452 /usr/bin/zsh 'A very advanced and programmable command interpreter (shell) for UNIX' \
453 /bin/bash 'The GNU Bourne Again shell, standard in many GNU/Linux distributions' \
454 /usr/bin/mksh 'The MirBSD Korn Shell - an enhanced version of the public domain ksh' || return 1
457 1) dlg MYHOST input "Hostname" "$_hostname" "${DIST,,}" limit || { i=0; continue; } ;;
458 2) dlg MYLOCALE menu "Locale" "$_locale" $LOCALES || { i=1; continue; } ;;
460 until [[ $ZONE && $SUBZ ]]; do
461 dlg ZONE menu "Timezone" "$_timez" America - Australia - Asia - Atlantic - Africa - Europe - Indian - Pacific - Arctic - Antarctica - || break
462 dlg SUBZ menu "Timezone" "$_timesubz" $(awk '/'"$ZONE"'\// {gsub(/'"$ZONE"'\//, ""); print $3 " - "}' /usr/share/zoneinfo/zone.tab | sort) || continue
463 yesno "Timezone" "\nConfirm time zone: $ZONE/$SUBZ\n" || unset ZONE
465 [[ $ZONE && $SUBZ ]] || { i=2; continue; } ;;
467 dlg KERNEL menu "Kernel" "\nChoose which kernel to use." \
468 linux 'Vanilla linux kernel and modules, with a few patches applied' \
469 linux-lts 'Long-term support (LTS) linux kernel and modules' \
470 linux-zen 'A effort of kernel hackers to provide the best kernel for everyday systems' \
471 linux-hardened 'A security-focused linux kernel with hardening patches to mitigate exploits' || { i=3; continue; }
476 (( i++ )) # progress through to the next choice
480 '/bin/bash') LOGINRC='.bash_profile' ;;
481 '/usr/bin/zsh') LOGINRC='.zprofile' ;;
482 '/usr/bin/mksh') LOGINRC='.profile' ;;
491 local v='' u='' p='' p2='' rp='' rp2=''
493 until [[ $NEWUSER ]]; do
496 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " User " --mixedform "$_user" 0 0 0 \
497 "Username:" 1 1 "$u" 1 11 "$COLUMNS" 0 0 \
498 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
499 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 \
500 "--- Root password, if left empty the user password will be used ---" 6 1 '' 6 68 "$COLUMNS" 0 2 \
501 "Password:" 8 1 '' 8 11 "$COLUMNS" 0 1 \
502 "Password2:" 9 1 '' 9 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
504 while read -r line; do
515 # root passwords empty, so use the user passwords
516 [[ -z $rp && -z $rp2 ]] && { rp="$p"; rp2="$p2"; }
518 # make sure a username was entered and that the passwords match
519 if [[ ${#u} -eq 0 || $u =~ \ |\' || $u =~ [^a-z0-9] ]]; then
520 msg "Invalid Username" "\nIncorrect user name.\n\nPlease try again.\n"; u=''
521 elif [[ -z $p ]]; then
522 msg "Empty Password" "\nThe user password cannot be left empty.\n\nPlease try again.\n"
523 elif [[ "$p" != "$p2" ]]; then
524 msg "Password Mismatch" "\nThe user passwords do not match.\n\nPlease try again.\n"
525 elif [[ "$rp" != "$rp2" ]]; then
526 msg "Password Mismatch" "\nThe root passwords do not match.\n\nPlease try again.\n"
538 dlg KEYMAP menu "Keyboard Layout" "$_keymap" \
539 us English cm English gb English au English gh English \
540 za English ng English ca French 'cd' French gn French \
541 tg French fr French de German at German ch German \
542 es Spanish latam Spanish br Portuguese pt Portuguese ma Arabic \
543 sy Arabic ara Arabic ua Ukrainian cz Czech ru Russian \
544 sk Slovak nl Dutch it Italian hu Hungarian cn Chinese \
545 tw Taiwanese vn Vietnamese kr Korean jp Japanese th Thai \
546 la Lao pl Polish se Swedish is Icelandic 'fi' Finnish \
547 dk Danish be Belgian in Indian al Albanian am Armenian \
548 bd Bangla ba Bosnian 'bg' Bulgarian dz Berber mm Burmese \
549 hr Croatian gr Greek il Hebrew ir Persian iq Iraqi \
550 af Afghani fo Faroese ge Georgian ee Estonian kg Kyrgyz \
551 kz Kazakh lt Lithuanian mt Maltese mn Mongolian ro Romanian \
552 no Norwegian rs Serbian si Slovenian tj Tajik lk Sinhala \
553 tr Turkish uz Uzbek ie Irish pk Urdu 'mv' Dhivehi \
554 np Nepali et Amharic sn Wolof ml Bambara tz Swahili \
555 ke Swahili bw Tswana ph Filipino my Malay tm Turkmen \
556 id Indonesian bt Dzongkha lv Latvian md Moldavian mao Maori \
557 by Belarusian az Azerbaijani mk Macedonian kh Khmer epo Esperanto \
558 me Montenegrin || return 1
560 if [[ $CMAPS == *"$KEYMAP"* ]]; then
563 dlg CMAP menu "Console Keymap" "$_vconsole" $CMAPS || return 1
566 if [[ $DISPLAY && $TERM != 'linux' ]]; then
567 setxkbmap "$KEYMAP" >/dev/null 2>&1
569 loadkeys "$CMAP" >/dev/null 2>&1
579 dlg INSTALL_WMS check "Sessions" "$_sessions\n" \
580 i3-gaps "A fork of i3wm with more features including gaps" "$(ofn i3-gaps "${INSTALL_WMS[*]}")" \
581 openbox "A lightweight, powerful, and highly configurable stacking wm" "$(ofn openbox "${INSTALL_WMS[*]}")" \
582 awesome "A customized Awesome WM session created by @elanapan" "$(ofn awesome "${INSTALL_WMS[*]}")" \
583 dwm "A dynamic WM for X that manages windows in tiled, floating, or monocle layouts" "$(ofn dwm "${INSTALL_WMS[*]}")" \
584 bspwm "A tiling wm that represents windows as the leaves of a binary tree" "$(ofn bspwm "${INSTALL_WMS[*]}")" \
585 fluxbox "A lightweight and highly-configurable window manager" "$(ofn fluxbox "${INSTALL_WMS[*]}")" \
586 gnome "A desktop environment that aims to be simple and easy to use" "$(ofn gnome "${INSTALL_WMS[*]}")" \
587 cinnamon "A desktop environment combining traditional desktop with modern effects" "$(ofn cinnamon "${INSTALL_WMS[*]}")" \
588 plasma "A kde software project currently comprising a full desktop environment" "$(ofn plasma "${INSTALL_WMS[*]}")" \
589 xfce4 "A lightweight and modular desktop environment based on gtk+2/3" "$(ofn xfce4 "${INSTALL_WMS[*]}")" || return 1
592 while IFS=' ' read -r i; do
594 done <<< "$INSTALL_WMS"
597 WM_PKGS="${INSTALL_WMS/dwm/}" # remove dwm from package list
598 WM_PKGS="${WM_PKGS// / }" # remove double spaces
599 WM_PKGS="${WM_PKGS# }" # remove leading space
601 # add archlabs base when choosing any session
602 [[ $WM_PKGS ]] && WM_PKGS+=" $AL_BASE_PKGS"
604 for i in $INSTALL_WMS; do
605 LOGIN_CHOICES+="$i - "
606 [[ ${WM_EXT[$i]} && $WM_PKGS != *"${WM_EXT[$i]}"* ]] && WM_PKGS+=" ${WM_EXT[$i]}"
609 select_login || return 1
610 [[ $WM_PKGS != *"$LOGIN_PKGS"* ]] && WM_PKGS+=" $LOGIN_PKGS"
612 while IFS=' ' read -r pkg; do
613 [[ $PACKAGES != *"$pkg"* ]] && PACKAGES+=" $pkg"
621 dlg USER_PKGS check " Packages " "$_packages" \
622 abiword "A Fully-featured word processor" "$(ofn abiword "${USER_PKGS[*]}")" \
623 alacritty "A cross-platform, GPU-accelerated terminal emulator" "$(ofn alacritty "${USER_PKGS[*]}")" \
624 atom "An open-source text editor developed by GitHub" "$(ofn atom "${USER_PKGS[*]}")" \
625 audacious "A free and advanced audio player based on GTK+" "$(ofn audacious "${USER_PKGS[*]}")" \
626 audacity "A program that lets you manipulate digital audio waveforms" "$(ofn audacity "${USER_PKGS[*]}")" \
627 cairo-dock "Light eye-candy fully themable animated dock" "$(ofn cairo-dock "${USER_PKGS[*]}")" \
628 calligra "A set of applications for productivity" "$(ofn calligra "${USER_PKGS[*]}")" \
629 chromium "An open-source web browser based on the Blink rendering engine" "$(ofn chromium "${USER_PKGS[*]}")" \
630 clementine "A modern music player and library organizer" "$(ofn clementine "${USER_PKGS[*]}")" \
631 cmus "A small, fast and powerful console music player" "$(ofn cmus "${USER_PKGS[*]}")" \
632 deadbeef "A GTK+ audio player for GNU/Linux" "$(ofn deadbeef "${USER_PKGS[*]}")" \
633 deluge "A BitTorrent client written in python" "$(ofn deluge "${USER_PKGS[*]}")" \
634 docky "Full fledged dock for opening applications and managing windows" "$(ofn docky "${USER_PKGS[*]}")" \
635 emacs "An extensible, customizable, self-documenting real-time display editor" "$(ofn emacs "${USER_PKGS[*]}")" \
636 epiphany "A GNOME web browser based on the WebKit rendering engine" "$(ofn epiphany "${USER_PKGS[*]}")" \
637 evince "A document viewer" "$(ofn evince "${USER_PKGS[*]}")" \
638 evolution "Manage your email, contacts and schedule" "$(ofn evolution "${USER_PKGS[*]}")" \
639 file-roller "Create and modify archives" "$(ofn file-roller "${USER_PKGS[*]}")" \
640 firefox "A popular open-source web browser from Mozilla" "$(ofn firefox "${USER_PKGS[*]}")" \
641 gcolor2 "A simple GTK+2 color selector" "$(ofn gcolor2 "${USER_PKGS[*]}")" \
642 geany "A fast and lightweight IDE" "$(ofn geany "${USER_PKGS[*]}")" \
643 geary "A lightweight email client for the GNOME desktop" "$(ofn geary "${USER_PKGS[*]}")" \
644 gimp "GNU Image Manipulation Program" "$(ofn gimp "${USER_PKGS[*]}")" \
645 gnome-disk-utility "Disk Management Utility" "$(ofn gnome-disk-utility "${USER_PKGS[*]}")" \
646 gnome-system-monitor "View current processes and monitor system state" "$(ofn gnome-system-monitor "${USER_PKGS[*]}")" \
647 gparted "A GUI frontend for creating and manipulating partition tables" "$(ofn gparted "${USER_PKGS[*]}")" \
648 gpick "Advanced color picker using GTK+ toolkit" "$(ofn gpick "${USER_PKGS[*]}")" \
649 gpicview "Lightweight image viewer" "$(ofn gpicview "${USER_PKGS[*]}")" \
650 guvcview "Capture video from camera devices" "$(ofn guvcview "${USER_PKGS[*]}")" \
651 hexchat "A popular and easy to use graphical IRC client" "$(ofn hexchat "${USER_PKGS[*]}")" \
652 inkscape "Professional vector graphics editor" "$(ofn inkscape "${USER_PKGS[*]}")" \
653 irssi "Modular text mode IRC client" "$(ofn irssi "${USER_PKGS[*]}")" \
654 kdenlive "A popular non-linear video editor for Linux" "$(ofn kdenlive "${USER_PKGS[*]}")" \
655 krita "Edit and paint images" "$(ofn krita "${USER_PKGS[*]}")" \
656 libreoffice-fresh "Full featured office suite" "$(ofn libreoffice-fresh "${USER_PKGS[*]}")" \
657 lollypop "A new music playing application" "$(ofn lollypop "${USER_PKGS[*]}")" \
658 mousepad "A simple text editor" "$(ofn mousepad "${USER_PKGS[*]}")" \
659 mpd "A flexible, powerful, server-side application for playing music" "$(ofn mpd "${USER_PKGS[*]}")" \
660 mpv "A media player based on mplayer" "$(ofn mpv "${USER_PKGS[*]}")" \
661 mupdf "Lightweight PDF and XPS viewer" "$(ofn mupdf "${USER_PKGS[*]}")" \
662 mutt "Small but very powerful text-based mail client" "$(ofn mutt "${USER_PKGS[*]}")" \
663 nautilus "The default file manager for Gnome" "$(ofn nautilus "${USER_PKGS[*]}")" \
664 ncmpcpp "A mpd client and almost exact clone of ncmpc with some new features" "$(ofn ncmpcpp "${USER_PKGS[*]}")" \
665 neovim "A fork of Vim aiming to improve user experience, plugins, and GUIs." "$(ofn neovim "${USER_PKGS[*]}")" \
666 nicotine+ "A graphical client for Soulseek" "$(ofn nicotine+ "${USER_PKGS[*]}")" \
667 noto-fonts "Google Noto fonts" "$(ofn noto-fonts "${USER_PKGS[*]}")" \
668 noto-fonts-cjk "Google Noto CJK fonts (Chinese, Japanese, Korean)" "$(ofn noto-fonts-cjk "${USER_PKGS[*]}")" \
669 obs-studio "Free opensource streaming/recording software" "$(ofn obs-studio "${USER_PKGS[*]}")" \
670 openshot "An open-source, non-linear video editor for Linux" "$(ofn openshot "${USER_PKGS[*]}")" \
671 opera "A Fast and secure, free of charge web browser from Opera Software" "$(ofn opera "${USER_PKGS[*]}")" \
672 pcmanfm "A fast and lightweight file manager based in Lxde" "$(ofn pcmanfm "${USER_PKGS[*]}")" \
673 pidgin "Multi-protocol instant messaging client" "$(ofn pidgin "${USER_PKGS[*]}")" \
674 plank "An elegant, simple, and clean dock" "$(ofn plank "${USER_PKGS[*]}")" \
675 qbittorrent "An advanced BitTorrent client" "$(ofn qbittorrent "${USER_PKGS[*]}")" \
676 qpdfview "A tabbed PDF viewer" "$(ofn qpdfview "${USER_PKGS[*]}")" \
677 qt5ct "GUI for managing Qt based application themes, icons, and fonts" "$(ofn qt5ct "${USER_PKGS[*]}")" \
678 qutebrowser "A keyboard-focused vim-like web browser based on Python and PyQt5" "$(ofn qutebrowser "${USER_PKGS[*]}")" \
679 rhythmbox "A Music playback and management application" "$(ofn rhythmbox "${USER_PKGS[*]}")" \
680 rxvt-unicode "A unicode enabled rxvt-clone terminal emulator" "$(ofn rxvt-unicode "${USER_PKGS[*]}")" \
681 sakura "A terminal emulator based on GTK and VTE" "$(ofn sakura "${USER_PKGS[*]}")" \
682 simplescreenrecorder "A feature-rich screen recorder" "$(ofn simplescreenrecorder "${USER_PKGS[*]}")" \
683 steam "A popular game distribution platform by Valve" "$(ofn steam "${USER_PKGS[*]}")" \
684 surf "A simple web browser based on WebKit2/GTK+" "$(ofn surf "${USER_PKGS[*]}")" \
685 terminator "Terminal emulator that supports tabs and grids" "$(ofn terminator "${USER_PKGS[*]}")" \
686 termite "A minimal VTE-based terminal emulator" "$(ofn termite "${USER_PKGS[*]}")" \
687 thunar "A modern file manager for the Xfce Desktop Environment" "$(ofn thunar "${USER_PKGS[*]}")" \
688 thunderbird "Standalone mail and news reader from mozilla" "$(ofn thunderbird "${USER_PKGS[*]}")" \
689 tilda "A GTK based drop down terminal for Linux and Unix" "$(ofn tilda "${USER_PKGS[*]}")" \
690 tilix "A tiling terminal emulator for Linux using GTK+ 3" "$(ofn tilix "${USER_PKGS[*]}")" \
691 transmission-cli "Free BitTorrent client CLI" "$(ofn transmission-cli "${USER_PKGS[*]}")" \
692 transmission-gtk "Free BitTorrent client GTK+ GUI" "$(ofn transmission-gtk "${USER_PKGS[*]}")" \
693 transmission-qt "Free BitTorrent client Qt GUI" "$(ofn transmission-qt "${USER_PKGS[*]}")" \
694 ttf-anonymous-pro "A family fixed-width fonts designed with code in mind" "$(ofn ttf-anonymous-pro "${USER_PKGS[*]}")" \
695 ttf-fira-code "Monospaced font with programming ligatures" "$(ofn ttf-fira-code "${USER_PKGS[*]}")" \
696 ttf-font-awesome "Iconic font designed for Bootstrap" "$(ofn ttf-font-awesome "${USER_PKGS[*]}")" \
697 ttf-hack "A hand groomed typeface based on Bitstream Vera Mono" "$(ofn ttf-hack "${USER_PKGS[*]}")" \
698 vlc "A free and open source cross-platform multimedia player" "$(ofn vlc "${USER_PKGS[*]}")" \
699 weechat "Fast, light and extensible IRC client" "$(ofn weechat "${USER_PKGS[*]}")" \
700 xarchiver "A GTK+ frontend to various command line archivers" "$(ofn xarchiver "${USER_PKGS[*]}")" \
701 xfce-terminal "A terminal emulator based in the Xfce Desktop Environment" "$(ofn xfce-terminal "${USER_PKGS[*]}")" \
702 xterm "The standard terminal emulator for the X window system" "$(ofn xterm "${USER_PKGS[*]}")" \
703 zathura "Minimalistic document viewer" "$(ofn zathura "${USER_PKGS[*]}")"
705 if [[ $USER_PKGS ]]; then
706 for i in $USER_PKGS; do
707 [[ ${PKG_EXT[$i]} && $USER_PKGS != *"${PKG_EXT[$i]}"* ]] && USER_PKGS+=" ${PKG_EXT[$i]}"
714 ###############################################################################
719 is_bg_install || return 0
720 local device choice devhash
721 devhash="$(lsblk -f | base64)"
723 part_device || return 1
728 if [[ $DISPLAY && $TERM != 'linux' ]] && hash gparted >/dev/null 2>&1; then
729 dlg choice menu "Edit Partitions" "$_part" \
730 "auto" "Whole device automatic partitioning" \
731 "shrink" "Shrink an existing ext2/3/4 or ntfs partition to make room for a new partition" \
732 "gparted" "GUI front end to parted" \
733 "cfdisk" "Curses based variant of fdisk" \
734 "parted" "GNU partition editor" \
735 "fdisk" "Dialog-driven creation and manipulation of partitions" \
736 "done" "Return to the main menu" || return 0
738 dlg choice menu "Edit Partitions" "$_part" \
739 "auto" "Whole device automatic partitioning" \
740 "shrink" "Shrink an existing ext2/3/4 or ntfs partition to make room for a new partition" \
741 "cfdisk" "Curses based variant of fdisk" \
742 "parted" "GNU partition editor" \
743 "fdisk" "Dialog-driven creation and manipulation of partitions" \
744 "done" "Return to the main menu" || return 0
747 if [[ $choice == 'done' ]]; then
749 elif [[ $choice == 'shrink' ]]; then
750 part_shrink "$device"
751 elif [[ $choice == 'auto' ]]; then
752 local root_size txt table boot_fs
753 root_size=$(lsblk -lno SIZE "$device" | awk 'NR == 1 {
756 print ($1 * 1000 - 512) / 1000 "G"
762 txt="\nWARNING:\n\nALL data on $device will be destroyed and the following partitions will be created\n\n- "
763 if [[ $SYS == 'BIOS' ]]; then
764 table="msdos" boot_fs="ext4"
765 txt+="An $boot_fs boot partition with the boot flag enabled (512M)\n- "
767 table="gpt" boot_fs="fat32"
768 txt+="A $boot_fs efi boot partition (512M)\n- "
770 txt+="An ext4 partition using all remaining space ($root_size)\n\nDo you want to continue?\n"
771 yesno "Auto Partition" "$txt" && part_auto "$device" "$table" "$boot_fs" "$root_size"
777 if [[ $devhash != "$(lsblk -f | base64)" ]]; then
778 msg "Probing Partitions" "\nInforming the kernel of partition changes using partprobe.\n" 0
779 partprobe >/dev/null 2>&1
787 if [[ $IGNORE_DEV ]]; then
788 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk "!/$IGNORE_DEV/"' && /disk|part|lvm|crypt|NAME/')"
790 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk '/disk|part|lvm|crypt|NAME/')"
792 msg "Device Tree" "\n\n$txt\n\n"
797 if [[ $1 == "$MNT/swapfile" && $SWAP_SIZE ]]; then
798 fallocate -l $SWAP_SIZE "$1" 2>$ERR
799 errshow "fallocate -l $SWAP_SIZE $1"
800 chmod 600 "$1" 2>$ERR
801 errshow "chmod 600 $1"
803 mkswap "$1" >/dev/null 2>$ERR
805 swapon "$1" >/dev/null 2>$ERR
812 local device="$1" table="$2" boot_fs="$3" size="$4" dev_info=""
813 dev_info="$(parted -s "$device" print)"
815 msg "Auto Partition" "\nRemoving partitions on $device and setting table to $table\n" 1
818 while read -r PART; do
819 parted -s "$device" rm "$PART" >/dev/null 2>&1
820 done <<< "$(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r)"
822 [[ $(awk '/Table:/ {print $3}' <<< "$dev_info") != "$table" ]] && parted -s "$device" mklabel "$table" >/dev/null 2>&1
824 msg "Auto Partition" "\nCreating a 512M $boot_fs boot partition.\n" 1
825 if [[ $SYS == "BIOS" ]]; then
826 parted -s "$device" mkpart primary "$boot_fs" 1MiB 513MiB >/dev/null 2>&1
828 parted -s "$device" mkpart ESP "$boot_fs" 1MiB 513MiB >/dev/null 2>&1
833 AUTO_BOOT_PART=$(lsblk -lno NAME,TYPE "$device" | awk 'NR==2 {print "/dev/" $1}')
835 if [[ $SYS == "BIOS" ]]; then
836 mkfs.ext4 -q "$AUTO_BOOT_PART" >/dev/null 2>&1
838 mkfs.vfat -F32 "$AUTO_BOOT_PART" >/dev/null 2>&1
841 msg "Auto Partition" "\nCreating a $size ext4 root partition.\n" 0
842 parted -s "$device" mkpart primary ext4 513MiB 100% >/dev/null 2>&1
844 AUTO_ROOT_PART="$(lsblk -lno NAME,TYPE "$device" | awk 'NR==3 {print "/dev/" $1}')"
845 mkfs.ext4 -q "$AUTO_ROOT_PART" >/dev/null 2>&1
847 FORMATTED+="$AUTO_BOOT_PART $AUTO_ROOT_PART "
848 msg "Auto Partition" "\nProcess complete.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$device")\n"
853 local regexp="$1" err=''
855 # string of partitions as /TYPE/PART SIZE
856 if [[ $IGNORE_DEV ]]; then
857 PARTS="$(lsblk -lno TYPE,NAME,SIZE |
858 awk "/$regexp/"' && !'"/$IGNORE_DEV/"' {
859 sub(/^part/, "/dev/")
860 sub(/^lvm|^crypt/, "/dev/mapper/")
864 PARTS="$(lsblk -lno TYPE,NAME,SIZE |
866 sub(/^part/, "/dev/")
867 sub(/^lvm|^crypt/, "/dev/mapper/")
872 # number of partitions total
874 while read -r line; do
878 # ensure we have enough partitions for the system and action type
880 'part|lvm|crypt') [[ $COUNT -lt 1 || ($SYS == 'UEFI' && $COUNT -lt 2) ]] && err="$_errpart" ;;
881 'part|crypt') (( COUNT < 1 )) && err="$_lvmerr" ;;
882 'part|lvm') (( COUNT < 2 )) && err="$_lukserr" ;;
885 # if there aren't enough partitions show the relevant error message
886 [[ $err ]] && { msg "Not Enough Partitions" "$err" 2; return 1; }
893 local part="$1" mountp="${MNT}$2" fs=""
894 fs="$(lsblk -lno FSTYPE "$part")"
897 if [[ $fs && ${FS_OPTS[$fs]} && $part != "$BOOT_PART" ]] && select_mntopts "$fs"; then
898 mount -o "$MNT_OPTS" "$part" "$mountp" >/dev/null 2>&1
900 mount "$part" "$mountp" >/dev/null 2>&1
903 part_mountconf "$part" "$mountp" || return 1
911 local part="$1" fs="$2" delay="$3"
913 msg "Format" "\nFormatting $part as $fs\n" 0
914 ${FS_CMDS[$fs]} "$part" >/dev/null 2>$ERR
915 errshow "${FS_CMDS[$fs]} $part" || return 1
924 local device="$1" fs=""
926 part_find "${device##*/}[^ ]" || return 1
927 (( COUNT == 1 )) && part="$(awk '{print $1}' <<< "${PARTS[@]}" )"
929 if (( COUNT == 1 )) || dlg part menu "Resize" "\nWhich partition on $device do you want to resize?" $PARTS; then
930 fs=$(lsblk -lno FSTYPE "$part")
933 msg "Resize" "\nGathering device size info.\n" 0
935 end=$(parted -s "$device" unit KiB print | awk '/^\s*'"$num"'/ {print $3}') # part size in KiB
936 devsize=$(parted -s "$device" unit KiB print | awk '/Disk '"${device//\//\\/}"':/ {print $3}') # whole device size in KiB
937 mount "$part" $MNT >/dev/null 2>&1; sleep 0.5
938 min=$(df --output=used --block-size=MiB "$part" | awk 'NR == 2 {print int($1) + 256}')
939 max=$(df --output=avail --block-size=MiB "$part" | awk 'NR == 2 {print int($1)}')
942 if dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Resize: $part " --rangebox "$_resize" 17 "$COLUMNS" "$min" "$max" $((max / 2)) 2>$ANS; then
944 size=$((size * 1024))
951 if ntfsresize -fc "$part"; then
952 ntfsresize -ff --size $(( (size * 1024) / 1000 ))k "$part" 2>$ERR # k=10^3 bytes
953 errshow "ntfsresize -f -s $(( (size * 1024) / 1000 ))k $part" || return 1
955 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"
960 e2fsck -f "$part"; sleep 0.5
961 resize2fs -f "$part" ${size}K 2>$ERR # K=2^10 bytes
962 errshow "resize2fs -f $part ${size}K" || return 1
966 parted "$device" resizepart "$num" ${size}KiB || return 1
969 if [[ $devsize == "$end" ]]; then
970 parted -s "$device" mkpart primary ext4 ${size}KiB 100% 2>$ERR
971 errshow "parted -s $device mkpart primary ext4 ${size}KiB 100%" || return 1
973 parted -s "$device" mkpart primary ext4 ${size}KiB ${end}KiB 2>$ERR
974 errshow "parted -s $device mkpart primary ext4 ${size}KiB ${end}KiB" || return 1
976 msg "Resize Complete" "\n$part has been successfully resized to $((size / 1024))M.\n" 1
978 "") msg "No Filesystem" "\nFor unformatted partitions, cfdisk can be used in the partition menu.\n" ;;
979 *) msg "Invalid Filesystem: $fs" "\nResizing only supports ext and ntfs.\n" ;;
986 if [[ $DEV_COUNT -eq 1 && $SYS_DEVS ]]; then
987 DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
988 elif (( DEV_COUNT > 1 )); then
990 dlg DEVICE menu "Boot Device" "\nSelect the device to use for bootloader install." $SYS_DEVS
992 dlg DEVICE menu "Select Device" "$_device" $SYS_DEVS
994 [[ $DEVICE ]] || return 1
995 elif [[ $DEV_COUNT -lt 1 && ! $1 ]]; then
996 msg "Device Error" "\nNo available devices.\n\nExiting..\n" 2; die 1
999 [[ $1 ]] && BOOT_DEV="$DEVICE"
1006 BOOT_DEV="${BOOT_PART%[1-9]}"
1007 BOOT_PART_NUM="${BOOT_PART: -1}"
1008 [[ $BOOT_PART = /dev/nvme* ]] && BOOT_DEV="${BOOT_PART%p[1-9]}"
1009 if [[ $SYS == 'UEFI' ]]; then
1010 parted -s $BOOT_DEV set $BOOT_PART_NUM esp on >/dev/null 2>&1
1012 parted -s $BOOT_DEV set $BOOT_PART_NUM boot on >/dev/null 2>&1
1019 local part="$1" devs=""
1020 devs="$(lsblk -lno NAME,FSTYPE,TYPE)"
1022 # Identify if $part is LUKS+LVM, LVM+LUKS, LVM alone, or LUKS alone
1023 if lsblk -lno TYPE "$part" | grep -q 'crypt'; then
1025 LUKS_NAME="${part#/dev/mapper/}"
1027 for dev in $(awk '/lvm/ && /crypto_LUKS/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
1028 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1029 LUKS_DEV="$LUKS_DEV cryptdevice=$dev:$LUKS_NAME"
1030 LVM='logical volume'
1035 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
1036 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1037 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
1038 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
1043 elif lsblk -lno TYPE "$part" | grep -q 'lvm'; then
1044 LVM='logical volume'
1045 VNAME="${part#/dev/mapper/}"
1047 for dev in $(awk '/crypt/ && /lvm2_member/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
1048 if lsblk -lno NAME "$dev" | grep -q "$VNAME"; then
1049 LUKS_NAME="${dev/\/dev\/mapper\//}"
1054 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
1055 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1056 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
1057 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
1068 if (( COUNT > 0 )); then
1069 PARTS="$(sed "/${i//\//\\/}/d" <<< "$PARTS")"
1077 if grep -qw "$1" /proc/mounts; then
1078 msg "Mount Success" "\nPartition $1 mounted at $2\n" 1
1082 msg "Mount Fail" "\nPartition $1 failed to mount at $2\n" 2
1087 ###############################################################################
1092 is_bg_install || return 0
1095 part_find 'part|lvm|crypt' || { SEL=2; return 1; }
1097 [[ $LUKS && $LUKS_PART ]] && part_countdec $LUKS_PART
1098 [[ $LVM && $LVM_PARTS ]] && part_countdec $LVM_PARTS
1100 select_root_partition || return 1
1102 if [[ $SYS == 'UEFI' ]]; then
1103 select_efi_partition || { BOOT_PART=''; return 1; }
1104 elif (( COUNT > 0 )); then
1105 select_boot_partition || { BOOT_PART=''; return 1; }
1108 if [[ $BOOT_PART ]]; then
1109 part_mount "$BOOT_PART" "/$BOOTDIR" && SEP_BOOT=true || return 1
1113 select_swap || return 1
1114 select_extra_partitions || return 1
1115 install_background || return 1
1122 dlg SWAP_PART menu "Swap Setup" "\nSelect whether to use a swapfile, swap partition, or none." \
1123 "none" "Don't allocate any swap space" \
1124 "swapfile" "Allocate $SYS_MEM at /swapfile" \
1127 if [[ -z $SWAP_PART || $SWAP_PART == "none" ]]; then
1130 elif [[ $SWAP_PART == "swapfile" ]]; then
1132 until [[ ${SWAP_SIZE:0:1} =~ [1-9] && ${SWAP_SIZE: -1} =~ (M|G) ]]; do
1133 (( 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
1134 dlg SWAP_SIZE input "Swap Setup" "$_swapsize" "$SYS_MEM" || { SWAP_PART=''; SWAP_SIZE=''; return 1; }
1137 part_swap "$MNT/$SWAP_PART"
1138 SWAP_PART="/$SWAP_PART"
1139 elif [[ $PARTS == *"$SWAP_PART"* ]]; then
1140 part_swap $SWAP_PART
1141 part_countdec $SWAP_PART
1142 SWAP_SIZE="$(lsblk -lno SIZE $SWAP_PART)"
1152 local fs="$1" opts=''
1153 local title="${fs^} Mount Options"
1155 for i in ${FS_OPTS[$fs]}; do
1159 until [[ $MNT_OPTS ]]; do
1160 dlg MNT_OPTS check "$title" "$_mount" $opts
1161 [[ $MNT_OPTS ]] || return 1
1162 MNT_OPTS="${MNT_OPTS// /,}"
1163 yesno "$title" "\nConfirm the following options: $MNT_OPTS\n" || MNT_OPTS=''
1172 until [[ $EXMNT ]]; do
1173 dlg EXMNT input "Extra Mount $part" "$_exmnt" "/" || return 1
1174 if [[ ${EXMNT:0:1} != "/" || ${#EXMNT} -le 1 || $EXMNT =~ \ |\' || $EXMNTS == *"$EXMNT"* ]]; then
1175 msg "Mountpoint Error" "$_errexpart"
1184 local part="$1" fs='' cur=''
1185 local txt="\nSelect which filesystem to use for: $part\n\nDefault: ext4"
1186 cur="$(lsblk -lno FSTYPE "$part" 2>/dev/null)"
1189 if [[ $cur && ($part != "$ROOT_PART" || $FORMATTED == *"$part"*) ]]; then
1190 dlg fs menu "Filesystem" "$txt\nCurrent: $cur" skip - ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1192 dlg fs menu "Filesystem" "$txt" ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1194 [[ $fs == 'skip' ]] && return 0
1195 yesno "Filesystem" "\nFormat $part as $fs?\n" || fs=''
1197 part_format "$part" "$fs"
1200 select_efi_partition()
1202 local pts size dev isize bsize ptcount=0
1204 # walk partition list and skip ones that are too small/big for boot
1205 while read -r dev size; do
1206 size_t="${size: -1:1}" # size type eg. K, M, G, T
1207 isize=${size:0:-1} # remove trailing size type character
1208 isize=${isize%.*} # remove any decimal (round down)
1209 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+=$'\n'"$dev $size"; (( ptcount++ )); }
1212 if [[ $AUTO_BOOT_PART ]]; then
1213 BOOT_PART="$AUTO_BOOT_PART"; return 0 # were done here
1214 elif (( ptcount == 1 )); then
1215 BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")"
1217 dlg BOOT_PART menu "EFI Partition" "$_uefi" $pts
1220 [[ $BOOT_PART ]] || return 1
1222 if grep -q 'fat' <<< "$(fsck -N "$BOOT_PART")"; then
1223 local txt="\nIMPORTANT:\n\nThe EFI partition $BOOT_PART $_format"
1224 if yesno "Format EFI Partition" "$txt" "Format $BOOT_PART" "Skip Formatting" 1; then
1225 part_format "$BOOT_PART" "vfat" 2
1228 part_format "$BOOT_PART" "vfat" 2
1234 select_boot_partition()
1236 local pts size dev isize bsize ptcount=0
1238 # walk partition list and skip ones that are too small/big for boot
1239 while read -r dev size; do
1240 size_t="${size: -1:1}" # size type eg. K, M, G, T
1241 isize=${size:0:-1} # remove trailing size type character
1242 isize=${isize%.*} # remove any decimal (round down)
1243 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+=$'\n'"$dev $size"; (( ptcount++ )); }
1246 if [[ $AUTO_BOOT_PART && ! $LVM ]]; then
1247 BOOT_PART="$AUTO_BOOT_PART"; return 0 # were done here
1248 elif [[ $LUKS && ! $LVM ]]; then
1249 dlg BOOT_PART menu "Boot Partition" "$_biosluks" $pts
1250 [[ $BOOT_PART ]] || return 1
1252 dlg BOOT_PART menu "Boot Partition" "$_bios" "skip" "don't use a separate boot" $pts
1253 [[ -z $BOOT_PART || $BOOT_PART == "skip" ]] && { BOOT_PART=''; return 0; }
1256 if grep -q 'ext[34]' <<< "$(fsck -N "$BOOT_PART")"; then
1257 local txt="\nIMPORTANT:\n\nThe boot partition $BOOT_PART $_format"
1258 if yesno "Format Boot Partition" "$txt" "Format $BOOT_PART" "Skip Formatting" 1; then
1259 part_format "$BOOT_PART" "ext4" 2
1262 part_format "$BOOT_PART" "ext4" 2
1267 select_root_partition()
1269 local pts size dev isize bsize ptcount=0
1271 # walk partition list and skip ones that are too small for / (root)
1272 while read -r dev size; do
1273 size_t="${size: -1:1}" # size type eg. K, M, G, T
1274 isize=${size:0:-1} # remove trailing size type character
1275 isize=${isize%.*} # remove any decimal (round down)
1276 [[ $size_t =~ [MK] || ($size_t == 'G' && $isize -lt 4) ]] || { pts+=$'\n'"$dev $size"; (( ptcount++ )); }
1279 if [[ $AUTO_ROOT_PART && -z $LVM && -z $LUKS ]]; then
1280 ROOT_PART="$AUTO_ROOT_PART"
1281 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1282 return 0 # we're done here
1283 elif (( ptcount == 1 )); then # only one available device
1284 ROOT_PART="$(awk 'NR==1 {print $1}' <<< "$pts")"
1286 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
1288 [[ $ROOT_PART ]] || return 1
1290 select_filesystem "$ROOT_PART" || { ROOT_PART=''; return 1; }
1291 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1296 select_extra_partitions()
1298 local part pts size dev isize bsize ptcount=0
1300 # walk partition list and skip ones that are too small to be usable
1301 while read -r dev size; do
1302 [[ ${size: -1:1} =~ [KM] ]] || { pts+=$'\n'"$dev $size"; (( ptcount++ )); }
1305 while (( ptcount > 0 )); do
1307 dlg part menu 'Mount Extra' "$_expart" 'done' 'finish mounting step' $pts || break
1308 if [[ $part == 'done' ]]; then
1310 elif select_filesystem "$part" && select_mountpoint && part_mount "$part" "$EXMNT"; then
1311 EXMNTS+="$part: $EXMNT "
1312 [[ $EXMNT == '/usr' && $HOOKS != *usr* ]] && HOOKS="usr $HOOKS"
1320 ###############################################################################
1328 genfstab -U $MNT >$MNT/etc/fstab 2>$ERR
1329 errshow 1 "genfstab -U $MNT >$MNT/etc/fstab"
1330 [[ -f $MNT/swapfile ]] && sed -i "s~${MNT}~~" $MNT/etc/fstab
1334 chrun "hwclock --systohc --utc" || chrun "hwclock --systohc --utc --directisa"
1337 chrun "chown -Rf $NEWUSER:users /home/$NEWUSER"
1341 dlg choice menu "Finalization" "$_edit" \
1342 finished "exit the installer and reboot" \
1343 keyboard "${EDIT_FILES[keyboard]}" \
1344 console "${EDIT_FILES[console]}" \
1345 locale "${EDIT_FILES[locale]}" \
1346 hostname "${EDIT_FILES[hostname]}" \
1347 sudoers "${EDIT_FILES[sudoers]}" \
1348 mkinitcpio "${EDIT_FILES[mkinitcpio]}" \
1349 fstab "${EDIT_FILES[fstab]}" \
1350 crypttab "${EDIT_FILES[crypttab]}" \
1351 bootloader "${EDIT_FILES[bootloader]}" \
1352 pacman "${EDIT_FILES[pacman]}" \
1353 login "${EDIT_FILES[login]}"
1355 if [[ -z $choice || $choice == 'finished' ]]; then
1356 [[ $DEBUG == true && -r $DBG ]] && vim $DBG
1360 for f in ${EDIT_FILES[$choice]}; do
1361 [[ -e ${MNT}$f ]] && exists+=" ${MNT}$f"
1363 if [[ $exists ]]; then
1366 msg "File Missing" "\nThe file(s) selected do not exist:\n\n${EDIT_FILES[$choice]}\n"
1374 if [[ $RSYNC_PID || $MIRROR_PID ]]; then
1376 printf "\nOne or more background install processes are still running, grabbing their output...\n"
1378 while kill -0 "$RSYNC_PID" 2>/dev/null || kill -0 "$MIRROR_PID" 2>/dev/null; do
1379 tail -n 1 /tmp/bg_out
1383 unset RSYNC_PID MIRROR_PID
1384 elif hash rsync >/dev/null 2>&1 && [[ -d /run/archiso/sfs/airootfs/etc/skel ]]; then
1385 rsync -ahv /run/archiso/sfs/airootfs/ $MNT/ 2>$ERR
1386 errshow 1 "rsync -ahv /run/archiso/sfs/airootfs/ $MNT/"
1387 install_mirrorlist "$MNT/etc/pacman.d/mirrorlist"
1388 chrun "pacman -Syyu --noconfirm && pacman -S $BASE_PKGS --needed --noconfirm"
1390 mkdir -p /etc/pacman.d/mirrorlist
1391 install_mirrorlist "/etc/pacman.d/mirrorlist"
1392 pacstrap "$MNT" base $ISO_BASE 2>$ERR
1393 errshow 1 "pacstrap $MNT base $KERNEL $ISO_BASE"
1394 mkdir -p "$MNT/etc/pacman.d/mirrorlist"
1395 cp -f /etc/pacman.d/mirrorlist "$MNT/etc/pacman.d/mirrorlist"
1396 chrun "pacman -Syyu --noconfirm && pacman -S $BASE_PKGS --needed --noconfirm"
1399 rm -rf $MNT/etc/mkinitcpio-archiso.conf
1400 find $MNT/usr/lib/initcpio -name 'archiso*' -type f -delete
1401 sed -i 's/volatile/auto/g' $MNT/etc/systemd/journald.conf
1402 find $MNT/boot -name '*-ucode.img' -delete
1405 find $MNT/etc/X11/xorg.conf.d/ -name '*.conf' -delete
1406 elif lspci | grep ' VGA ' | grep -q 'Intel'; then
1407 cat > $MNT/etc/X11/xorg.conf.d/20-intel.conf << EOF
1409 Identifier "Intel Graphics"
1411 Option "TearFree" "true"
1416 [[ -e /run/archiso/sfs/airootfs && $KERNEL == 'linux' ]] && cp -vf $RUN/x86_64/vmlinuz $MNT/boot/vmlinuz-linux
1418 cp -fv /etc/resolv.conf $MNT/etc/
1419 [[ -e /etc/NetworkManager/system-connections ]] && cp -rvf /etc/NetworkManager/system-connections $MNT/etc/NetworkManager/
1421 echo "LANG=$MYLOCALE" > $MNT/etc/locale.conf
1422 cp -f $MNT/etc/locale.conf $MNT/etc/default/locale
1423 sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${MYLOCALE}/${MYLOCALE}/g" $MNT/etc/locale.gen
1425 chrun "ln -svf /usr/share/zoneinfo/$ZONE/$SUBZ /etc/localtime"
1427 if [[ $BROADCOM_WL ]]; then
1428 echo 'blacklist bcma' >> $MNT/etc/modprobe.d/blacklist.conf
1429 rm -f $MNT/etc/modprobe/
1432 cat > $MNT/etc/X11/xorg.conf.d/00-keyboard.conf << EOF
1433 # Use localectl(1) to instruct systemd-localed to update it.
1434 Section "InputClass"
1435 Identifier "system-keyboard"
1436 MatchIsKeyboard "on"
1437 Option "XkbLayout" "$KEYMAP"
1440 cat > $MNT/etc/default/keyboard << EOF
1441 # KEYBOARD CONFIGURATION FILE
1442 # Consult the keyboard(5) manual page.
1449 printf "KEYMAP=%s\nFONT=%s\n" "$CMAP" "$FONT" > $MNT/etc/vconsole.conf
1450 echo "$MYHOST" > $MNT/etc/hostname
1451 cat > $MNT/etc/hosts << EOF
1454 ::1 localhost ip6-localhost ip6-loopback
1455 ff02::1 ip6-allnodes
1456 ff02::2 ip6-allrouters
1462 if [[ $ROOT_PART == /dev/mapper* ]]; then
1463 ROOT_PART_ID="$ROOT_PART"
1465 local uuid_type="UUID"
1466 [[ $BOOTLDR =~ (systemd-boot|refind-efi|efistub) ]] && uuid_type="PARTUUID"
1467 ROOT_PART_ID="$uuid_type=$(blkid -s $uuid_type -o value $ROOT_PART)"
1470 if [[ $SYS == 'UEFI' ]]; then
1472 find $MNT/$BOOTDIR/EFI/ -maxdepth 1 -mindepth 1 -iname "$DIST" -type d -delete
1474 find $MNT/$BOOTDIR/EFI/ -maxdepth 1 -mindepth 1 -iname 'BOOT' -type d -delete
1478 chrun "${BCMDS[$BOOTLDR]}" 2>$ERR
1479 errshow 1 "${BCMDS[$BOOTLDR]}"
1481 if [[ -d $MNT/hostrun ]]; then
1482 # cleanup the bind mounts we made earlier for the grub-probe module
1483 umount_dir $MNT/hostrun/{udev,lvm}
1484 rm -rf $MNT/hostrun >/dev/null 2>&1
1487 if [[ $SYS == 'UEFI' ]]; then
1488 # some UEFI firmware requires a generic esp/BOOT/BOOTX64.EFI
1489 mkdir -pv $MNT/$BOOTDIR/EFI/BOOT
1490 if [[ $BOOTLDR == 'grub' ]]; then
1491 cp -fv $MNT/$BOOTDIR/EFI/$DIST/grubx64.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI
1492 elif [[ $BOOTLDR == 'syslinux' ]]; then
1493 cp -rf $MNT/$BOOTDIR/EFI/syslinux/* $MNT/$BOOTDIR/EFI/BOOT/
1494 cp -f $MNT/$BOOTDIR/EFI/syslinux/syslinux.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI
1495 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1496 sed -i '/#extra_kernel_version_strings/ c extra_kernel_version_strings linux-hardened,linux-zen,linux-lts,linux' $MNT/$BOOTDIR/EFI/refind/refind.conf
1497 cp -fv $MNT/$BOOTDIR/EFI/refind/refind_x64.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI
1506 chrun "chpasswd <<< 'root:$ROOT_PASS'" 2>$ERR
1507 errshow 1 "set root password"
1508 if [[ $MYSHELL != "/usr/bin/zsh" ]]; then
1509 # root uses zsh by default, change it if something else was chosen
1510 chrun "usermod -s $MYSHELL root" 2>$ERR
1511 errshow 1 "usermod -s $MYSHELL root"
1512 [[ $MYSHELL == '/usr/bin/mksh' ]] && cp -fv $MNT/etc/skel/.mkshrc $MNT/root/.mkshrc
1515 local groups='audio,autologin,floppy,log,network,rfkill,scanner,storage,optical,power,wheel'
1517 chrun "groupadd -r autologin" 2>$ERR
1518 errshow 1 "groupadd -r autologin"
1519 chrun "useradd -m -u 1000 -g users -G $groups -s $MYSHELL $NEWUSER" 2>$ERR
1520 errshow 1 "useradd -m -u 1000 -g users -G $groups -s $MYSHELL $NEWUSER"
1521 chrun "chpasswd <<< '$NEWUSER:$USER_PASS'" 2>$ERR
1522 errshow 1 "set $NEWUSER password"
1524 if [[ $USER_PKGS == *neovim* && -d $MNT/home/$NEWUSER/.vim ]]; then
1525 mkdir -p $MNT/home/$NEWUSER/.config/nvim
1526 cp -fv $MNT/home/$NEWUSER/.vimrc $MNT/home/$NEWUSER/.config/nvim/init.vim
1527 cp -rfv $MNT/home/$NEWUSER/.vim/colors $MNT/home/$NEWUSER/.config/nvim/colors
1530 [[ $INSTALL_WMS == *dwm* ]] && install_suckless
1531 [[ $INSTALL_WMS == *awesome* ]] && install_awesome
1532 [[ $WM_PKGS == *xfce* ]] && echo 'volumeicon &' >> $MNT/home/$NEWUSER/.xprofile
1534 # remove some commands from ~/.xprofile when using KDE or Gnome as the login session
1535 if [[ $LOGIN_WM =~ (startkde|gnome-session) || ($LOGIN_TYPE == 'lightdm' && $WM_PKGS =~ (plasma|gnome)) ]]; then
1536 sed -i '/super/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1537 sed -i '/nitrogen/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1538 sed -i '/al-compositor/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1539 sed -i '/compton/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1547 if [[ -e $MNT/home/$NEWUSER/.xinitrc ]] && grep -q 'exec' $MNT/home/$NEWUSER/.xinitrc; then
1548 sed -i "/exec/ c exec ${LOGIN_WM}" $MNT/home/$NEWUSER/.xinitrc
1550 printf "exec %s\n" "$LOGIN_WM" >> $MNT/home/$NEWUSER/.xinitrc
1553 [[ ${EDIT_FILES[login]} == *"$LOGINRC"* ]] || EDIT_FILES[login]+=" /home/$NEWUSER/$LOGINRC"
1555 if [[ $AUTOLOGIN ]]; then
1556 sed -i "s/root/${NEWUSER}/g" $SERVICE/autologin.conf
1557 cat > $MNT/home/$NEWUSER/$LOGINRC <<EOF
1559 # sourced by ${MYSHELL##*/} when used as a login shell
1561 # automatically run startx when logging in on tty1
1562 if [ -z \$DISPLAY ] && [ \$XDG_VTNR -eq 1 ]; then
1573 SERVICE="$MNT/etc/systemd/system/getty@tty1.service.d"
1574 sed -i '/printf/d' $MNT/root/.zshrc
1575 install_${LOGIN_TYPE:-xinit}
1581 rm -rf $MNT/home/$NEWUSER/.{xinitrc,profile,zprofile,bash_profile}
1582 chrun 'systemctl set-default graphical.target && systemctl enable lightdm.service' 2>$ERR
1583 errshow 1 "systemctl set-default graphical.target && systemctl enable lightdm.service"
1584 cat > $MNT/etc/lightdm/lightdm-gtk-greeter.conf << EOF
1585 # LightDM GTK+ Configuration
1588 default-user-image=/usr/share/icons/ArchLabs-Dark/64x64/places/distributor-logo-archlabs.png
1589 background=/usr/share/backgrounds/archlabs/archlabs.jpg
1590 theme-name=Adwaita-dark
1591 icon-theme-name=Adwaita
1592 font-name=DejaVu Sans Mono 11
1593 position=30%,end 50%,end
1599 # downloads and sets up @elenapan's awesome WM config hosted on github
1601 if chrun "git clone https://github.com/elenapan/archlabs-awesome /home/$NEWUSER/archlabs-awesome"; then
1602 cp -rT "/mnt/home/$NEWUSER/archlabs-awesome" "/mnt/home/$NEWUSER"
1603 cp -rT "/mnt/home/$NEWUSER/archlabs-awesome" /mnt/etc/skel
1604 rm -rf "/home/$NEWUSER/"{.git,archlabs-awesome,screenshots}
1605 printf "You will need to instal pamac seperately if needed using: 'baph -i pamac-aur'\n"
1608 printf "failed to clone awesome config repo\n"
1615 local inpkg="$PACKAGES $USER_PKGS"
1617 [[ -x $MNT/usr/bin/X ]] || inpkg+=" $BASE_PKGS"
1619 if pacman -Qsq 'archlabs-installer' >/dev/null 2>&1; then
1620 rmpkg+=" archlabs-installer"
1621 elif [[ -e "$MNT/usr/bin/archlabs-installer" ]]; then
1622 rm -f "$MNT/usr/bin/archlabs-installer"
1625 # add extras or missed packages gathered throughout the install
1626 [[ $UCODE ]] && inpkg+=" $UCODE"
1627 [[ $KERNEL == 'linux' ]] || { inpkg+=" $KERNEL"; rmpkg+=" linux"; }
1628 [[ $MYSHELL == "/usr/bin/mksh" ]] && inpkg+=" mksh"
1629 if [[ $MYSHELL == '/usr/bin/zsh' ]]; then
1630 inpkg+=" zsh-completions"
1635 # packages only installed for certain WM/DE
1636 [[ $INSTALL_WMS =~ ^(plasma|gnome|cinnamon)$ ]] || inpkg+=" archlabs-ksuperkey"
1637 [[ $INSTALL_WMS =~ (openbox|bspwm|i3-gaps|dwm|fluxbox) ]] && inpkg+=" $WM_BASE_PKGS"
1639 # ensure a terminal gets installed
1640 [[ $inpkg =~ (term|urxvt|tilix|alacritty|sakura|tilda|plasma|cinnamon) || $INSTALL_WMS == *dwm* ]] || inpkg+=" xterm"
1642 # update fully first to avoid issues
1643 chrun "pacman -Syyu --noconfirm"
1645 # remove packages we no longer want
1646 [[ $rmpkg ]] && chrun "pacman -Rns $rmpkg --noconfirm"
1648 # for some reason the user has "no network" after install even though the
1649 # system is connected, reinstalling iputils fixes it
1650 chrun "pacman -S iputils --noconfirm"
1652 # install all the packages chosen throughout the install
1653 chrun "pacman -S $inpkg --needed --noconfirm" 2>$ERR
1654 errshow 1 "pacman -S $inpkg --needed --noconfirm"
1656 # extras for bootloaders
1657 if [[ $BOOTLDR == 'grub' ]]; then
1658 if [[ $SYS == 'BIOS' ]]; then
1659 chrun "pacman -S grub os-prober --needed --noconfirm" 2>$ERR
1660 errshow 1 "pacman -S grub os-prober --needed --noconfirm"
1662 chrun "pacman -S grub os-prober efibootmgr --needed --noconfirm" 2>$ERR
1663 errshow 1 "pacman -S grub os-prober efibootmgr --needed --noconfirm"
1665 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1666 chrun "pacman -S refind-efi efibootmgr --needed --noconfirm" 2>$ERR
1667 errshow 1 "pacman -S refind-efi efibootmgr --needed --noconfirm"
1668 elif [[ $SYS == 'UEFI' ]]; then
1669 chrun "pacman -S efibootmgr --needed --noconfirm" 2>$ERR
1670 errshow 1 "pacman -S efibootmgr --needed --noconfirm"
1673 sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" $MNT/etc/sudoers
1680 mkdir -pv $MNT/home/$NEWUSER/suckless
1682 for i in dwm dmenu st; do
1683 if chrun "git clone https://git.suckless.org/$i /home/$NEWUSER/suckless/$i"; then
1684 chrun "cd /home/$NEWUSER/suckless/$i; make PREFIX=/usr install; make clean; rm config.h"
1686 printf "failed to clone %s repo\n" "$i"
1690 if [[ -d $MNT/home/$NEWUSER/suckless/dwm && -x $MNT/usr/bin/dwm ]]; then
1691 printf "To configure dwm edit %s\n" "/home/$NEWUSER/suckless/dwm/config.h"
1692 printf "You can then recompile it with 'sudo make clean install'\n"
1697 install_mkinitcpio()
1701 # luks keyfile creation
1702 # currently not used due to not prompting for passphrase on startup
1703 # [[ $LUKS_UUID && $LUKS_PASS && $SYS == 'UEFI' && $BOOTLDR == 'grub' ]] && luks_keyfile
1705 [[ $LUKS ]] && add="encrypt"
1706 [[ $LVM ]] && { [[ $add ]] && add+=" lvm2" || add+="lvm2"; }
1707 sed -i "s/block filesystems/block ${add} filesystems ${HOOKS}/g" $MNT/etc/mkinitcpio.conf
1708 chrun "mkinitcpio -p $KERNEL" 2>$ERR
1709 errshow 1 "mkinitcpio -p $KERNEL"
1712 install_mirrorlist()
1714 local mfile="$1" # output mirrorlist file
1716 if hash reflector >/dev/null 2>&1; then
1717 reflector --score 120 -l 50 -f 5 --sort rate --save "$mfile"
1718 elif hash rankmirrors >/dev/null 2>&1; then
1719 ip_add="$(curl -fsSL "http://api.ipstack.com/check&?access_key=5f29642060ab983b31fdf4c2935d8c56&fields=ip" |
1720 python -c "import sys, json; print(json.load(sys.stdin)['ip'])")"
1721 country="$(curl -fsSL "http://api.ipstack.com/${ip_add}?access_key=5f29642060ab983b31fdf4c2935d8c56&fields=country_code" |
1722 python -c "import sys, json; print(json.load(sys.stdin)['country_code'])")"
1723 if [[ "$country" ]]; then
1724 if [[ $country =~ (CA|US) ]]; then
1725 mirror="https://www.archlinux.org/mirrorlist/?country=US&country=CA&use_mirror_status=on"
1726 elif [[ $country =~ (AU|NZ) ]]; then
1727 mirror="https://www.archlinux.org/mirrorlist/?country=AU&country=NZ&use_mirror_status=on"
1729 mirror="https://www.archlinux.org/mirrorlist/?country=${country}&use_mirror_status=on"
1732 mirror="https://www.archlinux.org/mirrorlist/?country=all&use_mirror_status=on"
1735 curl -fsSL "$mirror" | sed -e 's/^#Server/Server/' -e '/^#/d' | rankmirrors -n 6 - >"$mfile"
1741 install_background()
1743 if [[ -d /run/archiso/sfs/airootfs/etc/skel ]] && grep -qw "$MNT" /proc/mounts && (grep -qw "$MNT/$BOOTDIR" /proc/mounts || [[ $SYS == 'BIOS' && -z $LUKS ]]); then
1744 yesno "Background Install" "\nBegin install in the background?\n" || return 0
1745 rsync -a /run/archiso/sfs/airootfs/ $MNT/ &
1747 ( install_mirrorlist "$MNT/etc/pacman.d/mirrorlist" && sleep 1 && mkdir -p $MNT/var/lib/pacman && chrun "pacman -Syyu $BASE_PKGS --needed --noconfirm" >> /tmp/bg_out 2>&1 ) &
1749 # end the background processes before exiting
1750 trap "kill $RSYNC_PID $MIRROR_PID 2>/dev/null" EXIT
1755 ###############################################################################
1760 EDIT_FILES[bootloader]="/etc/default/grub"
1762 if [[ $SYS == 'BIOS' ]]; then
1763 [[ $BOOT_DEV ]] || { part_device 1 || return 1; }
1764 BCMDS[grub]="grub-install --recheck --force --target=i386-pc $BOOT_DEV"
1766 # if [[ $ROOT_PART == */dev/mapper/* && -z $LVM && -z $LUKS_PASS ]]; then
1767 # luks_pass "$_luksopen" 1 || return 1
1769 BCMDS[grub]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1770 grub-install --recheck --force --target=x86_64-efi --efi-directory=/$BOOTDIR --bootloader-id=$DIST"
1771 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1774 BCMDS[grub]="mkdir -p /run/udev /run/lvm &&
1775 mount --bind /hostrun/udev /run/udev &&
1776 mount --bind /hostrun/lvm /run/lvm &&
1778 grub-mkconfig -o /boot/grub/grub.cfg &&
1779 sleep 1 && umount /run/udev /run/lvm"
1786 sed -i "s/GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR=\"${DIST}\"/g;
1787 s/GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"\"/g" $MNT/etc/default/grub
1789 if [[ $LUKS_DEV ]]; then
1790 sed -i "s~#GRUB_ENABLE_CRYPTODISK~GRUB_ENABLE_CRYPTODISK~g;
1791 s~GRUB_CMDLINE_LINUX=.*~GRUB_CMDLINE_LINUX=\"${LUKS_DEV}\"~g" $MNT/etc/default/grub 2>$ERR
1792 errshow 1 "sed -i 's~#GRUB_ENABLE_CRYPTODISK~GRUB_ENABLE_CRYPTODISK~g;
1793 s~GRUB_CMDLINE_LINUX=.*~GRUB_CMDLINE_LINUX=\"${LUKS_DEV}\"~g' $MNT/etc/default/grub"
1796 if [[ $SYS == 'BIOS' && $LVM && -z $SEP_BOOT ]]; then
1797 sed -i "s/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g" $MNT/etc/default/grub 2>$ERR
1798 errshow 1 "sed -i 's/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g' $MNT/etc/default/grub"
1801 # setup for os-prober module
1802 mkdir -p /run/{lvm,udev} $MNT/hostrun/{lvm,udev}
1803 mount --bind /run/lvm $MNT/hostrun/lvm
1804 mount --bind /run/udev $MNT/hostrun/udev
1811 EDIT_FILES[bootloader]=""
1816 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1817 efibootmgr -v -d $BOOT_DEV -p $BOOT_PART_NUM -c -L '${DIST} Linux' -l /vmlinuz-${KERNEL} \
1818 -u 'root=$ROOT_PART_ID rw $([[ $UCODE ]] && printf 'initrd=\%s.img ' "$UCODE")initrd=\initramfs-${KERNEL}.img'"
1823 if [[ $SYS == 'BIOS' ]]; then
1824 EDIT_FILES[bootloader]="/boot/syslinux/syslinux.cfg"
1826 EDIT_FILES[bootloader]="/boot/EFI/syslinux/syslinux.cfg"
1827 BCMDS[syslinux]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1828 efibootmgr -v -c -d $BOOT_DEV -p $BOOT_PART_NUM -l /EFI/syslinux/syslinux.efi -L $DIST"
1834 local c="$MNT/boot/syslinux" s="/usr/lib/syslinux/bios" d=".."
1835 [[ $SYS == 'UEFI' ]] && { c="$MNT/boot/EFI/syslinux"; s="/usr/lib/syslinux/efi64/"; d=''; }
1837 mkdir -pv "$c" && cp -rfv $s/* "$c/" && cp -f "$RUN/syslinux/splash.png" "$c/"
1838 cat > "$c/syslinux.cfg" << EOF
1840 MENU TITLE $DIST Boot Menu
1841 MENU BACKGROUND splash.png
1845 # see: https://www.syslinux.org/wiki/index.php/Comboot/menu.c32
1854 MENU HELPMSGENDROW 29
1855 MENU COLOR border 30;44 #40ffffff #a0000000 std
1856 MENU COLOR title 1;36;44 #9033ccff #a0000000 std
1857 MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
1858 MENU COLOR unsel 37;44 #50ffffff #a0000000 std
1859 MENU COLOR help 37;40 #c0ffffff #a0000000 std
1860 MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
1861 MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
1862 MENU COLOR msg07 37;40 #90ffffff #a0000000 std
1863 MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
1866 MENU LABEL $DIST Linux
1867 LINUX $d/vmlinuz-$KERNEL
1868 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1869 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL.img
1871 LABEL ${DIST}fallback
1872 MENU LABEL $DIST Linux Fallback
1873 LINUX $d/vmlinuz-$KERNEL
1874 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1875 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL-fallback.img
1876 $([[ $SYS == 'BIOS' ]] && printf "\n%s" "# examples of chainloading other bootloaders
1881 #APPEND file=$d/grub/boot.img
1893 EDIT_FILES[bootloader]="/boot/refind_linux.conf"
1894 BCMDS[refind-efi]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1900 cat > $MNT/boot/refind_linux.conf << EOF
1901 "$DIST Linux" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1902 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1903 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL.img"
1904 "$DIST Linux Fallback" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1905 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1906 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL-fallback.img"
1908 mkdir -p $MNT/etc/pacman.d/hooks
1909 cat > $MNT/etc/pacman.d/hooks/refind.hook << EOF
1916 Description = Updating rEFInd on ESP
1917 When = PostTransaction
1918 Exec = /usr/bin/refind-install
1922 setup_systemd-boot()
1924 EDIT_FILES[bootloader]="/boot/loader/entries/$DIST.conf"
1925 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1926 bootctl --path=/boot install"
1929 prerun_systemd-boot()
1931 mkdir -p $MNT/boot/loader/entries
1932 cat > $MNT/boot/loader/loader.conf << EOF
1937 cat > $MNT/boot/loader/entries/$DIST.conf << EOF
1939 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1940 initrd /initramfs-$KERNEL.img
1941 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1943 cat > $MNT/boot/loader/entries/$DIST-fallback.conf << EOF
1944 title $DIST Linux Fallback
1945 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1946 initrd /initramfs-$KERNEL-fallback.img
1947 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1949 mkdir -p $MNT/etc/pacman.d/hooks
1950 cat > $MNT/etc/pacman.d/hooks/systemd-boot.hook << EOF
1957 Description = Updating systemd-boot
1958 When = PostTransaction
1959 Exec = /usr/bin/bootctl update
1961 systemd-machine-id-setup --root="$MNT"
1965 ###############################################################################
1970 is_bg_install || return 1
1973 dlg choice menu "Logical Volume Management" "$_lvmmenu" \
1974 "$_lvmnew" "vgcreate -f, lvcreate -L -n" \
1975 "$_lvmdel" "vgremove -f" \
1976 "$_lvmdelall" "lvrmeove, vgremove, pvremove -f" \
1977 "back" "return to the main menu"
1980 "$_lvmnew") lvm_create || return 1 ;;
1981 "$_lvmdel") lvm_delgroup && yesno "$_lvmdel" "$_lvmdelask" && vgremove -f "$DEL_VG" >/dev/null 2>&1 ;;
1982 "$_lvmdelall") lvm_del_all ;;
1991 pv="$(pvs -o pv_name --noheading 2>/dev/null)"
1992 v="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
1993 VGROUP="$(vgs -o vg_name --noheading 2>/dev/null)"
1995 if [[ $VGROUP && $v && $pv ]]; then
1996 msg "Logical Volume Management" "\nActivating existing logical volume management (LVM).\n\n" 1
1997 modprobe dm-mod >/dev/null 2>$ERR
1998 errshow 'modprobe dm-mod'
1999 vgscan >/dev/null 2>&1
2000 vgchange -ay >/dev/null 2>&1
2006 VGROUP='' LVM_PARTS='' VGROUP_MB=0
2008 lvm_mkgroup || return 1
2009 local txt="\nThe last (or only) logical volume will automatically use all remaining space in the volume group."
2010 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
2011 [[ $VOL_COUNT ]] || return 1
2012 lvm_extra_lvs || return 1
2013 lvm_volume_name "$_lvmlvname\nNOTE: This LV will use up all remaining space in the volume group (${VGROUP_MB}MB)" || return 1
2014 lvcreate -l +100%FREE "$VGROUP" -n "$VNAME" >/dev/null 2>$ERR
2015 errshow "lvcreate -l +100%FREE $VGROUP -n $VNAME" || return 1
2016 LVM='logical volume'; sleep 0.5
2017 txt="\nDone, volume: $VGROUP-$VNAME (${VOLUME_SIZE:-${VGROUP_MB}MB}) has been created.\n"
2018 msg "$_lvmnew (LV:$VOL_COUNT)" "$txt\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE $LVM_PARTS)\n"
2024 local txt="${VGROUP}: ${SIZE}$SIZE_UNIT (${VGROUP_MB}MB remaining).$_lvmlvsize"
2028 dlg VOLUME_SIZE input "$_lvmnew (LV:$VOL_COUNT)" "$txt" ''
2029 if [[ -z $VOLUME_SIZE ]]; then
2031 break # allow bailing with escape or an empty choice
2032 elif (( ${VOLUME_SIZE:0:1} == 0 )); then
2033 ERR_SIZE=1 # size values can't begin with '0'
2035 # walk the string and make sure all but the last char are digits
2036 local lv=$((${#VOLUME_SIZE} - 1))
2037 for (( i=0; i<lv; i++ )); do
2038 [[ ${VOLUME_SIZE:$i:1} =~ [0-9] ]] || { ERR_SIZE=1; break; }
2040 if (( ERR_SIZE != 1 )); then
2041 case ${VOLUME_SIZE:$lv:1} in
2042 [mMgG]) local s=${VOLUME_SIZE:0:$lv} m=$((s * 1000))
2043 case ${VOLUME_SIZE:$lv:1} in
2044 [Gg]) (( m >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - m)) ;;
2045 [Mm]) (( ${VOLUME_SIZE:0:$lv} >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - s)) ;;
2052 if (( ERR_SIZE )); then
2053 msg "Invalid Logical Volume Size" "$_lvmerrlvsize"
2065 local txt="\nConfirm creation of volume group: $VGROUP\n\nwith the following partition(s):"
2067 until [[ $named ]]; do
2068 lvm_partitions || return 1
2069 lvm_group_name || return 1
2070 yesno "$_lvmnew" "$txt $LVM_PARTS\n" && named=true
2073 vgcreate -f "$VGROUP" $LVM_PARTS >/dev/null 2>$ERR
2074 errshow "vgcreate -f $VGROUP $LVM_PARTS" || return 1
2076 SIZE=$(vgdisplay "$VGROUP" | awk '/VG Size/ { gsub(/[^0-9.]/, ""); print int($0) }')
2077 SIZE_UNIT="$(vgdisplay "$VGROUP" | awk '/VG Size/ { print substr($NF, 0, 1) }')"
2079 if [[ $SIZE_UNIT == 'G' ]]; then
2080 VGROUP_MB=$((SIZE * 1000))
2085 msg "$_lvmnew" "\nVolume group: $VGROUP ($SIZE $SIZE_UNIT) has been created\n"
2092 pv="$(pvs -o pv_name --noheading 2>/dev/null)"
2093 v="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
2094 VGROUP="$(vgs -o vg_name --noheading 2>/dev/null)"
2096 if [[ $VGROUP || $v || $pv ]]; then
2097 if yesno "$_lvmdelall" "$_lvmdelask"; then
2098 for i in $v; do lvremove -f "/dev/mapper/$i" >/dev/null 2>&1; done
2099 for i in $VGROUP; do vgremove -f "$i" >/dev/null 2>&1; done
2100 for i in $pv; do pvremove -f "$i" >/dev/null 2>&1; done
2104 msg "Delete LVM" "\nNo LVMs to remove...\n" 2
2114 for i in $(lvs --noheadings | awk '{print $2}' | uniq); do
2115 VOL_GROUP_LIST+="$i $(vgdisplay "$i" | awk '/VG Size/ {print $3$4}') "
2117 [[ $VOL_GROUP_LIST ]] || { msg "No Groups" "\nNo volume groups found."; return 1; }
2119 dlg DEL_VG menu "Logical Volume Management" "\nSelect volume group to delete.\n\nAll logical volumes within will also be deleted." $VOL_GROUP_LIST
2125 while (( VOL_COUNT > 1 )); do
2126 lvm_volume_name "$_lvmlvname" && get_lv_size || return 1
2127 lvcreate -L "$VOLUME_SIZE" "$VGROUP" -n "$VNAME" >/dev/null 2>$ERR
2128 errshow "lvcreate -L $VOLUME_SIZE $VGROUP -n $VNAME" || return 1
2129 msg "$_lvmnew (LV:$VOL_COUNT)" "\nDone, logical volume (LV) $VNAME ($VOLUME_SIZE) has been created.\n"
2137 part_find 'part|crypt' || return 1
2138 PARTS="$(awk 'NF > 0 {print $0 " off"}' <<< "$PARTS")"
2139 dlg LVM_PARTS check "$_lvmnew" "\nSelect the partition(s) to use for the physical volume (PV)." $PARTS
2146 until [[ $VGROUP ]]; do
2147 dlg VGROUP input "$_lvmnew" "$_lvmvgname" "mygroup"
2148 if [[ -z $VGROUP ]]; then
2150 elif [[ ${VGROUP:0:1} == "/" || $VGROUP =~ \ |\' ]] || lsblk | grep -q "$VGROUP"; then
2151 msg "LVM Name Error" "$_lvmerrvgname"
2161 local txt="$1" default="mainvolume"
2162 (( VOL_COUNT > 1 )) && default="extravolume$VOL_COUNT"
2163 until [[ $VNAME ]]; do
2164 dlg VNAME input "$_lvmnew (LV:$VOL_COUNT)" "\n$txt" "$default"
2165 if [[ -z $VNAME ]]; then
2167 elif [[ ${VNAME:0:1} == "/" || $VNAME =~ \ |\' ]] || lsblk | grep -q "$VNAME"; then
2168 msg "LVM Name Error" "$_lvmerlvname"
2175 ###############################################################################
2181 is_bg_install || return 1
2182 dlg choice menu "LUKS Encryption" "$_luksmenu" \
2183 "$_luksnew" "cryptsetup -q luksFormat" \
2184 "$_luksopen" "cryptsetup open --type luks" \
2185 "$_luksadv" "cryptsetup -q -s -c luksFormat" \
2186 "back" "Return to the main menu"
2189 "$_luksnew") luks_basic || return 1 ;;
2190 "$_luksopen") luks_open || return 1 ;;
2191 "$_luksadv") luks_advanced || return 1 ;;
2199 modprobe -a dm-mod dm_crypt >/dev/null 2>&1
2201 part_find 'part|crypt|lvm' || return 1
2203 if (( COUNT == 1 )); then
2204 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2206 dlg LUKS_PART menu "$_luksopen" "\nSelect which partition to open." $PARTS
2209 [[ $LUKS_PART ]] || return 1
2211 luks_pass "$_luksopen" || return 1
2212 msg "$_luksopen" "\nOpening encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2213 cryptsetup open --type luks "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2214 errshow "cryptsetup open --type luks $LUKS_PART $LUKS_NAME" || return 1
2215 LUKS='encrypted'; luks_show
2222 local t="$1" op="$2" v='' p='' p2=''
2224 until [[ $LUKS_PASS ]]; do
2228 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " \
2229 --mixedform "\nEnter the password to decrypt $ROOT_PART\n\nThis is needed to create a keyfile." 0 0 0 \
2230 "Password:" 1 1 '' 1 11 "$COLUMNS" 0 1 \
2231 "Password2:" 2 1 '' 2 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
2234 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " --mixedform "$_luksomenu" 0 0 0 \
2235 "Name:" 1 1 "${LUKS_NAME:-cryptroot}" 1 7 "$COLUMNS" 0 0 \
2236 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
2237 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
2241 while read -r line; do
2257 if [[ -z $op && -z $n ]]; then
2258 msg "Name Empty" "\nEncrypted device name cannot be empty.\n\nPlease try again.\n" 2
2259 elif [[ -z $p || "$p" != "$p2" ]]; then
2260 [[ $op ]] || LUKS_NAME="$n"
2261 msg "Password Mismatch" "\nThe passwords entered do not match.\n\nPlease try again.\n" 2
2263 [[ $op ]] || LUKS_NAME="$n"
2274 msg "$_luksnew" "\nEncrypted partition opened and ready for mounting.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$LUKS_PART")\n\n"
2279 modprobe -a dm-mod dm_crypt >/dev/null 2>&1
2281 part_find 'part|lvm' || return 1
2283 if [[ $AUTO_ROOT_PART ]]; then
2284 LUKS_PART="$AUTO_ROOT_PART"
2285 elif (( COUNT == 1 )); then
2286 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2288 dlg LUKS_PART menu "$_luksnew" "\nSelect the partition you want to encrypt." $PARTS
2291 [[ $LUKS_PART ]] || return 1
2292 luks_pass "$_luksnew"
2297 luks_setup || return 1
2298 msg "$_luksnew" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2299 cryptsetup -q luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2>$ERR
2300 errshow "cryptsetup -q luksFormat $LUKS_PART" || return 1
2301 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2302 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2303 LUKS='encrypted'; luks_show
2309 if [[ ! -e $MNT/crypto_keyfile.bin ]]; then
2310 # printf "Creating LUKS keyfile /crypto_keyfile.bin\n"
2312 n="$(lsblk -lno NAME,UUID,TYPE | awk "/$LUKS_UUID/"' && /part|crypt|lvm/ {print $1}')"
2313 local mkkey="dd bs=512 count=8 if=/dev/urandom of=/crypto_keyfile.bin"
2314 mkkey="$mkkey && chmod 000 /crypto_keyfile.bin"
2315 mkkey="$mkkey && cryptsetup luksAddKey /dev/$n /crypto_keyfile.bin <<< '$LUKS_PASS'"
2317 sed -i 's/FILES=()/FILES=(\/crypto_keyfile.bin)/g' $MNT/etc/mkinitcpio.conf 2>$ERR
2327 dlg cipher input "LUKS Encryption" "$_lukskey" "-s 512 -c aes-xts-plain64"
2328 [[ $cipher ]] || return 1
2329 msg "$_luksadv" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2330 cryptsetup -q $cipher luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2>$ERR
2331 errshow "cryptsetup -q $cipher luksFormat $LUKS_PART" || return 1
2332 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2333 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2340 ###############################################################################
2345 [[ "$2" == *"$1"* ]] && printf "on" || printf "off"
2354 if [[ -d $MNT ]] && command cd /; then
2356 if (( ecode == 127 )); then
2357 umount_dir /run/archiso/bootmnt
2368 local var="$1" dialog_type="$2" title="$3" body="$4" n=0
2370 (( ($# / 2) > SHL )) && n=$SHL
2373 case "$dialog_type" in
2374 menu) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --menu "$body" 0 0 $n "$@" 2>"$ANS" || return 1 ;;
2375 check) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --checklist "$body" 0 0 $n "$@" 2>"$ANS" || return 1 ;;
2380 if [[ $1 == 'limit' ]]; then
2381 dialog --backtitle "$DIST Installer - $SYS - v$VER" --max-input 63 --title " $title " --inputbox "$body" 0 0 "$def" 2>"$ANS" || return 1
2383 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --inputbox "$body" 0 0 "$def" 2>"$ANS" || return 1
2387 [[ -s "$ANS" ]] && printf -v "$var" "%s" "$(< "$ANS")"
2392 local title="$1" body="$2"
2394 if (( $# == 3 )); then
2395 dialog --backtitle "$DIST Installer - $SYS - v$VER" --sleep "$3" --title " $title " --infobox "$body\n" 0 0
2397 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --msgbox "$body\n" 0 0
2403 local title="$1" body="$2" yes='Yes' no='No'
2404 (( $# >= 3 )) && yes="$3"
2405 (( $# >= 4 )) && no="$4"
2407 if (( $# == 5 )); then
2408 dialog --backtitle "$DIST Installer - $SYS - v$VER" --defaultno --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2410 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2416 arch-chroot "$MNT" bash -c "$1"
2421 export PS4='| ${BASH_SOURCE} LINE:${LINENO} FUNC:${FUNCNAME[0]:+ ${FUNCNAME[0]}()} |> '
2430 printf "\n^C caught, cleaning up...\n"
2438 if [[ $COLUMNS -ge 110 && ${#str} -gt $((COLUMNS - 30)) ]]; then
2440 i = 2; p1 = p2 = p3 = p4 = ""; p1 = $1; q = int(NF / 4)
2441 for (; i <= q; i++) { p1 = p1 " " $i }
2442 for (; i <= q * 2; i++) { p2 = p2 " " $i }
2443 for (; i <= q * 3; i++) { p3 = p3 " " $i }
2444 for (; i <= NF; i++) { p4 = p4 " " $i }
2445 printf "%s\n %s\n %s\n %s", p1, p2, p3, p4
2447 printf "%s\n" "$str"
2448 elif [[ $str ]]; then
2449 printf "%s\n" "$str"
2456 "\e]P0191919" # #191919
2457 "\e]P1D15355" # #D15355
2458 "\e]P2609960" # #609960
2459 "\e]P3FFCC66" # #FFCC66
2460 "\e]P4255A9B" # #255A9B
2461 "\e]P5AF86C8" # #AF86C8
2462 "\e]P62EC8D3" # #2EC8D3
2463 "\e]P7949494" # #949494
2464 "\e]P8191919" # #191919
2465 "\e]P9D15355" # #D15355
2466 "\e]PA609960" # #609960
2467 "\e]PBFF9157" # #FF9157
2468 "\e]PC4E88CF" # #4E88CF
2469 "\e]PDAF86C8" # #AF86C8
2470 "\e]PE2ec8d3" # #2ec8d3
2471 "\e]PFE1E1E1" # #E1E1E1
2474 [[ $TERM == 'linux' ]] && printf "%b" "${colors[@]}" && clear
2479 [ $? -eq 0 ] && return 0
2481 local fatal=0 err=""
2482 err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
2484 (( $1 == 1 )) && { fatal=1; shift; }
2486 local txt="\nThe command exited abnormally:\n\n$1\n\n"
2489 txt+="With the following message:\n\n$err\n\n"
2491 txt+="With no error message:\n\n"
2494 if (( fatal )); then
2495 txt+="Errors at this stage are fatal and the install cannot continue.\n"
2497 txt+="Errors at this stage are non-fatal and can be either fixed or ignored depending on the error.\n"
2499 msg "Install Error" "$txt"
2501 if (( fatal )); then
2502 [[ -r $DBG && $TERM == 'linux' ]] && less "$DBG"
2511 msg "Broadcom Wireless Setup" "\nDetected chipset is Broadcom BCM4352\n\nDisabling bcma/b43 modules and loading wl module.\n" 1
2512 { rmmod wl; rmmod bcma; rmmod b43; rmmod ssb; modprobe wl; depmod -a; } >/dev/null 2>&1
2520 if (( $1 >= 0 )) && ! grep -qw "$MNT" /proc/mounts; then
2521 msg "Not Mounted" "\nPartition(s) must be mounted first.\n" 2
2523 elif [[ $1 -ge 1 && -z $BOOTLDR ]]; then
2524 msg "No Bootloader" "\nBootloader must be selected first.\n" 2
2526 elif [[ $1 -ge 2 && (-z $NEWUSER || -z $USER_PASS) ]]; then
2527 msg "No User" "\nA user must be created first.\n" 2
2529 elif [[ $1 -ge 3 && -z $CONFIG_DONE ]]; then
2530 msg "Not Configured" "\nSystem configuration must be done first.\n" 2
2533 (( i )) # return code
2538 mount | grep -q 'swap' && swapoff -a
2540 [[ -d $dir ]] || continue
2541 umount "$dir" 2>/dev/null || { sleep 0.5; umount -f "$dir" 2>/dev/null || umount -l "$dir"; }
2547 msg "Network Connect" "\nVerifying network connection\n" 1
2548 curl -sIN --connect-timeout 5 'https://www.archlinux.org/' | sed '1q' | grep -q '200'
2553 if chk_connect; then
2556 if hash nmtui >/dev/null 2>&1; then
2558 if [[ $TERM == 'linux' ]]; then
2559 printf "%b" "\e]P1191919" "\e]P4191919"
2561 printf "%b" "\e]P1D15355" "\e]P4255a9b"
2574 [[ $RSYNC_PID || $MIRROR_PID ]] || return 0
2575 msg "Install Running" "\nA background install process is currently running.\n" 2
2581 IGNORE_DEV="$(lsblk -lno NAME,MOUNTPOINT | awk '/\/run\/archiso\/bootmnt/ {sub(/[1-9]/, ""); print $1}')"
2583 if [[ $IGNORE_DEV ]]; then
2584 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ && !'"/$IGNORE_DEV/"' {print "/dev/" $1 " " $2}')"
2586 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ {print "/dev/" $1 " " $2}')"
2589 if [[ -z $SYS_DEVS ]]; then
2590 msg "Device Error" "\nNo available devices...\n\nExiting..\n" 2
2595 while read -r line; do
2597 done <<< "$SYS_DEVS"
2604 elif grep -q 'AuthenticAMD' /proc/cpuinfo; then
2606 elif grep -q 'GenuineIntel' /proc/cpuinfo; then
2610 modprobe -q efivarfs >/dev/null 2>&1
2612 _prep="\nOnce a step is finished a step you will be returned here, if the step was successful the cursor will be advanced to the next step.\nIf a step is unsuccessful the cursor will be placed on the step required to advance (when possible).\n\nTo begin the install you should have:\n\n - A root (/) partition mounted."
2613 if [[ -d /sys/firmware/efi/efivars ]]; then
2615 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars
2616 _prep+="\n - An EFI boot partition mounted."
2620 _prep+="\n\nOnce finished mounting, a portion of the install can be done in the background while you continue configuring the system:\n"
2621 _prep+="\n - Choose the system bootloader.\n - Create a user and password."
2622 _prep+="\n - Basic system configuration, kernel, shell, login, packages, etc..\n\nOnce you're happy with the choices and the required steps are complete, the main install can be started."
2625 ###############################################################################
2628 # enable some nicer colours in the linux console
2631 if (( UID != 0 )); then
2632 msg "Not Root" "\nThis installer must be run as root or using sudo.\n\nExiting..\n" 2
2634 elif ! grep -qwm 1 'lm' /proc/cpuinfo; then
2635 msg "Not x86_64 Architecture" "\nThis installer only supports x86_64 architectures.\n\nExiting..\n" 2
2637 elif [[ $1 =~ (-d|--debug) ]]; then
2641 # trap ^C to perform cleanup
2647 msg "Welcome to the $DIST Installer" "\nThis will help you get $DIST setup on your system.\nHaving previous GNU/Linux and shell experience will be an asset, however we try our best to keep things simple.\n\nIf you are unsure about an option, a default will be listed or\nthe first selected option will usually be the default (excluding language and timezone).\n\n\nMenu Navigation:\n\n - Select items with the arrow keys or the option number.\n - Use [Space] to toggle options and [Enter] to confirm.\n - Switch between buttons 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"
2649 select_keymap || { clear; die 0; }
2651 # try to fix problematic broadcom wireless chipset before network check
2652 lspci -vnn -d 14e4: | grep -q 'BCM4352' && load_bcm
2654 net_connect || { msg "Not Connected" "\nThis installer requires an active internet connection.\n\nExiting..\n" 2; die 1; }
2660 # vim:fdm=marker:fmr={,}