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 _autologin="\nDo you want autologin enabled for USER?\n\nIf so the following two files will be created (disable autologin by removing them):\n\n - /home/USER/RC (run startx when logging in on tty1)\n - /etc/systemd/system/getty@tty1.service.d/autologin.conf (login USER without password)\n"
271 _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."
272 _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."
275 _luksnew="Basic LUKS Encryption"
276 _luksadv="Advanced LUKS Encryption"
277 _luksopen="Open Existing LUKS Partition"
278 _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."
279 _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."
280 _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)."
283 _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."
284 _lvmnew="Create Volume Group and Volume(s)"
285 _lvmdel="Delete an Existing Volume Group"
286 _lvmdelall="Delete ALL Volume Group(s) and Volume(s)"
287 _lvmvgname="\nEnter a name for the volume group (VG) being created from the partition(s) selected."
288 _lvmlvname="\nEnter a name for the logical volume (LV) being created.\n\nThis is similar to setting a label for a partition."
289 _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."
290 _lvmdelask="\nConfirm deletion of volume group(s) and logical volume(s).\n\nDeleting a volume group, will delete all logical volumes within it.\n"
293 _errexpart="\nCannot mount partition due to a problem with the mountpoint.\n\nEnsure it begins with a slash (/) followed by atleast one character.\n"
294 _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"
295 _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"
296 _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"
297 _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"
298 _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"
299 _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"
305 ###############################################################################
307 # main is the entry point which calls functions including outside of its block
308 # once those functions finished they always are returned here with the
309 # exception of install_main(), it exits upon completion
313 (( SEL < 12 )) && (( SEL++ ))
315 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Prepare " --default-item $SEL --cancel-label 'Exit' --menu "$_prep" 0 0 0 \
316 1 "Device tree (optional)" \
317 2 "Partitioning (optional)" \
318 3 "LUKS setup (optional)" \
319 4 "LVM setup (optional)" \
320 5 "Mount partitions" \
321 6 "System bootloader" \
322 7 "User and password" \
323 8 "System configuration" \
324 9 "Select WM/DE (optional)" \
325 10 "Select Packages (optional)" \
326 11 "View configuration (optional)" \
327 12 "Start the installation" 2>"$ANS"
330 [[ -z $WARN && $SEL =~ (2|5) ]] && { msg "Data Warning" "$_warn"; WARN=true; }
333 2) part_menu || (( SEL-- )) ;;
334 3) luks_menu || (( SEL-- )) ;;
335 4) lvm_menu || (( SEL-- )) ;;
336 5) mount_menu || (( SEL-- )) ;;
337 6) prechecks 0 && { select_boot || (( SEL-- )); } ;;
338 7) prechecks 1 && { select_mkuser || (( SEL-- )); } ;;
339 8) prechecks 2 && { select_config || (( SEL-- )); } ;;
340 9) prechecks 3 && { select_sessions || (( SEL-- )); } ;;
341 10) prechecks 3 && { select_packages || (( SEL-- )); } ;;
342 11) prechecks 3 && select_show ;;
343 12) prechecks 3 && install_main ;;
344 *) yesno "Exit" "\nUnmount partitions (if any) and exit the installer?\n" && die 0
350 if [[ $SYS == 'BIOS' ]]; then
351 dlg BOOTLDR menu "BIOS Bootloader" "\nSelect which bootloader to use." \
352 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
353 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network" || return 1
355 dlg BOOTLDR menu "UEFI Bootloader" "\nSelect which bootloader to use." \
356 "systemd-boot" "A simple UEFI boot manager which executes configured EFI images" \
357 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
358 "refind-efi" "A UEFI boot manager that aims to be platform neutral and simplify multi-boot" \
359 "efistub" "Boot the kernel image directly (no chainloading support)" \
360 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network (no chainloading support)" || return 1
368 local cmd="${BCMDS[$BOOTLDR]}"
369 local pkgs="${USER_PKGS// / } ${PACKAGES// / }"
370 local exmnt="${EXMNT:-none}"
371 [[ $BOOT_PART ]] && mnt="/$BOOTDIR"
372 [[ $INSTALL_WMS == *dwm* ]] && pkgs="dwm st dmenu $pkgs"
374 msg "Show Configuration" "
376 ---------- PARTITION CONFIGURATION ------------
378 Root: ${ROOT_PART:-none}
379 Boot: ${BOOT_PART:-${BOOT_DEV:-none}}
380 Swap: ${SWAP_PART:-none}
381 Size: ${SWAP_SIZE:-none}
382 Extra: ${EXMNTS:-$exmnt}
383 Hooks: ${HOOKS:-none}
388 ---------- BOOTLOADER CONFIGURATION -----------
390 Bootloader: ${BOOTLDR:-none}
391 Mountpoint: ${mnt:-none}
392 Command: ${cmd:-none}
395 ------------ SYSTEM CONFIGURATION -------------
397 Locale: ${MYLOCALE:-none}
398 Keymap: ${KEYMAP:-none}
399 Hostname: ${MYHOST:-none}
400 Timezone: ${ZONE:-none}/${SUBZ:-none}
403 ------------ USER CONFIGURATION --------------
405 User: ${NEWUSER:-none}
406 Shell: ${MYSHELL:-none}
407 Session: ${LOGIN_WM:-none}
408 Autologin: ${AUTOLOGIN:-none}
409 DM or xinit: ${LOGIN_TYPE:-none}
412 ------------ PACKAGES AND MIRRORS -------------
414 Kernel: ${KERNEL:-none}
415 Sessions: ${INSTALL_WMS:-none}
416 Packages: ${USER_PKGS// / } ${PACKAGES// / }
422 [[ $INSTALL_WMS ]] || return 0
424 if [[ -z $LOGIN_TYPE ]]; then
425 dlg LOGIN_TYPE menu "Login Management" "\nSelect what kind of login management to use." \
426 "xinit" "Console login without a display manager" \
427 "lightdm" "Lightweight display manager with a gtk greeter" || return 1
430 if [[ $LOGIN_TYPE == 'lightdm' ]]; then
432 EDIT_FILES[login]="/etc/lightdm/lightdm.conf /etc/lightdm/lightdm-gtk-greeter.conf"
434 # define what wm/de to use for xinit
435 if (( $(wc -w <<< "$INSTALL_WMS") > 1 )); then
436 dlg LOGIN_WM menu "Login Management" "$_login" $LOGIN_CHOICES || return 1
437 LOGIN_WM="${WM_SESSIONS[$LOGIN_WM]}"
439 [[ -z $LOGIN_WM ]] && LOGIN_WM="${WM_SESSIONS[${INSTALL_WMS%% *}]}"
442 yesno "Autologin" "$(sed "s|USER|$NEWUSER|g; s|RC|$LOGINRC|g" <<< "$_autologin")" && AUTOLOGIN=true || AUTOLOGIN=''
444 EDIT_FILES[login]="/home/$NEWUSER/.xinitrc /home/$NEWUSER/.xprofile"
453 until [[ $CONFIG_DONE ]]; do
455 0) 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
460 1) dlg MYHOST input "Hostname" "$_hostname" "${DIST,,}" limit || { i=0; continue; } ;;
461 2) dlg MYLOCALE menu "Locale" "$_locale" $LOCALES || { i=1; continue; } ;;
463 until [[ $ZONE && $SUBZ ]]; do
464 dlg ZONE menu "Timezone" "$_timez" America - Australia - Asia - Atlantic - Africa - Europe - Indian - Pacific - Arctic - Antarctica - || break
465 dlg SUBZ menu "Timezone" "$_timesubz" $(awk '/'"$ZONE"'\// {gsub(/'"$ZONE"'\//, ""); print $3 " - "}' /usr/share/zoneinfo/zone.tab | sort) || continue
466 yesno "Timezone" "\nConfirm time zone: $ZONE/$SUBZ\n" || unset ZONE
468 [[ $ZONE && $SUBZ ]] || { i=2; continue; } ;;
469 4) dlg KERNEL menu "Kernel" "\nChoose which kernel to use." \
470 linux 'Vanilla linux kernel and modules, with a few patches applied' \
471 linux-lts 'Long-term support (LTS) linux kernel and modules' \
472 linux-zen 'A effort of kernel hackers to provide the best kernel for everyday systems' \
473 linux-hardened 'A security-focused linux kernel with hardening patches to mitigate exploits' || { i=3; continue; }
477 (( i++ )) # progress through to the next choice
481 '/bin/bash') LOGINRC='.bash_profile' ;;
482 '/usr/bin/zsh') LOGINRC='.zprofile' ;;
483 '/usr/bin/mksh') LOGINRC='.profile' ;;
492 local v='' u='' p='' p2='' rp='' rp2=''
494 until [[ $NEWUSER ]]; do
497 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " User " --mixedform "$_user" 0 0 0 \
498 "Username:" 1 1 "$u" 1 11 "$COLUMNS" 0 0 \
499 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
500 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 \
501 "--- Root password, if left empty the user password will be used ---" 6 1 '' 6 68 "$COLUMNS" 0 2 \
502 "Password:" 8 1 '' 8 11 "$COLUMNS" 0 1 \
503 "Password2:" 9 1 '' 9 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
505 while read -r line; do
506 case $i in 0) u="$line" ;; 1) p="$line" ;; 2) p2="$line" ;; 3) rp="$line" ;; 4) rp2="$line" ;; esac
510 # root passwords empty, so use the user passwords
511 [[ -z $rp && -z $rp2 ]] && { rp="$p"; rp2="$p2"; }
513 # make sure a username was entered and that the passwords match
514 if [[ ${#u} -eq 0 || $u =~ \ |\' || $u =~ [^a-z0-9] ]]; then
515 msg "Invalid Username" "\nIncorrect user name.\n\nPlease try again.\n"; u=''
516 elif [[ -z $p ]]; then
517 msg "Empty Password" "\nThe user password cannot be left empty.\n\nPlease try again.\n"
518 elif [[ "$p" != "$p2" ]]; then
519 msg "Password Mismatch" "\nThe user passwords do not match.\n\nPlease try again.\n"
520 elif [[ "$rp" != "$rp2" ]]; then
521 msg "Password Mismatch" "\nThe root passwords do not match.\n\nPlease try again.\n"
533 dlg KEYMAP menu "Keyboard Layout" "$_keymap" \
534 us English cm English gb English au English gh English \
535 za English ng English ca French 'cd' French gn French \
536 tg French fr French de German at German ch German \
537 es Spanish latam Spanish br Portuguese pt Portuguese ma Arabic \
538 sy Arabic ara Arabic ua Ukrainian cz Czech ru Russian \
539 sk Slovak nl Dutch it Italian hu Hungarian cn Chinese \
540 tw Taiwanese vn Vietnamese kr Korean jp Japanese th Thai \
541 la Lao pl Polish se Swedish is Icelandic 'fi' Finnish \
542 dk Danish be Belgian in Indian al Albanian am Armenian \
543 bd Bangla ba Bosnian 'bg' Bulgarian dz Berber mm Burmese \
544 hr Croatian gr Greek il Hebrew ir Persian iq Iraqi \
545 af Afghani fo Faroese ge Georgian ee Estonian kg Kyrgyz \
546 kz Kazakh lt Lithuanian mt Maltese mn Mongolian ro Romanian \
547 no Norwegian rs Serbian si Slovenian tj Tajik lk Sinhala \
548 tr Turkish uz Uzbek ie Irish pk Urdu 'mv' Dhivehi \
549 np Nepali et Amharic sn Wolof ml Bambara tz Swahili \
550 ke Swahili bw Tswana ph Filipino my Malay tm Turkmen \
551 id Indonesian bt Dzongkha lv Latvian md Moldavian mao Maori \
552 by Belarusian az Azerbaijani mk Macedonian kh Khmer epo Esperanto \
553 me Montenegrin || return 1
555 if [[ $CMAPS == *"$KEYMAP"* ]]; then
558 dlg CMAP menu "Console Keymap" "$_vconsole" $CMAPS || return 1
561 if [[ $DISPLAY && $TERM != 'linux' ]]; then
562 setxkbmap "$KEYMAP" >/dev/null 2>&1
564 loadkeys "$CMAP" >/dev/null 2>&1
574 dlg INSTALL_WMS check "Sessions" "$_sessions\n" \
575 i3-gaps "A fork of i3wm with more features including gaps" "$(ofn i3-gaps "${INSTALL_WMS[*]}")" \
576 openbox "A lightweight, powerful, and highly configurable stacking wm" "$(ofn openbox "${INSTALL_WMS[*]}")" \
577 awesome "A customized Awesome WM session created by @elanapan" "$(ofn awesome "${INSTALL_WMS[*]}")" \
578 dwm "A dynamic WM for X that manages windows in tiled, floating, or monocle layouts" "$(ofn dwm "${INSTALL_WMS[*]}")" \
579 bspwm "A tiling wm that represents windows as the leaves of a binary tree" "$(ofn bspwm "${INSTALL_WMS[*]}")" \
580 fluxbox "A lightweight and highly-configurable window manager" "$(ofn fluxbox "${INSTALL_WMS[*]}")" \
581 gnome "A desktop environment that aims to be simple and easy to use" "$(ofn gnome "${INSTALL_WMS[*]}")" \
582 cinnamon "A desktop environment combining traditional desktop with modern effects" "$(ofn cinnamon "${INSTALL_WMS[*]}")" \
583 plasma "A kde software project currently comprising a full desktop environment" "$(ofn plasma "${INSTALL_WMS[*]}")" \
584 xfce4 "A lightweight and modular desktop environment based on gtk+2/3" "$(ofn xfce4 "${INSTALL_WMS[*]}")"
586 [[ $INSTALL_WMS ]] || return 0
588 WM_PKGS="${INSTALL_WMS/dwm/}" # remove dwm from package list
589 WM_PKGS="${WM_PKGS// / }" # remove double spaces
590 WM_PKGS="${WM_PKGS# }" # remove leading space
592 # add archlabs base when choosing any session
593 [[ $WM_PKGS ]] && WM_PKGS+=" $AL_BASE_PKGS"
595 for i in $INSTALL_WMS; do
596 LOGIN_CHOICES+="$i - "
597 [[ ${WM_EXT[$i]} && $WM_PKGS != *"${WM_EXT[$i]}"* ]] && WM_PKGS+=" ${WM_EXT[$i]}"
600 select_login || return 1
602 while IFS=' ' read -r pkg; do
603 [[ $PACKAGES != *"$pkg"* ]] && PACKAGES+=" $pkg"
611 dlg USER_PKGS check " Packages " "$_packages" \
612 abiword "A Fully-featured word processor" "$(ofn abiword "${USER_PKGS[*]}")" \
613 alacritty "A cross-platform, GPU-accelerated terminal emulator" "$(ofn alacritty "${USER_PKGS[*]}")" \
614 atom "An open-source text editor developed by GitHub" "$(ofn atom "${USER_PKGS[*]}")" \
615 audacious "A free and advanced audio player based on GTK+" "$(ofn audacious "${USER_PKGS[*]}")" \
616 audacity "A program that lets you manipulate digital audio waveforms" "$(ofn audacity "${USER_PKGS[*]}")" \
617 cairo-dock "Light eye-candy fully themable animated dock" "$(ofn cairo-dock "${USER_PKGS[*]}")" \
618 calligra "A set of applications for productivity" "$(ofn calligra "${USER_PKGS[*]}")" \
619 chromium "An open-source web browser based on the Blink rendering engine" "$(ofn chromium "${USER_PKGS[*]}")" \
620 clementine "A modern music player and library organizer" "$(ofn clementine "${USER_PKGS[*]}")" \
621 cmus "A small, fast and powerful console music player" "$(ofn cmus "${USER_PKGS[*]}")" \
622 deadbeef "A GTK+ audio player for GNU/Linux" "$(ofn deadbeef "${USER_PKGS[*]}")" \
623 deluge "A BitTorrent client written in python" "$(ofn deluge "${USER_PKGS[*]}")" \
624 docky "Full fledged dock for opening applications and managing windows" "$(ofn docky "${USER_PKGS[*]}")" \
625 emacs "An extensible, customizable, self-documenting real-time display editor" "$(ofn emacs "${USER_PKGS[*]}")" \
626 epiphany "A GNOME web browser based on the WebKit rendering engine" "$(ofn epiphany "${USER_PKGS[*]}")" \
627 evince "A document viewer" "$(ofn evince "${USER_PKGS[*]}")" \
628 evolution "Manage your email, contacts and schedule" "$(ofn evolution "${USER_PKGS[*]}")" \
629 file-roller "Create and modify archives" "$(ofn file-roller "${USER_PKGS[*]}")" \
630 firefox "A popular open-source web browser from Mozilla" "$(ofn firefox "${USER_PKGS[*]}")" \
631 gcolor2 "A simple GTK+2 color selector" "$(ofn gcolor2 "${USER_PKGS[*]}")" \
632 geany "A fast and lightweight IDE" "$(ofn geany "${USER_PKGS[*]}")" \
633 geary "A lightweight email client for the GNOME desktop" "$(ofn geary "${USER_PKGS[*]}")" \
634 gimp "GNU Image Manipulation Program" "$(ofn gimp "${USER_PKGS[*]}")" \
635 gnome-disk-utility "Disk Management Utility" "$(ofn gnome-disk-utility "${USER_PKGS[*]}")" \
636 gnome-system-monitor "View current processes and monitor system state" "$(ofn gnome-system-monitor "${USER_PKGS[*]}")" \
637 gparted "A GUI frontend for creating and manipulating partition tables" "$(ofn gparted "${USER_PKGS[*]}")" \
638 gpick "Advanced color picker using GTK+ toolkit" "$(ofn gpick "${USER_PKGS[*]}")" \
639 gpicview "Lightweight image viewer" "$(ofn gpicview "${USER_PKGS[*]}")" \
640 guvcview "Capture video from camera devices" "$(ofn guvcview "${USER_PKGS[*]}")" \
641 hexchat "A popular and easy to use graphical IRC client" "$(ofn hexchat "${USER_PKGS[*]}")" \
642 inkscape "Professional vector graphics editor" "$(ofn inkscape "${USER_PKGS[*]}")" \
643 irssi "Modular text mode IRC client" "$(ofn irssi "${USER_PKGS[*]}")" \
644 kdenlive "A popular non-linear video editor for Linux" "$(ofn kdenlive "${USER_PKGS[*]}")" \
645 krita "Edit and paint images" "$(ofn krita "${USER_PKGS[*]}")" \
646 libreoffice-fresh "Full featured office suite" "$(ofn libreoffice-fresh "${USER_PKGS[*]}")" \
647 lollypop "A new music playing application" "$(ofn lollypop "${USER_PKGS[*]}")" \
648 mousepad "A simple text editor" "$(ofn mousepad "${USER_PKGS[*]}")" \
649 mpd "A flexible, powerful, server-side application for playing music" "$(ofn mpd "${USER_PKGS[*]}")" \
650 mpv "A media player based on mplayer" "$(ofn mpv "${USER_PKGS[*]}")" \
651 mupdf "Lightweight PDF and XPS viewer" "$(ofn mupdf "${USER_PKGS[*]}")" \
652 mutt "Small but very powerful text-based mail client" "$(ofn mutt "${USER_PKGS[*]}")" \
653 nautilus "The default file manager for Gnome" "$(ofn nautilus "${USER_PKGS[*]}")" \
654 ncmpcpp "A mpd client and almost exact clone of ncmpc with some new features" "$(ofn ncmpcpp "${USER_PKGS[*]}")" \
655 neovim "A fork of Vim aiming to improve user experience, plugins, and GUIs." "$(ofn neovim "${USER_PKGS[*]}")" \
656 nicotine+ "A graphical client for Soulseek" "$(ofn nicotine+ "${USER_PKGS[*]}")" \
657 noto-fonts "Google Noto fonts" "$(ofn noto-fonts "${USER_PKGS[*]}")" \
658 noto-fonts-cjk "Google Noto CJK fonts (Chinese, Japanese, Korean)" "$(ofn noto-fonts-cjk "${USER_PKGS[*]}")" \
659 obs-studio "Free opensource streaming/recording software" "$(ofn obs-studio "${USER_PKGS[*]}")" \
660 openshot "An open-source, non-linear video editor for Linux" "$(ofn openshot "${USER_PKGS[*]}")" \
661 opera "A Fast and secure, free of charge web browser from Opera Software" "$(ofn opera "${USER_PKGS[*]}")" \
662 pcmanfm "A fast and lightweight file manager based in Lxde" "$(ofn pcmanfm "${USER_PKGS[*]}")" \
663 pidgin "Multi-protocol instant messaging client" "$(ofn pidgin "${USER_PKGS[*]}")" \
664 plank "An elegant, simple, and clean dock" "$(ofn plank "${USER_PKGS[*]}")" \
665 qbittorrent "An advanced BitTorrent client" "$(ofn qbittorrent "${USER_PKGS[*]}")" \
666 qpdfview "A tabbed PDF viewer" "$(ofn qpdfview "${USER_PKGS[*]}")" \
667 qt5ct "GUI for managing Qt based application themes, icons, and fonts" "$(ofn qt5ct "${USER_PKGS[*]}")" \
668 qutebrowser "A keyboard-focused vim-like web browser based on Python and PyQt5" "$(ofn qutebrowser "${USER_PKGS[*]}")" \
669 rhythmbox "A Music playback and management application" "$(ofn rhythmbox "${USER_PKGS[*]}")" \
670 rxvt-unicode "A unicode enabled rxvt-clone terminal emulator" "$(ofn rxvt-unicode "${USER_PKGS[*]}")" \
671 sakura "A terminal emulator based on GTK and VTE" "$(ofn sakura "${USER_PKGS[*]}")" \
672 simplescreenrecorder "A feature-rich screen recorder" "$(ofn simplescreenrecorder "${USER_PKGS[*]}")" \
673 steam "A popular game distribution platform by Valve" "$(ofn steam "${USER_PKGS[*]}")" \
674 surf "A simple web browser based on WebKit2/GTK+" "$(ofn surf "${USER_PKGS[*]}")" \
675 terminator "Terminal emulator that supports tabs and grids" "$(ofn terminator "${USER_PKGS[*]}")" \
676 termite "A minimal VTE-based terminal emulator" "$(ofn termite "${USER_PKGS[*]}")" \
677 thunar "A modern file manager for the Xfce Desktop Environment" "$(ofn thunar "${USER_PKGS[*]}")" \
678 thunderbird "Standalone mail and news reader from mozilla" "$(ofn thunderbird "${USER_PKGS[*]}")" \
679 tilda "A GTK based drop down terminal for Linux and Unix" "$(ofn tilda "${USER_PKGS[*]}")" \
680 tilix "A tiling terminal emulator for Linux using GTK+ 3" "$(ofn tilix "${USER_PKGS[*]}")" \
681 transmission-cli "Free BitTorrent client CLI" "$(ofn transmission-cli "${USER_PKGS[*]}")" \
682 transmission-gtk "Free BitTorrent client GTK+ GUI" "$(ofn transmission-gtk "${USER_PKGS[*]}")" \
683 transmission-qt "Free BitTorrent client Qt GUI" "$(ofn transmission-qt "${USER_PKGS[*]}")" \
684 ttf-anonymous-pro "A family fixed-width fonts designed with code in mind" "$(ofn ttf-anonymous-pro "${USER_PKGS[*]}")" \
685 ttf-fira-code "Monospaced font with programming ligatures" "$(ofn ttf-fira-code "${USER_PKGS[*]}")" \
686 ttf-font-awesome "Iconic font designed for Bootstrap" "$(ofn ttf-font-awesome "${USER_PKGS[*]}")" \
687 ttf-hack "A hand groomed typeface based on Bitstream Vera Mono" "$(ofn ttf-hack "${USER_PKGS[*]}")" \
688 vlc "A free and open source cross-platform multimedia player" "$(ofn vlc "${USER_PKGS[*]}")" \
689 weechat "Fast, light and extensible IRC client" "$(ofn weechat "${USER_PKGS[*]}")" \
690 xarchiver "A GTK+ frontend to various command line archivers" "$(ofn xarchiver "${USER_PKGS[*]}")" \
691 xfce-terminal "A terminal emulator based in the Xfce Desktop Environment" "$(ofn xfce-terminal "${USER_PKGS[*]}")" \
692 xterm "The standard terminal emulator for the X window system" "$(ofn xterm "${USER_PKGS[*]}")" \
693 zathura "Minimalistic document viewer" "$(ofn zathura "${USER_PKGS[*]}")"
695 if [[ $USER_PKGS ]]; then
696 for i in $USER_PKGS; do
697 [[ ${PKG_EXT[$i]} && $USER_PKGS != *"${PKG_EXT[$i]}"* ]] && USER_PKGS+=" ${PKG_EXT[$i]}"
704 ###############################################################################
706 # non-essential partitioning helpers called by the user when using the optional
707 # partition menu and selecting a device to edit
711 is_bg_install || return 0
712 local device choice devhash
713 devhash="$(lsblk -f | base64)"
715 part_device || return 1
720 if [[ $DISPLAY && $TERM != 'linux' ]] && hash gparted >/dev/null 2>&1; then
721 dlg choice menu "Edit Partitions" "$_part" \
722 "auto" "Whole device automatic partitioning" \
723 "shrink" "Shrink an existing ext2/3/4 or ntfs partition to make room for a new partition" \
724 "gparted" "GUI front end to parted" \
725 "cfdisk" "Curses based variant of fdisk" \
726 "parted" "GNU partition editor" \
727 "fdisk" "Dialog-driven creation and manipulation of partitions" \
728 "done" "Return to the main menu" || return 0
730 dlg choice menu "Edit Partitions" "$_part" \
731 "auto" "Whole device automatic partitioning" \
732 "shrink" "Shrink an existing ext2/3/4 or ntfs partition to make room for a new partition" \
733 "cfdisk" "Curses based variant of fdisk" \
734 "parted" "GNU partition editor" \
735 "fdisk" "Dialog-driven creation and manipulation of partitions" \
736 "done" "Return to the main menu" || return 0
739 if [[ $choice == 'done' ]]; then
741 elif [[ $choice == 'shrink' ]]; then
742 part_shrink "$device"
743 elif [[ $choice == 'auto' ]]; then
744 local root_size txt table boot_fs
745 root_size=$(lsblk -lno SIZE "$device" | awk 'NR == 1 {
748 print ($1 * 1000 - 512) / 1000 "G"
754 txt="\nWARNING:\n\nALL data on $device will be destroyed and the following partitions will be created\n\n- "
755 if [[ $SYS == 'BIOS' ]]; then
756 table="msdos" boot_fs="ext4"
757 txt+="An $boot_fs boot partition with the boot flag enabled (512M)\n- "
759 table="gpt" boot_fs="fat32"
760 txt+="A $boot_fs efi boot partition (512M)\n- "
762 txt+="An ext4 partition using all remaining space ($root_size)\n\nDo you want to continue?\n"
763 yesno "Auto Partition" "$txt" && part_auto "$device" "$table" "$boot_fs" "$root_size"
769 if [[ $devhash != "$(lsblk -f | base64)" ]]; then
770 msg "Probing Partitions" "\nInforming the kernel of partition changes using partprobe.\n" 0
771 partprobe >/dev/null 2>&1
779 if [[ $IGNORE_DEV ]]; then
780 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk "!/$IGNORE_DEV/"' && /disk|part|lvm|crypt|NAME/')"
782 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk '/disk|part|lvm|crypt|NAME/')"
784 msg "Device Tree" "\n\n$txt\n\n"
789 if [[ $1 == "$MNT/swapfile" && $SWAP_SIZE ]]; then
790 fallocate -l $SWAP_SIZE "$1" 2>$ERR
791 errshow "fallocate -l $SWAP_SIZE $1"
792 chmod 600 "$1" 2>$ERR
793 errshow "chmod 600 $1"
795 mkswap "$1" >/dev/null 2>$ERR
797 swapon "$1" >/dev/null 2>$ERR
804 local device="$1" table="$2" boot_fs="$3" size="$4" dev_info=""
805 dev_info="$(parted -s "$device" print)"
807 msg "Auto Partition" "\nRemoving partitions on $device and setting table to $table\n" 1
810 while read -r PART; do
811 parted -s "$device" rm "$PART" >/dev/null 2>&1
812 done <<< "$(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r)"
814 [[ $(awk '/Table:/ {print $3}' <<< "$dev_info") != "$table" ]] && parted -s "$device" mklabel "$table" >/dev/null 2>&1
816 msg "Auto Partition" "\nCreating a 512M $boot_fs boot partition.\n" 1
817 if [[ $SYS == "BIOS" ]]; then
818 parted -s "$device" mkpart primary "$boot_fs" 1MiB 513MiB >/dev/null 2>&1
820 parted -s "$device" mkpart ESP "$boot_fs" 1MiB 513MiB >/dev/null 2>&1
825 AUTO_BOOT_PART=$(lsblk -lno NAME,TYPE "$device" | awk 'NR==2 {print "/dev/" $1}')
827 if [[ $SYS == "BIOS" ]]; then
828 mkfs.ext4 -q "$AUTO_BOOT_PART" >/dev/null 2>&1
830 mkfs.vfat -F32 "$AUTO_BOOT_PART" >/dev/null 2>&1
833 msg "Auto Partition" "\nCreating a $size ext4 root partition.\n" 0
834 parted -s "$device" mkpart primary ext4 513MiB 100% >/dev/null 2>&1
836 AUTO_ROOT_PART="$(lsblk -lno NAME,TYPE "$device" | awk 'NR==3 {print "/dev/" $1}')"
837 mkfs.ext4 -q "$AUTO_ROOT_PART" >/dev/null 2>&1
839 FORMATTED+="$AUTO_BOOT_PART $AUTO_ROOT_PART "
840 msg "Auto Partition" "\nProcess complete.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$device")\n"
847 local device="$1" fs=""
849 part_find "${device##*/}[^ ]" || return 1
850 (( COUNT == 1 )) && part="$(awk '{print $1}' <<< "${PARTS[@]}" )"
852 if (( COUNT == 1 )) || dlg part menu "Resize" "\nWhich partition on $device do you want to resize?" $PARTS; then
853 fs=$(lsblk -lno FSTYPE "$part")
856 msg "Resize" "\nGathering device size info.\n" 0
858 end=$(parted -s "$device" unit KiB print | awk '/^\s*'"$num"'/ {print $3}') # part size in KiB
859 devsize=$(parted -s "$device" unit KiB print | awk '/Disk '"${device//\//\\/}"':/ {print $3}') # whole device size in KiB
860 mount "$part" $MNT >/dev/null 2>&1; sleep 0.5
861 min=$(df --output=used --block-size=MiB "$part" | awk 'NR == 2 {print int($1) + 256}')
862 max=$(df --output=avail --block-size=MiB "$part" | awk 'NR == 2 {print int($1)}')
865 if dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Resize: $part " --rangebox "$_resize" 17 "$COLUMNS" "$min" "$max" $((max / 2)) 2>$ANS; then
867 size=$((size * 1024))
874 if ntfsresize -fc "$part"; then
875 ntfsresize -ff --size $(( (size * 1024) / 1000 ))k "$part" 2>$ERR # k=10^3 bytes
876 errshow "ntfsresize -f -s $(( (size * 1024) / 1000 ))k $part" || return 1
878 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"
883 e2fsck -f "$part"; sleep 0.5
884 resize2fs -f "$part" ${size}K 2>$ERR # K=2^10 bytes
885 errshow "resize2fs -f $part ${size}K" || return 1
889 parted "$device" resizepart "$num" ${size}KiB || return 1
892 if [[ $devsize == "$end" ]]; then
893 parted -s "$device" mkpart primary ext4 ${size}KiB 100% 2>$ERR
894 errshow "parted -s $device mkpart primary ext4 ${size}KiB 100%" || return 1
896 parted -s "$device" mkpart primary ext4 ${size}KiB ${end}KiB 2>$ERR
897 errshow "parted -s $device mkpart primary ext4 ${size}KiB ${end}KiB" || return 1
899 msg "Resize Complete" "\n$part has been successfully resized to $((size / 1024))M.\n" 1
901 "") msg "No Filesystem" "\nFor unformatted partitions, cfdisk can be used in the partition menu.\n" ;;
902 *) msg "Invalid Filesystem: $fs" "\nResizing only supports ext and ntfs.\n" ;;
907 ###############################################################################
908 # partition management functions
909 # these are helpers for use by other functions to do essential setup/teardown
913 local regexp="$1" err=''
915 # string of partitions as /TYPE/PART SIZE
916 if [[ $IGNORE_DEV ]]; then
917 PARTS="$(lsblk -lno TYPE,NAME,SIZE |
918 awk "/$regexp/"' && !'"/$IGNORE_DEV/"' {
919 sub(/^part/, "/dev/")
920 sub(/^lvm|^crypt/, "/dev/mapper/")
924 PARTS="$(lsblk -lno TYPE,NAME,SIZE |
926 sub(/^part/, "/dev/")
927 sub(/^lvm|^crypt/, "/dev/mapper/")
932 # number of partitions total
934 while read -r line; do
938 # ensure we have enough partitions for the system and action type
940 'part|lvm|crypt') [[ $COUNT -lt 1 || ($SYS == 'UEFI' && $COUNT -lt 2) ]] && err="$_errpart" ;;
941 'part|crypt') (( COUNT < 1 )) && err="$_lvmerr" ;;
942 'part|lvm') (( COUNT < 2 )) && err="$_lukserr" ;;
945 # if there aren't enough partitions show the relevant error message
946 [[ $err ]] && { msg "Not Enough Partitions" "$err" 2; return 1; }
953 local part="$1" mountp="${MNT}$2" fs=""
954 fs="$(lsblk -lno FSTYPE "$part")"
957 if [[ $fs && ${FS_OPTS[$fs]} && $part != "$BOOT_PART" ]] && select_mntopts "$fs"; then
958 mount -o "$MNT_OPTS" "$part" "$mountp" >/dev/null 2>&1
960 mount "$part" "$mountp" >/dev/null 2>&1
963 part_mountconf "$part" "$mountp" || return 1
971 local part="$1" fs="$2" delay="$3"
973 msg "Format" "\nFormatting $part as $fs\n" 0
974 ${FS_CMDS[$fs]} "$part" >/dev/null 2>$ERR
975 errshow "${FS_CMDS[$fs]} $part" || return 1
982 if [[ $DEV_COUNT -eq 1 && $SYS_DEVS ]]; then
983 DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
984 elif (( DEV_COUNT > 1 )); then
986 dlg DEVICE menu "Boot Device" "\nSelect the device to use for bootloader install." $SYS_DEVS
988 dlg DEVICE menu "Select Device" "$_device" $SYS_DEVS
990 [[ $DEVICE ]] || return 1
991 elif [[ $DEV_COUNT -lt 1 && ! $1 ]]; then
992 msg "Device Error" "\nNo available devices.\n\nExiting..\n" 2
996 [[ $1 ]] && BOOT_DEV="$DEVICE"
1003 BOOT_DEV="${BOOT_PART%[1-9]}"
1004 BOOT_PART_NUM="${BOOT_PART: -1}"
1005 [[ $BOOT_PART = /dev/nvme* ]] && BOOT_DEV="${BOOT_PART%p[1-9]}"
1006 if [[ $SYS == 'UEFI' ]]; then
1007 parted -s $BOOT_DEV set $BOOT_PART_NUM esp on >/dev/null 2>&1
1009 parted -s $BOOT_DEV set $BOOT_PART_NUM boot on >/dev/null 2>&1
1016 local part="$1" devs=""
1017 devs="$(lsblk -lno NAME,FSTYPE,TYPE)"
1019 # Identify if $part is LUKS+LVM, LVM+LUKS, LVM alone, or LUKS alone
1020 if lsblk -lno TYPE "$part" | grep -q 'crypt'; then
1022 LUKS_NAME="${part#/dev/mapper/}"
1024 for dev in $(awk '/lvm/ && /crypto_LUKS/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
1025 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1026 LUKS_DEV="$LUKS_DEV cryptdevice=$dev:$LUKS_NAME"
1027 LVM='logical volume'
1032 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
1033 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1034 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
1035 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
1040 elif lsblk -lno TYPE "$part" | grep -q 'lvm'; then
1041 LVM='logical volume'
1042 VNAME="${part#/dev/mapper/}"
1044 for dev in $(awk '/crypt/ && /lvm2_member/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
1045 if lsblk -lno NAME "$dev" | grep -q "$VNAME"; then
1046 LUKS_NAME="${dev/\/dev\/mapper\//}"
1051 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
1052 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1053 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
1054 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
1065 if (( COUNT > 0 )); then
1066 PARTS="$(sed "/${pt//\//\\/}/d" <<< "$PARTS")"
1074 if grep -qw "$1" /proc/mounts; then
1075 msg "Mount Success" "\nPartition $1 mounted at $2\n" 1
1079 msg "Mount Fail" "\nPartition $1 failed to mount at $2\n" 2
1084 ###############################################################################
1086 # mount_menu is the entry point which calls all other functions
1087 # once finished it returns to the main menu: main()
1091 msg "Info" "\nGathering device info.\n" 0
1092 is_bg_install || return 0
1095 part_find 'part|lvm|crypt' || { SEL=2; return 1; }
1097 [[ $LUKS && $LUKS_PART ]] && part_countdec $LUKS_PART
1098 [[ $LVM && $LVM_PARTS ]] && part_countdec $LVM_PARTS
1100 select_root_partition || return 1
1102 if [[ $SYS == 'UEFI' ]]; then
1103 select_efi_partition || { BOOT_PART=''; return 1; }
1104 elif (( COUNT > 0 )); then
1105 select_boot_partition || { BOOT_PART=''; return 1; }
1108 if [[ $BOOT_PART ]]; then
1109 part_mount "$BOOT_PART" "/$BOOTDIR" && SEP_BOOT=true || return 1
1113 select_swap || return 1
1114 select_extra_partitions || return 1
1122 dlg SWAP_PART menu "Swap Setup" "\nSelect whether to use a swapfile, swap partition, or none." \
1123 "none" "Don't allocate any swap space" \
1124 "swapfile" "Allocate $SYS_MEM at /swapfile" \
1127 if [[ -z $SWAP_PART || $SWAP_PART == "none" ]]; then
1130 elif [[ $SWAP_PART == "swapfile" ]]; then
1132 until [[ ${SWAP_SIZE:0:1} =~ [1-9] && ${SWAP_SIZE: -1} =~ (M|G) ]]; do
1133 (( i > 0 )) && msg "Swap Size Error" "\nSwap size must be 1(M|G) or greater, and can only contain whole numbers\n\nSize entered: $SWAP_SIZE\n" 2
1134 dlg SWAP_SIZE input "Swap Setup" "$_swapsize" "$SYS_MEM" || { SWAP_PART=''; SWAP_SIZE=''; return 1; }
1137 part_swap "$MNT/$SWAP_PART"
1138 SWAP_PART="/$SWAP_PART"
1139 elif [[ $PARTS == *"$SWAP_PART"* ]]; then
1140 part_swap $SWAP_PART
1141 part_countdec $SWAP_PART
1142 SWAP_SIZE="$(lsblk -lno SIZE $SWAP_PART)"
1152 local fs="$1" opts=''
1153 local title="${fs^} Mount Options"
1155 for i in ${FS_OPTS[$fs]}; do
1159 until [[ $MNT_OPTS ]]; do
1160 dlg MNT_OPTS check "$title" "$_mount" $opts
1161 [[ $MNT_OPTS ]] || return 1
1162 MNT_OPTS="${MNT_OPTS// /,}"
1163 yesno "$title" "\nConfirm the following options: $MNT_OPTS\n" || MNT_OPTS=''
1172 until [[ $EXMNT ]]; do
1173 dlg EXMNT input "Extra Mount $part" "$_exmnt" "/" || return 1
1174 if [[ ${EXMNT:0:1} != "/" || ${#EXMNT} -le 1 || $EXMNT =~ \ |\' || $EXMNTS == *"$EXMNT"* ]]; then
1175 msg "Mountpoint Error" "$_errexpart"
1184 local part="$1" fs='' cur=''
1185 local txt="\nSelect which filesystem to use for: $part\n\nDefault: ext4"
1186 cur="$(lsblk -lno FSTYPE "$part" 2>/dev/null)"
1189 if [[ $cur && ($part != "$ROOT_PART" || $FORMATTED == *"$part"*) ]]; then
1190 dlg fs menu "Filesystem" "$txt\nCurrent: $cur" skip - ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1192 dlg fs menu "Filesystem" "$txt" ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1194 [[ $fs == 'skip' ]] && return 0
1195 yesno "Filesystem" "\nFormat $part as $fs?\n" || fs=''
1197 part_format "$part" "$fs"
1200 select_efi_partition()
1202 if [[ $AUTO_BOOT_PART ]]; then
1203 msg "EFI Boot Partition" "\nUsing partition created during automatic format.\n" 1
1204 BOOT_PART="$AUTO_BOOT_PART"; return 0 # were done here
1206 local pts size dev isize bsize ptcount=0
1208 # walk partition list and skip ones that are too small/big for boot
1209 while read -r dev size; do
1210 size_t="${size: -1:1}" # size type eg. K, M, G, T
1211 isize=${size:0:-1} # remove trailing size type character
1212 isize=${isize%.*} # remove any decimal (round down)
1213 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1216 if (( ptcount == 1 )); then
1217 msg "EFI Boot Partition" "\nOnly one partition available that meets size requirements.\n" 1
1218 BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")"
1220 dlg BOOT_PART menu "EFI Partition" "$_uefi" $pts
1224 [[ $BOOT_PART ]] || return 1
1226 if grep -q 'fat' <<< "$(fsck -N "$BOOT_PART")"; then
1227 local txt="\nIMPORTANT:\n\nThe EFI partition $BOOT_PART $_format"
1228 if yesno "Format EFI Partition" "$txt" "Format $BOOT_PART" "Skip Formatting" 1; then
1229 part_format "$BOOT_PART" "vfat" 2
1232 part_format "$BOOT_PART" "vfat" 2
1238 select_boot_partition()
1240 if [[ $AUTO_BOOT_PART && ! $LVM ]]; then
1241 msg "BIOS Boot Partition" "\nUsing partition created during automatic format.\n" 1
1242 BOOT_PART="$AUTO_BOOT_PART"; return 0 # were done here
1244 local pts size dev isize bsize ptcount=0
1246 # walk partition list and skip ones that are too small/big for boot
1247 while read -r dev size; do
1248 size_t="${size: -1:1}" # size type eg. K, M, G, T
1249 isize=${size:0:-1} # remove trailing size type character
1250 isize=${isize%.*} # remove any decimal (round down)
1251 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1254 if [[ $LUKS && ! $LVM ]]; then
1255 dlg BOOT_PART menu "Boot Partition" "$_biosluks" $pts
1256 [[ $BOOT_PART ]] || return 1
1258 dlg BOOT_PART menu "Boot Partition" "$_bios" "skip" "don't use a separate boot" $pts
1259 [[ -z $BOOT_PART || $BOOT_PART == "skip" ]] && { BOOT_PART=''; return 0; }
1263 if grep -q 'ext[34]' <<< "$(fsck -N "$BOOT_PART")"; then
1264 local txt="\nIMPORTANT:\n\nThe boot partition $BOOT_PART $_format"
1265 if yesno "Format Boot Partition" "$txt" "Format $BOOT_PART" "Skip Formatting" 1; then
1266 part_format "$BOOT_PART" "ext4" 2
1269 part_format "$BOOT_PART" "ext4" 2
1274 select_root_partition()
1276 if [[ $AUTO_ROOT_PART && -z $LVM && -z $LUKS ]]; then
1277 ROOT_PART="$AUTO_ROOT_PART"
1278 msg "Select Root Partition (/)" "\nUsing partition created during automatic format.\n" 1
1279 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1280 return 0 # we're done here
1282 local pts size dev isize bsize ptcount=0
1284 # walk partition list and skip ones that are too small for / (root)
1285 while read -r dev size; do
1286 size_t="${size: -1:1}" # size type eg. K, M, G, T
1287 isize=${size:0:-1} # remove trailing size type character
1288 isize=${isize%.*} # remove any decimal (round down)
1289 [[ $size_t =~ [MK] || ($size_t == 'G' && $isize -lt 4) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1292 if (( ptcount == 1 )); then # only one available device
1293 msg "Select Root Partition (/)" "\nOnly one partition available that meets size requirements.\n" 1
1294 ROOT_PART="$(awk 'NR==1 {print $1}' <<< "$pts")"
1296 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
1299 [[ $ROOT_PART ]] || return 1
1301 select_filesystem "$ROOT_PART" || { ROOT_PART=''; return 1; }
1302 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1307 select_extra_partitions()
1311 # walk partition list and skip ones that are too small to be usable
1312 while read -r dev size; do
1313 [[ ${size: -1:1} =~ [KM] ]] && part_countdec "$dev"
1316 while (( COUNT > 0 )); do
1318 dlg part menu 'Mount Extra' "$_expart" 'done' 'finish mounting step' $PARTS || break
1319 if [[ $part == 'done' ]]; then
1321 elif select_filesystem "$part" && select_mountpoint && part_mount "$part" "$EXMNT"; then
1322 EXMNTS+="$part: $EXMNT "
1323 [[ $EXMNT == '/usr' && $HOOKS != *usr* ]] && HOOKS="usr $HOOKS"
1331 ###############################################################################
1333 # main is the entry point which calls all other install functions, once
1334 # complete it shows a dialog to edit files on the new system before reboot
1341 genfstab -U $MNT >$MNT/etc/fstab 2>$ERR
1342 errshow 1 "genfstab -U $MNT >$MNT/etc/fstab"
1343 [[ -f $MNT/swapfile ]] && sed -i "s~${MNT}~~" $MNT/etc/fstab
1347 chrun "hwclock --systohc --utc" || chrun "hwclock --systohc --utc --directisa"
1350 chrun "chown -Rf $NEWUSER:users /home/$NEWUSER"
1354 dlg choice menu "Finalization" "$_edit" \
1355 finished "exit the installer and reboot" \
1356 keyboard "${EDIT_FILES[keyboard]}" \
1357 console "${EDIT_FILES[console]}" \
1358 locale "${EDIT_FILES[locale]}" \
1359 hostname "${EDIT_FILES[hostname]}" \
1360 sudoers "${EDIT_FILES[sudoers]}" \
1361 mkinitcpio "${EDIT_FILES[mkinitcpio]}" \
1362 fstab "${EDIT_FILES[fstab]}" \
1363 crypttab "${EDIT_FILES[crypttab]}" \
1364 bootloader "${EDIT_FILES[bootloader]}" \
1365 pacman "${EDIT_FILES[pacman]}" \
1366 login "${EDIT_FILES[login]}"
1368 if [[ -z $choice || $choice == 'finished' ]]; then
1369 [[ $DEBUG == true && -r $DBG ]] && vim $DBG
1373 for f in ${EDIT_FILES[$choice]}; do
1374 [[ -e ${MNT}$f ]] && exists+=" ${MNT}$f"
1376 if [[ $exists ]]; then
1379 msg "File Missing" "\nThe file(s) selected do not exist:\n\n${EDIT_FILES[$choice]}\n"
1387 if [[ $RSYNC_PID || $MIRROR_PID ]]; then
1388 local oldmsg="" msg=""
1389 printf "\nOne or more background install processes are still running, grabbing their output...\n"
1390 while kill -0 "$RSYNC_PID" 2>/dev/null || kill -0 "$MIRROR_PID" 2>/dev/null; do
1391 msg="$(tail -n 1 /tmp/bg_out)"
1392 if [[ "$msg" != "$oldmsg" ]]; then
1393 printf "\n%s" "$msg"
1400 unset RSYNC_PID MIRROR_PID
1402 rsync -ahv /run/archiso/sfs/airootfs/ $MNT/ 2>$ERR
1403 errshow 1 "rsync -ahv /run/archiso/sfs/airootfs/ $MNT/"
1404 install_mirrorlist "$MNT/etc/pacman.d/mirrorlist"
1405 chrun "pacman -Syyu --noconfirm && pacman -S $BASE_PKGS --needed --noconfirm"
1408 rm -rf $MNT/etc/mkinitcpio-archiso.conf
1409 find $MNT/usr/lib/initcpio -name 'archiso*' -type f -delete
1410 sed -i 's/volatile/auto/g' $MNT/etc/systemd/journald.conf
1411 find $MNT/boot -name '*-ucode.img' -delete
1414 find $MNT/etc/X11/xorg.conf.d/ -name '*.conf' -delete
1415 elif lspci | grep ' VGA ' | grep -q 'Intel'; then
1416 cat > $MNT/etc/X11/xorg.conf.d/20-intel.conf <<- EOF
1418 Identifier "Intel Graphics"
1420 Option "TearFree" "true"
1425 [[ -e /run/archiso/sfs/airootfs && $KERNEL == 'linux' ]] && cp -vf $RUN/x86_64/vmlinuz $MNT/boot/vmlinuz-linux
1427 cp -fv /etc/resolv.conf $MNT/etc/
1428 [[ -e /etc/NetworkManager/system-connections ]] && cp -rvf /etc/NetworkManager/system-connections $MNT/etc/NetworkManager/
1430 echo "LANG=$MYLOCALE" > $MNT/etc/locale.conf
1431 cp -f $MNT/etc/locale.conf $MNT/etc/default/locale
1432 sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${MYLOCALE}/${MYLOCALE}/g" $MNT/etc/locale.gen
1434 chrun "ln -svf /usr/share/zoneinfo/$ZONE/$SUBZ /etc/localtime"
1436 if [[ $BROADCOM_WL ]]; then
1437 echo 'blacklist bcma' >> $MNT/etc/modprobe.d/blacklist.conf
1438 rm -f $MNT/etc/modprobe/
1441 cat > $MNT/etc/X11/xorg.conf.d/00-keyboard.conf <<- EOF
1442 # Use localectl(1) to instruct systemd-localed to update it.
1443 Section "InputClass"
1444 Identifier "system-keyboard"
1445 MatchIsKeyboard "on"
1446 Option "XkbLayout" "$KEYMAP"
1450 cat > $MNT/etc/default/keyboard <<- EOF
1451 # KEYBOARD CONFIGURATION FILE
1452 # Consult the keyboard(5) manual page.
1459 printf "KEYMAP=%s\nFONT=%s\n" "$CMAP" "$FONT" > $MNT/etc/vconsole.conf
1460 echo "$MYHOST" > $MNT/etc/hostname
1461 cat > $MNT/etc/hosts <<- EOF
1464 ::1 localhost ip6-localhost ip6-loopback
1465 ff02::1 ip6-allnodes
1466 ff02::2 ip6-allrouters
1472 if [[ $ROOT_PART == /dev/mapper* ]]; then
1473 ROOT_PART_ID="$ROOT_PART"
1475 local uuid_type="UUID"
1476 [[ $BOOTLDR =~ (systemd-boot|refind-efi|efistub) ]] && uuid_type="PARTUUID"
1477 ROOT_PART_ID="$uuid_type=$(blkid -s $uuid_type -o value $ROOT_PART)"
1480 if [[ $SYS == 'UEFI' ]]; then
1482 find $MNT/$BOOTDIR/EFI/ -maxdepth 1 -mindepth 1 -iname "$DIST" -type d -delete
1484 find $MNT/$BOOTDIR/EFI/ -maxdepth 1 -mindepth 1 -iname 'BOOT' -type d -delete
1488 chrun "${BCMDS[$BOOTLDR]}" 2>$ERR
1489 errshow 1 "${BCMDS[$BOOTLDR]}"
1491 if [[ -d $MNT/hostrun ]]; then
1492 # cleanup the bind mounts we made earlier for the grub-probe module
1493 umount_dir $MNT/hostrun/{udev,lvm}
1494 rm -rf $MNT/hostrun >/dev/null 2>&1
1497 if [[ $SYS == 'UEFI' ]]; then
1498 # some UEFI firmware requires a generic esp/BOOT/BOOTX64.EFI
1499 mkdir -pv $MNT/$BOOTDIR/EFI/BOOT
1500 if [[ $BOOTLDR == 'grub' ]]; then
1501 cp -fv $MNT/$BOOTDIR/EFI/$DIST/grubx64.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI
1502 elif [[ $BOOTLDR == 'syslinux' ]]; then
1503 cp -rf $MNT/$BOOTDIR/EFI/syslinux/* $MNT/$BOOTDIR/EFI/BOOT/
1504 cp -f $MNT/$BOOTDIR/EFI/syslinux/syslinux.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI
1505 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1506 sed -i '/#extra_kernel_version_strings/ c extra_kernel_version_strings linux-hardened,linux-zen,linux-lts,linux' $MNT/$BOOTDIR/EFI/refind/refind.conf
1507 cp -fv $MNT/$BOOTDIR/EFI/refind/refind_x64.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI
1516 rm -f $MNT/root/.zshrc # remove welcome message from root zshrc
1517 chrun "chpasswd <<< 'root:$ROOT_PASS'" 2>$ERR
1518 errshow 1 "set root password"
1519 if [[ $MYSHELL != "/usr/bin/zsh" ]]; then # root uses zsh by default, change it if something else was chosen
1520 chrun "usermod -s $MYSHELL root" 2>$ERR
1521 errshow 1 "usermod -s $MYSHELL root"
1522 # copy the default mkshrc to /root if mksh was picked
1523 [[ $MYSHELL == '/usr/bin/mksh' ]] && cp -fv $MNT/etc/skel/.mkshrc $MNT/root/.mkshrc
1526 local groups='audio,autologin,floppy,log,network,rfkill,scanner,storage,optical,power,wheel'
1528 chrun "groupadd -r autologin" 2>$ERR
1529 errshow 1 "groupadd -r autologin"
1530 chrun "useradd -m -u 1000 -g users -G $groups -s $MYSHELL $NEWUSER" 2>$ERR
1531 errshow 1 "useradd -m -u 1000 -g users -G $groups -s $MYSHELL $NEWUSER"
1532 chrun "chpasswd <<< '$NEWUSER:$USER_PASS'" 2>$ERR
1533 errshow 1 "set $NEWUSER password"
1535 # if neovim was picked copy vim configs to ~/.config/nvim
1536 if [[ $USER_PKGS == *neovim* ]]; then
1537 mkdir -p $MNT/home/$NEWUSER/.config/nvim
1538 cp -fv $MNT/home/$NEWUSER/.vimrc $MNT/home/$NEWUSER/.config/nvim/init.vim
1539 cp -rfv $MNT/home/$NEWUSER/.vim/colors $MNT/home/$NEWUSER/.config/nvim/colors
1542 case $INSTALL_WMS in *awesome*) install_awesome ;; *dwm*) install_suckless ;; esac
1544 [[ $WM_PKGS == *xfce* ]] && echo 'volumeicon &' >> $MNT/home/$NEWUSER/.xprofile
1546 # remove some commands from ~/.xprofile when using KDE or Gnome as the login session
1547 if [[ $LOGIN_WM =~ (startkde|gnome-session) || ($LOGIN_TYPE == 'lightdm' && $WM_PKGS =~ (plasma|gnome)) ]]; then
1548 sed -i '/super/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1549 sed -i '/nitrogen/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1550 sed -i '/al-compositor/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1551 sed -i '/compton/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1560 if [[ $INSTALL_WMS ]]; then
1561 if [[ -e $MNT/home/$NEWUSER/.xinitrc ]] && grep -q 'exec' "$MNT/home/$NEWUSER/.xinitrc"; then
1562 sed -i "/exec/ c exec ${LOGIN_WM}" "$MNT/home/$NEWUSER/.xinitrc"
1563 elif [[ $INSTALL_WMS ]]; then
1564 printf "exec %s\n" "$LOGIN_WM" >> "$MNT/home/$NEWUSER/.xinitrc"
1566 printf "exec %s\n" "$LOGIN_WM" >> "$MNT/home/$NEWUSER/.xinitrc"
1568 elif [[ -e $MNT/home/$NEWUSER/.xinitrc ]]; then
1569 # no sessions available so remove the exec from ~/.xinitrc and return
1570 sed -i '/exec/d' "$MNT/home/$NEWUSER/.xinitrc"
1574 [[ ${EDIT_FILES[login]} == *"$LOGINRC"* ]] || EDIT_FILES[login]+=" /home/$NEWUSER/$LOGINRC"
1576 if [[ $AUTOLOGIN ]]; then
1577 sed -i "s/root/${NEWUSER}/g" $SERVICE/autologin.conf
1578 cat > "$MNT/home/$NEWUSER/$LOGINRC" <<- EOF
1580 # sourced by ${MYSHELL##*/} when used as a login shell
1582 # automatically run startx when logging in on tty1
1583 [ -z \$DISPLAY ] && [ \$XDG_VTNR -eq 1 ] && exec startx
1592 SERVICE="$MNT/etc/systemd/system/getty@tty1.service.d"
1593 install_${LOGIN_TYPE:-xinit}
1598 rm -rf "$SERVICE" "$MNT/home/$NEWUSER"/.{xinitrc,profile,zprofile,bash_profile}
1599 chrun 'systemctl enable lightdm.service' 2>$ERR
1600 errshow 1 "systemctl enable lightdm.service"
1601 cat > $MNT/etc/lightdm/lightdm-gtk-greeter.conf <<- EOF
1602 # LightDM GTK+ Configuration
1605 default-user-image=/usr/share/icons/ArchLabs-Dark/64x64/places/distributor-logo-archlabs.png
1606 background=/usr/share/backgrounds/archlabs/archlabs.jpg
1607 theme-name=Adwaita-dark
1608 icon-theme-name=Adwaita
1609 font-name=DejaVu Sans Mono 11
1610 position=30%,end 50%,end
1616 # downloads and sets up @elenapan's awesome WM config hosted on github
1617 if chrun "git clone https://github.com/elenapan/archlabs-awesome /home/$NEWUSER/archlabs-awesome"; then
1618 cp -rT "/mnt/home/$NEWUSER/archlabs-awesome" "/mnt/home/$NEWUSER"
1619 cp -rT "/mnt/home/$NEWUSER/archlabs-awesome" /mnt/etc/skel
1620 rm -rf "/home/$NEWUSER/"{.git,archlabs-awesome,screenshots}
1621 printf "You will need to install pamac separately using: 'baph -i pamac-aur'\n"
1624 printf "failed to clone awesome config repo\n"
1631 local inpkg="$BASE_PKGS ${LOGIN_PKGS[$LOGIN_TYPE]} $PACKAGES $USER_PKGS $UCODE "
1633 if pacman -Qsq 'archlabs-installer' >/dev/null 2>&1; then
1634 rmpkg+="archlabs-installer "
1635 elif [[ -e "$MNT/usr/bin/archlabs-installer" ]]; then
1636 rm -f "$MNT/usr/bin/archlabs-installer"
1639 # add extra packages chosen throughout the install
1640 if [[ $MYSHELL == '/usr/bin/zsh' ]]; then
1641 inpkg+="zsh-completions "
1644 [[ $MYSHELL == '/usr/bin/mksh' ]] && inpkg+="mksh "
1646 if [[ $KERNEL != 'linux' ]]; then
1651 # gnome, plasma, and cinnamon have their own superkey bind and ksuperkey conflicts
1652 [[ $INSTALL_WMS =~ ^(plasma|gnome|cinnamon)$ ]] || inpkg+="archlabs-ksuperkey "
1654 # window manager only packages
1655 [[ $INSTALL_WMS =~ (openbox|bspwm|i3-gaps|dwm|fluxbox) ]] && inpkg+="$WM_BASE_PKGS "
1657 # ensure a terminal gets installed if one wasn't chosen or a DE that installs one
1658 [[ $inpkg =~ (term|urxvt|tilix|alacritty|sakura|tilda|plasma|cinnamon) || $INSTALL_WMS == *dwm* ]] || inpkg+=" xterm"
1660 # update first to avoid issues
1661 chrun "pacman -Syyu --noconfirm"
1663 # remove the packages we don't want on the installed system
1664 [[ $rmpkg ]] && chrun "pacman -Rns $rmpkg --noconfirm"
1666 # reinstalling iputils fixes the network issue for non-root users
1667 chrun "pacman -S iputils --noconfirm"
1669 # install the packages chosen throughout the install
1670 chrun "pacman -S $inpkg --needed --noconfirm" 2>$ERR
1671 errshow 1 "pacman -S $inpkg --needed --noconfirm"
1673 # bootloader packages
1674 if [[ $BOOTLDR == 'grub' ]]; then
1675 [[ $SYS == 'UEFI' ]] && local efib="efibootmgr"
1676 chrun "pacman -S os-prober grub $efib --needed --noconfirm" 2>$ERR
1677 errshow 1 "pacman -S os-prober grub $efib --needed --noconfirm"
1678 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1679 chrun "pacman -S refind-efi efibootmgr --needed --noconfirm" 2>$ERR
1680 errshow 1 "pacman -S refind-efi efibootmgr --needed --noconfirm"
1681 elif [[ $SYS == 'UEFI' ]]; then
1682 chrun "pacman -S efibootmgr --needed --noconfirm" 2>$ERR
1683 errshow 1 "pacman -S efibootmgr --needed --noconfirm"
1686 # allow members of the wheel group to run commands as root
1687 sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" $MNT/etc/sudoers
1694 mkdir -pv "$MNT/home/$NEWUSER/suckless"
1696 for i in dwm dmenu st; do
1697 if chrun "git clone https://git.suckless.org/$i /home/$NEWUSER/suckless/$i"; then
1698 chrun "cd /home/$NEWUSER/suckless/$i; make PREFIX=/usr install; make clean; rm config.h"
1700 printf "failed to clone %s repo\n" "$i"
1704 if [[ -x $MNT/usr/bin/dwm ]]; then
1705 printf "To configure dwm edit %s\n" "/home/$NEWUSER/suckless/dwm/config.h"
1706 printf "You can then recompile it with 'sudo make clean install'\n"
1711 install_mkinitcpio()
1715 # luks keyfile creation
1716 # currently not used due to not prompting for passphrase on startup
1717 # [[ $LUKS_UUID && $LUKS_PASS && $SYS == 'UEFI' && $BOOTLDR == 'grub' ]] && luks_keyfile
1719 [[ $LUKS ]] && add="encrypt"
1720 [[ $LVM ]] && { [[ $add ]] && add+=" lvm2" || add+="lvm2"; }
1721 sed -i "s/block filesystems/block ${add} filesystems ${HOOKS}/g" $MNT/etc/mkinitcpio.conf
1722 chrun "mkinitcpio -p $KERNEL" 2>$ERR
1723 errshow 1 "mkinitcpio -p $KERNEL"
1726 install_mirrorlist()
1728 local mfile="$1" # output mirrorlist file
1730 if hash reflector >/dev/null 2>&1; then
1731 reflector --score 80 -l 40 -f 5 --sort rate --save "$mfile"
1732 elif hash rankmirrors >/dev/null 2>&1; then
1733 local key="access_key=5f29642060ab983b31fdf4c2935d8c56"
1734 ip_add="$(curl -fsSL "http://api.ipstack.com/check&?$key&fields=ip" | python -c "import sys, json; print(json.load(sys.stdin)['ip'])")"
1735 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'])")"
1736 if [[ "$country" ]]; then
1737 if [[ $country =~ (CA|US) ]]; then
1738 # use both CA and US mirrors for CA or US countries
1739 mirror="https://www.archlinux.org/mirrorlist/?country=US&country=CA&use_mirror_status=on"
1740 elif [[ $country =~ (AU|NZ) ]]; then
1741 # use both AU and NZ mirrors for AU or NZ countries
1742 mirror="https://www.archlinux.org/mirrorlist/?country=AU&country=NZ&use_mirror_status=on"
1744 mirror="https://www.archlinux.org/mirrorlist/?country=${country}&use_mirror_status=on"
1746 else # no country code so just grab all mirrors, will be a very slow sort but we don't have other options
1747 mirror="https://www.archlinux.org/mirrorlist/?country=all&use_mirror_status=on"
1749 curl -fsSL "$mirror" | sed -e 's/^#Server/Server/' -e '/^#/d' | rankmirrors -n 6 - >"$mfile"
1755 install_background()
1757 yesno "Background Install" "\nBegin install in the background?\n" || return 0
1759 rsync -a /run/archiso/sfs/airootfs/ $MNT/ &
1762 mkdir -p $MNT/var/lib/pacman # can help with pacman errors
1763 ( install_mirrorlist "$MNT/etc/pacman.d/mirrorlist" && sleep 1 && chrun "pacman -Syyu $BASE_PKGS --needed --noconfirm" >> /tmp/bg_out 2>&1 ) &
1766 # end the background processes before exiting
1767 trap "kill $RSYNC_PID $MIRROR_PID 2>/dev/null" EXIT
1770 ###############################################################################
1772 # prerun_* set up the configs needed before actually running the commands
1773 # setup_* are run after selecting a bootloader and build the command used later
1774 # they can also be used for further user input as these run before control is taken away
1778 EDIT_FILES[bootloader]="/etc/default/grub"
1780 if [[ $SYS == 'BIOS' ]]; then
1781 [[ $BOOT_DEV ]] || { part_device 1 || return 1; }
1782 BCMDS[grub]="grub-install --recheck --force --target=i386-pc $BOOT_DEV"
1784 # since we're not using the keyfile this is dead code
1785 # if [[ $ROOT_PART == */dev/mapper/* && -z $LVM && -z $LUKS_PASS ]]; then
1786 # luks_pass "$_luksopen" 1 || return 1
1788 BCMDS[grub]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1789 grub-install --recheck --force --target=x86_64-efi --efi-directory=/$BOOTDIR --bootloader-id=$DIST"
1790 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1793 BCMDS[grub]="mkdir -p /run/udev /run/lvm &&
1794 mount --bind /hostrun/udev /run/udev &&
1795 mount --bind /hostrun/lvm /run/lvm &&
1797 grub-mkconfig -o /boot/grub/grub.cfg &&
1798 sleep 1 && umount /run/udev /run/lvm"
1805 sed -i "s/GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR=\"${DIST}\"/g; s/GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"\"/g" $MNT/etc/default/grub
1807 if [[ $LUKS_DEV ]]; then
1808 sed -i "s~#GRUB_ENABLE_CRYPTODISK~GRUB_ENABLE_CRYPTODISK~g; s~GRUB_CMDLINE_LINUX=.*~GRUB_CMDLINE_LINUX=\"${LUKS_DEV}\"~g" $MNT/etc/default/grub 2>$ERR
1809 errshow 1 "sed -i 's~#GRUB_ENABLE_CRYPTODISK~GRUB_ENABLE_CRYPTODISK~g; s~GRUB_CMDLINE_LINUX=.*~GRUB_CMDLINE_LINUX=\"${LUKS_DEV}\"~g' $MNT/etc/default/grub"
1812 if [[ $SYS == 'BIOS' && $LVM && -z $SEP_BOOT ]]; then
1813 sed -i "s/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g" $MNT/etc/default/grub 2>$ERR
1814 errshow 1 "sed -i 's/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g' $MNT/etc/default/grub"
1817 # setup for os-prober module
1818 mkdir -p /run/{lvm,udev} $MNT/hostrun/{lvm,udev}
1819 mount --bind /run/lvm $MNT/hostrun/lvm
1820 mount --bind /run/udev $MNT/hostrun/udev
1827 EDIT_FILES[bootloader]=""
1832 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1833 efibootmgr -v -d $BOOT_DEV -p $BOOT_PART_NUM -c -L '${DIST} Linux' -l /vmlinuz-${KERNEL} \
1834 -u 'root=$ROOT_PART_ID rw $([[ $UCODE ]] && printf 'initrd=\%s.img ' "$UCODE")initrd=\initramfs-${KERNEL}.img'"
1839 if [[ $SYS == 'BIOS' ]]; then
1840 EDIT_FILES[bootloader]="/boot/syslinux/syslinux.cfg"
1842 EDIT_FILES[bootloader]="/boot/EFI/syslinux/syslinux.cfg"
1843 BCMDS[syslinux]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1844 efibootmgr -v -c -d $BOOT_DEV -p $BOOT_PART_NUM -l /EFI/syslinux/syslinux.efi -L $DIST"
1850 local c="$MNT/boot/syslinux" s="/usr/lib/syslinux/bios" d=".."
1851 [[ $SYS == 'UEFI' ]] && { c="$MNT/boot/EFI/syslinux"; s="/usr/lib/syslinux/efi64/"; d=''; }
1853 mkdir -pv "$c" && cp -rfv $s/* "$c/" && cp -f "$RUN/syslinux/splash.png" "$c/"
1854 cat > "$c/syslinux.cfg" <<- EOF
1856 MENU TITLE $DIST Boot Menu
1857 MENU BACKGROUND splash.png
1861 # see: https://www.syslinux.org/wiki/index.php/Comboot/menu.c32
1870 MENU HELPMSGENDROW 29
1871 MENU COLOR border 30;44 #40ffffff #a0000000 std
1872 MENU COLOR title 1;36;44 #9033ccff #a0000000 std
1873 MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
1874 MENU COLOR unsel 37;44 #50ffffff #a0000000 std
1875 MENU COLOR help 37;40 #c0ffffff #a0000000 std
1876 MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
1877 MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
1878 MENU COLOR msg07 37;40 #90ffffff #a0000000 std
1879 MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
1882 MENU LABEL $DIST Linux
1883 LINUX $d/vmlinuz-$KERNEL
1884 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1885 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL.img
1887 LABEL ${DIST}fallback
1888 MENU LABEL $DIST Linux Fallback
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-fallback.img
1898 EDIT_FILES[bootloader]="/boot/refind_linux.conf"
1899 BCMDS[refind-efi]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1905 cat > $MNT/boot/refind_linux.conf <<- EOF
1906 "$DIST Linux" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1907 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1908 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL.img"
1909 "$DIST Linux Fallback" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1910 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1911 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL-fallback.img"
1913 mkdir -p $MNT/etc/pacman.d/hooks
1914 cat > $MNT/etc/pacman.d/hooks/refind.hook <<- EOF
1921 Description = Updating rEFInd on ESP
1922 When = PostTransaction
1923 Exec = /usr/bin/refind-install
1927 setup_systemd-boot()
1929 EDIT_FILES[bootloader]="/boot/loader/entries/$DIST.conf"
1930 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1931 bootctl --path=/boot install"
1934 prerun_systemd-boot()
1936 mkdir -p $MNT/boot/loader/entries
1937 cat > $MNT/boot/loader/loader.conf <<- EOF
1942 cat > $MNT/boot/loader/entries/$DIST.conf <<- EOF
1944 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1945 initrd /initramfs-$KERNEL.img
1946 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1948 cat > $MNT/boot/loader/entries/$DIST-fallback.conf <<- EOF
1949 title $DIST Linux Fallback
1950 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1951 initrd /initramfs-$KERNEL-fallback.img
1952 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1954 mkdir -p $MNT/etc/pacman.d/hooks
1955 cat > $MNT/etc/pacman.d/hooks/systemd-boot.hook <<- EOF
1962 Description = Updating systemd-boot
1963 When = PostTransaction
1964 Exec = /usr/bin/bootctl update
1966 systemd-machine-id-setup --root="$MNT"
1970 ###############################################################################
1975 is_bg_install || return 1
1978 dlg choice menu "Logical Volume Management" "$_lvmmenu" \
1979 "$_lvmnew" "vgcreate -f, lvcreate -L -n" \
1980 "$_lvmdel" "vgremove -f" \
1981 "$_lvmdelall" "lvrmeove, vgremove, pvremove -f" \
1982 "back" "return to the main menu"
1985 "$_lvmnew") lvm_create || return 1 ;;
1986 "$_lvmdel") lvm_delgroup && yesno "$_lvmdel" "$_lvmdelask" && vgremove -f "$DEL_VG" >/dev/null 2>&1 ;;
1987 "$_lvmdelall") lvm_del_all ;;
1996 pv="$(pvs -o pv_name --noheading 2>/dev/null)"
1997 v="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
1998 VGROUP="$(vgs -o vg_name --noheading 2>/dev/null)"
2000 if [[ $VGROUP && $v && $pv ]]; then
2001 msg "Logical Volume Management" "\nActivating existing logical volume management (LVM).\n\n" 1
2002 modprobe dm-mod >/dev/null 2>$ERR
2003 errshow 'modprobe dm-mod'
2004 vgscan >/dev/null 2>&1
2005 vgchange -ay >/dev/null 2>&1
2011 VGROUP='' LVM_PARTS='' VGROUP_MB=0
2013 lvm_mkgroup || return 1
2014 local txt="\nThe last (or only) logical volume will automatically use all remaining space in the volume group."
2015 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
2016 [[ $VOL_COUNT ]] || return 1
2017 lvm_extra_lvs || return 1
2018 lvm_volume_name "$_lvmlvname\nNOTE: This LV will use up all remaining space in the volume group (${VGROUP_MB}MB)" || return 1
2019 lvcreate -l +100%FREE "$VGROUP" -n "$VNAME" >/dev/null 2>$ERR
2020 errshow "lvcreate -l +100%FREE $VGROUP -n $VNAME" || return 1
2021 LVM='logical volume'; sleep 0.5
2022 txt="\nDone, volume: $VGROUP-$VNAME (${VOLUME_SIZE:-${VGROUP_MB}MB}) has been created.\n"
2023 msg "$_lvmnew (LV:$VOL_COUNT)" "$txt\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE $LVM_PARTS)\n"
2029 local txt="${VGROUP}: ${SIZE}$SIZE_UNIT (${VGROUP_MB}MB remaining).$_lvmlvsize"
2033 dlg VOLUME_SIZE input "$_lvmnew (LV:$VOL_COUNT)" "$txt" ''
2034 if [[ -z $VOLUME_SIZE ]]; then
2036 break # allow bailing with escape or an empty choice
2037 elif (( ${VOLUME_SIZE:0:1} == 0 )); then
2038 ERR_SIZE=1 # size values can't begin with '0'
2040 # walk the string and make sure all but the last char are digits
2041 local lv=$((${#VOLUME_SIZE} - 1))
2042 for (( i=0; i<lv; i++ )); do
2043 [[ ${VOLUME_SIZE:$i:1} =~ [0-9] ]] || { ERR_SIZE=1; break; }
2045 if (( ERR_SIZE != 1 )); then
2046 case ${VOLUME_SIZE:$lv:1} in
2047 [mMgG]) local s=${VOLUME_SIZE:0:$lv} m=$((s * 1000))
2048 case ${VOLUME_SIZE:$lv:1} in
2049 [Gg]) (( m >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - m)) ;;
2050 [Mm]) (( ${VOLUME_SIZE:0:$lv} >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - s)) ;;
2057 if (( ERR_SIZE )); then
2058 msg "Invalid Logical Volume Size" "$_lvmerrlvsize"
2070 local txt="\nConfirm creation of volume group: $VGROUP\n\nwith the following partition(s):"
2072 until [[ $named ]]; do
2073 lvm_partitions || return 1
2074 lvm_group_name || return 1
2075 yesno "$_lvmnew" "$txt $LVM_PARTS\n" && named=true
2078 vgcreate -f "$VGROUP" $LVM_PARTS >/dev/null 2>$ERR
2079 errshow "vgcreate -f $VGROUP $LVM_PARTS" || return 1
2081 SIZE=$(vgdisplay "$VGROUP" | awk '/VG Size/ { gsub(/[^0-9.]/, ""); print int($0) }')
2082 SIZE_UNIT="$(vgdisplay "$VGROUP" | awk '/VG Size/ { print substr($NF, 0, 1) }')"
2084 if [[ $SIZE_UNIT == 'G' ]]; then
2085 VGROUP_MB=$((SIZE * 1000))
2090 msg "$_lvmnew" "\nVolume group: $VGROUP ($SIZE $SIZE_UNIT) has been created\n"
2097 pv="$(pvs -o pv_name --noheading 2>/dev/null)"
2098 v="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
2099 VGROUP="$(vgs -o vg_name --noheading 2>/dev/null)"
2101 if [[ $VGROUP || $v || $pv ]]; then
2102 if yesno "$_lvmdelall" "$_lvmdelask"; then
2103 for i in $v; do lvremove -f "/dev/mapper/$i" >/dev/null 2>&1; done
2104 for i in $VGROUP; do vgremove -f "$i" >/dev/null 2>&1; done
2105 for i in $pv; do pvremove -f "$i" >/dev/null 2>&1; done
2109 msg "Delete LVM" "\nNo LVMs to remove...\n" 2
2119 for i in $(lvs --noheadings | awk '{print $2}' | uniq); do
2120 VOL_GROUP_LIST+="$i $(vgdisplay "$i" | awk '/VG Size/ {print $3$4}') "
2122 [[ $VOL_GROUP_LIST ]] || { msg "No Groups" "\nNo volume groups found."; return 1; }
2124 dlg DEL_VG menu "Logical Volume Management" "\nSelect volume group to delete.\n\nAll logical volumes within will also be deleted." $VOL_GROUP_LIST
2130 while (( VOL_COUNT > 1 )); do
2131 lvm_volume_name "$_lvmlvname" && get_lv_size || return 1
2132 lvcreate -L "$VOLUME_SIZE" "$VGROUP" -n "$VNAME" >/dev/null 2>$ERR
2133 errshow "lvcreate -L $VOLUME_SIZE $VGROUP -n $VNAME" || return 1
2134 msg "$_lvmnew (LV:$VOL_COUNT)" "\nDone, logical volume (LV) $VNAME ($VOLUME_SIZE) has been created.\n"
2142 part_find 'part|crypt' || return 1
2143 PARTS="$(awk 'NF > 0 {print $0 " off"}' <<< "$PARTS")"
2144 dlg LVM_PARTS check "$_lvmnew" "\nSelect the partition(s) to use for the physical volume (PV)." $PARTS
2151 until [[ $VGROUP ]]; do
2152 dlg VGROUP input "$_lvmnew" "$_lvmvgname" "mygroup"
2153 if [[ -z $VGROUP ]]; then
2155 elif [[ ${VGROUP:0:1} == "/" || $VGROUP =~ \ |\' ]] || lsblk | grep -q "$VGROUP"; then
2156 msg "LVM Name Error" "$_lvmerrvgname"
2166 local txt="$1" default="mainvolume"
2167 (( VOL_COUNT > 1 )) && default="extravolume$VOL_COUNT"
2168 until [[ $VNAME ]]; do
2169 dlg VNAME input "$_lvmnew (LV:$VOL_COUNT)" "\n$txt" "$default"
2170 if [[ -z $VNAME ]]; then
2172 elif [[ ${VNAME:0:1} == "/" || $VNAME =~ \ |\' ]] || lsblk | grep -q "$VNAME"; then
2173 msg "LVM Name Error" "$_lvmerlvname"
2180 ###############################################################################
2186 is_bg_install || return 1
2187 dlg choice menu "LUKS Encryption" "$_luksmenu" \
2188 "$_luksnew" "cryptsetup -q luksFormat" \
2189 "$_luksopen" "cryptsetup open --type luks" \
2190 "$_luksadv" "cryptsetup -q -s -c luksFormat" \
2191 "back" "Return to the main menu"
2194 "$_luksnew") luks_basic || return 1 ;;
2195 "$_luksopen") luks_open || return 1 ;;
2196 "$_luksadv") luks_advanced || return 1 ;;
2204 modprobe -a dm-mod dm_crypt >/dev/null 2>&1
2206 part_find 'part|crypt|lvm' || return 1
2208 if (( COUNT == 1 )); then
2209 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2211 dlg LUKS_PART menu "$_luksopen" "\nSelect which partition to open." $PARTS
2214 [[ $LUKS_PART ]] || return 1
2216 luks_pass "$_luksopen" || return 1
2217 msg "$_luksopen" "\nOpening encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2218 cryptsetup open --type luks "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2219 errshow "cryptsetup open --type luks $LUKS_PART $LUKS_NAME" || return 1
2220 LUKS='encrypted'; luks_show
2227 local t="$1" op="$2" v='' p='' p2=''
2229 until [[ $LUKS_PASS ]]; do
2233 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " \
2234 --mixedform "\nEnter the password to decrypt $ROOT_PART\n\nThis is needed to create a keyfile." 0 0 0 \
2235 "Password:" 1 1 '' 1 11 "$COLUMNS" 0 1 \
2236 "Password2:" 2 1 '' 2 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
2239 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " --mixedform "$_luksomenu" 0 0 0 \
2240 "Name:" 1 1 "${LUKS_NAME:-cryptroot}" 1 7 "$COLUMNS" 0 0 \
2241 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
2242 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
2246 while read -r line; do
2262 if [[ -z $op && -z $n ]]; then
2263 msg "Name Empty" "\nEncrypted device name cannot be empty.\n\nPlease try again.\n" 2
2264 elif [[ -z $p || "$p" != "$p2" ]]; then
2265 [[ $op ]] || LUKS_NAME="$n"
2266 msg "Password Mismatch" "\nThe passwords entered do not match.\n\nPlease try again.\n" 2
2268 [[ $op ]] || LUKS_NAME="$n"
2279 msg "$_luksnew" "\nEncrypted partition opened and ready for mounting.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$LUKS_PART")\n\n"
2284 modprobe -a dm-mod dm_crypt >/dev/null 2>&1
2286 part_find 'part|lvm' || return 1
2288 if [[ $AUTO_ROOT_PART ]]; then
2289 LUKS_PART="$AUTO_ROOT_PART"
2290 elif (( COUNT == 1 )); then
2291 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2293 dlg LUKS_PART menu "$_luksnew" "\nSelect the partition you want to encrypt." $PARTS
2296 [[ $LUKS_PART ]] || return 1
2297 luks_pass "$_luksnew"
2302 luks_setup || return 1
2303 msg "$_luksnew" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2304 cryptsetup -q luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2>$ERR
2305 errshow "cryptsetup -q luksFormat $LUKS_PART" || return 1
2306 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2307 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2308 LUKS='encrypted'; luks_show
2314 if [[ ! -e $MNT/crypto_keyfile.bin ]]; then
2315 # printf "Creating LUKS keyfile /crypto_keyfile.bin\n"
2317 n="$(lsblk -lno NAME,UUID,TYPE | awk "/$LUKS_UUID/"' && /part|crypt|lvm/ {print $1}')"
2318 local mkkey="dd bs=512 count=8 if=/dev/urandom of=/crypto_keyfile.bin"
2319 mkkey="$mkkey && chmod 000 /crypto_keyfile.bin"
2320 mkkey="$mkkey && cryptsetup luksAddKey /dev/$n /crypto_keyfile.bin <<< '$LUKS_PASS'"
2322 sed -i 's/FILES=()/FILES=(\/crypto_keyfile.bin)/g' $MNT/etc/mkinitcpio.conf 2>$ERR
2332 dlg cipher input "LUKS Encryption" "$_lukskey" "-s 512 -c aes-xts-plain64"
2333 [[ $cipher ]] || return 1
2334 msg "$_luksadv" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2335 cryptsetup -q $cipher luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2>$ERR
2336 errshow "cryptsetup -q $cipher luksFormat $LUKS_PART" || return 1
2337 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2338 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2345 ###############################################################################
2347 # some help avoid repetition and improve usability of some commands
2348 # others are initial setup functions used before reaching the main loop
2352 # does $2 contain $1
2353 [[ "$2" == *"$1"* ]] && printf "on" || printf "off"
2358 # cleanup and exit the installer cleanly with exit code $1
2359 # when ecode is 127 unmount /run/archiso/bootmnt and reboot
2364 if [[ -d $MNT ]] && command cd /; then
2366 if (( ecode == 127 )); then
2367 umount_dir /run/archiso/bootmnt
2378 local var="$1" # assign output from dialog to var
2379 local dlg_t="$2" # display a dialog of type dlg_t (menu, check, input)
2380 local title="$3" # dialog title
2381 local body="$4" # dialog message
2382 local n=0 # number of items to display
2384 shift 4 # shift off args assigned above
2386 # when passed a large amount of arguments (menu list) adjust menu height
2387 (( ($# / 2) > SHL )) && n=$SHL
2391 menu) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --menu "$body" 0 0 $n "$@" 2>"$ANS" || return 1 ;;
2392 check) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --checklist "$body" 0 0 $n "$@" 2>"$ANS" || return 1 ;;
2395 local def="$1" # assign default value for input
2397 if [[ $1 == 'limit' ]]; then
2398 dialog --backtitle "$DIST Installer - $SYS - v$VER" --max-input 63 --title " $title " --inputbox "$body" 0 0 "$def" 2>"$ANS" || return 1
2400 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --inputbox "$body" 0 0 "$def" 2>"$ANS" || return 1
2404 # if answer file isn't empty read from it into $var
2405 [[ -s "$ANS" ]] && printf -v "$var" "%s" "$(< "$ANS")"
2410 # displays a message dialog
2411 # when more than 2 args the message will disappear after sleep time ($3)
2417 dialog --backtitle "$DIST Installer - $SYS - v$VER" --sleep "$1" --title " $title " --infobox "$body\n" 0 0
2419 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --msgbox "$body\n" 0 0
2425 local title="$1" body="$2" yes='Yes' no='No'
2426 (( $# >= 3 )) && yes="$3"
2427 (( $# >= 4 )) && no="$4"
2429 if (( $# == 5 )); then
2430 dialog --backtitle "$DIST Installer - $SYS - v$VER" --defaultno --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2432 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2438 arch-chroot "$MNT" bash -c "$1"
2443 export PS4='| ${BASH_SOURCE} LINE:${LINENO} FUNC:${FUNCNAME[0]:+ ${FUNCNAME[0]}()} |> '
2452 printf "\n^C caught, cleaning up...\n"
2459 "\e]P0191919" # #191919
2460 "\e]P1D15355" # #D15355
2461 "\e]P2609960" # #609960
2462 "\e]P3FFCC66" # #FFCC66
2463 "\e]P4255A9B" # #255A9B
2464 "\e]P5AF86C8" # #AF86C8
2465 "\e]P62EC8D3" # #2EC8D3
2466 "\e]P7949494" # #949494
2467 "\e]P8191919" # #191919
2468 "\e]P9D15355" # #D15355
2469 "\e]PA609960" # #609960
2470 "\e]PBFF9157" # #FF9157
2471 "\e]PC4E88CF" # #4E88CF
2472 "\e]PDAF86C8" # #AF86C8
2473 "\e]PE2ec8d3" # #2ec8d3
2474 "\e]PFE1E1E1" # #E1E1E1
2477 [[ $TERM == 'linux' ]] && printf "%b" "${colors[@]}" && clear
2482 [ $? -eq 0 ] && return 0
2484 local fatal=0 err=""
2485 err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
2487 (( $1 == 1 )) && { fatal=1; shift; }
2489 local txt="\nThe command exited abnormally:\n\n$1\n\n"
2492 txt+="With the following message:\n\n$err\n\n"
2494 txt+="With no error message:\n\n"
2497 if (( fatal )); then
2498 txt+="Errors at this stage are fatal and the install cannot continue.\n"
2500 txt+="Errors at this stage are non-fatal and can be either fixed or ignored depending on the error.\n"
2502 msg "Install Error" "$txt"
2504 if (( fatal )); then
2505 [[ -r $DBG && $TERM == 'linux' ]] && less "$DBG"
2514 msg "Broadcom Wireless Setup" "\nDetected chipset is Broadcom BCM4352\n\nDisabling bcma/b43 modules and loading wl module.\n" 1
2515 { rmmod wl; rmmod bcma; rmmod b43; rmmod ssb; modprobe wl; depmod -a; } >/dev/null 2>&1
2523 if (( $1 >= 0 )) && ! grep -qw "$MNT" /proc/mounts; then
2524 msg "Not Mounted" "\nPartition(s) must be mounted first.\n" 2
2526 elif [[ $1 -ge 1 && -z $BOOTLDR ]]; then
2527 msg "No Bootloader" "\nBootloader must be selected first.\n" 2
2529 elif [[ $1 -ge 2 && (-z $NEWUSER || -z $USER_PASS) ]]; then
2530 msg "No User" "\nA user must be created first.\n" 2
2532 elif [[ $1 -ge 3 && -z $CONFIG_DONE ]]; then
2533 msg "Not Configured" "\nSystem configuration must be done first.\n" 2
2536 (( i )) # return code
2541 mount | grep -q 'swap' && swapoff -a
2543 [[ -d $dir && "$(mount | grep "on $dir ")" ]] || continue
2544 umount "$dir" 2>/dev/null || { sleep 0.5; umount -f "$dir" 2>/dev/null || umount -l "$dir"; }
2550 msg "Network Connect" "\nVerifying network connection\n" 1
2551 curl -sIN --connect-timeout 5 'https://www.archlinux.org/' | sed '1q' | grep -q '200'
2556 if chk_connect; then
2559 if hash nmtui >/dev/null 2>&1; then
2561 if [[ $TERM == 'linux' ]]; then
2562 printf "%b" "\e]P1191919" "\e]P4191919"
2564 printf "%b" "\e]P1D15355" "\e]P4255a9b"
2577 [[ $RSYNC_PID || $MIRROR_PID ]] || return 0
2578 msg "Install Running" "\nA background install process is currently running.\n" 2
2584 IGNORE_DEV="$(lsblk -lno NAME,MOUNTPOINT | awk '/\/run\/archiso\/bootmnt/ {sub(/[1-9]/, ""); print $1}')"
2586 if [[ $IGNORE_DEV ]]; then
2587 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ && !'"/$IGNORE_DEV/"' {print "/dev/" $1 " " $2}')"
2589 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ {print "/dev/" $1 " " $2}')"
2592 if [[ -z $SYS_DEVS ]]; then
2593 msg "Device Error" "\nNo available devices...\n\nExiting..\n" 2
2598 while read -r line; do
2600 done <<< "$SYS_DEVS"
2607 elif grep -q 'AuthenticAMD' /proc/cpuinfo; then
2609 elif grep -q 'GenuineIntel' /proc/cpuinfo; then
2613 modprobe -q efivarfs >/dev/null 2>&1
2615 _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."
2616 if [[ -d /sys/firmware/efi/efivars ]]; then
2618 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars
2619 _prep+="\n - An EFI boot partition mounted."
2623 _prep+="\n\nOnce finished mounting, a portion of the install can be done in the background while you continue configuring the system:\n"
2624 _prep+="\n - Choose the system bootloader.\n - Create a user and password."
2625 _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."
2628 ###############################################################################
2631 # enable some nicer colours in the linux console
2634 if (( UID != 0 )); then
2635 msg "Not Root" "\nThis installer must be run as root or using sudo.\n\nExiting..\n" 2
2637 elif ! grep -qwm 1 'lm' /proc/cpuinfo; then
2638 msg "Not x86_64 Architecture" "\nThis installer only supports x86_64 architectures.\n\nExiting..\n" 2
2640 elif [[ $1 =~ (-d|--debug) ]]; then
2644 # trap ^C to perform cleanup
2650 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"
2652 select_keymap || { clear; die 0; }
2654 # try to fix problematic broadcom wireless chipset before network check
2655 lspci -vnn -d 14e4: | grep -q 'BCM4352' && load_bcm
2657 net_connect || { msg "Not Connected" "\nThis installer requires an active internet connection.\n\nExiting..\n" 2; die 1; }
2663 # vim:fdm=marker:fmr={,}