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.53" # 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='' # 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 {
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 # console keyboard mappings
130 CMAPS="$(find /usr/share/kbd/keymaps -name '*.map.gz' | awk '{gsub(/\.map\.gz|.*\//, ""); print $1 " - "}' | sort)"
133 [[ $LINES ]] || LINES=$(tput lines)
134 [[ $COLUMNS ]] || COLUMNS=$(tput cols)
140 # commands used to install each bootloader, however 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 used in ~/.xinitrc {
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]='archlabs-skel-bspwm' # see deps of archlabs-skel-bspwm
170 [fluxbox]='archlabs-skel-fluxbox' # see deps of archlabs-skel-fluxbox
171 [i3-gaps]='archlabs-skel-i3-gaps' # see deps of archlabs-skel-i3-gaps
172 [openbox]='archlabs-skel-openbox' # see deps of archlabs-skel-openbox
173 [xfce4]='archlabs-skel-xfce4 xfce4-goodies' # see deps of archlabs-skel-xfce4
176 # files offered for editing 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 and flags 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 {
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 # packages installed for each login option {
220 declare -A LOGIN_PKGS=(
222 [lightdm]='lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings accountsservice'
225 # extras installed for user selected packages {
226 # if a package requires additional packages that aren't already dependencies
227 # they can be added here eg. [package]="extra"
231 [mupdf]='mupdf-tools'
232 [qt5ct]='qt5-styleplugins'
233 [vlc]='qt5ct qt5-styleplugins'
234 [zathura]='zathura-pdf-poppler'
235 [noto-fonts]='noto-fonts-emoji'
236 [cairo-dock]='cairo-dock-plug-ins'
237 [qutebrowser]='qt5ct qt5-styleplugins'
238 [qbittorrent]='qt5ct qt5-styleplugins'
239 [transmission-qt]='qt5ct qt5-styleplugins'
240 [kdenlive]='kdebase-meta dvdauthor frei0r-plugins breeze breeze-gtk qt5ct qt5-styleplugins'
245 # dialog text variables
248 # Basics (somewhat in order)
249 _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"
250 _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"
251 _device="\nSelect a device to use from the list below.\n\nDevices (/dev) are the available drives on the system. /sda, /sdb, /sdc ..."
252 _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."
253 _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."
254 _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"
255 _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)."
256 _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."
257 _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."
258 _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."
259 _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"
260 _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."
261 _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."
262 _exmnt="\nWhere do you want the partition mounted?\n\nEnsure the name begins with a slash (/).\nExamples include: /usr, /home, /var, etc."
263 _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."
264 _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."
265 _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"
266 _timez="\nThe time zone is used to set the system clock.\n\nSelect your country or continent from the list below"
267 _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."
268 _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."
269 _login="\nSelect which of your session choices to use for the initial login.\n\nYou can be change this later by editing your ~/.xinitrc"
270 _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."
271 _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."
274 _luksnew="Basic LUKS Encryption"
275 _luksadv="Advanced LUKS Encryption"
276 _luksopen="Open Existing LUKS Partition"
277 _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."
278 _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."
279 _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)."
282 _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."
283 _lvmnew="Create Volume Group and Volume(s)"
284 _lvmdel="Delete an Existing Volume Group"
285 _lvmdelall="Delete ALL Volume Group(s) and Volume(s)"
286 _lvmvgname="\nEnter a name for the volume group (VG) being created from the partition(s) selected."
287 _lvmlvname="\nEnter a name for the logical volume (LV) being created.\n\nThis is similar to setting a label for a partition."
288 _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."
289 _lvmdelask="\nConfirm deletion of volume group(s) and logical volume(s).\n\nDeleting a volume group, will delete all logical volumes within it.\n"
292 _errexpart="\nCannot mount partition due to a problem with the mountpoint.\n\nEnsure it begins with a slash (/) followed by atleast one character.\n"
293 _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"
294 _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"
295 _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"
296 _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"
297 _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"
298 _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"
304 ###############################################################################
306 # main is the entry point which calls functions including outside of its block
307 # once those functions finished they always are returned here with the
308 # exception of install_main(), it exits upon completion
312 (( SEL < 12 )) && (( SEL++ ))
314 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Prepare " --default-item $SEL --cancel-label 'Exit' --menu "$_prep" 0 0 0 \
315 1 "Device tree (optional)" \
316 2 "Partitioning (optional)" \
317 3 "LUKS setup (optional)" \
318 4 "LVM setup (optional)" \
319 5 "Mount partitions" \
320 6 "System bootloader" \
321 7 "User and password" \
322 8 "System configuration" \
323 9 "Select WM/DE (optional)" \
324 10 "Select Packages (optional)" \
325 11 "View configuration (optional)" \
326 12 "Start the installation" 2>"$ANS"
329 [[ -z $WARN && $SEL =~ (2|5) ]] && { msg "Data Warning" "$_warn"; WARN=true; }
332 2) part_menu || (( SEL-- )) ;;
333 3) luks_menu || (( SEL-- )) ;;
334 4) lvm_menu || (( SEL-- )) ;;
335 5) mount_menu || (( SEL-- )) ;;
336 6) prechecks 0 && { select_boot || (( SEL-- )); } ;;
337 7) prechecks 1 && { select_mkuser || (( SEL-- )); } ;;
338 8) prechecks 2 && { select_config || (( SEL-- )); } ;;
339 9) prechecks 3 && { select_sessions || (( SEL-- )); } ;;
340 10) prechecks 3 && { select_packages || (( SEL-- )); } ;;
341 11) prechecks 3 && select_show ;;
342 12) prechecks 3 && install_main ;;
343 *) yesno "Exit" "\nUnmount partitions (if any) and exit the installer?\n" && die 0
349 if [[ $SYS == 'BIOS' ]]; then
350 dlg BOOTLDR menu "BIOS Bootloader" "\nSelect which bootloader to use." \
351 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
352 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network" || return 1
354 dlg BOOTLDR menu "UEFI Bootloader" "\nSelect which bootloader to use." \
355 "systemd-boot" "A simple UEFI boot manager which executes configured EFI images" \
356 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
357 "refind-efi" "A UEFI boot manager that aims to be platform neutral and simplify multi-boot" \
358 "efistub" "Boot the kernel image directly (no chainloading support)" \
359 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network (no chainloading support)" || return 1
367 local cmd="${BCMDS[$BOOTLDR]}"
368 local pkgs="${USER_PKGS// / } ${PACKAGES// / }"
369 local exmnt="${EXMNT:-none}"
370 [[ $BOOT_PART ]] && mnt="/$BOOTDIR"
371 [[ $INSTALL_WMS == *dwm* ]] && pkgs="dwm st dmenu $pkgs"
373 msg "Show Configuration" "
375 ---------- PARTITION CONFIGURATION ------------
377 Root: ${ROOT_PART:-none}
378 Boot: ${BOOT_PART:-${BOOT_DEV:-none}}
379 Swap: ${SWAP_PART:-none}
380 Size: ${SWAP_SIZE:-none}
381 Extra: ${EXMNTS:-$exmnt}
382 Hooks: ${HOOKS:-none}
387 ---------- BOOTLOADER CONFIGURATION -----------
389 Bootloader: ${BOOTLDR:-none}
390 Mountpoint: ${mnt:-none}
391 Command: ${cmd:-none}
394 ------------ SYSTEM CONFIGURATION -------------
396 Locale: ${MYLOCALE:-none}
397 Keymap: ${KEYMAP:-none}
398 Hostname: ${MYHOST:-none}
399 Timezone: ${ZONE:-none}/${SUBZ:-none}
402 ------------ USER CONFIGURATION --------------
404 User: ${NEWUSER:-none}
405 Shell: ${MYSHELL:-none}
406 Session: ${LOGIN_WM:-none}
407 Autologin: ${AUTOLOGIN:-none}
408 DM or xinit: ${LOGIN_TYPE:-none}
411 ------------ PACKAGES AND MIRRORS -------------
413 Kernel: ${KERNEL:-none}
414 Sessions: ${INSTALL_WMS:-none}
415 Packages: ${USER_PKGS// / } ${PACKAGES// / }
421 if [[ -z $LOGIN_TYPE ]]; then
422 dlg LOGIN_TYPE menu "Login Management" "\nSelect what kind of login management to use." \
423 "xinit" "Console login without a display manager" \
424 "lightdm" "Lightweight display manager with a gtk greeter" || return 1
427 if [[ $LOGIN_TYPE == 'lightdm' ]]; then
429 EDIT_FILES[login]="/etc/lightdm/lightdm.conf /etc/lightdm/lightdm-gtk-greeter.conf"
431 if (( WM_NUM == 1 )); then
432 LOGIN_WM="${WM_SESSIONS[$INSTALL_WMS]}"
434 dlg LOGIN_WM menu "Login Management" "$_login" $LOGIN_CHOICES || return 1
435 LOGIN_WM="${WM_SESSIONS[$LOGIN_WM]}"
438 local txt="\nDo you want autologin enabled for $NEWUSER?\n\n"
439 txt+="If so the following two files will be created (disable autologin by removing them):\n\n"
440 txt+="- /home/$NEWUSER/$LOGINRC (run startx when logging in on tty1)\n"
441 txt+="- /etc/systemd/system/getty@tty1.service.d/autologin.conf (login $NEWUSER without password)\n"
442 yesno "Autologin" "$txt" && AUTOLOGIN=true || AUTOLOGIN=''
443 EDIT_FILES[login]="/home/$NEWUSER/.xinitrc /home/$NEWUSER/.xprofile"
452 until [[ $CONFIG_DONE ]]; do
455 dlg MYSHELL menu "Shell" "\nChoose which shell to use." \
456 /usr/bin/zsh 'A very advanced and programmable command interpreter (shell) for UNIX' \
457 /bin/bash 'The GNU Bourne Again shell, standard in many GNU/Linux distributions' \
458 /usr/bin/mksh 'The MirBSD Korn Shell - an enhanced version of the public domain ksh' || return 1
461 1) dlg MYHOST input "Hostname" "$_hostname" "${DIST,,}" limit || { i=0; continue; } ;;
462 2) dlg MYLOCALE menu "Locale" "$_locale" $LOCALES || { i=1; continue; } ;;
464 until [[ $ZONE && $SUBZ ]]; do
465 dlg ZONE menu "Timezone" "$_timez" America - Australia - Asia - Atlantic - Africa - Europe - Indian - Pacific - Arctic - Antarctica - || break
466 dlg SUBZ menu "Timezone" "$_timesubz" $(awk '/'"$ZONE"'\// {gsub(/'"$ZONE"'\//, ""); print $3 " - "}' /usr/share/zoneinfo/zone.tab | sort) || continue
467 yesno "Timezone" "\nConfirm time zone: $ZONE/$SUBZ\n" || unset ZONE
469 [[ $ZONE && $SUBZ ]] || { i=2; continue; } ;;
471 dlg KERNEL menu "Kernel" "\nChoose which kernel to use." \
472 linux 'Vanilla linux kernel and modules, with a few patches applied' \
473 linux-lts 'Long-term support (LTS) linux kernel and modules' \
474 linux-zen 'A effort of kernel hackers to provide the best kernel for everyday systems' \
475 linux-hardened 'A security-focused linux kernel with hardening patches to mitigate exploits' || { i=3; continue; }
480 (( i++ )) # progress through to the next choice
484 '/bin/bash') LOGINRC='.bash_profile' ;;
485 '/usr/bin/zsh') LOGINRC='.zprofile' ;;
486 '/usr/bin/mksh') LOGINRC='.profile' ;;
495 local v='' u='' p='' p2='' rp='' rp2=''
497 until [[ $NEWUSER ]]; do
500 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " User " --mixedform "$_user" 0 0 0 \
501 "Username:" 1 1 "$u" 1 11 "$COLUMNS" 0 0 \
502 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
503 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 \
504 "--- Root password, if left empty the user password will be used ---" 6 1 '' 6 68 "$COLUMNS" 0 2 \
505 "Password:" 8 1 '' 8 11 "$COLUMNS" 0 1 \
506 "Password2:" 9 1 '' 9 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
508 while read -r line; do
519 # root passwords empty, so use the user passwords
520 [[ -z $rp && -z $rp2 ]] && { rp="$p"; rp2="$p2"; }
522 # make sure a username was entered and that the passwords match
523 if [[ ${#u} -eq 0 || $u =~ \ |\' || $u =~ [^a-z0-9] ]]; then
524 msg "Invalid Username" "\nIncorrect user name.\n\nPlease try again.\n"; u=''
525 elif [[ -z $p ]]; then
526 msg "Empty Password" "\nThe user password cannot be left empty.\n\nPlease try again.\n"
527 elif [[ "$p" != "$p2" ]]; then
528 msg "Password Mismatch" "\nThe user passwords do not match.\n\nPlease try again.\n"
529 elif [[ "$rp" != "$rp2" ]]; then
530 msg "Password Mismatch" "\nThe root passwords do not match.\n\nPlease try again.\n"
542 dlg KEYMAP menu "Keyboard Layout" "$_keymap" \
543 us English cm English gb English au English gh English \
544 za English ng English ca French 'cd' French gn French \
545 tg French fr French de German at German ch German \
546 es Spanish latam Spanish br Portuguese pt Portuguese ma Arabic \
547 sy Arabic ara Arabic ua Ukrainian cz Czech ru Russian \
548 sk Slovak nl Dutch it Italian hu Hungarian cn Chinese \
549 tw Taiwanese vn Vietnamese kr Korean jp Japanese th Thai \
550 la Lao pl Polish se Swedish is Icelandic 'fi' Finnish \
551 dk Danish be Belgian in Indian al Albanian am Armenian \
552 bd Bangla ba Bosnian 'bg' Bulgarian dz Berber mm Burmese \
553 hr Croatian gr Greek il Hebrew ir Persian iq Iraqi \
554 af Afghani fo Faroese ge Georgian ee Estonian kg Kyrgyz \
555 kz Kazakh lt Lithuanian mt Maltese mn Mongolian ro Romanian \
556 no Norwegian rs Serbian si Slovenian tj Tajik lk Sinhala \
557 tr Turkish uz Uzbek ie Irish pk Urdu 'mv' Dhivehi \
558 np Nepali et Amharic sn Wolof ml Bambara tz Swahili \
559 ke Swahili bw Tswana ph Filipino my Malay tm Turkmen \
560 id Indonesian bt Dzongkha lv Latvian md Moldavian mao Maori \
561 by Belarusian az Azerbaijani mk Macedonian kh Khmer epo Esperanto \
562 me Montenegrin || return 1
564 if [[ $CMAPS == *"$KEYMAP"* ]]; then
567 dlg CMAP menu "Console Keymap" "$_vconsole" $CMAPS || return 1
570 if [[ $DISPLAY && $TERM != 'linux' ]]; then
571 setxkbmap "$KEYMAP" >/dev/null 2>&1
573 loadkeys "$CMAP" >/dev/null 2>&1
583 dlg INSTALL_WMS check "Sessions" "$_sessions\n" \
584 i3-gaps "A fork of i3wm with more features including gaps" "$(ofn i3-gaps "${INSTALL_WMS[*]}")" \
585 openbox "A lightweight, powerful, and highly configurable stacking wm" "$(ofn openbox "${INSTALL_WMS[*]}")" \
586 awesome "A customized Awesome WM session created by @elanapan" "$(ofn awesome "${INSTALL_WMS[*]}")" \
587 dwm "A dynamic WM for X that manages windows in tiled, floating, or monocle layouts" "$(ofn dwm "${INSTALL_WMS[*]}")" \
588 bspwm "A tiling wm that represents windows as the leaves of a binary tree" "$(ofn bspwm "${INSTALL_WMS[*]}")" \
589 fluxbox "A lightweight and highly-configurable window manager" "$(ofn fluxbox "${INSTALL_WMS[*]}")" \
590 gnome "A desktop environment that aims to be simple and easy to use" "$(ofn gnome "${INSTALL_WMS[*]}")" \
591 cinnamon "A desktop environment combining traditional desktop with modern effects" "$(ofn cinnamon "${INSTALL_WMS[*]}")" \
592 plasma "A kde software project currently comprising a full desktop environment" "$(ofn plasma "${INSTALL_WMS[*]}")" \
593 xfce4 "A lightweight and modular desktop environment based on gtk+2/3" "$(ofn xfce4 "${INSTALL_WMS[*]}")" || return 1
596 while IFS=' ' read -r i; do
598 done <<< "$INSTALL_WMS"
601 WM_PKGS="${INSTALL_WMS/dwm/}" # remove dwm from package list
602 WM_PKGS="${WM_PKGS// / }" # remove double spaces
603 WM_PKGS="${WM_PKGS# }" # remove leading space
605 # add archlabs base when choosing any session
606 [[ $WM_PKGS ]] && WM_PKGS+=" $AL_BASE_PKGS"
608 for i in $INSTALL_WMS; do
609 LOGIN_CHOICES+="$i - "
610 [[ ${WM_EXT[$i]} && $WM_PKGS != *"${WM_EXT[$i]}"* ]] && WM_PKGS+=" ${WM_EXT[$i]}"
613 select_login || return 1
615 while IFS=' ' read -r pkg; do
616 [[ $PACKAGES != *"$pkg"* ]] && PACKAGES+=" $pkg"
624 dlg USER_PKGS check " Packages " "$_packages" \
625 abiword "A Fully-featured word processor" "$(ofn abiword "${USER_PKGS[*]}")" \
626 alacritty "A cross-platform, GPU-accelerated terminal emulator" "$(ofn alacritty "${USER_PKGS[*]}")" \
627 atom "An open-source text editor developed by GitHub" "$(ofn atom "${USER_PKGS[*]}")" \
628 audacious "A free and advanced audio player based on GTK+" "$(ofn audacious "${USER_PKGS[*]}")" \
629 audacity "A program that lets you manipulate digital audio waveforms" "$(ofn audacity "${USER_PKGS[*]}")" \
630 cairo-dock "Light eye-candy fully themable animated dock" "$(ofn cairo-dock "${USER_PKGS[*]}")" \
631 calligra "A set of applications for productivity" "$(ofn calligra "${USER_PKGS[*]}")" \
632 chromium "An open-source web browser based on the Blink rendering engine" "$(ofn chromium "${USER_PKGS[*]}")" \
633 clementine "A modern music player and library organizer" "$(ofn clementine "${USER_PKGS[*]}")" \
634 cmus "A small, fast and powerful console music player" "$(ofn cmus "${USER_PKGS[*]}")" \
635 deadbeef "A GTK+ audio player for GNU/Linux" "$(ofn deadbeef "${USER_PKGS[*]}")" \
636 deluge "A BitTorrent client written in python" "$(ofn deluge "${USER_PKGS[*]}")" \
637 docky "Full fledged dock for opening applications and managing windows" "$(ofn docky "${USER_PKGS[*]}")" \
638 emacs "An extensible, customizable, self-documenting real-time display editor" "$(ofn emacs "${USER_PKGS[*]}")" \
639 epiphany "A GNOME web browser based on the WebKit rendering engine" "$(ofn epiphany "${USER_PKGS[*]}")" \
640 evince "A document viewer" "$(ofn evince "${USER_PKGS[*]}")" \
641 evolution "Manage your email, contacts and schedule" "$(ofn evolution "${USER_PKGS[*]}")" \
642 file-roller "Create and modify archives" "$(ofn file-roller "${USER_PKGS[*]}")" \
643 firefox "A popular open-source web browser from Mozilla" "$(ofn firefox "${USER_PKGS[*]}")" \
644 gcolor2 "A simple GTK+2 color selector" "$(ofn gcolor2 "${USER_PKGS[*]}")" \
645 geany "A fast and lightweight IDE" "$(ofn geany "${USER_PKGS[*]}")" \
646 geary "A lightweight email client for the GNOME desktop" "$(ofn geary "${USER_PKGS[*]}")" \
647 gimp "GNU Image Manipulation Program" "$(ofn gimp "${USER_PKGS[*]}")" \
648 gnome-disk-utility "Disk Management Utility" "$(ofn gnome-disk-utility "${USER_PKGS[*]}")" \
649 gnome-system-monitor "View current processes and monitor system state" "$(ofn gnome-system-monitor "${USER_PKGS[*]}")" \
650 gparted "A GUI frontend for creating and manipulating partition tables" "$(ofn gparted "${USER_PKGS[*]}")" \
651 gpick "Advanced color picker using GTK+ toolkit" "$(ofn gpick "${USER_PKGS[*]}")" \
652 gpicview "Lightweight image viewer" "$(ofn gpicview "${USER_PKGS[*]}")" \
653 guvcview "Capture video from camera devices" "$(ofn guvcview "${USER_PKGS[*]}")" \
654 hexchat "A popular and easy to use graphical IRC client" "$(ofn hexchat "${USER_PKGS[*]}")" \
655 inkscape "Professional vector graphics editor" "$(ofn inkscape "${USER_PKGS[*]}")" \
656 irssi "Modular text mode IRC client" "$(ofn irssi "${USER_PKGS[*]}")" \
657 kdenlive "A popular non-linear video editor for Linux" "$(ofn kdenlive "${USER_PKGS[*]}")" \
658 krita "Edit and paint images" "$(ofn krita "${USER_PKGS[*]}")" \
659 libreoffice-fresh "Full featured office suite" "$(ofn libreoffice-fresh "${USER_PKGS[*]}")" \
660 lollypop "A new music playing application" "$(ofn lollypop "${USER_PKGS[*]}")" \
661 mousepad "A simple text editor" "$(ofn mousepad "${USER_PKGS[*]}")" \
662 mpd "A flexible, powerful, server-side application for playing music" "$(ofn mpd "${USER_PKGS[*]}")" \
663 mpv "A media player based on mplayer" "$(ofn mpv "${USER_PKGS[*]}")" \
664 mupdf "Lightweight PDF and XPS viewer" "$(ofn mupdf "${USER_PKGS[*]}")" \
665 mutt "Small but very powerful text-based mail client" "$(ofn mutt "${USER_PKGS[*]}")" \
666 nautilus "The default file manager for Gnome" "$(ofn nautilus "${USER_PKGS[*]}")" \
667 ncmpcpp "A mpd client and almost exact clone of ncmpc with some new features" "$(ofn ncmpcpp "${USER_PKGS[*]}")" \
668 neovim "A fork of Vim aiming to improve user experience, plugins, and GUIs." "$(ofn neovim "${USER_PKGS[*]}")" \
669 nicotine+ "A graphical client for Soulseek" "$(ofn nicotine+ "${USER_PKGS[*]}")" \
670 noto-fonts "Google Noto fonts" "$(ofn noto-fonts "${USER_PKGS[*]}")" \
671 noto-fonts-cjk "Google Noto CJK fonts (Chinese, Japanese, Korean)" "$(ofn noto-fonts-cjk "${USER_PKGS[*]}")" \
672 obs-studio "Free opensource streaming/recording software" "$(ofn obs-studio "${USER_PKGS[*]}")" \
673 openshot "An open-source, non-linear video editor for Linux" "$(ofn openshot "${USER_PKGS[*]}")" \
674 opera "A Fast and secure, free of charge web browser from Opera Software" "$(ofn opera "${USER_PKGS[*]}")" \
675 pcmanfm "A fast and lightweight file manager based in Lxde" "$(ofn pcmanfm "${USER_PKGS[*]}")" \
676 pidgin "Multi-protocol instant messaging client" "$(ofn pidgin "${USER_PKGS[*]}")" \
677 plank "An elegant, simple, and clean dock" "$(ofn plank "${USER_PKGS[*]}")" \
678 qbittorrent "An advanced BitTorrent client" "$(ofn qbittorrent "${USER_PKGS[*]}")" \
679 qpdfview "A tabbed PDF viewer" "$(ofn qpdfview "${USER_PKGS[*]}")" \
680 qt5ct "GUI for managing Qt based application themes, icons, and fonts" "$(ofn qt5ct "${USER_PKGS[*]}")" \
681 qutebrowser "A keyboard-focused vim-like web browser based on Python and PyQt5" "$(ofn qutebrowser "${USER_PKGS[*]}")" \
682 rhythmbox "A Music playback and management application" "$(ofn rhythmbox "${USER_PKGS[*]}")" \
683 rxvt-unicode "A unicode enabled rxvt-clone terminal emulator" "$(ofn rxvt-unicode "${USER_PKGS[*]}")" \
684 sakura "A terminal emulator based on GTK and VTE" "$(ofn sakura "${USER_PKGS[*]}")" \
685 simplescreenrecorder "A feature-rich screen recorder" "$(ofn simplescreenrecorder "${USER_PKGS[*]}")" \
686 steam "A popular game distribution platform by Valve" "$(ofn steam "${USER_PKGS[*]}")" \
687 surf "A simple web browser based on WebKit2/GTK+" "$(ofn surf "${USER_PKGS[*]}")" \
688 terminator "Terminal emulator that supports tabs and grids" "$(ofn terminator "${USER_PKGS[*]}")" \
689 termite "A minimal VTE-based terminal emulator" "$(ofn termite "${USER_PKGS[*]}")" \
690 thunar "A modern file manager for the Xfce Desktop Environment" "$(ofn thunar "${USER_PKGS[*]}")" \
691 thunderbird "Standalone mail and news reader from mozilla" "$(ofn thunderbird "${USER_PKGS[*]}")" \
692 tilda "A GTK based drop down terminal for Linux and Unix" "$(ofn tilda "${USER_PKGS[*]}")" \
693 tilix "A tiling terminal emulator for Linux using GTK+ 3" "$(ofn tilix "${USER_PKGS[*]}")" \
694 transmission-cli "Free BitTorrent client CLI" "$(ofn transmission-cli "${USER_PKGS[*]}")" \
695 transmission-gtk "Free BitTorrent client GTK+ GUI" "$(ofn transmission-gtk "${USER_PKGS[*]}")" \
696 transmission-qt "Free BitTorrent client Qt GUI" "$(ofn transmission-qt "${USER_PKGS[*]}")" \
697 ttf-anonymous-pro "A family fixed-width fonts designed with code in mind" "$(ofn ttf-anonymous-pro "${USER_PKGS[*]}")" \
698 ttf-fira-code "Monospaced font with programming ligatures" "$(ofn ttf-fira-code "${USER_PKGS[*]}")" \
699 ttf-font-awesome "Iconic font designed for Bootstrap" "$(ofn ttf-font-awesome "${USER_PKGS[*]}")" \
700 ttf-hack "A hand groomed typeface based on Bitstream Vera Mono" "$(ofn ttf-hack "${USER_PKGS[*]}")" \
701 vlc "A free and open source cross-platform multimedia player" "$(ofn vlc "${USER_PKGS[*]}")" \
702 weechat "Fast, light and extensible IRC client" "$(ofn weechat "${USER_PKGS[*]}")" \
703 xarchiver "A GTK+ frontend to various command line archivers" "$(ofn xarchiver "${USER_PKGS[*]}")" \
704 xfce-terminal "A terminal emulator based in the Xfce Desktop Environment" "$(ofn xfce-terminal "${USER_PKGS[*]}")" \
705 xterm "The standard terminal emulator for the X window system" "$(ofn xterm "${USER_PKGS[*]}")" \
706 zathura "Minimalistic document viewer" "$(ofn zathura "${USER_PKGS[*]}")"
708 if [[ $USER_PKGS ]]; then
709 for i in $USER_PKGS; do
710 [[ ${PKG_EXT[$i]} && $USER_PKGS != *"${PKG_EXT[$i]}"* ]] && USER_PKGS+=" ${PKG_EXT[$i]}"
717 ###############################################################################
719 # non-essential partitioning helpers called by the user when using the optional
720 # partition menu and selecting a device to edit
724 is_bg_install || return 0
725 local device choice devhash
726 devhash="$(lsblk -f | base64)"
728 part_device || return 1
733 if [[ $DISPLAY && $TERM != 'linux' ]] && hash gparted >/dev/null 2>&1; then
734 dlg choice menu "Edit Partitions" "$_part" \
735 "auto" "Whole device automatic partitioning" \
736 "shrink" "Shrink an existing ext2/3/4 or ntfs partition to make room for a new partition" \
737 "gparted" "GUI front end to parted" \
738 "cfdisk" "Curses based variant of fdisk" \
739 "parted" "GNU partition editor" \
740 "fdisk" "Dialog-driven creation and manipulation of partitions" \
741 "done" "Return to the main menu" || return 0
743 dlg choice menu "Edit Partitions" "$_part" \
744 "auto" "Whole device automatic partitioning" \
745 "shrink" "Shrink an existing ext2/3/4 or ntfs partition to make room for a new partition" \
746 "cfdisk" "Curses based variant of fdisk" \
747 "parted" "GNU partition editor" \
748 "fdisk" "Dialog-driven creation and manipulation of partitions" \
749 "done" "Return to the main menu" || return 0
752 if [[ $choice == 'done' ]]; then
754 elif [[ $choice == 'shrink' ]]; then
755 part_shrink "$device"
756 elif [[ $choice == 'auto' ]]; then
757 local root_size txt table boot_fs
758 root_size=$(lsblk -lno SIZE "$device" | awk 'NR == 1 {
761 print ($1 * 1000 - 512) / 1000 "G"
767 txt="\nWARNING:\n\nALL data on $device will be destroyed and the following partitions will be created\n\n- "
768 if [[ $SYS == 'BIOS' ]]; then
769 table="msdos" boot_fs="ext4"
770 txt+="An $boot_fs boot partition with the boot flag enabled (512M)\n- "
772 table="gpt" boot_fs="fat32"
773 txt+="A $boot_fs efi boot partition (512M)\n- "
775 txt+="An ext4 partition using all remaining space ($root_size)\n\nDo you want to continue?\n"
776 yesno "Auto Partition" "$txt" && part_auto "$device" "$table" "$boot_fs" "$root_size"
782 if [[ $devhash != "$(lsblk -f | base64)" ]]; then
783 msg "Probing Partitions" "\nInforming the kernel of partition changes using partprobe.\n" 0
784 partprobe >/dev/null 2>&1
792 if [[ $IGNORE_DEV ]]; then
793 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk "!/$IGNORE_DEV/"' && /disk|part|lvm|crypt|NAME/')"
795 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk '/disk|part|lvm|crypt|NAME/')"
797 msg "Device Tree" "\n\n$txt\n\n"
802 if [[ $1 == "$MNT/swapfile" && $SWAP_SIZE ]]; then
803 fallocate -l $SWAP_SIZE "$1" 2>$ERR
804 errshow "fallocate -l $SWAP_SIZE $1"
805 chmod 600 "$1" 2>$ERR
806 errshow "chmod 600 $1"
808 mkswap "$1" >/dev/null 2>$ERR
810 swapon "$1" >/dev/null 2>$ERR
817 local device="$1" table="$2" boot_fs="$3" size="$4" dev_info=""
818 dev_info="$(parted -s "$device" print)"
820 msg "Auto Partition" "\nRemoving partitions on $device and setting table to $table\n" 1
823 while read -r PART; do
824 parted -s "$device" rm "$PART" >/dev/null 2>&1
825 done <<< "$(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r)"
827 [[ $(awk '/Table:/ {print $3}' <<< "$dev_info") != "$table" ]] && parted -s "$device" mklabel "$table" >/dev/null 2>&1
829 msg "Auto Partition" "\nCreating a 512M $boot_fs boot partition.\n" 1
830 if [[ $SYS == "BIOS" ]]; then
831 parted -s "$device" mkpart primary "$boot_fs" 1MiB 513MiB >/dev/null 2>&1
833 parted -s "$device" mkpart ESP "$boot_fs" 1MiB 513MiB >/dev/null 2>&1
838 AUTO_BOOT_PART=$(lsblk -lno NAME,TYPE "$device" | awk 'NR==2 {print "/dev/" $1}')
840 if [[ $SYS == "BIOS" ]]; then
841 mkfs.ext4 -q "$AUTO_BOOT_PART" >/dev/null 2>&1
843 mkfs.vfat -F32 "$AUTO_BOOT_PART" >/dev/null 2>&1
846 msg "Auto Partition" "\nCreating a $size ext4 root partition.\n" 0
847 parted -s "$device" mkpart primary ext4 513MiB 100% >/dev/null 2>&1
849 AUTO_ROOT_PART="$(lsblk -lno NAME,TYPE "$device" | awk 'NR==3 {print "/dev/" $1}')"
850 mkfs.ext4 -q "$AUTO_ROOT_PART" >/dev/null 2>&1
852 FORMATTED+="$AUTO_BOOT_PART $AUTO_ROOT_PART "
853 msg "Auto Partition" "\nProcess complete.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$device")\n"
860 local device="$1" fs=""
862 part_find "${device##*/}[^ ]" || return 1
863 (( COUNT == 1 )) && part="$(awk '{print $1}' <<< "${PARTS[@]}" )"
865 if (( COUNT == 1 )) || dlg part menu "Resize" "\nWhich partition on $device do you want to resize?" $PARTS; then
866 fs=$(lsblk -lno FSTYPE "$part")
869 msg "Resize" "\nGathering device size info.\n" 0
871 end=$(parted -s "$device" unit KiB print | awk '/^\s*'"$num"'/ {print $3}') # part size in KiB
872 devsize=$(parted -s "$device" unit KiB print | awk '/Disk '"${device//\//\\/}"':/ {print $3}') # whole device size in KiB
873 mount "$part" $MNT >/dev/null 2>&1; sleep 0.5
874 min=$(df --output=used --block-size=MiB "$part" | awk 'NR == 2 {print int($1) + 256}')
875 max=$(df --output=avail --block-size=MiB "$part" | awk 'NR == 2 {print int($1)}')
878 if dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Resize: $part " --rangebox "$_resize" 17 "$COLUMNS" "$min" "$max" $((max / 2)) 2>$ANS; then
880 size=$((size * 1024))
887 if ntfsresize -fc "$part"; then
888 ntfsresize -ff --size $(( (size * 1024) / 1000 ))k "$part" 2>$ERR # k=10^3 bytes
889 errshow "ntfsresize -f -s $(( (size * 1024) / 1000 ))k $part" || return 1
891 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"
896 e2fsck -f "$part"; sleep 0.5
897 resize2fs -f "$part" ${size}K 2>$ERR # K=2^10 bytes
898 errshow "resize2fs -f $part ${size}K" || return 1
902 parted "$device" resizepart "$num" ${size}KiB || return 1
905 if [[ $devsize == "$end" ]]; then
906 parted -s "$device" mkpart primary ext4 ${size}KiB 100% 2>$ERR
907 errshow "parted -s $device mkpart primary ext4 ${size}KiB 100%" || return 1
909 parted -s "$device" mkpart primary ext4 ${size}KiB ${end}KiB 2>$ERR
910 errshow "parted -s $device mkpart primary ext4 ${size}KiB ${end}KiB" || return 1
912 msg "Resize Complete" "\n$part has been successfully resized to $((size / 1024))M.\n" 1
914 "") msg "No Filesystem" "\nFor unformatted partitions, cfdisk can be used in the partition menu.\n" ;;
915 *) msg "Invalid Filesystem: $fs" "\nResizing only supports ext and ntfs.\n" ;;
920 ###############################################################################
921 # partition management functions
922 # these are helpers for use by other functions to do essential setup/teardown
926 local regexp="$1" err=''
928 # string of partitions as /TYPE/PART SIZE
929 if [[ $IGNORE_DEV ]]; then
930 PARTS="$(lsblk -lno TYPE,NAME,SIZE |
931 awk "/$regexp/"' && !'"/$IGNORE_DEV/"' {
932 sub(/^part/, "/dev/")
933 sub(/^lvm|^crypt/, "/dev/mapper/")
937 PARTS="$(lsblk -lno TYPE,NAME,SIZE |
939 sub(/^part/, "/dev/")
940 sub(/^lvm|^crypt/, "/dev/mapper/")
945 # number of partitions total
947 while read -r line; do
951 # ensure we have enough partitions for the system and action type
953 'part|lvm|crypt') [[ $COUNT -lt 1 || ($SYS == 'UEFI' && $COUNT -lt 2) ]] && err="$_errpart" ;;
954 'part|crypt') (( COUNT < 1 )) && err="$_lvmerr" ;;
955 'part|lvm') (( COUNT < 2 )) && err="$_lukserr" ;;
958 # if there aren't enough partitions show the relevant error message
959 [[ $err ]] && { msg "Not Enough Partitions" "$err" 2; return 1; }
966 local part="$1" mountp="${MNT}$2" fs=""
967 fs="$(lsblk -lno FSTYPE "$part")"
970 if [[ $fs && ${FS_OPTS[$fs]} && $part != "$BOOT_PART" ]] && select_mntopts "$fs"; then
971 mount -o "$MNT_OPTS" "$part" "$mountp" >/dev/null 2>&1
973 mount "$part" "$mountp" >/dev/null 2>&1
976 part_mountconf "$part" "$mountp" || return 1
984 local part="$1" fs="$2" delay="$3"
986 msg "Format" "\nFormatting $part as $fs\n" 0
987 ${FS_CMDS[$fs]} "$part" >/dev/null 2>$ERR
988 errshow "${FS_CMDS[$fs]} $part" || return 1
995 if [[ $DEV_COUNT -eq 1 && $SYS_DEVS ]]; then
996 DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
997 elif (( DEV_COUNT > 1 )); then
999 dlg DEVICE menu "Boot Device" "\nSelect the device to use for bootloader install." $SYS_DEVS
1001 dlg DEVICE menu "Select Device" "$_device" $SYS_DEVS
1003 [[ $DEVICE ]] || return 1
1004 elif [[ $DEV_COUNT -lt 1 && ! $1 ]]; then
1005 msg "Device Error" "\nNo available devices.\n\nExiting..\n" 2; die 1
1008 [[ $1 ]] && BOOT_DEV="$DEVICE"
1015 BOOT_DEV="${BOOT_PART%[1-9]}"
1016 BOOT_PART_NUM="${BOOT_PART: -1}"
1017 [[ $BOOT_PART = /dev/nvme* ]] && BOOT_DEV="${BOOT_PART%p[1-9]}"
1018 if [[ $SYS == 'UEFI' ]]; then
1019 parted -s $BOOT_DEV set $BOOT_PART_NUM esp on >/dev/null 2>&1
1021 parted -s $BOOT_DEV set $BOOT_PART_NUM boot on >/dev/null 2>&1
1028 local part="$1" devs=""
1029 devs="$(lsblk -lno NAME,FSTYPE,TYPE)"
1031 # Identify if $part is LUKS+LVM, LVM+LUKS, LVM alone, or LUKS alone
1032 if lsblk -lno TYPE "$part" | grep -q 'crypt'; then
1034 LUKS_NAME="${part#/dev/mapper/}"
1036 for dev in $(awk '/lvm/ && /crypto_LUKS/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
1037 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1038 LUKS_DEV="$LUKS_DEV cryptdevice=$dev:$LUKS_NAME"
1039 LVM='logical volume'
1044 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
1045 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1046 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
1047 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
1052 elif lsblk -lno TYPE "$part" | grep -q 'lvm'; then
1053 LVM='logical volume'
1054 VNAME="${part#/dev/mapper/}"
1056 for dev in $(awk '/crypt/ && /lvm2_member/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
1057 if lsblk -lno NAME "$dev" | grep -q "$VNAME"; then
1058 LUKS_NAME="${dev/\/dev\/mapper\//}"
1063 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
1064 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1065 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
1066 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
1077 if (( COUNT > 0 )); then
1078 PARTS="$(sed "/${pt//\//\\/}/d" <<< "$PARTS")"
1086 if grep -qw "$1" /proc/mounts; then
1087 msg "Mount Success" "\nPartition $1 mounted at $2\n" 1
1091 msg "Mount Fail" "\nPartition $1 failed to mount at $2\n" 2
1096 ###############################################################################
1098 # mount_menu is the entry point which calls all other functions
1099 # once finished it returns to the main menu: main()
1103 msg "Info" "\nGathering device info.\n" 0
1104 is_bg_install || return 0
1107 part_find 'part|lvm|crypt' || { SEL=2; return 1; }
1109 [[ $LUKS && $LUKS_PART ]] && part_countdec $LUKS_PART
1110 [[ $LVM && $LVM_PARTS ]] && part_countdec $LVM_PARTS
1112 select_root_partition || return 1
1114 if [[ $SYS == 'UEFI' ]]; then
1115 select_efi_partition || { BOOT_PART=''; return 1; }
1116 elif (( COUNT > 0 )); then
1117 select_boot_partition || { BOOT_PART=''; return 1; }
1120 if [[ $BOOT_PART ]]; then
1121 part_mount "$BOOT_PART" "/$BOOTDIR" && SEP_BOOT=true || return 1
1125 select_swap || return 1
1126 select_extra_partitions || return 1
1134 dlg SWAP_PART menu "Swap Setup" "\nSelect whether to use a swapfile, swap partition, or none." \
1135 "none" "Don't allocate any swap space" \
1136 "swapfile" "Allocate $SYS_MEM at /swapfile" \
1139 if [[ -z $SWAP_PART || $SWAP_PART == "none" ]]; then
1142 elif [[ $SWAP_PART == "swapfile" ]]; then
1144 until [[ ${SWAP_SIZE:0:1} =~ [1-9] && ${SWAP_SIZE: -1} =~ (M|G) ]]; do
1145 (( 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
1146 dlg SWAP_SIZE input "Swap Setup" "$_swapsize" "$SYS_MEM" || { SWAP_PART=''; SWAP_SIZE=''; return 1; }
1149 part_swap "$MNT/$SWAP_PART"
1150 SWAP_PART="/$SWAP_PART"
1151 elif [[ $PARTS == *"$SWAP_PART"* ]]; then
1152 part_swap $SWAP_PART
1153 part_countdec $SWAP_PART
1154 SWAP_SIZE="$(lsblk -lno SIZE $SWAP_PART)"
1164 local fs="$1" opts=''
1165 local title="${fs^} Mount Options"
1167 for i in ${FS_OPTS[$fs]}; do
1171 until [[ $MNT_OPTS ]]; do
1172 dlg MNT_OPTS check "$title" "$_mount" $opts
1173 [[ $MNT_OPTS ]] || return 1
1174 MNT_OPTS="${MNT_OPTS// /,}"
1175 yesno "$title" "\nConfirm the following options: $MNT_OPTS\n" || MNT_OPTS=''
1184 until [[ $EXMNT ]]; do
1185 dlg EXMNT input "Extra Mount $part" "$_exmnt" "/" || return 1
1186 if [[ ${EXMNT:0:1} != "/" || ${#EXMNT} -le 1 || $EXMNT =~ \ |\' || $EXMNTS == *"$EXMNT"* ]]; then
1187 msg "Mountpoint Error" "$_errexpart"
1196 local part="$1" fs='' cur=''
1197 local txt="\nSelect which filesystem to use for: $part\n\nDefault: ext4"
1198 cur="$(lsblk -lno FSTYPE "$part" 2>/dev/null)"
1201 if [[ $cur && ($part != "$ROOT_PART" || $FORMATTED == *"$part"*) ]]; then
1202 dlg fs menu "Filesystem" "$txt\nCurrent: $cur" skip - ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1204 dlg fs menu "Filesystem" "$txt" ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1206 [[ $fs == 'skip' ]] && return 0
1207 yesno "Filesystem" "\nFormat $part as $fs?\n" || fs=''
1209 part_format "$part" "$fs"
1212 select_efi_partition()
1214 if [[ $AUTO_BOOT_PART ]]; then
1215 msg "EFI Boot Partition" "\nUsing partition created during automatic format.\n" 1
1216 BOOT_PART="$AUTO_BOOT_PART"; return 0 # were done here
1218 local pts size dev isize bsize ptcount=0
1220 # walk partition list and skip ones that are too small/big for boot
1221 while read -r dev size; do
1222 size_t="${size: -1:1}" # size type eg. K, M, G, T
1223 isize=${size:0:-1} # remove trailing size type character
1224 isize=${isize%.*} # remove any decimal (round down)
1225 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1228 if (( ptcount == 1 )); then
1229 msg "EFI Boot Partition" "\nOnly one partition that meets size requirements available.\n" 1
1230 BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")"
1232 dlg BOOT_PART menu "EFI Partition" "$_uefi" $pts
1236 [[ $BOOT_PART ]] || return 1
1238 if grep -q 'fat' <<< "$(fsck -N "$BOOT_PART")"; then
1239 local txt="\nIMPORTANT:\n\nThe EFI partition $BOOT_PART $_format"
1240 if yesno "Format EFI Partition" "$txt" "Format $BOOT_PART" "Skip Formatting" 1; then
1241 part_format "$BOOT_PART" "vfat" 2
1244 part_format "$BOOT_PART" "vfat" 2
1250 select_boot_partition()
1252 if [[ $AUTO_BOOT_PART && ! $LVM ]]; then
1253 msg "BIOS Boot Partition" "\nUsing partition created during automatic format.\n" 1
1254 BOOT_PART="$AUTO_BOOT_PART"; return 0 # were done here
1256 local pts size dev isize bsize ptcount=0
1258 # walk partition list and skip ones that are too small/big for boot
1259 while read -r dev size; do
1260 size_t="${size: -1:1}" # size type eg. K, M, G, T
1261 isize=${size:0:-1} # remove trailing size type character
1262 isize=${isize%.*} # remove any decimal (round down)
1263 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1266 if [[ $LUKS && ! $LVM ]]; then
1267 dlg BOOT_PART menu "Boot Partition" "$_biosluks" $pts
1268 [[ $BOOT_PART ]] || return 1
1270 dlg BOOT_PART menu "Boot Partition" "$_bios" "skip" "don't use a separate boot" $pts
1271 [[ -z $BOOT_PART || $BOOT_PART == "skip" ]] && { BOOT_PART=''; return 0; }
1275 if grep -q 'ext[34]' <<< "$(fsck -N "$BOOT_PART")"; then
1276 local txt="\nIMPORTANT:\n\nThe boot partition $BOOT_PART $_format"
1277 if yesno "Format Boot Partition" "$txt" "Format $BOOT_PART" "Skip Formatting" 1; then
1278 part_format "$BOOT_PART" "ext4" 2
1281 part_format "$BOOT_PART" "ext4" 2
1286 select_root_partition()
1288 if [[ $AUTO_ROOT_PART && -z $LVM && -z $LUKS ]]; then
1289 ROOT_PART="$AUTO_ROOT_PART"
1290 msg "Select Root Partition (/)" "\nUsing partition created during automatic format.\n" 1
1291 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1292 return 0 # we're done here
1294 local pts size dev isize bsize ptcount=0
1296 # walk partition list and skip ones that are too small for / (root)
1297 while read -r dev size; do
1298 size_t="${size: -1:1}" # size type eg. K, M, G, T
1299 isize=${size:0:-1} # remove trailing size type character
1300 isize=${isize%.*} # remove any decimal (round down)
1301 [[ $size_t =~ [MK] || ($size_t == 'G' && $isize -lt 4) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1304 if (( ptcount == 1 )); then # only one available device
1305 msg "Select Root Partition (/)" "\nOnly one partition that meets size requirements available.\n" 1
1306 ROOT_PART="$(awk 'NR==1 {print $1}' <<< "$pts")"
1308 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
1311 [[ $ROOT_PART ]] || return 1
1313 select_filesystem "$ROOT_PART" || { ROOT_PART=''; return 1; }
1314 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1319 select_extra_partitions()
1323 # walk partition list and skip ones that are too small to be usable
1324 while read -r dev size; do
1325 [[ ${size: -1:1} =~ [KM] ]] && part_countdec "$dev"
1328 while (( COUNT > 0 )); do
1330 dlg part menu 'Mount Extra' "$_expart" 'done' 'finish mounting step' $PARTS || break
1331 if [[ $part == 'done' ]]; then
1333 elif select_filesystem "$part" && select_mountpoint && part_mount "$part" "$EXMNT"; then
1334 EXMNTS+="$part: $EXMNT "
1335 [[ $EXMNT == '/usr' && $HOOKS != *usr* ]] && HOOKS="usr $HOOKS"
1343 ###############################################################################
1345 # main is the entry point which calls all other install functions, once
1346 # complete it shows a dialog to edit files on the new system before reboot
1353 genfstab -U $MNT >$MNT/etc/fstab 2>$ERR
1354 errshow 1 "genfstab -U $MNT >$MNT/etc/fstab"
1355 [[ -f $MNT/swapfile ]] && sed -i "s~${MNT}~~" $MNT/etc/fstab
1359 chrun "hwclock --systohc --utc" || chrun "hwclock --systohc --utc --directisa"
1362 chrun "chown -Rf $NEWUSER:users /home/$NEWUSER"
1366 dlg choice menu "Finalization" "$_edit" \
1367 finished "exit the installer and reboot" \
1368 keyboard "${EDIT_FILES[keyboard]}" \
1369 console "${EDIT_FILES[console]}" \
1370 locale "${EDIT_FILES[locale]}" \
1371 hostname "${EDIT_FILES[hostname]}" \
1372 sudoers "${EDIT_FILES[sudoers]}" \
1373 mkinitcpio "${EDIT_FILES[mkinitcpio]}" \
1374 fstab "${EDIT_FILES[fstab]}" \
1375 crypttab "${EDIT_FILES[crypttab]}" \
1376 bootloader "${EDIT_FILES[bootloader]}" \
1377 pacman "${EDIT_FILES[pacman]}" \
1378 login "${EDIT_FILES[login]}"
1380 if [[ -z $choice || $choice == 'finished' ]]; then
1381 [[ $DEBUG == true && -r $DBG ]] && vim $DBG
1385 for f in ${EDIT_FILES[$choice]}; do
1386 [[ -e ${MNT}$f ]] && exists+=" ${MNT}$f"
1388 if [[ $exists ]]; then
1391 msg "File Missing" "\nThe file(s) selected do not exist:\n\n${EDIT_FILES[$choice]}\n"
1399 if [[ $RSYNC_PID || $MIRROR_PID ]]; then
1400 local oldmsg="" msg=""
1401 printf "\nOne or more background install processes are still running, grabbing their output...\n"
1402 while kill -0 "$RSYNC_PID" 2>/dev/null || kill -0 "$MIRROR_PID" 2>/dev/null; do
1403 msg="$(tail -n 1 /tmp/bg_out)"
1404 if [[ "$msg" != "$oldmsg" ]]; then
1405 printf "\n%s" "$msg"
1412 unset RSYNC_PID MIRROR_PID
1414 rsync -ahv /run/archiso/sfs/airootfs/ $MNT/ 2>$ERR
1415 errshow 1 "rsync -ahv /run/archiso/sfs/airootfs/ $MNT/"
1416 install_mirrorlist "$MNT/etc/pacman.d/mirrorlist"
1417 chrun "pacman -Syyu --noconfirm && pacman -S $BASE_PKGS --needed --noconfirm"
1420 rm -rf $MNT/etc/mkinitcpio-archiso.conf
1421 find $MNT/usr/lib/initcpio -name 'archiso*' -type f -delete
1422 sed -i 's/volatile/auto/g' $MNT/etc/systemd/journald.conf
1423 find $MNT/boot -name '*-ucode.img' -delete
1426 find $MNT/etc/X11/xorg.conf.d/ -name '*.conf' -delete
1427 elif lspci | grep ' VGA ' | grep -q 'Intel'; then
1428 cat > $MNT/etc/X11/xorg.conf.d/20-intel.conf <<- EOF
1430 Identifier "Intel Graphics"
1432 Option "TearFree" "true"
1437 [[ -e /run/archiso/sfs/airootfs && $KERNEL == 'linux' ]] && cp -vf $RUN/x86_64/vmlinuz $MNT/boot/vmlinuz-linux
1439 cp -fv /etc/resolv.conf $MNT/etc/
1440 [[ -e /etc/NetworkManager/system-connections ]] && cp -rvf /etc/NetworkManager/system-connections $MNT/etc/NetworkManager/
1442 echo "LANG=$MYLOCALE" > $MNT/etc/locale.conf
1443 cp -f $MNT/etc/locale.conf $MNT/etc/default/locale
1444 sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${MYLOCALE}/${MYLOCALE}/g" $MNT/etc/locale.gen
1446 chrun "ln -svf /usr/share/zoneinfo/$ZONE/$SUBZ /etc/localtime"
1448 if [[ $BROADCOM_WL ]]; then
1449 echo 'blacklist bcma' >> $MNT/etc/modprobe.d/blacklist.conf
1450 rm -f $MNT/etc/modprobe/
1453 cat > $MNT/etc/X11/xorg.conf.d/00-keyboard.conf <<- EOF
1454 # Use localectl(1) to instruct systemd-localed to update it.
1455 Section "InputClass"
1456 Identifier "system-keyboard"
1457 MatchIsKeyboard "on"
1458 Option "XkbLayout" "$KEYMAP"
1462 cat > $MNT/etc/default/keyboard <<- EOF
1463 # KEYBOARD CONFIGURATION FILE
1464 # Consult the keyboard(5) manual page.
1471 printf "KEYMAP=%s\nFONT=%s\n" "$CMAP" "$FONT" > $MNT/etc/vconsole.conf
1472 echo "$MYHOST" > $MNT/etc/hostname
1473 cat > $MNT/etc/hosts <<- EOF
1476 ::1 localhost ip6-localhost ip6-loopback
1477 ff02::1 ip6-allnodes
1478 ff02::2 ip6-allrouters
1484 if [[ $ROOT_PART == /dev/mapper* ]]; then
1485 ROOT_PART_ID="$ROOT_PART"
1487 local uuid_type="UUID"
1488 [[ $BOOTLDR =~ (systemd-boot|refind-efi|efistub) ]] && uuid_type="PARTUUID"
1489 ROOT_PART_ID="$uuid_type=$(blkid -s $uuid_type -o value $ROOT_PART)"
1492 if [[ $SYS == 'UEFI' ]]; then
1494 find $MNT/$BOOTDIR/EFI/ -maxdepth 1 -mindepth 1 -iname "$DIST" -type d -delete
1496 find $MNT/$BOOTDIR/EFI/ -maxdepth 1 -mindepth 1 -iname 'BOOT' -type d -delete
1500 chrun "${BCMDS[$BOOTLDR]}" 2>$ERR
1501 errshow 1 "${BCMDS[$BOOTLDR]}"
1503 if [[ -d $MNT/hostrun ]]; then
1504 # cleanup the bind mounts we made earlier for the grub-probe module
1505 umount_dir $MNT/hostrun/{udev,lvm}
1506 rm -rf $MNT/hostrun >/dev/null 2>&1
1509 if [[ $SYS == 'UEFI' ]]; then
1510 # some UEFI firmware requires a generic esp/BOOT/BOOTX64.EFI
1511 mkdir -pv $MNT/$BOOTDIR/EFI/BOOT
1512 if [[ $BOOTLDR == 'grub' ]]; then
1513 cp -fv $MNT/$BOOTDIR/EFI/$DIST/grubx64.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI
1514 elif [[ $BOOTLDR == 'syslinux' ]]; then
1515 cp -rf $MNT/$BOOTDIR/EFI/syslinux/* $MNT/$BOOTDIR/EFI/BOOT/
1516 cp -f $MNT/$BOOTDIR/EFI/syslinux/syslinux.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI
1517 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1518 sed -i '/#extra_kernel_version_strings/ c extra_kernel_version_strings linux-hardened,linux-zen,linux-lts,linux' $MNT/$BOOTDIR/EFI/refind/refind.conf
1519 cp -fv $MNT/$BOOTDIR/EFI/refind/refind_x64.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI
1528 rm -f $MNT/root/.zshrc # remove welcome message from root zshrc
1529 chrun "chpasswd <<< 'root:$ROOT_PASS'" 2>$ERR
1530 errshow 1 "set root password"
1531 if [[ $MYSHELL != "/usr/bin/zsh" ]]; then # root uses zsh by default, change it if something else was chosen
1532 chrun "usermod -s $MYSHELL root" 2>$ERR
1533 errshow 1 "usermod -s $MYSHELL root"
1534 # copy the default mkshrc to /root if mksh was picked
1535 [[ $MYSHELL == '/usr/bin/mksh' ]] && cp -fv $MNT/etc/skel/.mkshrc $MNT/root/.mkshrc
1538 local groups='audio,autologin,floppy,log,network,rfkill,scanner,storage,optical,power,wheel'
1540 chrun "groupadd -r autologin" 2>$ERR
1541 errshow 1 "groupadd -r autologin"
1542 chrun "useradd -m -u 1000 -g users -G $groups -s $MYSHELL $NEWUSER" 2>$ERR
1543 errshow 1 "useradd -m -u 1000 -g users -G $groups -s $MYSHELL $NEWUSER"
1544 chrun "chpasswd <<< '$NEWUSER:$USER_PASS'" 2>$ERR
1545 errshow 1 "set $NEWUSER password"
1547 # if neovim was picked copy vim configs to ~/.config/nvim
1548 if [[ $USER_PKGS == *neovim* ]]; then
1549 mkdir -p $MNT/home/$NEWUSER/.config/nvim
1550 cp -fv $MNT/home/$NEWUSER/.vimrc $MNT/home/$NEWUSER/.config/nvim/init.vim
1551 cp -rfv $MNT/home/$NEWUSER/.vim/colors $MNT/home/$NEWUSER/.config/nvim/colors
1554 case $INSTALL_WMS in *awesome*) install_awesome ;; *dwm*) install_suckless ;; esac
1556 [[ $WM_PKGS == *xfce* ]] && echo 'volumeicon &' >> $MNT/home/$NEWUSER/.xprofile
1558 # remove some commands from ~/.xprofile when using KDE or Gnome as the login session
1559 if [[ $LOGIN_WM =~ (startkde|gnome-session) || ($LOGIN_TYPE == 'lightdm' && $WM_PKGS =~ (plasma|gnome)) ]]; then
1560 sed -i '/super/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1561 sed -i '/nitrogen/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1562 sed -i '/al-compositor/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1563 sed -i '/compton/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1571 if [[ -e $MNT/home/$NEWUSER/.xinitrc ]] && grep -q 'exec' "$MNT/home/$NEWUSER/.xinitrc"; then
1572 sed -i "/exec/ c exec ${LOGIN_WM}" "$MNT/home/$NEWUSER/.xinitrc"
1574 printf "exec %s\n" "$LOGIN_WM" >> "$MNT/home/$NEWUSER/.xinitrc"
1577 [[ ${EDIT_FILES[login]} == *"$LOGINRC"* ]] || EDIT_FILES[login]+=" /home/$NEWUSER/$LOGINRC"
1579 if [[ $AUTOLOGIN ]]; then
1580 sed -i "s/root/${NEWUSER}/g" $SERVICE/autologin.conf
1581 cat > "$MNT/home/$NEWUSER/$LOGINRC" <<- EOF
1583 # sourced by ${MYSHELL##*/} when used as a login shell
1585 # automatically run startx when logging in on tty1
1586 [ -z \$DISPLAY ] && [ \$XDG_VTNR -eq 1 ] && exec startx
1595 SERVICE="$MNT/etc/systemd/system/getty@tty1.service.d"
1596 install_${LOGIN_TYPE:-xinit}
1601 rm -rf "$SERVICE" "$MNT/home/$NEWUSER"/.{xinitrc,profile,zprofile,bash_profile}
1602 chrun 'systemctl set-default graphical.target && systemctl enable lightdm.service' 2>$ERR
1603 errshow 1 "systemctl set-default graphical.target && systemctl enable lightdm.service"
1604 cat > $MNT/etc/lightdm/lightdm-gtk-greeter.conf <<- EOF
1605 # LightDM GTK+ Configuration
1608 default-user-image=/usr/share/icons/ArchLabs-Dark/64x64/places/distributor-logo-archlabs.png
1609 background=/usr/share/backgrounds/archlabs/archlabs.jpg
1610 theme-name=Adwaita-dark
1611 icon-theme-name=Adwaita
1612 font-name=DejaVu Sans Mono 11
1613 position=30%,end 50%,end
1619 # downloads and sets up @elenapan's awesome WM config hosted on github
1620 if chrun "git clone https://github.com/elenapan/archlabs-awesome /home/$NEWUSER/archlabs-awesome"; then
1621 cp -rT "/mnt/home/$NEWUSER/archlabs-awesome" "/mnt/home/$NEWUSER"
1622 cp -rT "/mnt/home/$NEWUSER/archlabs-awesome" /mnt/etc/skel
1623 rm -rf "/home/$NEWUSER/"{.git,archlabs-awesome,screenshots}
1624 printf "You will need to install pamac separately using: 'baph -i pamac-aur'\n"
1627 printf "failed to clone awesome config repo\n"
1634 local inpkg="$BASE_PKGS ${LOGIN_PKGS[$LOGIN_TYPE]} $PACKAGES $USER_PKGS $UCODE "
1636 if pacman -Qsq 'archlabs-installer' >/dev/null 2>&1; then
1637 rmpkg+="archlabs-installer "
1638 elif [[ -e "$MNT/usr/bin/archlabs-installer" ]]; then
1639 rm -f "$MNT/usr/bin/archlabs-installer"
1642 # add extra packages chosen throughout the install
1643 if [[ $MYSHELL == '/usr/bin/zsh' ]]; then
1644 inpkg+="zsh-completions "
1647 [[ $MYSHELL == '/usr/bin/mksh' ]] && inpkg+="mksh "
1649 if [[ $KERNEL != 'linux' ]]; then
1654 # gnome, plasma, and cinnamon have their own superkey bind and ksuperkey conflicts
1655 [[ $INSTALL_WMS =~ ^(plasma|gnome|cinnamon)$ ]] || inpkg+="archlabs-ksuperkey "
1657 # window manager only packages
1658 [[ $INSTALL_WMS =~ (openbox|bspwm|i3-gaps|dwm|fluxbox) ]] && inpkg+="$WM_BASE_PKGS "
1660 # ensure a terminal gets installed if one wasn't chosen or a DE that installs one
1661 [[ $inpkg =~ (term|urxvt|tilix|alacritty|sakura|tilda|plasma|cinnamon) || $INSTALL_WMS == *dwm* ]] || inpkg+=" xterm"
1663 # update first to avoid issues
1664 chrun "pacman -Syyu --noconfirm"
1666 # remove the packages we don't want on the installed system
1667 [[ $rmpkg ]] && chrun "pacman -Rns $rmpkg --noconfirm"
1669 # reinstalling iputils fixes the network issue for non-root users
1670 chrun "pacman -S iputils --noconfirm"
1672 # install the packages chosen throughout the install
1673 chrun "pacman -S $inpkg --needed --noconfirm" 2>$ERR
1674 errshow 1 "pacman -S $inpkg --needed --noconfirm"
1676 # bootloader packages
1677 if [[ $BOOTLDR == 'grub' ]]; then
1678 [[ $SYS == 'UEFI' ]] && local efib="efibootmgr"
1679 chrun "pacman -S os-prober grub $efib --needed --noconfirm" 2>$ERR
1680 errshow 1 "pacman -S os-prober grub $efib --needed --noconfirm"
1681 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1682 chrun "pacman -S refind-efi efibootmgr --needed --noconfirm" 2>$ERR
1683 errshow 1 "pacman -S refind-efi efibootmgr --needed --noconfirm"
1684 elif [[ $SYS == 'UEFI' ]]; then
1685 chrun "pacman -S efibootmgr --needed --noconfirm" 2>$ERR
1686 errshow 1 "pacman -S efibootmgr --needed --noconfirm"
1689 # allow members of the wheel group to run commands as root
1690 sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" $MNT/etc/sudoers
1697 mkdir -pv "$MNT/home/$NEWUSER/suckless"
1699 for i in dwm dmenu st; do
1700 if chrun "git clone https://git.suckless.org/$i /home/$NEWUSER/suckless/$i"; then
1701 chrun "cd /home/$NEWUSER/suckless/$i; make PREFIX=/usr install; make clean; rm config.h"
1703 printf "failed to clone %s repo\n" "$i"
1707 if [[ -x $MNT/usr/bin/dwm ]]; then
1708 printf "To configure dwm edit %s\n" "/home/$NEWUSER/suckless/dwm/config.h"
1709 printf "You can then recompile it with 'sudo make clean install'\n"
1714 install_mkinitcpio()
1718 # luks keyfile creation
1719 # currently not used due to not prompting for passphrase on startup
1720 # [[ $LUKS_UUID && $LUKS_PASS && $SYS == 'UEFI' && $BOOTLDR == 'grub' ]] && luks_keyfile
1722 [[ $LUKS ]] && add="encrypt"
1723 [[ $LVM ]] && { [[ $add ]] && add+=" lvm2" || add+="lvm2"; }
1724 sed -i "s/block filesystems/block ${add} filesystems ${HOOKS}/g" $MNT/etc/mkinitcpio.conf
1725 chrun "mkinitcpio -p $KERNEL" 2>$ERR
1726 errshow 1 "mkinitcpio -p $KERNEL"
1729 install_mirrorlist()
1731 local mfile="$1" # output mirrorlist file
1733 if hash reflector >/dev/null 2>&1; then
1734 reflector --score 80 -l 40 -f 5 --sort rate --save "$mfile"
1735 elif hash rankmirrors >/dev/null 2>&1; then
1736 local key="access_key=5f29642060ab983b31fdf4c2935d8c56"
1737 ip_add="$(curl -fsSL "http://api.ipstack.com/check&?$key&fields=ip" | python -c "import sys, json; print(json.load(sys.stdin)['ip'])")"
1738 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'])")"
1739 if [[ "$country" ]]; then
1740 if [[ $country =~ (CA|US) ]]; then
1741 # use both CA and US mirrors for CA or US countries
1742 mirror="https://www.archlinux.org/mirrorlist/?country=US&country=CA&use_mirror_status=on"
1743 elif [[ $country =~ (AU|NZ) ]]; then
1744 # use both AU and NZ mirrors for AU or NZ countries
1745 mirror="https://www.archlinux.org/mirrorlist/?country=AU&country=NZ&use_mirror_status=on"
1747 mirror="https://www.archlinux.org/mirrorlist/?country=${country}&use_mirror_status=on"
1749 else # no country code so just grab all mirrors, will be a very slow sort but we don't have other options
1750 mirror="https://www.archlinux.org/mirrorlist/?country=all&use_mirror_status=on"
1752 curl -fsSL "$mirror" | sed -e 's/^#Server/Server/' -e '/^#/d' | rankmirrors -n 6 - >"$mfile"
1758 install_background()
1760 yesno "Background Install" "\nBegin install in the background?\n" || return 0
1762 rsync -a /run/archiso/sfs/airootfs/ $MNT/ &
1765 mkdir -p $MNT/var/lib/pacman # can help with pacman errors
1766 ( install_mirrorlist "$MNT/etc/pacman.d/mirrorlist" && sleep 1 && chrun "pacman -Syyu $BASE_PKGS --needed --noconfirm" >> /tmp/bg_out 2>&1 ) &
1769 # end the background processes before exiting
1770 trap "kill $RSYNC_PID $MIRROR_PID 2>/dev/null" EXIT
1773 ###############################################################################
1775 # prerun_* set up the configs needed before actually running the commands
1776 # setup_* are run after selecting a bootloader and build the command used later
1777 # they can also be used for further user input as these run before control is taken away
1781 EDIT_FILES[bootloader]="/etc/default/grub"
1783 if [[ $SYS == 'BIOS' ]]; then
1784 [[ $BOOT_DEV ]] || { part_device 1 || return 1; }
1785 BCMDS[grub]="grub-install --recheck --force --target=i386-pc $BOOT_DEV"
1787 # since we're not using the keyfile this is dead code
1788 # if [[ $ROOT_PART == */dev/mapper/* && -z $LVM && -z $LUKS_PASS ]]; then
1789 # luks_pass "$_luksopen" 1 || return 1
1791 BCMDS[grub]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1792 grub-install --recheck --force --target=x86_64-efi --efi-directory=/$BOOTDIR --bootloader-id=$DIST"
1793 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1796 BCMDS[grub]="mkdir -p /run/udev /run/lvm &&
1797 mount --bind /hostrun/udev /run/udev &&
1798 mount --bind /hostrun/lvm /run/lvm &&
1800 grub-mkconfig -o /boot/grub/grub.cfg &&
1801 sleep 1 && umount /run/udev /run/lvm"
1808 sed -i "s/GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR=\"${DIST}\"/g;
1809 s/GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"\"/g" $MNT/etc/default/grub
1811 if [[ $LUKS_DEV ]]; then
1812 sed -i "s~#GRUB_ENABLE_CRYPTODISK~GRUB_ENABLE_CRYPTODISK~g;
1813 s~GRUB_CMDLINE_LINUX=.*~GRUB_CMDLINE_LINUX=\"${LUKS_DEV}\"~g" $MNT/etc/default/grub 2>$ERR
1814 errshow 1 "sed -i 's~#GRUB_ENABLE_CRYPTODISK~GRUB_ENABLE_CRYPTODISK~g;
1815 s~GRUB_CMDLINE_LINUX=.*~GRUB_CMDLINE_LINUX=\"${LUKS_DEV}\"~g' $MNT/etc/default/grub"
1818 if [[ $SYS == 'BIOS' && $LVM && -z $SEP_BOOT ]]; then
1819 sed -i "s/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g" $MNT/etc/default/grub 2>$ERR
1820 errshow 1 "sed -i 's/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g' $MNT/etc/default/grub"
1823 # setup for os-prober module
1824 mkdir -p /run/{lvm,udev} $MNT/hostrun/{lvm,udev}
1825 mount --bind /run/lvm $MNT/hostrun/lvm
1826 mount --bind /run/udev $MNT/hostrun/udev
1833 EDIT_FILES[bootloader]=""
1838 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1839 efibootmgr -v -d $BOOT_DEV -p $BOOT_PART_NUM -c -L '${DIST} Linux' -l /vmlinuz-${KERNEL} \
1840 -u 'root=$ROOT_PART_ID rw $([[ $UCODE ]] && printf 'initrd=\%s.img ' "$UCODE")initrd=\initramfs-${KERNEL}.img'"
1845 if [[ $SYS == 'BIOS' ]]; then
1846 EDIT_FILES[bootloader]="/boot/syslinux/syslinux.cfg"
1848 EDIT_FILES[bootloader]="/boot/EFI/syslinux/syslinux.cfg"
1849 BCMDS[syslinux]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1850 efibootmgr -v -c -d $BOOT_DEV -p $BOOT_PART_NUM -l /EFI/syslinux/syslinux.efi -L $DIST"
1856 local c="$MNT/boot/syslinux" s="/usr/lib/syslinux/bios" d=".."
1857 [[ $SYS == 'UEFI' ]] && { c="$MNT/boot/EFI/syslinux"; s="/usr/lib/syslinux/efi64/"; d=''; }
1859 mkdir -pv "$c" && cp -rfv $s/* "$c/" && cp -f "$RUN/syslinux/splash.png" "$c/"
1860 cat > "$c/syslinux.cfg" <<- EOF
1862 MENU TITLE $DIST Boot Menu
1863 MENU BACKGROUND splash.png
1867 # see: https://www.syslinux.org/wiki/index.php/Comboot/menu.c32
1876 MENU HELPMSGENDROW 29
1877 MENU COLOR border 30;44 #40ffffff #a0000000 std
1878 MENU COLOR title 1;36;44 #9033ccff #a0000000 std
1879 MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
1880 MENU COLOR unsel 37;44 #50ffffff #a0000000 std
1881 MENU COLOR help 37;40 #c0ffffff #a0000000 std
1882 MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
1883 MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
1884 MENU COLOR msg07 37;40 #90ffffff #a0000000 std
1885 MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
1888 MENU LABEL $DIST Linux
1889 LINUX $d/vmlinuz-$KERNEL
1890 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1891 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL.img
1893 LABEL ${DIST}fallback
1894 MENU LABEL $DIST Linux Fallback
1895 LINUX $d/vmlinuz-$KERNEL
1896 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1897 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL-fallback.img
1904 EDIT_FILES[bootloader]="/boot/refind_linux.conf"
1905 BCMDS[refind-efi]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1911 cat > $MNT/boot/refind_linux.conf <<- EOF
1912 "$DIST Linux" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1913 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1914 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL.img"
1915 "$DIST Linux Fallback" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1916 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1917 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL-fallback.img"
1919 mkdir -p $MNT/etc/pacman.d/hooks
1920 cat > $MNT/etc/pacman.d/hooks/refind.hook <<- EOF
1927 Description = Updating rEFInd on ESP
1928 When = PostTransaction
1929 Exec = /usr/bin/refind-install
1933 setup_systemd-boot()
1935 EDIT_FILES[bootloader]="/boot/loader/entries/$DIST.conf"
1936 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1937 bootctl --path=/boot install"
1940 prerun_systemd-boot()
1942 mkdir -p $MNT/boot/loader/entries
1944 cat > $MNT/boot/loader/loader.conf <<- EOF
1950 cat > $MNT/boot/loader/entries/$DIST.conf <<- EOF
1952 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1953 initrd /initramfs-$KERNEL.img
1954 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1957 cat > $MNT/boot/loader/entries/$DIST-fallback.conf <<- EOF
1958 title $DIST Linux Fallback
1959 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1960 initrd /initramfs-$KERNEL-fallback.img
1961 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1964 mkdir -p $MNT/etc/pacman.d/hooks
1965 cat > $MNT/etc/pacman.d/hooks/systemd-boot.hook <<- EOF
1972 Description = Updating systemd-boot
1973 When = PostTransaction
1974 Exec = /usr/bin/bootctl update
1977 systemd-machine-id-setup --root="$MNT"
1981 ###############################################################################
1986 is_bg_install || return 1
1989 dlg choice menu "Logical Volume Management" "$_lvmmenu" \
1990 "$_lvmnew" "vgcreate -f, lvcreate -L -n" \
1991 "$_lvmdel" "vgremove -f" \
1992 "$_lvmdelall" "lvrmeove, vgremove, pvremove -f" \
1993 "back" "return to the main menu"
1996 "$_lvmnew") lvm_create || return 1 ;;
1997 "$_lvmdel") lvm_delgroup && yesno "$_lvmdel" "$_lvmdelask" && vgremove -f "$DEL_VG" >/dev/null 2>&1 ;;
1998 "$_lvmdelall") lvm_del_all ;;
2007 pv="$(pvs -o pv_name --noheading 2>/dev/null)"
2008 v="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
2009 VGROUP="$(vgs -o vg_name --noheading 2>/dev/null)"
2011 if [[ $VGROUP && $v && $pv ]]; then
2012 msg "Logical Volume Management" "\nActivating existing logical volume management (LVM).\n\n" 1
2013 modprobe dm-mod >/dev/null 2>$ERR
2014 errshow 'modprobe dm-mod'
2015 vgscan >/dev/null 2>&1
2016 vgchange -ay >/dev/null 2>&1
2022 VGROUP='' LVM_PARTS='' VGROUP_MB=0
2024 lvm_mkgroup || return 1
2025 local txt="\nThe last (or only) logical volume will automatically use all remaining space in the volume group."
2026 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
2027 [[ $VOL_COUNT ]] || return 1
2028 lvm_extra_lvs || return 1
2029 lvm_volume_name "$_lvmlvname\nNOTE: This LV will use up all remaining space in the volume group (${VGROUP_MB}MB)" || return 1
2030 lvcreate -l +100%FREE "$VGROUP" -n "$VNAME" >/dev/null 2>$ERR
2031 errshow "lvcreate -l +100%FREE $VGROUP -n $VNAME" || return 1
2032 LVM='logical volume'; sleep 0.5
2033 txt="\nDone, volume: $VGROUP-$VNAME (${VOLUME_SIZE:-${VGROUP_MB}MB}) has been created.\n"
2034 msg "$_lvmnew (LV:$VOL_COUNT)" "$txt\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE $LVM_PARTS)\n"
2040 local txt="${VGROUP}: ${SIZE}$SIZE_UNIT (${VGROUP_MB}MB remaining).$_lvmlvsize"
2044 dlg VOLUME_SIZE input "$_lvmnew (LV:$VOL_COUNT)" "$txt" ''
2045 if [[ -z $VOLUME_SIZE ]]; then
2047 break # allow bailing with escape or an empty choice
2048 elif (( ${VOLUME_SIZE:0:1} == 0 )); then
2049 ERR_SIZE=1 # size values can't begin with '0'
2051 # walk the string and make sure all but the last char are digits
2052 local lv=$((${#VOLUME_SIZE} - 1))
2053 for (( i=0; i<lv; i++ )); do
2054 [[ ${VOLUME_SIZE:$i:1} =~ [0-9] ]] || { ERR_SIZE=1; break; }
2056 if (( ERR_SIZE != 1 )); then
2057 case ${VOLUME_SIZE:$lv:1} in
2058 [mMgG]) local s=${VOLUME_SIZE:0:$lv} m=$((s * 1000))
2059 case ${VOLUME_SIZE:$lv:1} in
2060 [Gg]) (( m >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - m)) ;;
2061 [Mm]) (( ${VOLUME_SIZE:0:$lv} >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - s)) ;;
2068 if (( ERR_SIZE )); then
2069 msg "Invalid Logical Volume Size" "$_lvmerrlvsize"
2081 local txt="\nConfirm creation of volume group: $VGROUP\n\nwith the following partition(s):"
2083 until [[ $named ]]; do
2084 lvm_partitions || return 1
2085 lvm_group_name || return 1
2086 yesno "$_lvmnew" "$txt $LVM_PARTS\n" && named=true
2089 vgcreate -f "$VGROUP" $LVM_PARTS >/dev/null 2>$ERR
2090 errshow "vgcreate -f $VGROUP $LVM_PARTS" || return 1
2092 SIZE=$(vgdisplay "$VGROUP" | awk '/VG Size/ { gsub(/[^0-9.]/, ""); print int($0) }')
2093 SIZE_UNIT="$(vgdisplay "$VGROUP" | awk '/VG Size/ { print substr($NF, 0, 1) }')"
2095 if [[ $SIZE_UNIT == 'G' ]]; then
2096 VGROUP_MB=$((SIZE * 1000))
2101 msg "$_lvmnew" "\nVolume group: $VGROUP ($SIZE $SIZE_UNIT) has been created\n"
2108 pv="$(pvs -o pv_name --noheading 2>/dev/null)"
2109 v="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
2110 VGROUP="$(vgs -o vg_name --noheading 2>/dev/null)"
2112 if [[ $VGROUP || $v || $pv ]]; then
2113 if yesno "$_lvmdelall" "$_lvmdelask"; then
2114 for i in $v; do lvremove -f "/dev/mapper/$i" >/dev/null 2>&1; done
2115 for i in $VGROUP; do vgremove -f "$i" >/dev/null 2>&1; done
2116 for i in $pv; do pvremove -f "$i" >/dev/null 2>&1; done
2120 msg "Delete LVM" "\nNo LVMs to remove...\n" 2
2130 for i in $(lvs --noheadings | awk '{print $2}' | uniq); do
2131 VOL_GROUP_LIST+="$i $(vgdisplay "$i" | awk '/VG Size/ {print $3$4}') "
2133 [[ $VOL_GROUP_LIST ]] || { msg "No Groups" "\nNo volume groups found."; return 1; }
2135 dlg DEL_VG menu "Logical Volume Management" "\nSelect volume group to delete.\n\nAll logical volumes within will also be deleted." $VOL_GROUP_LIST
2141 while (( VOL_COUNT > 1 )); do
2142 lvm_volume_name "$_lvmlvname" && get_lv_size || return 1
2143 lvcreate -L "$VOLUME_SIZE" "$VGROUP" -n "$VNAME" >/dev/null 2>$ERR
2144 errshow "lvcreate -L $VOLUME_SIZE $VGROUP -n $VNAME" || return 1
2145 msg "$_lvmnew (LV:$VOL_COUNT)" "\nDone, logical volume (LV) $VNAME ($VOLUME_SIZE) has been created.\n"
2153 part_find 'part|crypt' || return 1
2154 PARTS="$(awk 'NF > 0 {print $0 " off"}' <<< "$PARTS")"
2155 dlg LVM_PARTS check "$_lvmnew" "\nSelect the partition(s) to use for the physical volume (PV)." $PARTS
2162 until [[ $VGROUP ]]; do
2163 dlg VGROUP input "$_lvmnew" "$_lvmvgname" "mygroup"
2164 if [[ -z $VGROUP ]]; then
2166 elif [[ ${VGROUP:0:1} == "/" || $VGROUP =~ \ |\' ]] || lsblk | grep -q "$VGROUP"; then
2167 msg "LVM Name Error" "$_lvmerrvgname"
2177 local txt="$1" default="mainvolume"
2178 (( VOL_COUNT > 1 )) && default="extravolume$VOL_COUNT"
2179 until [[ $VNAME ]]; do
2180 dlg VNAME input "$_lvmnew (LV:$VOL_COUNT)" "\n$txt" "$default"
2181 if [[ -z $VNAME ]]; then
2183 elif [[ ${VNAME:0:1} == "/" || $VNAME =~ \ |\' ]] || lsblk | grep -q "$VNAME"; then
2184 msg "LVM Name Error" "$_lvmerlvname"
2191 ###############################################################################
2197 is_bg_install || return 1
2198 dlg choice menu "LUKS Encryption" "$_luksmenu" \
2199 "$_luksnew" "cryptsetup -q luksFormat" \
2200 "$_luksopen" "cryptsetup open --type luks" \
2201 "$_luksadv" "cryptsetup -q -s -c luksFormat" \
2202 "back" "Return to the main menu"
2205 "$_luksnew") luks_basic || return 1 ;;
2206 "$_luksopen") luks_open || return 1 ;;
2207 "$_luksadv") luks_advanced || return 1 ;;
2215 modprobe -a dm-mod dm_crypt >/dev/null 2>&1
2217 part_find 'part|crypt|lvm' || return 1
2219 if (( COUNT == 1 )); then
2220 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2222 dlg LUKS_PART menu "$_luksopen" "\nSelect which partition to open." $PARTS
2225 [[ $LUKS_PART ]] || return 1
2227 luks_pass "$_luksopen" || return 1
2228 msg "$_luksopen" "\nOpening encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2229 cryptsetup open --type luks "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2230 errshow "cryptsetup open --type luks $LUKS_PART $LUKS_NAME" || return 1
2231 LUKS='encrypted'; luks_show
2238 local t="$1" op="$2" v='' p='' p2=''
2240 until [[ $LUKS_PASS ]]; do
2244 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " \
2245 --mixedform "\nEnter the password to decrypt $ROOT_PART\n\nThis is needed to create a keyfile." 0 0 0 \
2246 "Password:" 1 1 '' 1 11 "$COLUMNS" 0 1 \
2247 "Password2:" 2 1 '' 2 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
2250 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " --mixedform "$_luksomenu" 0 0 0 \
2251 "Name:" 1 1 "${LUKS_NAME:-cryptroot}" 1 7 "$COLUMNS" 0 0 \
2252 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
2253 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
2257 while read -r line; do
2273 if [[ -z $op && -z $n ]]; then
2274 msg "Name Empty" "\nEncrypted device name cannot be empty.\n\nPlease try again.\n" 2
2275 elif [[ -z $p || "$p" != "$p2" ]]; then
2276 [[ $op ]] || LUKS_NAME="$n"
2277 msg "Password Mismatch" "\nThe passwords entered do not match.\n\nPlease try again.\n" 2
2279 [[ $op ]] || LUKS_NAME="$n"
2290 msg "$_luksnew" "\nEncrypted partition opened and ready for mounting.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$LUKS_PART")\n\n"
2295 modprobe -a dm-mod dm_crypt >/dev/null 2>&1
2297 part_find 'part|lvm' || return 1
2299 if [[ $AUTO_ROOT_PART ]]; then
2300 LUKS_PART="$AUTO_ROOT_PART"
2301 elif (( COUNT == 1 )); then
2302 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2304 dlg LUKS_PART menu "$_luksnew" "\nSelect the partition you want to encrypt." $PARTS
2307 [[ $LUKS_PART ]] || return 1
2308 luks_pass "$_luksnew"
2313 luks_setup || return 1
2314 msg "$_luksnew" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2315 cryptsetup -q luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2>$ERR
2316 errshow "cryptsetup -q luksFormat $LUKS_PART" || return 1
2317 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2318 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2319 LUKS='encrypted'; luks_show
2325 if [[ ! -e $MNT/crypto_keyfile.bin ]]; then
2326 # printf "Creating LUKS keyfile /crypto_keyfile.bin\n"
2328 n="$(lsblk -lno NAME,UUID,TYPE | awk "/$LUKS_UUID/"' && /part|crypt|lvm/ {print $1}')"
2329 local mkkey="dd bs=512 count=8 if=/dev/urandom of=/crypto_keyfile.bin"
2330 mkkey="$mkkey && chmod 000 /crypto_keyfile.bin"
2331 mkkey="$mkkey && cryptsetup luksAddKey /dev/$n /crypto_keyfile.bin <<< '$LUKS_PASS'"
2333 sed -i 's/FILES=()/FILES=(\/crypto_keyfile.bin)/g' $MNT/etc/mkinitcpio.conf 2>$ERR
2343 dlg cipher input "LUKS Encryption" "$_lukskey" "-s 512 -c aes-xts-plain64"
2344 [[ $cipher ]] || return 1
2345 msg "$_luksadv" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2346 cryptsetup -q $cipher luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2>$ERR
2347 errshow "cryptsetup -q $cipher luksFormat $LUKS_PART" || return 1
2348 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2349 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2356 ###############################################################################
2358 # some help avoid repetition and improve usability of some commands
2359 # others are initial setup functions used before reaching the main loop
2363 [[ "$2" == *"$1"* ]] && printf "on" || printf "off"
2372 if [[ -d $MNT ]] && command cd /; then
2374 if (( ecode == 127 )); then
2375 umount_dir /run/archiso/bootmnt
2386 local var="$1" dialog_type="$2" title="$3" body="$4" n=0
2388 (( ($# / 2) > SHL )) && n=$SHL
2391 case "$dialog_type" in
2392 menu) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --menu "$body" 0 0 $n "$@" 2>"$ANS" || return 1 ;;
2393 check) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --checklist "$body" 0 0 $n "$@" 2>"$ANS" || return 1 ;;
2398 if [[ $1 == 'limit' ]]; then
2399 dialog --backtitle "$DIST Installer - $SYS - v$VER" --max-input 63 --title " $title " --inputbox "$body" 0 0 "$def" 2>"$ANS" || return 1
2401 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --inputbox "$body" 0 0 "$def" 2>"$ANS" || return 1
2405 [[ -s "$ANS" ]] && printf -v "$var" "%s" "$(< "$ANS")"
2410 local title="$1" body="$2"
2412 if (( $# == 3 )); then
2413 dialog --backtitle "$DIST Installer - $SYS - v$VER" --sleep "$3" --title " $title " --infobox "$body\n" 0 0
2415 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --msgbox "$body\n" 0 0
2421 local title="$1" body="$2" yes='Yes' no='No'
2422 (( $# >= 3 )) && yes="$3"
2423 (( $# >= 4 )) && no="$4"
2425 if (( $# == 5 )); then
2426 dialog --backtitle "$DIST Installer - $SYS - v$VER" --defaultno --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2428 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2434 arch-chroot "$MNT" bash -c "$1"
2439 export PS4='| ${BASH_SOURCE} LINE:${LINENO} FUNC:${FUNCNAME[0]:+ ${FUNCNAME[0]}()} |> '
2448 printf "\n^C caught, cleaning up...\n"
2455 "\e]P0191919" # #191919
2456 "\e]P1D15355" # #D15355
2457 "\e]P2609960" # #609960
2458 "\e]P3FFCC66" # #FFCC66
2459 "\e]P4255A9B" # #255A9B
2460 "\e]P5AF86C8" # #AF86C8
2461 "\e]P62EC8D3" # #2EC8D3
2462 "\e]P7949494" # #949494
2463 "\e]P8191919" # #191919
2464 "\e]P9D15355" # #D15355
2465 "\e]PA609960" # #609960
2466 "\e]PBFF9157" # #FF9157
2467 "\e]PC4E88CF" # #4E88CF
2468 "\e]PDAF86C8" # #AF86C8
2469 "\e]PE2ec8d3" # #2ec8d3
2470 "\e]PFE1E1E1" # #E1E1E1
2473 [[ $TERM == 'linux' ]] && printf "%b" "${colors[@]}" && clear
2478 [ $? -eq 0 ] && return 0
2480 local fatal=0 err=""
2481 err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
2483 (( $1 == 1 )) && { fatal=1; shift; }
2485 local txt="\nThe command exited abnormally:\n\n$1\n\n"
2488 txt+="With the following message:\n\n$err\n\n"
2490 txt+="With no error message:\n\n"
2493 if (( fatal )); then
2494 txt+="Errors at this stage are fatal and the install cannot continue.\n"
2496 txt+="Errors at this stage are non-fatal and can be either fixed or ignored depending on the error.\n"
2498 msg "Install Error" "$txt"
2500 if (( fatal )); then
2501 [[ -r $DBG && $TERM == 'linux' ]] && less "$DBG"
2510 msg "Broadcom Wireless Setup" "\nDetected chipset is Broadcom BCM4352\n\nDisabling bcma/b43 modules and loading wl module.\n" 1
2511 { rmmod wl; rmmod bcma; rmmod b43; rmmod ssb; modprobe wl; depmod -a; } >/dev/null 2>&1
2519 if (( $1 >= 0 )) && ! grep -qw "$MNT" /proc/mounts; then
2520 msg "Not Mounted" "\nPartition(s) must be mounted first.\n" 2
2522 elif [[ $1 -ge 1 && -z $BOOTLDR ]]; then
2523 msg "No Bootloader" "\nBootloader must be selected first.\n" 2
2525 elif [[ $1 -ge 2 && (-z $NEWUSER || -z $USER_PASS) ]]; then
2526 msg "No User" "\nA user must be created first.\n" 2
2528 elif [[ $1 -ge 3 && -z $CONFIG_DONE ]]; then
2529 msg "Not Configured" "\nSystem configuration must be done first.\n" 2
2532 (( i )) # return code
2537 mount | grep -q 'swap' && swapoff -a
2539 [[ -d $dir && "$(mount | grep "on $dir ")" ]] || continue
2540 umount "$dir" 2>/dev/null || { sleep 0.5; umount -f "$dir" 2>/dev/null || umount -l "$dir"; }
2546 msg "Network Connect" "\nVerifying network connection\n" 1
2547 curl -sIN --connect-timeout 5 'https://www.archlinux.org/' | sed '1q' | grep -q '200'
2552 if chk_connect; then
2555 if hash nmtui >/dev/null 2>&1; then
2557 if [[ $TERM == 'linux' ]]; then
2558 printf "%b" "\e]P1191919" "\e]P4191919"
2560 printf "%b" "\e]P1D15355" "\e]P4255a9b"
2573 [[ $RSYNC_PID || $MIRROR_PID ]] || return 0
2574 msg "Install Running" "\nA background install process is currently running.\n" 2
2580 IGNORE_DEV="$(lsblk -lno NAME,MOUNTPOINT | awk '/\/run\/archiso\/bootmnt/ {sub(/[1-9]/, ""); print $1}')"
2582 if [[ $IGNORE_DEV ]]; then
2583 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ && !'"/$IGNORE_DEV/"' {print "/dev/" $1 " " $2}')"
2585 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ {print "/dev/" $1 " " $2}')"
2588 if [[ -z $SYS_DEVS ]]; then
2589 msg "Device Error" "\nNo available devices...\n\nExiting..\n" 2
2594 while read -r line; do
2596 done <<< "$SYS_DEVS"
2603 elif grep -q 'AuthenticAMD' /proc/cpuinfo; then
2605 elif grep -q 'GenuineIntel' /proc/cpuinfo; then
2609 modprobe -q efivarfs >/dev/null 2>&1
2611 _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."
2612 if [[ -d /sys/firmware/efi/efivars ]]; then
2614 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars
2615 _prep+="\n - An EFI boot partition mounted."
2619 _prep+="\n\nOnce finished mounting, a portion of the install can be done in the background while you continue configuring the system:\n"
2620 _prep+="\n - Choose the system bootloader.\n - Create a user and password."
2621 _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."
2624 ###############################################################################
2627 # enable some nicer colours in the linux console
2630 if (( UID != 0 )); then
2631 msg "Not Root" "\nThis installer must be run as root or using sudo.\n\nExiting..\n" 2
2633 elif ! grep -qwm 1 'lm' /proc/cpuinfo; then
2634 msg "Not x86_64 Architecture" "\nThis installer only supports x86_64 architectures.\n\nExiting..\n" 2
2636 elif [[ $1 =~ (-d|--debug) ]]; then
2640 # trap ^C to perform cleanup
2646 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"
2648 select_keymap || { clear; die 0; }
2650 # try to fix problematic broadcom wireless chipset before network check
2651 lspci -vnn -d 14e4: | grep -q 'BCM4352' && load_bcm
2653 net_connect || { msg "Not Connected" "\nThis installer requires an active internet connection.\n\nExiting..\n" 2; die 1; }
2659 # vim:fdm=marker:fmr={,}