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
9 # linux distributor, if unset will be ArchLabs
10 # this can be set in the environment prior to install, eg.
12 # $ DIST="My Distro" archlabs-installer
14 # will result in "My Distro Linux" used where needed
18 VER="2.0.61" # installer version
19 MNT="/mnt" # install mountpoint
20 ANS="/tmp/ans" # dialog answer file
22 # ------------------------------------------------------ #
23 # When manually mounting your partitions, you need
24 # to set these values to avoid using the mount menu.
25 # ------------------------------------------------------ #
27 # root partition, eg. /dev/sda2
30 # boot partition, required on UEFI eg. /dev/sda1
33 # boot device, used for some bootloaders eg. /dev/sda
36 # bootloader to use, can be:
37 # UEFI: grub, syslinux, efistub, systemd-boot, refind-efi
38 # BIOS: grub, syslinux
41 # directory to mount the boot partition (if any) for most bootloaders
42 # this will need to be 'boot' however a popular one for grub is 'boot/efi'
45 # ------------------------------------------------------ #
47 # bulk default values {
49 # these values will be selected during the install, it is not recommended
50 # to edit them here unless you know what you're doing.
52 UCODE='' # cpu microcode (if any), can be: amd-ucode, intel-ucode
53 KERNEL='' # linux kernel, can be: linux, linux-lts, linux-zen, or linux-hardened
54 MYSHELL='' # full path for the shell, eg. /usr/bin/zsh
56 SWAP_PART='' # swap partition or file path
57 SWAP_SIZE='' # swap size, only used when creating a swapfile
59 EXMNT='' # holder for additional partitions while mounting
60 EXMNTS='' # when an extra partition is mounted append it's info
62 FONT="ter-i16n" # font used for the linux console
63 HOOKS="shutdown" # list of additional HOOKS to add in /etc/mkinitcpio.conf
65 LOGIN_TYPE='' # login manager can be: lightdm, xinit, ly
66 LOGIN_WM='' # default login session to be placed in ~/.xinitrc
67 LOGINRC='' # login shell rc file, eg. .zprofile, .bash_profile, .profile
69 INSTALL_WMS='' # space separated list of chosen wm/de
71 WM_PKGS='' # list of packages added during wm/de choice (not user edited)
72 PACKAGES='' # list of all packages to install including WM_PKGS (not user edited)
73 USER_PKGS='' # packages selected by the user during install
75 NEWUSER='' # username for the new user
76 USER_PASS='' # new user's password
77 ROOT_PASS='' # root password
79 LUKS='' # empty when not using encryption
80 LUKS_DEV='' # boot parameter string for LUKS
81 LUKS_PART='' # partition used for encryption
82 LUKS_PASS='' # encryption password
83 LUKS_UUID='' # encrypted partition UUID
84 LUKS_NAME='' # name used for encryption
86 LVM='' # empty when not using lvm
87 LVM_PARTS='' # partitions used for volume group
88 VGROUP_MB=0 # available space in volume group
90 WARN='' # issued mounting/partitioning warning
91 SEP_BOOT='' # separate boot partition for BIOS
92 AUTOLOGIN='' # enable autologin for xinit
93 CONFIG_DONE='' # basic configuration is finished
95 FORMATTED='' # partitions we formatted and should allow skipping
96 AUTO_ROOT_PART='' # root value from auto partition
97 AUTO_BOOT_PART='' # boot value from auto partition
100 AL_BASE_PKGS="archlabs-skel-base archlabs-fonts archlabs-themes archlabs-dARK archlabs-icons archlabs-wallpapers archlabs-scripts"
102 # baseline (usually installed in the background)
103 BASE_PKGS="base-devel xorg xorg-drivers sudo git gvfs gtk3 gtk-engines gtk-engine-murrine pavucontrol tumbler xdg-user-dirs "
104 BASE_PKGS+="playerctl ffmpeg gstreamer libmad libmatroska gst-libav gst-plugins-base gst-plugins-good scrot bash-completion"
106 # extras for window managers
107 WM_BASE_PKGS="arandr archlabs-networkmanager-dmenu nitrogen polkit-gnome volumeicon xclip exo laptop-detect "
108 WM_BASE_PKGS+="xdotool compton wmctrl gnome-keyring dunst feh gsimplecal xfce4-power-manager xfce4-settings"
111 SEL=0 # currently selected menu item
112 ERR="/tmp/errlog" # error log used internally
113 DBG="/tmp/debuglog" # debug log when passed -d
114 RUN="/run/archiso/bootmnt/arch/boot" # path for live /boot
115 VM="$(dmesg | grep -i "hypervisor")" # is the system a vm
118 export DIALOGOPTS="--cr-wrap"
122 # giant ugly variable container :P {
125 SYS_MEM="$(awk '/MemTotal/ {print int($2 / 1024) "M"}' /proc/meminfo)"
127 # locales from /etc/locale.gen
128 LOCALES="$(awk '/\.UTF-8/ {gsub(/# .*|#/, ""); if ($1) {print $1 " - "}}' /etc/locale.gen)"
130 # console keyboard mappings
131 CMAPS="$(find /usr/share/kbd/keymaps -name '*.map.gz' | awk '{gsub(/\.map\.gz|.*\//, ""); print $1 " - "}' | sort)"
134 [[ $LINES ]] || LINES=$(tput lines)
135 [[ $COLUMNS ]] || COLUMNS=$(tput cols)
141 # commands used to install each bootloader, however most get modified during runtime {
143 [refind-efi]='refind-install' # minor modification
144 [grub]='grub-install --recheck --force' # heavily modified
145 [syslinux]='syslinux-install_update -i -a -m' # modified on UEFI
146 [efistub]='efibootmgr -v -d /dev/sda -p 1 -c -l' # heavily modified
147 [systemd-boot]='bootctl --path=/boot install' # not modified
150 # executable name for each wm/de used in ~/.xinitrc {
151 declare -A WM_SESSIONS=(
158 [gnome]='gnome-session'
159 [fluxbox]='startfluxbox'
160 [openbox]='openbox-session'
161 [cinnamon]='cinnamon-session'
164 # packages installed for each wm/de, most are depends of the skel packages {
168 [cinnamon]='gnome-terminal' # doesn't install a terminal on it's own
169 [plasma]='kdebase-meta' # base plasma application set
170 [awesome]='archlabs-skel-awesome' # see deps of archlabs-skel-awesome
171 [bspwm]='archlabs-skel-bspwm' # see deps of archlabs-skel-bspwm
172 [fluxbox]='archlabs-skel-fluxbox' # see deps of archlabs-skel-fluxbox
173 [i3-gaps]='archlabs-skel-i3-gaps' # see deps of archlabs-skel-i3-gaps
174 [openbox]='archlabs-skel-openbox' # see deps of archlabs-skel-openbox
175 [xfce4]='archlabs-skel-xfce4 xfce4-goodies' # see deps of archlabs-skel-xfce4
178 # files offered for editing after install is complete {
179 declare -A EDIT_FILES=(
180 [login]='' # login is populated once we know the username and shell
182 [sudoers]='/etc/sudoers'
183 [crypttab]='/etc/crypttab'
184 [pacman]='/etc/pacman.conf'
185 [console]='/etc/vconsole.conf'
186 [mkinitcpio]='/etc/mkinitcpio.conf'
187 [hostname]='/etc/hostname /etc/hosts'
188 [bootloader]="/boot/loader/entries/$DIST.conf"
189 [locale]='/etc/locale.conf /etc/default/locale'
190 [keyboard]='/etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard'
193 # mkfs command and flags for filesystem formatting {
198 [ntfs]='mkfs.ntfs -q'
199 [ext2]='mkfs.ext2 -q'
200 [ext3]='mkfs.ext3 -q'
201 [ext4]='mkfs.ext4 -q'
202 [vfat]='mkfs.vfat -F32'
203 [nilfs2]='mkfs.nilfs2 -q'
204 [reiserfs]='mkfs.reiserfs -q'
207 # mount options for each filesystem {
213 [jfs]='discard errors=continue errors=panic nointegrity'
214 [reiserfs]='acl nolog notail replayonly user_xattr off'
215 [ext4]='discard dealloc nofail noacl relatime noatime nobarrier nodelalloc'
216 [xfs]='discard filestreams ikeep largeio noalign nobarrier norecovery noquota wsync'
217 [nilfs2]='discard nobarrier errors=continue errors=panic order=relaxed order=strict norecovery'
218 [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'
221 # packages installed for each login option {
222 declare -A LOGIN_PKGS=(
227 [lightdm]='lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings accountsservice'
230 # extras installed for user selected packages {
231 # if a package requires additional packages that aren't already dependencies
232 # they can be added here eg. [package]="extra"
236 [mupdf]='mupdf-tools'
237 [qt5ct]='qt5-styleplugins'
238 [vlc]='qt5ct qt5-styleplugins'
239 [zathura]='zathura-pdf-poppler'
240 [noto-fonts]='noto-fonts-emoji'
241 [cairo-dock]='cairo-dock-plug-ins'
242 [qutebrowser]='qt5ct qt5-styleplugins'
243 [qbittorrent]='qt5ct qt5-styleplugins'
244 [transmission-qt]='qt5ct qt5-styleplugins'
245 [bluez]='bluez-libs bluez-utils bluez-tools bluez-plugins bluez-hid2hci'
246 [kdenlive]='kdebase-meta dvdauthor frei0r-plugins breeze breeze-gtk qt5ct qt5-styleplugins'
251 # dialog text variables
254 # Basics (somewhat in order)
255 _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"
256 _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"
257 _device="\nSelect a device to use from the list below.\n\nDevices (/dev) are the available drives on the system. /sda, /sdb, /sdc ..."
258 _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."
259 _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."
260 _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"
261 _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)."
262 _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."
263 _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."
264 _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."
265 _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"
266 _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."
267 _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."
268 _exmnt="\nWhere do you want the partition mounted?\n\nEnsure the name begins with a slash (/).\nExamples include: /usr, /home, /var, etc."
269 _user="\nEnter a name and password for the new user account.\n\nThe name must not use capital letters, contain any periods (.), end with a hyphen (-), or include any colons (:)\n\nNOTE: Use [Up], [Down], or [Tab] to switch between fields, and [Enter] to accept."
270 _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."
271 _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"
272 _timez="\nThe time zone is used to set the system clock.\n\nSelect your country or continent from the list below"
273 _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."
274 _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."
275 _login="\nSelect which of your session choices to use for the initial login.\n\nYou can be change this later by editing your ~/.xinitrc"
276 _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"
277 _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."
278 _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."
281 _luksnew="Basic LUKS Encryption"
282 _luksadv="Advanced LUKS Encryption"
283 _luksopen="Open Existing LUKS Partition"
284 _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."
285 _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."
286 _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)."
289 _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."
290 _lvmnew="Create Volume Group and Volume(s)"
291 _lvmdel="Delete an Existing Volume Group"
292 _lvmdelall="Delete ALL Volume Group(s) and Volume(s)"
293 _lvmvgname="\nEnter a name for the volume group (VG) being created from the partition(s) selected."
294 _lvmlvname="\nEnter a name for the logical volume (LV) being created.\n\nThis is similar to setting a label for a partition."
295 _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."
296 _lvmdelask="\nConfirm deletion of volume group(s) and logical volume(s).\n\nDeleting a volume group, will delete all logical volumes within it.\n"
299 _errexpart="\nCannot mount partition due to a problem with the mountpoint.\n\nEnsure it begins with a slash (/) followed by atleast one character.\n"
300 _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"
301 _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"
302 _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"
303 _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"
304 _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"
305 _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"
311 ###############################################################################
313 # main is the entry point which calls functions including outside of its block
314 # once those functions finished they always are returned here with the
315 # exception of install_main(), it exits upon completion
319 (( SEL < 12 )) && (( SEL++ ))
321 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Prepare " --default-item $SEL --cancel-label 'Exit' --menu "$_prep" 0 0 0 \
322 1 "Device tree (optional)" \
323 2 "Partitioning (optional)" \
324 3 "LUKS setup (optional)" \
325 4 "LVM setup (optional)" \
326 5 "Mount partitions" \
327 6 "System bootloader" \
328 7 "User and password" \
329 8 "System configuration" \
330 9 "Select WM/DE (optional)" \
331 10 "Select Packages (optional)" \
332 11 "View configuration (optional)" \
333 12 "Start the installation" 2>"$ANS"
336 [[ -z $WARN && $SEL =~ (2|5) ]] && { msg "Data Warning" "$_warn"; WARN=true; }
339 2) part_menu || (( SEL-- )) ;;
340 3) luks_menu || (( SEL-- )) ;;
341 4) lvm_menu || (( SEL-- )) ;;
342 5) mount_menu || (( SEL-- )) ;;
343 6) prechecks 0 && { select_boot || (( SEL-- )); } ;;
344 7) prechecks 1 && { select_mkuser || (( SEL-- )); } ;;
345 8) prechecks 2 && { select_config || (( SEL-- )); } ;;
346 9) prechecks 3 && { select_sessions || (( SEL-- )); } ;;
347 10) prechecks 3 && { select_packages || (( SEL-- )); } ;;
348 11) prechecks 3 && select_show ;;
349 12) prechecks 3 && install_main ;;
350 *) yesno "Exit" "\nUnmount partitions (if any) and exit the installer?\n" && die 0
356 if [[ $SYS == 'BIOS' ]]; then
357 dlg BOOTLDR menu "BIOS Bootloader" "\nSelect which bootloader to use." \
358 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
359 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network" || return 1
361 dlg BOOTLDR menu "UEFI Bootloader" "\nSelect which bootloader to use." \
362 "systemd-boot" "A simple UEFI boot manager which executes configured EFI images" \
363 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
364 "refind-efi" "A UEFI boot manager that aims to be platform neutral and simplify multi-boot" \
365 "efistub" "Boot the kernel image directly (no chainloading support)" \
366 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network (no chainloading support)" || return 1
373 local pkgs="${USER_PKGS// / } ${PACKAGES// / }"
374 [[ $BOOT_PART ]] && local mnt="/$BOOTDIR"
375 [[ $INSTALL_WMS == *dwm* ]] && pkgs="dwm st dmenu $pkgs"
376 pkgs="${pkgs// / }" pkgs="${pkgs# }"
377 msg "Show Configuration" "
378 ---------- PARTITION CONFIGURATION ------------
380 Root: ${ROOT_PART:-none}
381 Boot: ${BOOT_PART:-${BOOT_DEV:-none}}
383 Swap: ${SWAP_PART:-none}
384 Size: ${SWAP_SIZE:-none}
385 Extra: ${EXMNTS:-${EXMNT:-none}}
386 Hooks: ${HOOKS:-none}
392 ------------ SYSTEM CONFIGURATION -------------
394 Locale: ${MYLOCALE:-none}
395 Keymap: ${KEYMAP:-none}
396 Hostname: ${MYHOST:-none}
397 Timezone: ${ZONE:-none}/${SUBZ:-none}
400 ------------ USER CONFIGURATION ---------------
402 Username: ${NEWUSER:-none}
403 Login Shell: ${MYSHELL:-none}
404 Login Session: ${LOGIN_WM:-none}
405 Autologin: ${AUTOLOGIN:-none}
406 Login Type: ${LOGIN_TYPE:-none}
409 ----------- PACKAGE CONFIGURATION -------------
411 Kernel: ${KERNEL:-none}
412 Bootloader: ${BOOTLDR:-none}
413 Packages: ${pkgs:-none}
419 [[ $INSTALL_WMS ]] || return 0
421 AUTOLOGIN='' # no autologin unless using xinit
423 if [[ -z $LOGIN_TYPE ]]; then
424 dlg LOGIN_TYPE menu "Login Management" "\nSelect what kind of login management to use." \
425 "xinit" "Console login without a display manager" \
426 "ly" "TUI display manager with a ncurses-like interface" \
427 "lightdm" "Lightweight display manager with a gtk greeter" \
428 "gdm" "Gnome display manager" \
429 "sddm" "Simple desktop display manager" || return 1
433 ly) EDIT_FILES[login]="/etc/ly/config.ini" ;;
434 gdm|sddm) EDIT_FILES[login]="" ;;
435 lightdm) EDIT_FILES[login]="/etc/lightdm/lightdm.conf /etc/lightdm/lightdm-gtk-greeter.conf" ;;
436 xinit) EDIT_FILES[login]="/home/$NEWUSER/.xinitrc /home/$NEWUSER/.xprofile"
437 if (( $(wc -w <<< "$INSTALL_WMS") > 1 )); then
438 dlg LOGIN_WM menu "Login Management" "$_login" $LOGIN_CHOICES || return 1
439 LOGIN_WM="${WM_SESSIONS[$LOGIN_WM]}"
441 [[ -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=''
452 until [[ $CONFIG_DONE ]]; do
454 0) dlg MYSHELL menu "Shell" "\nChoose which shell to use." \
455 /usr/bin/zsh 'A very advanced and programmable command interpreter (shell) for UNIX' \
456 /bin/bash 'The GNU Bourne Again shell, standard in many GNU/Linux distributions' \
457 /usr/bin/mksh 'The MirBSD Korn Shell - an enhanced version of the public domain ksh' || return 1
459 1) dlg MYHOST input "Hostname" "$_hostname" "${DIST,,}" limit || { i=0; continue; } ;;
460 2) dlg MYLOCALE menu "Locale" "$_locale" $LOCALES || { i=1; continue; } ;;
462 until [[ $ZONE && $SUBZ ]]; do
463 dlg ZONE menu "Timezone" "$_timez" America - Australia - Asia - Atlantic - Africa - Europe - Indian - Pacific - Arctic - Antarctica - || break
464 dlg SUBZ menu "Timezone" "$_timesubz" $(awk '/'"$ZONE"'\// {gsub(/'"$ZONE"'\//, ""); print $3 " - "}' /usr/share/zoneinfo/zone.tab | sort) || continue
466 [[ $ZONE && $SUBZ ]] || { i=2; continue; } ;;
467 4) dlg KERNEL menu "Kernel" "\nChoose which kernel to use." \
468 linux 'Vanilla linux kernel and modules, with a few patches applied' \
469 linux-lts 'Long-term support (LTS) linux kernel and modules' \
470 linux-zen 'A effort of kernel hackers to provide the best kernel for everyday systems' \
471 linux-hardened 'A security-focused linux kernel with hardening patches to mitigate exploits' || { i=3; continue; }
475 (( i++ )) # progress through to the next choice
478 case $MYSHELL in *bash) LOGINRC='.bash_profile' ;; *zsh) LOGINRC='.zprofile' ;; *mksh) LOGINRC='.profile' ;; esac
486 local v='' u='' p='' p2='' rp='' rp2=''
488 until [[ $NEWUSER ]]; do
491 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " User " --mixedform "$_user" 0 0 0 \
492 "Username:" 1 1 "$u" 1 11 "$COLUMNS" 0 0 \
493 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
494 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 \
495 "--- Root password, if left empty the user password will be used ---" 6 1 '' 6 68 "$COLUMNS" 0 2 \
496 "Password:" 8 1 '' 8 11 "$COLUMNS" 0 1 \
497 "Password2:" 9 1 '' 9 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
499 while read -r line; do
500 case $i in 0) u="$line" ;; 1) p="$line" ;; 2) p2="$line" ;; 3) rp="$line" ;; 4) rp2="$line" ;; esac
504 # root passwords empty, so use the user passwords
505 [[ -z $rp && -z $rp2 ]] && { rp="$p"; rp2="$p2"; }
507 # make sure a username was entered and that the passwords match
508 if [[ ${#u} -eq 0 || $u =~ \ |\' || $u =~ [^a-z0-9] ]]; then
509 msg "Invalid Username" "\nIncorrect user name.\n\nPlease try again.\n"; u=''
510 elif [[ -z $p ]]; then
511 msg "Empty Password" "\nThe user password cannot be left empty.\n\nPlease try again.\n"
512 elif [[ "$p" != "$p2" ]]; then
513 msg "Password Mismatch" "\nThe user passwords do not match.\n\nPlease try again.\n"
514 elif [[ "$rp" != "$rp2" ]]; then
515 msg "Password Mismatch" "\nThe root passwords do not match.\n\nPlease try again.\n"
527 dlg KEYMAP menu "Keyboard Layout" "$_keymap" \
528 us English cm English gb English au English gh English \
529 za English ng English ca French 'cd' French gn French \
530 tg French fr French de German at German ch German \
531 es Spanish latam Spanish br Portuguese pt Portuguese ma Arabic \
532 sy Arabic ara Arabic ua Ukrainian cz Czech ru Russian \
533 sk Slovak nl Dutch it Italian hu Hungarian cn Chinese \
534 tw Taiwanese vn Vietnamese kr Korean jp Japanese th Thai \
535 la Lao pl Polish se Swedish is Icelandic 'fi' Finnish \
536 dk Danish be Belgian in Indian al Albanian am Armenian \
537 bd Bangla ba Bosnian 'bg' Bulgarian dz Berber mm Burmese \
538 hr Croatian gr Greek il Hebrew ir Persian iq Iraqi \
539 af Afghani fo Faroese ge Georgian ee Estonian kg Kyrgyz \
540 kz Kazakh lt Lithuanian mt Maltese mn Mongolian ro Romanian \
541 no Norwegian rs Serbian si Slovenian tj Tajik lk Sinhala \
542 tr Turkish uz Uzbek ie Irish pk Urdu 'mv' Dhivehi \
543 np Nepali et Amharic sn Wolof ml Bambara tz Swahili \
544 ke Swahili bw Tswana ph Filipino my Malay tm Turkmen \
545 id Indonesian bt Dzongkha lv Latvian md Moldavian mao Maori \
546 by Belarusian az Azerbaijani mk Macedonian kh Khmer epo Esperanto \
547 me Montenegrin || return 1
549 if [[ $CMAPS == *"$KEYMAP"* ]]; then
552 dlg CMAP menu "Console Keymap" "$_vconsole" $CMAPS || return 1
555 if [[ $DISPLAY && $TERM != 'linux' ]]; then
556 setxkbmap "$KEYMAP" >/dev/null 2>&1
558 loadkeys "$CMAP" >/dev/null 2>&1
568 dlg INSTALL_WMS check "Sessions" "$_sessions\n" \
569 i3-gaps "A fork of i3wm with more features including gaps" "$(ofn i3-gaps "${INSTALL_WMS[*]}")" \
570 openbox "A lightweight, powerful, and highly configurable stacking wm" "$(ofn openbox "${INSTALL_WMS[*]}")" \
571 awesome "A customized Awesome WM session created by @elanapan" "$(ofn awesome "${INSTALL_WMS[*]}")" \
572 dwm "A dynamic WM for X that manages windows in tiled, floating, or monocle layouts" "$(ofn dwm "${INSTALL_WMS[*]}")" \
573 bspwm "A tiling wm that represents windows as the leaves of a binary tree" "$(ofn bspwm "${INSTALL_WMS[*]}")" \
574 fluxbox "A lightweight and highly-configurable window manager" "$(ofn fluxbox "${INSTALL_WMS[*]}")" \
575 gnome "A desktop environment that aims to be simple and easy to use" "$(ofn gnome "${INSTALL_WMS[*]}")" \
576 cinnamon "A desktop environment combining traditional desktop with modern effects" "$(ofn cinnamon "${INSTALL_WMS[*]}")" \
577 plasma "A kde software project currently comprising a full desktop environment" "$(ofn plasma "${INSTALL_WMS[*]}")" \
578 xfce4 "A lightweight and modular desktop environment based on gtk+2/3" "$(ofn xfce4 "${INSTALL_WMS[*]}")"
580 [[ $INSTALL_WMS ]] || return 0
582 WM_PKGS="${INSTALL_WMS/dwm/}" # remove dwm from package list
583 WM_PKGS="${WM_PKGS// / }" # remove double spaces
584 WM_PKGS="${WM_PKGS# }" # remove leading space
586 # add archlabs base when choosing any session
587 [[ $WM_PKGS ]] && WM_PKGS+=" $AL_BASE_PKGS"
589 for i in $INSTALL_WMS; do
590 LOGIN_CHOICES+="$i - "
591 [[ ${WM_EXT[$i]} && $WM_PKGS != *"${WM_EXT[$i]}"* ]] && WM_PKGS+=" ${WM_EXT[$i]}"
594 select_login || return 1
596 while IFS=' ' read -r pkg; do
597 [[ $PACKAGES != *"$pkg"* ]] && PACKAGES+=" $pkg"
605 dlg USER_PKGS check " Packages " "$_packages" \
606 abiword "A Fully-featured word processor" "$(ofn abiword "${USER_PKGS[*]}")" \
607 alacritty "A cross-platform, GPU-accelerated terminal emulator" "$(ofn alacritty "${USER_PKGS[*]}")" \
608 atom "An open-source text editor developed by GitHub" "$(ofn atom "${USER_PKGS[*]}")" \
609 audacious "A free and advanced audio player based on GTK+" "$(ofn audacious "${USER_PKGS[*]}")" \
610 audacity "A program that lets you manipulate digital audio waveforms" "$(ofn audacity "${USER_PKGS[*]}")" \
611 blueman "GUI bluetooth device manager" "$(ofn blueman "${USER_PKGS[*]}")" \
612 bluez "Simple CLI based bluetooth support" "$(ofn bluez "${USER_PKGS[*]}")" \
613 cairo-dock "Light eye-candy fully themable animated dock" "$(ofn cairo-dock "${USER_PKGS[*]}")" \
614 calligra "A set of applications for productivity" "$(ofn calligra "${USER_PKGS[*]}")" \
615 chromium "An open-source web browser based on the Blink rendering engine" "$(ofn chromium "${USER_PKGS[*]}")" \
616 clementine "A modern music player and library organizer" "$(ofn clementine "${USER_PKGS[*]}")" \
617 cmus "A small, fast and powerful console music player" "$(ofn cmus "${USER_PKGS[*]}")" \
618 deadbeef "A GTK+ audio player for GNU/Linux" "$(ofn deadbeef "${USER_PKGS[*]}")" \
619 deluge "A BitTorrent client written in python" "$(ofn deluge "${USER_PKGS[*]}")" \
620 docky "Full fledged dock for opening applications and managing windows" "$(ofn docky "${USER_PKGS[*]}")" \
621 emacs "An extensible, customizable, self-documenting real-time display editor" "$(ofn emacs "${USER_PKGS[*]}")" \
622 epiphany "A GNOME web browser based on the WebKit rendering engine" "$(ofn epiphany "${USER_PKGS[*]}")" \
623 evince "A document viewer" "$(ofn evince "${USER_PKGS[*]}")" \
624 evolution "Manage your email, contacts and schedule" "$(ofn evolution "${USER_PKGS[*]}")" \
625 file-roller "Create and modify archives" "$(ofn file-roller "${USER_PKGS[*]}")" \
626 firefox "A popular open-source web browser from Mozilla" "$(ofn firefox "${USER_PKGS[*]}")" \
627 gcolor2 "A simple GTK+2 color selector" "$(ofn gcolor2 "${USER_PKGS[*]}")" \
628 geany "A fast and lightweight IDE" "$(ofn geany "${USER_PKGS[*]}")" \
629 geary "A lightweight email client for the GNOME desktop" "$(ofn geary "${USER_PKGS[*]}")" \
630 gimp "GNU Image Manipulation Program" "$(ofn gimp "${USER_PKGS[*]}")" \
631 gnome-calculator "GNOME Scientific calculator" "$(ofn gnome-calculator "${USER_PKGS[*]}")" \
632 gnome-disk-utility "Disk Management Utility" "$(ofn gnome-disk-utility "${USER_PKGS[*]}")" \
633 gnome-system-monitor "View current processes and monitor system state" "$(ofn gnome-system-monitor "${USER_PKGS[*]}")" \
634 gparted "A GUI frontend for creating and manipulating partition tables" "$(ofn gparted "${USER_PKGS[*]}")" \
635 gpick "Advanced color picker using GTK+ toolkit" "$(ofn gpick "${USER_PKGS[*]}")" \
636 gpicview "Lightweight image viewer" "$(ofn gpicview "${USER_PKGS[*]}")" \
637 guvcview "Capture video from camera devices" "$(ofn guvcview "${USER_PKGS[*]}")" \
638 hexchat "A popular and easy to use graphical IRC client" "$(ofn hexchat "${USER_PKGS[*]}")" \
639 inkscape "Professional vector graphics editor" "$(ofn inkscape "${USER_PKGS[*]}")" \
640 irssi "Modular text mode IRC client" "$(ofn irssi "${USER_PKGS[*]}")" \
641 kdenlive "A popular non-linear video editor for Linux" "$(ofn kdenlive "${USER_PKGS[*]}")" \
642 krita "Edit and paint images" "$(ofn krita "${USER_PKGS[*]}")" \
643 libreoffice-fresh "Full featured office suite" "$(ofn libreoffice-fresh "${USER_PKGS[*]}")" \
644 lollypop "A new music playing application" "$(ofn lollypop "${USER_PKGS[*]}")" \
645 mousepad "A simple text editor" "$(ofn mousepad "${USER_PKGS[*]}")" \
646 mpd "A flexible, powerful, server-side application for playing music" "$(ofn mpd "${USER_PKGS[*]}")" \
647 mpv "A media player based on mplayer" "$(ofn mpv "${USER_PKGS[*]}")" \
648 mupdf "Lightweight PDF and XPS viewer" "$(ofn mupdf "${USER_PKGS[*]}")" \
649 mutt "Small but very powerful text-based mail client" "$(ofn mutt "${USER_PKGS[*]}")" \
650 nautilus "The default file manager for Gnome" "$(ofn nautilus "${USER_PKGS[*]}")" \
651 ncmpcpp "A mpd client and almost exact clone of ncmpc with some new features" "$(ofn ncmpcpp "${USER_PKGS[*]}")" \
652 neovim "A fork of Vim aiming to improve user experience, plugins, and GUIs." "$(ofn neovim "${USER_PKGS[*]}")" \
653 nicotine+ "A graphical client for Soulseek" "$(ofn nicotine+ "${USER_PKGS[*]}")" \
654 noto-fonts "Google Noto fonts" "$(ofn noto-fonts "${USER_PKGS[*]}")" \
655 noto-fonts-cjk "Google Noto CJK fonts (Chinese, Japanese, Korean)" "$(ofn noto-fonts-cjk "${USER_PKGS[*]}")" \
656 obs-studio "Free opensource streaming/recording software" "$(ofn obs-studio "${USER_PKGS[*]}")" \
657 openshot "An open-source, non-linear video editor for Linux" "$(ofn openshot "${USER_PKGS[*]}")" \
658 opera "A Fast and secure, free of charge web browser from Opera Software" "$(ofn opera "${USER_PKGS[*]}")" \
659 pcmanfm "A fast and lightweight file manager based in Lxde" "$(ofn pcmanfm "${USER_PKGS[*]}")" \
660 pidgin "Multi-protocol instant messaging client" "$(ofn pidgin "${USER_PKGS[*]}")" \
661 plank "An elegant, simple, and clean dock" "$(ofn plank "${USER_PKGS[*]}")" \
662 qbittorrent "An advanced BitTorrent client" "$(ofn qbittorrent "${USER_PKGS[*]}")" \
663 qpdfview "A tabbed PDF viewer" "$(ofn qpdfview "${USER_PKGS[*]}")" \
664 qt5ct "GUI for managing Qt based application themes, icons, and fonts" "$(ofn qt5ct "${USER_PKGS[*]}")" \
665 qutebrowser "A keyboard-focused vim-like web browser based on Python and PyQt5" "$(ofn qutebrowser "${USER_PKGS[*]}")" \
666 rhythmbox "A Music playback and management application" "$(ofn rhythmbox "${USER_PKGS[*]}")" \
667 rxvt-unicode "A unicode enabled rxvt-clone terminal emulator" "$(ofn rxvt-unicode "${USER_PKGS[*]}")" \
668 sakura "A terminal emulator based on GTK and VTE" "$(ofn sakura "${USER_PKGS[*]}")" \
669 simple-scan "Simple scanning utility" "$(ofn simple-scan "${USER_PKGS[*]}")" \
670 simplescreenrecorder "A feature-rich screen recorder" "$(ofn simplescreenrecorder "${USER_PKGS[*]}")" \
671 steam "A popular game distribution platform by Valve" "$(ofn steam "${USER_PKGS[*]}")" \
672 surf "A simple web browser based on WebKit2/GTK+" "$(ofn surf "${USER_PKGS[*]}")" \
673 terminator "Terminal emulator that supports tabs and grids" "$(ofn terminator "${USER_PKGS[*]}")" \
674 termite "A minimal VTE-based terminal emulator" "$(ofn termite "${USER_PKGS[*]}")" \
675 thunar "A modern file manager for the Xfce Desktop Environment" "$(ofn thunar "${USER_PKGS[*]}")" \
676 thunderbird "Standalone mail and news reader from mozilla" "$(ofn thunderbird "${USER_PKGS[*]}")" \
677 tilda "A GTK based drop down terminal for Linux and Unix" "$(ofn tilda "${USER_PKGS[*]}")" \
678 tilix "A tiling terminal emulator for Linux using GTK+ 3" "$(ofn tilix "${USER_PKGS[*]}")" \
679 transmission-cli "Free BitTorrent client CLI" "$(ofn transmission-cli "${USER_PKGS[*]}")" \
680 transmission-gtk "GTK+ Front end for transmission" "$(ofn transmission-gtk "${USER_PKGS[*]}")" \
681 transmission-qt "Qt Front end for transmission" "$(ofn transmission-qt "${USER_PKGS[*]}")" \
682 ttf-anonymous-pro "A family fixed-width fonts designed with code in mind" "$(ofn ttf-anonymous-pro "${USER_PKGS[*]}")" \
683 ttf-fira-code "Monospaced font with programming ligatures" "$(ofn ttf-fira-code "${USER_PKGS[*]}")" \
684 ttf-font-awesome "Iconic font designed for Bootstrap" "$(ofn ttf-font-awesome "${USER_PKGS[*]}")" \
685 ttf-hack "A hand groomed typeface based on Bitstream Vera Mono" "$(ofn ttf-hack "${USER_PKGS[*]}")" \
686 vlc "A free and open source cross-platform multimedia player" "$(ofn vlc "${USER_PKGS[*]}")" \
687 weechat "Fast, light and extensible IRC client" "$(ofn weechat "${USER_PKGS[*]}")" \
688 xapps "Common library for X-Apps project" "$(ofn xapps "${USER_PKGS[*]}")" \
689 xarchiver "A GTK+ frontend to various command line archivers" "$(ofn xarchiver "${USER_PKGS[*]}")" \
690 xed "A small and lightweight text editor. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
691 xfce-terminal "A terminal emulator based in the Xfce Desktop Environment" "$(ofn xfce-terminal "${USER_PKGS[*]}")" \
692 xreader "Document viewer for files like PDF and Postscript. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
693 xterm "The standard terminal emulator for the X window system" "$(ofn xterm "${USER_PKGS[*]}")" \
694 zathura "Minimalistic document viewer" "$(ofn zathura "${USER_PKGS[*]}")"
696 if [[ $USER_PKGS ]]; then
697 for i in $USER_PKGS; do
698 [[ ${PKG_EXT[$i]} && $USER_PKGS != *"${PKG_EXT[$i]}"* ]] && USER_PKGS+=" ${PKG_EXT[$i]}"
705 ###############################################################################
707 # non-essential partitioning helpers called by the user when using the optional
708 # partition menu and selecting a device to edit
712 is_bg_install || return 0
713 local device choice devhash
714 devhash="$(lsblk -f | base64)"
716 part_device || return 1
721 if [[ $DISPLAY && $TERM != 'linux' ]] && hash gparted >/dev/null 2>&1; then
722 dlg choice menu "Edit Partitions" "$_part" \
723 "auto" "Whole device automatic partitioning" \
724 "shrink" "Shrink an existing ext2/3/4 or ntfs partition to make room for a new partition" \
725 "gparted" "GUI front end to parted" \
726 "cfdisk" "Curses based variant of fdisk" \
727 "parted" "GNU partition editor" \
728 "fdisk" "Dialog-driven creation and manipulation of partitions" \
729 "done" "Return to the main menu" || return 0
731 dlg choice menu "Edit Partitions" "$_part" \
732 "auto" "Whole device automatic partitioning" \
733 "shrink" "Shrink an existing ext2/3/4 or ntfs partition to make room for a new partition" \
734 "cfdisk" "Curses based variant of fdisk" \
735 "parted" "GNU partition editor" \
736 "fdisk" "Dialog-driven creation and manipulation of partitions" \
737 "done" "Return to the main menu" || return 0
740 if [[ $choice == 'done' ]]; then
742 elif [[ $choice == 'shrink' ]]; then
743 part_shrink "$device"
744 elif [[ $choice == 'auto' ]]; then
745 local root_size txt table boot_fs
746 root_size=$(lsblk -lno SIZE "$device" | awk 'NR == 1 {
749 print ($1 * 1000 - 512) / 1000 "G"
755 txt="\nWARNING:\n\nALL data on $device will be destroyed and the following partitions will be created\n\n- "
756 if [[ $SYS == 'BIOS' ]]; then
757 table="msdos" boot_fs="ext4"
758 txt+="An $boot_fs boot partition with the boot flag enabled (512M)\n- "
760 table="gpt" boot_fs="fat32"
761 txt+="A $boot_fs efi boot partition (512M)\n- "
763 txt+="An ext4 partition using all remaining space ($root_size)\n\nDo you want to continue?\n"
764 yesno "Auto Partition" "$txt" && msg "Info" "\nGathering device info.\n" 0 && part_auto "$device" "$table" "$boot_fs" "$root_size"
771 if [[ $devhash != "$(lsblk -f | base64)" ]]; then
772 msg "Probing Partitions" "\nInforming the kernel of partition changes using partprobe.\n" 0
773 partprobe >/dev/null 2>&1
774 [[ $choice == 'auto' ]] && return
782 if [[ $IGNORE_DEV ]]; then
783 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk "!/$IGNORE_DEV/"' && /disk|part|lvm|crypt|NAME/')"
785 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk '/disk|part|lvm|crypt|NAME/')"
787 msg "Device Tree" "\n\n$txt\n\n"
792 local device="$1" table="$2" boot_fs="$3" size="$4" dev_info=""
793 dev_info="$(parted -s "$device" print)"
795 msg "Auto Partition" "\nRemoving partitions on $device and setting table to $table\n" 1
798 while read -r PART; do
799 parted -s "$device" rm "$PART" >/dev/null 2>&1
800 done <<< "$(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r)"
802 [[ $(awk '/Table:/ {print $3}' <<< "$dev_info") != "$table" ]] && parted -s "$device" mklabel "$table" >/dev/null 2>&1
804 msg "Auto Partition" "\nCreating a 512M $boot_fs boot partition.\n" 1
805 if [[ $SYS == "BIOS" ]]; then
806 parted -s "$device" mkpart primary "$boot_fs" 1MiB 513MiB >/dev/null 2>&1
808 parted -s "$device" mkpart ESP "$boot_fs" 1MiB 513MiB >/dev/null 2>&1
813 AUTO_BOOT_PART=$(lsblk -lno NAME,TYPE "$device" | awk 'NR==2 {print "/dev/" $1}')
815 if [[ $SYS == "BIOS" ]]; then
816 mkfs.ext4 -q "$AUTO_BOOT_PART" >/dev/null 2>&1
818 mkfs.vfat -F32 "$AUTO_BOOT_PART" >/dev/null 2>&1
821 msg "Auto Partition" "\nCreating a $size ext4 root partition.\n" 0
822 parted -s "$device" mkpart primary ext4 513MiB 100% >/dev/null 2>&1
824 AUTO_ROOT_PART="$(lsblk -lno NAME,TYPE "$device" | awk 'NR==3 {print "/dev/" $1}')"
825 mkfs.ext4 -q "$AUTO_ROOT_PART" >/dev/null 2>&1
827 FORMATTED+="$AUTO_BOOT_PART $AUTO_ROOT_PART "
828 msg "Auto Partition" "\nProcess complete.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$device")\n"
835 local device="$1" fs=""
837 part_find "${device##*/}[^ ]" || return 1
838 (( COUNT == 1 )) && part="$(awk '{print $1}' <<< "${PARTS[@]}" )"
840 if (( COUNT == 1 )) || dlg part menu "Resize" "\nWhich partition on $device do you want to resize?" $PARTS; then
841 fs=$(lsblk -lno FSTYPE "$part")
844 msg "Resize" "\nGathering device size info.\n" 0
846 end=$(parted -s "$device" unit KiB print | awk '/^\s*'"$num"'/ {print $3}') # part size in KiB
847 devsize=$(parted -s "$device" unit KiB print | awk '/Disk '"${device//\//\\/}"':/ {print $3}') # whole device size in KiB
848 mount "$part" $MNT >/dev/null 2>&1; sleep 0.5
849 min=$(df --output=used --block-size=MiB "$part" | awk 'NR == 2 {print int($1) + 256}')
850 max=$(df --output=avail --block-size=MiB "$part" | awk 'NR == 2 {print int($1)}')
853 if dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Resize: $part " --rangebox "$_resize" 17 "$COLUMNS" "$min" "$max" $((max / 2)) 2>$ANS; then
855 size=$((size * 1024))
862 if ntfsresize -fc "$part"; then
863 ntfsresize -ff --size $(( (size * 1024) / 1000 ))k "$part" 2>$ERR # k=10^3 bytes
864 errshow "ntfsresize -f -s $(( (size * 1024) / 1000 ))k $part" || return 1
866 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"
871 e2fsck -f "$part"; sleep 0.5
872 resize2fs -f "$part" ${size}K 2>$ERR # K=2^10 bytes
873 errshow "resize2fs -f $part ${size}K" || return 1
877 parted "$device" resizepart "$num" ${size}KiB || return 1
880 if [[ $devsize == "$end" ]]; then
881 parted -s "$device" mkpart primary ext4 ${size}KiB 100% 2>$ERR
882 errshow "parted -s $device mkpart primary ext4 ${size}KiB 100%" || return 1
884 parted -s "$device" mkpart primary ext4 ${size}KiB ${end}KiB 2>$ERR
885 errshow "parted -s $device mkpart primary ext4 ${size}KiB ${end}KiB" || return 1
887 msg "Resize Complete" "\n$part has been successfully resized to $((size / 1024))M.\n" 1
889 "") msg "No Filesystem" "\nFor unformatted partitions, cfdisk can be used in the partition menu.\n" ;;
890 *) msg "Invalid Filesystem: $fs" "\nResizing only supports ext and ntfs.\n" ;;
895 ###############################################################################
896 # partition management functions
897 # these are helpers for use by other functions to do essential setup/teardown
901 local regexp="$1" err=''
903 # string of partitions as /TYPE/PART SIZE
904 if [[ $IGNORE_DEV ]]; then
905 PARTS="$(lsblk -lno TYPE,NAME,SIZE |
906 awk "/$regexp/"' && !'"/$IGNORE_DEV/"' {
907 sub(/^part/, "/dev/")
908 sub(/^lvm|^crypt/, "/dev/mapper/")
912 PARTS="$(lsblk -lno TYPE,NAME,SIZE |
914 sub(/^part/, "/dev/")
915 sub(/^lvm|^crypt/, "/dev/mapper/")
920 # number of partitions total
922 while read -r line; do
926 # ensure we have enough partitions for the system and action type
928 'part|lvm|crypt') [[ $COUNT -lt 1 || ($SYS == 'UEFI' && $COUNT -lt 2) ]] && err="$_errpart" ;;
929 'part|crypt') (( COUNT < 1 )) && err="$_lvmerr" ;;
930 'part|lvm') (( COUNT < 2 )) && err="$_lukserr" ;;
933 # if there aren't enough partitions show the relevant error message
934 [[ $err ]] && { msg "Not Enough Partitions" "$err" 2; return 1; }
941 if [[ $1 == "$MNT/swapfile" && $SWAP_SIZE ]]; then
942 fallocate -l $SWAP_SIZE "$1" 2>$ERR
943 errshow "fallocate -l $SWAP_SIZE $1"
944 chmod 600 "$1" 2>$ERR
945 errshow "chmod 600 $1"
947 mkswap "$1" >/dev/null 2>$ERR
949 swapon "$1" >/dev/null 2>$ERR
956 local part="$1" mountp="${MNT}$2" fs=""
957 fs="$(lsblk -lno FSTYPE "$part")"
960 if [[ $fs && ${FS_OPTS[$fs]} && $part != "$BOOT_PART" ]] && select_mntopts "$fs"; then
961 mount -o "$MNT_OPTS" "$part" "$mountp" >/dev/null 2>&1
963 mount "$part" "$mountp" >/dev/null 2>&1
966 part_mountconf "$part" "$mountp" || return 1
974 local part="$1" fs="$2" delay="$3"
976 msg "Format" "\nFormatting $part as $fs\n" 0
977 ${FS_CMDS[$fs]} "$part" >/dev/null 2>$ERR
978 errshow "${FS_CMDS[$fs]} $part" || return 1
985 if [[ $DEV_COUNT -eq 1 && $SYS_DEVS ]]; then
986 DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
987 elif (( DEV_COUNT > 1 )); then
989 dlg DEVICE menu "Boot Device" "\nSelect the device to use for bootloader install." $SYS_DEVS
991 dlg DEVICE menu "Select Device" "$_device" $SYS_DEVS
993 [[ $DEVICE ]] || return 1
994 elif [[ $DEV_COUNT -lt 1 && ! $1 ]]; then
995 msg "Device Error" "\nNo available devices.\n\nExiting..\n" 2
999 [[ $1 ]] && BOOT_DEV="$DEVICE"
1006 BOOT_DEV="${BOOT_PART%[1-9]}"
1007 BOOT_PART_NUM="${BOOT_PART: -1}"
1008 [[ $BOOT_PART = /dev/nvme* ]] && BOOT_DEV="${BOOT_PART%p[1-9]}"
1009 if [[ $SYS == 'UEFI' ]]; then
1010 parted -s $BOOT_DEV set $BOOT_PART_NUM esp on >/dev/null 2>&1
1012 parted -s $BOOT_DEV set $BOOT_PART_NUM boot on >/dev/null 2>&1
1019 local part="$1" devs=""
1020 devs="$(lsblk -lno NAME,FSTYPE,TYPE)"
1022 # Identify if $part is LUKS+LVM, LVM+LUKS, LVM alone, or LUKS alone
1023 if lsblk -lno TYPE "$part" | grep -q 'crypt'; then
1025 LUKS_NAME="${part#/dev/mapper/}"
1027 for dev in $(awk '/lvm/ && /crypto_LUKS/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
1028 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1029 LUKS_DEV="$LUKS_DEV cryptdevice=$dev:$LUKS_NAME"
1030 LVM='logical volume'
1035 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
1036 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1037 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
1038 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
1043 elif lsblk -lno TYPE "$part" | grep -q 'lvm'; then
1044 LVM='logical volume'
1045 VNAME="${part#/dev/mapper/}"
1047 for dev in $(awk '/crypt/ && /lvm2_member/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
1048 if lsblk -lno NAME "$dev" | grep -q "$VNAME"; then
1049 LUKS_NAME="${dev/\/dev\/mapper\//}"
1054 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
1055 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1056 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
1057 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
1068 if (( COUNT > 0 )); then
1069 PARTS="$(sed "/${pt//\//\\/}/d" <<< "$PARTS")"
1077 if grep -qw "$1" /proc/mounts; then
1078 msg "Mount Success" "\nPartition $1 mounted at $2\n" 1
1082 msg "Mount Fail" "\nPartition $1 failed to mount at $2\n" 2
1087 ###############################################################################
1089 # mount_menu is the entry point which calls all other functions
1090 # once finished it returns to the main menu: main()
1094 msg "Info" "\nGathering device info.\n" 0
1095 is_bg_install || return 0
1098 part_find 'part|lvm|crypt' || { SEL=2; return 1; }
1100 [[ $LUKS && $LUKS_PART ]] && part_countdec $LUKS_PART
1101 [[ $LVM && $LVM_PARTS ]] && part_countdec $LVM_PARTS
1103 select_root_partition || return 1
1105 if [[ $SYS == 'UEFI' ]]; then
1106 select_efi_partition || { BOOT_PART=''; return 1; }
1107 elif (( COUNT > 0 )); then
1108 select_boot_partition || { BOOT_PART=''; return 1; }
1111 if [[ $BOOT_PART ]]; then
1112 part_mount "$BOOT_PART" "/$BOOTDIR" && SEP_BOOT=true || return 1
1116 select_swap || return 1
1117 select_extra_partitions || return 1
1125 dlg SWAP_PART menu "Swap Setup" "\nSelect whether to use a swapfile, swap partition, or none." \
1126 "none" "Don't allocate any swap space" \
1127 "swapfile" "Allocate $SYS_MEM at /swapfile" \
1130 if [[ -z $SWAP_PART || $SWAP_PART == "none" ]]; then
1133 elif [[ $SWAP_PART == "swapfile" ]]; then
1135 until [[ ${SWAP_SIZE:0:1} =~ [1-9] && ${SWAP_SIZE: -1} =~ (M|G) ]]; do
1136 (( 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
1137 dlg SWAP_SIZE input "Swap Setup" "$_swapsize" "$SYS_MEM" || { SWAP_PART=''; SWAP_SIZE=''; return 1; }
1140 part_swap "$MNT/$SWAP_PART"
1141 SWAP_PART="/$SWAP_PART"
1142 elif [[ $PARTS == *"$SWAP_PART"* ]]; then
1143 part_swap $SWAP_PART
1144 part_countdec $SWAP_PART
1145 SWAP_SIZE="$(lsblk -lno SIZE $SWAP_PART)"
1155 local fs="$1" opts=''
1156 local title="${fs^} Mount Options"
1158 for i in ${FS_OPTS[$fs]}; do
1162 until [[ $MNT_OPTS ]]; do
1163 dlg MNT_OPTS check "$title" "$_mount" $opts
1164 [[ $MNT_OPTS ]] || return 1
1165 MNT_OPTS="${MNT_OPTS// /,}"
1166 yesno "$title" "\nConfirm the following options: $MNT_OPTS\n" || MNT_OPTS=''
1175 until [[ $EXMNT ]]; do
1176 dlg EXMNT input "Extra Mount $part" "$_exmnt" "/" || return 1
1177 if [[ ${EXMNT:0:1} != "/" || ${#EXMNT} -le 1 || $EXMNT =~ \ |\' || $EXMNTS == *"$EXMNT"* ]]; then
1178 msg "Mountpoint Error" "$_errexpart"
1187 local part="$1" fs='' cur=''
1188 local txt="\nSelect which filesystem to use for: $part\n\nDefault: ext4"
1189 cur="$(lsblk -lno FSTYPE "$part" 2>/dev/null)"
1192 if [[ $cur && ($part != "$ROOT_PART" || $FORMATTED == *"$part"*) ]]; then
1193 dlg fs menu "Filesystem" "$txt\nCurrent: $cur" skip - ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1195 dlg fs menu "Filesystem" "$txt" ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1197 [[ $fs == 'skip' ]] && return 0
1198 yesno "Filesystem" "\nFormat $part as $fs?\n" || fs=''
1200 part_format "$part" "$fs"
1203 select_efi_partition()
1205 if [[ $AUTO_BOOT_PART ]]; then
1206 msg "EFI Boot Partition" "\nUsing partition created during automatic format.\n" 2
1207 BOOT_PART="$AUTO_BOOT_PART"; return 0 # were done here
1209 local pts size dev isize bsize ptcount=0
1211 # walk partition list and skip ones that are too small/big for boot
1212 while read -r dev size; do
1213 size_t="${size: -1:1}" # size type eg. K, M, G, T
1214 isize=${size:0:-1} # remove trailing size type character
1215 isize=${isize%.*} # remove any decimal (round down)
1216 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1219 if (( ptcount == 1 )); then
1220 msg "EFI Boot Partition" "\nOnly one partition available that meets size requirements.\n" 1
1221 BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")"
1223 dlg BOOT_PART menu "EFI Partition" "$_uefi" $pts
1227 [[ $BOOT_PART ]] || return 1
1229 if grep -q 'fat' <<< "$(fsck -N "$BOOT_PART")"; then
1230 local txt="\nIMPORTANT:\n\nThe EFI partition $BOOT_PART $_format"
1231 if yesno "Format EFI Partition" "$txt" "Format $BOOT_PART" "Skip Formatting" 1; then
1232 part_format "$BOOT_PART" "vfat" 2
1235 part_format "$BOOT_PART" "vfat" 2
1241 select_boot_partition()
1243 if [[ $AUTO_BOOT_PART && ! $LVM ]]; then
1244 msg "BIOS Boot Partition" "\nUsing partition created during automatic format.\n" 2
1245 BOOT_PART="$AUTO_BOOT_PART"; return 0 # were done here
1247 local pts size dev isize bsize ptcount=0
1249 # walk partition list and skip ones that are too small/big for boot
1250 while read -r dev size; do
1251 size_t="${size: -1:1}" # size type eg. K, M, G, T
1252 isize=${size:0:-1} # remove trailing size type character
1253 isize=${isize%.*} # remove any decimal (round down)
1254 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1257 if [[ $LUKS && ! $LVM ]]; then
1258 dlg BOOT_PART menu "Boot Partition" "$_biosluks" $pts
1259 [[ $BOOT_PART ]] || return 1
1261 dlg BOOT_PART menu "Boot Partition" "$_bios" "skip" "don't use a separate boot" $pts
1262 [[ -z $BOOT_PART || $BOOT_PART == "skip" ]] && { BOOT_PART=''; return 0; }
1266 if grep -q 'ext[34]' <<< "$(fsck -N "$BOOT_PART")"; then
1267 local txt="\nIMPORTANT:\n\nThe boot partition $BOOT_PART $_format"
1268 if yesno "Format Boot Partition" "$txt" "Format $BOOT_PART" "Skip Formatting" 1; then
1269 part_format "$BOOT_PART" "ext4" 2
1272 part_format "$BOOT_PART" "ext4" 2
1277 select_root_partition()
1279 if [[ $AUTO_ROOT_PART && -z $LVM && -z $LUKS ]]; then
1280 ROOT_PART="$AUTO_ROOT_PART"
1281 msg "Select Root Partition (/)" "\nUsing partition created during automatic format.\n" 2
1282 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1283 return 0 # we're done here
1285 local pts size dev isize bsize ptcount=0
1287 # walk partition list and skip ones that are too small for / (root)
1288 while read -r dev size; do
1289 size_t="${size: -1:1}" # size type eg. K, M, G, T
1290 isize=${size:0:-1} # remove trailing size type character
1291 isize=${isize%.*} # remove any decimal (round down)
1292 [[ $size_t =~ [MK] || ($size_t == 'G' && $isize -lt 4) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1295 if (( ptcount == 1 )); then # only one available device
1296 msg "Select Root Partition (/)" "\nOnly one partition available that meets size requirements.\n" 2
1297 ROOT_PART="$(awk 'NR==1 {print $1}' <<< "$pts")"
1299 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
1302 [[ $ROOT_PART ]] || return 1
1304 select_filesystem "$ROOT_PART" || { ROOT_PART=''; return 1; }
1305 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1310 select_extra_partitions()
1314 # walk partition list and skip ones that are too small to be usable
1315 while read -r dev size; do
1316 [[ ${size: -1:1} =~ [KM] ]] && part_countdec "$dev"
1319 while (( COUNT > 0 )); do
1321 dlg part menu 'Mount Extra' "$_expart" 'done' 'finish mounting step' $PARTS || break
1322 if [[ $part == 'done' ]]; then
1324 elif select_filesystem "$part" && select_mountpoint && part_mount "$part" "$EXMNT"; then
1325 EXMNTS+="$part: $EXMNT "
1326 [[ $EXMNT == '/usr' && $HOOKS != *usr* ]] && HOOKS="usr $HOOKS"
1334 ###############################################################################
1336 # main is the entry point which calls all other install functions, once
1337 # complete it shows a dialog to edit files on the new system before reboot
1344 genfstab -U $MNT >$MNT/etc/fstab 2>$ERR
1345 errshow 1 "genfstab -U $MNT >$MNT/etc/fstab"
1346 [[ -f $MNT/swapfile ]] && sed -i "s~${MNT}~~" $MNT/etc/fstab
1350 chrun "hwclock --systohc --utc" || chrun "hwclock --systohc --utc --directisa"
1353 chrun "chown -Rf $NEWUSER:users /home/$NEWUSER"
1356 dlg choice menu "Finalization" "$_edit" \
1357 finished "exit the installer and reboot" \
1358 keyboard "${EDIT_FILES[keyboard]}" \
1359 console "${EDIT_FILES[console]}" \
1360 locale "${EDIT_FILES[locale]}" \
1361 hostname "${EDIT_FILES[hostname]}" \
1362 sudoers "${EDIT_FILES[sudoers]}" \
1363 mkinitcpio "${EDIT_FILES[mkinitcpio]}" \
1364 fstab "${EDIT_FILES[fstab]}" \
1365 crypttab "${EDIT_FILES[crypttab]}" \
1366 bootloader "${EDIT_FILES[bootloader]}" \
1367 pacman "${EDIT_FILES[pacman]}" \
1368 login "${EDIT_FILES[login]}"
1370 if [[ -z $choice || $choice == 'finished' ]]; then
1371 [[ $DEBUG == true && -r $DBG ]] && vim $DBG
1375 for f in ${EDIT_FILES[$choice]}; do
1376 [[ -e ${MNT}$f ]] && exists+=" ${MNT}$f"
1378 if [[ $exists ]]; then
1381 msg "File Missing" "\nThe file(s) selected do not exist:\n\n${EDIT_FILES[$choice]}\n"
1389 if kill -0 "$RSYNC_PID" 2>/dev/null || kill -0 "$MIRROR_PID" 2>/dev/null; then
1390 printf "\nOne or more background install processes are still running, grabbing their output...\n" && cat /tmp/bg_out
1391 while kill -0 "$RSYNC_PID" 2>/dev/null || kill -0 "$MIRROR_PID" 2>/dev/null; do
1396 unset RSYNC_PID MIRROR_PID
1398 rm -rf $MNT/etc/mkinitcpio-archiso.conf
1399 find $MNT/usr/lib/initcpio -name 'archiso*' -type f -delete
1400 sed -i 's/volatile/auto/g' $MNT/etc/systemd/journald.conf
1401 find $MNT/boot -name '*-ucode.img' -delete
1403 if [[ $DIST != "ArchLabs" ]]; then
1404 for f in $MNT/etc/{lsb-release,os-release}; do
1405 sed -i "s/ArchLabs/$DIST/g" $MNT/etc/{lsb-release,os-release}
1410 find $MNT/etc/X11/xorg.conf.d/ -name '*.conf' -delete
1411 elif lspci | grep ' VGA ' | grep -q 'Intel'; then
1412 cat > $MNT/etc/X11/xorg.conf.d/20-intel.conf <<- EOF
1414 Identifier "Intel Graphics"
1416 Option "TearFree" "true"
1421 [[ -e /run/archiso/sfs/airootfs && $KERNEL == 'linux' ]] && cp -vf $RUN/x86_64/vmlinuz $MNT/boot/vmlinuz-linux
1423 cp -fv /etc/resolv.conf $MNT/etc/
1424 [[ -e /etc/NetworkManager/system-connections ]] && cp -rvf /etc/NetworkManager/system-connections $MNT/etc/NetworkManager/
1426 echo "LANG=$MYLOCALE" > $MNT/etc/locale.conf
1427 cp -f $MNT/etc/locale.conf $MNT/etc/default/locale
1428 sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${MYLOCALE}/${MYLOCALE}/g" $MNT/etc/locale.gen
1430 chrun "ln -svf /usr/share/zoneinfo/$ZONE/$SUBZ /etc/localtime"
1432 cat > $MNT/etc/X11/xorg.conf.d/00-keyboard.conf <<- EOF
1433 # Use localectl(1) to instruct systemd-localed to update it.
1434 Section "InputClass"
1435 Identifier "system-keyboard"
1436 MatchIsKeyboard "on"
1437 Option "XkbLayout" "$KEYMAP"
1441 cat > $MNT/etc/default/keyboard <<- EOF
1442 # KEYBOARD CONFIGURATION FILE
1443 # Consult the keyboard(5) manual page.
1450 printf "KEYMAP=%s\nFONT=%s\n" "$CMAP" "$FONT" > $MNT/etc/vconsole.conf
1451 echo "$MYHOST" > $MNT/etc/hostname
1452 cat > $MNT/etc/hosts <<- EOF
1455 ::1 localhost ip6-localhost ip6-loopback
1456 ff02::1 ip6-allnodes
1457 ff02::2 ip6-allrouters
1463 echo "Installing $BOOTLDR"
1465 if [[ $ROOT_PART == /dev/mapper* ]]; then
1466 ROOT_PART_ID="$ROOT_PART"
1468 local uuid_type="UUID"
1469 [[ $BOOTLDR =~ (systemd-boot|refind-efi|efistub) ]] && uuid_type="PARTUUID"
1470 ROOT_PART_ID="$uuid_type=$(blkid -s $uuid_type -o value $ROOT_PART)"
1473 if [[ $SYS == 'UEFI' ]]; then
1474 # remove our old install and generic BOOT/ dir
1475 find $MNT/$BOOTDIR/EFI/ -maxdepth 1 -mindepth 1 -iname "$DIST" -type d -delete
1476 find $MNT/$BOOTDIR/EFI/ -maxdepth 1 -mindepth 1 -iname 'BOOT' -type d -delete
1480 chrun "${BCMDS[$BOOTLDR]}" 2>$ERR
1481 errshow 1 "${BCMDS[$BOOTLDR]}"
1483 if [[ -d $MNT/hostrun ]]; then
1484 # cleanup the bind mounts we made earlier for the grub-probe module
1485 umount_dir $MNT/hostrun/{udev,lvm}
1486 rm -rf $MNT/hostrun >/dev/null 2>&1
1489 if [[ $SYS == 'UEFI' ]]; then
1490 # some UEFI firmware requires a generic esp/BOOT/BOOTX64.EFI
1491 mkdir -pv $MNT/$BOOTDIR/EFI/BOOT
1492 if [[ $BOOTLDR == 'grub' ]]; then
1493 cp -fv $MNT/$BOOTDIR/EFI/$DIST/grubx64.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI
1494 elif [[ $BOOTLDR == 'syslinux' ]]; then
1495 cp -rf $MNT/$BOOTDIR/EFI/syslinux/* $MNT/$BOOTDIR/EFI/BOOT/
1496 cp -f $MNT/$BOOTDIR/EFI/syslinux/syslinux.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI
1497 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1498 sed -i '/#extra_kernel_version_strings/ c extra_kernel_version_strings linux-hardened,linux-zen,linux-lts,linux' $MNT/$BOOTDIR/EFI/refind/refind.conf
1499 cp -fv $MNT/$BOOTDIR/EFI/refind/refind_x64.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI
1508 echo "Creating new user $NEWUSER and setting password"
1509 rm -f $MNT/root/.zshrc # remove welcome message from root zshrc
1511 chrun "chpasswd <<< 'root:$ROOT_PASS'" 2>$ERR
1512 errshow 1 "set root password"
1513 if [[ $MYSHELL != "/usr/bin/zsh" ]]; then # root uses zsh by default, change it if something else was chosen
1514 chrun "usermod -s $MYSHELL root" 2>$ERR
1515 errshow 1 "usermod -s $MYSHELL root"
1516 # copy the default mkshrc to /root if mksh was picked
1517 [[ $MYSHELL == '/usr/bin/mksh' ]] && cp -fv $MNT/etc/skel/.mkshrc $MNT/root/.mkshrc
1520 local groups='audio,floppy,log,network,rfkill,scanner,storage,optical,power,wheel'
1522 chrun "useradd -m -u 1000 -g users -G $groups -s $MYSHELL $NEWUSER" 2>$ERR
1523 errshow 1 "useradd -m -u 1000 -g users -G $groups -s $MYSHELL $NEWUSER"
1524 chrun "chpasswd <<< '$NEWUSER:$USER_PASS'" 2>$ERR
1525 errshow 1 "set $NEWUSER password"
1527 # if neovim was picked copy vim configs to ~/.config/nvim
1528 if [[ $USER_PKGS == *neovim* ]]; then
1529 mkdir -p $MNT/home/$NEWUSER/.config/nvim
1530 cp -fv $MNT/home/$NEWUSER/.vimrc $MNT/home/$NEWUSER/.config/nvim/init.vim
1531 cp -rfv $MNT/home/$NEWUSER/.vim/colors $MNT/home/$NEWUSER/.config/nvim/colors
1534 [[ $INSTALL_WMS == *dwm* ]] && install_suckless
1536 [[ $WM_PKGS == *xfce* ]] && echo 'volumeicon &' >> $MNT/home/$NEWUSER/.xprofile
1538 # remove some commands from ~/.xprofile when using KDE or Gnome as the login session
1539 if [[ $LOGIN_WM =~ (startkde|gnome-session) || ($LOGIN_TYPE =~ (lightdm|ly) && $WM_PKGS =~ (plasma|gnome)) ]]; then
1540 sed -i '/super/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1541 sed -i '/nitrogen/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1542 sed -i '/compton/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1545 # create user home directories (Music, Documents, Downloads, etc..)
1546 chrun 'xdg-user-dirs-update'
1553 local serv="$MNT/etc/systemd/system/getty@tty1.service.d"
1555 echo "Setting up $LOGIN_TYPE"
1558 ly|sddm|gdm|lightdm)
1559 rm -rf "$serv" "$MNT/home/$NEWUSER/.xinitrc"
1560 chrun "systemctl enable $LOGIN_TYPE.service" 2>$ERR
1561 errshow 1 "systemctl enable $LOGIN_TYPE.service"
1562 if [[ $LOGIN_TYPE == 'lightdm' ]]; then
1563 cat > $MNT/etc/lightdm/lightdm-gtk-greeter.conf <<- EOF
1565 default-user-image=/usr/share/icons/ArchLabs-Dark/64x64/places/distributor-logo-archlabs.png
1566 background=/usr/share/backgrounds/archlabs/archlabs.jpg
1567 theme-name=Adwaita-dark
1568 icon-theme-name=Adwaita
1569 font-name=DejaVu Sans Mono 11
1570 position=30%,end 50%,end
1575 if [[ $INSTALL_WMS ]]; then
1576 sed -i "/exec/ c exec ${LOGIN_WM}" "$MNT/home/$NEWUSER/.xinitrc"
1577 elif [[ -e $MNT/home/$NEWUSER/.xinitrc ]]; then
1578 sed -i '/exec/d' "$MNT/home/$NEWUSER/.xinitrc"
1581 if [[ $AUTOLOGIN ]]; then
1582 sed -i "s/root/${NEWUSER}/g" $serv/autologin.conf
1583 cat > "$MNT/home/$NEWUSER/$LOGINRC" <<- EOF
1584 # automatically run startx when logging in on tty1
1585 [ -z \$DISPLAY ] && [ \$XDG_VTNR -eq 1 ] && exec startx
1596 local rmpkg="archlabs-installer "
1597 local inpkg="$BASE_PKGS ${LOGIN_PKGS[$LOGIN_TYPE]} $PACKAGES $USER_PKGS "
1599 # add extra packages chosen throughout the install
1600 if [[ $MYSHELL == '/usr/bin/zsh' ]]; then
1601 inpkg+="zsh-completions "
1604 [[ $MYSHELL == '/usr/bin/mksh' ]] && inpkg+="mksh "
1607 # using a different kernel, remove the stock one
1608 if [[ $KERNEL != 'linux' ]]; then
1613 # gnome, plasma, and cinnamon have their own superkey bind and ksuperkey conflicts
1614 [[ $INSTALL_WMS =~ ^(plasma|gnome|cinnamon)$ ]] || inpkg+="archlabs-ksuperkey "
1616 # window manager only packages
1617 [[ $INSTALL_WMS =~ (openbox|bspwm|i3-gaps|dwm|fluxbox) ]] && inpkg+="$WM_BASE_PKGS "
1619 # ensure a terminal gets installed if one wasn't chosen or a DE that installs one
1620 [[ $inpkg =~ (term|urxvt|tilix|alacritty|sakura|tilda|plasma|cinnamon) || $INSTALL_WMS == *dwm* ]] || inpkg+="xterm "
1622 # update first to avoid issues
1623 chrun "pacman -Syyu --noconfirm"
1625 # remove the packages we don't want on the installed system
1626 [[ $rmpkg ]] && chrun "pacman -Rnsc $rmpkg --noconfirm"
1628 # reinstalling iputils fixes the network issue for non-root users
1629 chrun "pacman -S iputils $UCODE --noconfirm"
1631 # install the packages chosen throughout the install
1632 chrun "pacman -S $inpkg --needed --noconfirm" 2>$ERR
1633 errshow 1 "pacman -S $inpkg --needed --noconfirm"
1635 # bootloader packages
1636 if [[ $BOOTLDR == 'grub' ]]; then
1637 [[ $SYS == 'UEFI' ]] && local efib="efibootmgr"
1638 chrun "pacman -S os-prober grub $efib --needed --noconfirm" 2>$ERR
1639 errshow 1 "pacman -S os-prober grub $efib --needed --noconfirm"
1640 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1641 chrun "pacman -S refind-efi efibootmgr --needed --noconfirm" 2>$ERR
1642 errshow 1 "pacman -S refind-efi efibootmgr --needed --noconfirm"
1643 elif [[ $SYS == 'UEFI' ]]; then
1644 chrun "pacman -S efibootmgr --needed --noconfirm" 2>$ERR
1645 errshow 1 "pacman -S efibootmgr --needed --noconfirm"
1648 # allow members of the wheel group to run commands as root
1649 sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" $MNT/etc/sudoers
1656 mkdir -pv "$MNT/home/$NEWUSER/suckless"
1658 for i in dwm dmenu st; do
1659 if chrun "git clone https://git.suckless.org/$i /home/$NEWUSER/suckless/$i"; then
1660 chrun "cd /home/$NEWUSER/suckless/$i; make PREFIX=/usr install; make clean; rm config.h"
1662 printf "failed to clone %s repo\n" "$i"
1666 if [[ -x $MNT/usr/bin/dwm ]]; then
1667 printf "To configure dwm edit %s\n" "/home/$NEWUSER/suckless/dwm/config.h"
1668 printf "You can then recompile it with 'sudo make clean install'\n"
1673 install_mkinitcpio()
1677 # luks keyfile creation
1678 # currently not used due to not prompting for passphrase on startup
1679 # [[ $LUKS_UUID && $LUKS_PASS && $SYS == 'UEFI' && $BOOTLDR == 'grub' ]] && luks_keyfile
1681 [[ $LUKS ]] && add="encrypt"
1682 [[ $LVM ]] && { [[ $add ]] && add+=" lvm2" || add+="lvm2"; }
1683 sed -i "s/block filesystems/block ${add} filesystems ${HOOKS}/g" $MNT/etc/mkinitcpio.conf
1684 chrun "mkinitcpio -p $KERNEL" 2>$ERR
1685 errshow 1 "mkinitcpio -p $KERNEL"
1688 install_mirrorlist()
1690 local mfile="$1" # output mirrorlist file
1692 if hash reflector >/dev/null 2>&1; then
1693 reflector --verbose --score 80 -l 40 -f 5 --sort rate --save "$mfile"
1694 elif hash rankmirrors >/dev/null 2>&1; then
1695 echo "Sorting mirrorlist"
1696 local key="access_key=5f29642060ab983b31fdf4c2935d8c56"
1697 ip_add="$(curl -fsSL "http://api.ipstack.com/check&?$key&fields=ip" | python -c "import sys, json; print(json.load(sys.stdin)['ip'])")"
1698 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'])")"
1699 if [[ "$country" ]]; then
1700 if [[ $country =~ (CA|US) ]]; then
1701 # use both CA and US mirrors for CA or US countries
1702 mirror="https://www.archlinux.org/mirrorlist/?country=US&country=CA&use_mirror_status=on"
1703 elif [[ $country =~ (AU|NZ) ]]; then
1704 # use both AU and NZ mirrors for AU or NZ countries
1705 mirror="https://www.archlinux.org/mirrorlist/?country=AU&country=NZ&use_mirror_status=on"
1707 mirror="https://www.archlinux.org/mirrorlist/?country=${country}&use_mirror_status=on"
1709 else # no country code so just grab all mirrors, will be a very slow sort but we don't have other options
1710 mirror="https://www.archlinux.org/mirrorlist/?country=all&use_mirror_status=on"
1712 curl -fsSL "$mirror" | sed -e 's/^#Server/Server/' -e '/^#/d' | rankmirrors -n 6 - >"$mfile"
1718 install_background()
1720 msg "Background Install" "\nInstall will now begin in the background?\n" 2
1721 rsync -a /run/archiso/sfs/airootfs/ $MNT/ &
1723 ( install_mirrorlist "$MNT/etc/pacman.d/mirrorlist" >>/tmp/bg_out 2>&1 ) &
1725 # end the background processes before exiting
1726 trap "kill $RSYNC_PID $MIRROR_PID 2>/dev/null" EXIT
1729 ###############################################################################
1731 # prerun_* set up the configs needed before actually running the commands
1732 # setup_* are run after selecting a bootloader and build the command used later
1733 # they can also be used for further user input as these run before control is taken away
1737 EDIT_FILES[bootloader]="/etc/default/grub"
1739 if [[ $SYS == 'BIOS' ]]; then
1740 [[ $BOOT_DEV ]] || { part_device 1 || return 1; }
1741 BCMDS[grub]="grub-install --recheck --force --target=i386-pc $BOOT_DEV"
1743 # since we're not using the keyfile this is dead code
1744 # if [[ $ROOT_PART == */dev/mapper/* && -z $LVM && -z $LUKS_PASS ]]; then
1745 # luks_pass "$_luksopen" 1 || return 1
1747 BCMDS[grub]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1748 grub-install --recheck --force --target=x86_64-efi --efi-directory=/$BOOTDIR --bootloader-id=$DIST"
1749 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1752 BCMDS[grub]="mkdir -p /run/udev /run/lvm &&
1753 mount --bind /hostrun/udev /run/udev &&
1754 mount --bind /hostrun/lvm /run/lvm &&
1756 grub-mkconfig -o /boot/grub/grub.cfg &&
1757 sleep 1 && umount /run/udev /run/lvm"
1764 sed -i "s/GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR=\"${DIST}\"/g; s/GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"\"/g" $MNT/etc/default/grub
1766 if [[ $LUKS_DEV ]]; then
1767 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
1768 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"
1771 if [[ $SYS == 'BIOS' && $LVM && -z $SEP_BOOT ]]; then
1772 sed -i "s/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g" $MNT/etc/default/grub 2>$ERR
1773 errshow 1 "sed -i 's/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g' $MNT/etc/default/grub"
1776 # setup for os-prober module
1777 mkdir -p /run/{lvm,udev} $MNT/hostrun/{lvm,udev}
1778 mount --bind /run/lvm $MNT/hostrun/lvm
1779 mount --bind /run/udev $MNT/hostrun/udev
1786 EDIT_FILES[bootloader]=""
1791 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1792 efibootmgr -v -d $BOOT_DEV -p $BOOT_PART_NUM -c -L '${DIST} Linux' -l /vmlinuz-${KERNEL} \
1793 -u 'root=$ROOT_PART_ID rw $([[ $UCODE ]] && printf 'initrd=\%s.img ' "$UCODE")initrd=\initramfs-${KERNEL}.img'"
1798 if [[ $SYS == 'BIOS' ]]; then
1799 EDIT_FILES[bootloader]="/boot/syslinux/syslinux.cfg"
1801 EDIT_FILES[bootloader]="/boot/EFI/syslinux/syslinux.cfg"
1802 BCMDS[syslinux]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1803 efibootmgr -v -c -d $BOOT_DEV -p $BOOT_PART_NUM -l /EFI/syslinux/syslinux.efi -L $DIST"
1809 local c="$MNT/boot/syslinux" s="/usr/lib/syslinux/bios" d=".."
1810 [[ $SYS == 'UEFI' ]] && { c="$MNT/boot/EFI/syslinux"; s="/usr/lib/syslinux/efi64/"; d=''; }
1812 mkdir -pv "$c" && cp -rfv $s/* "$c/" && cp -f "$RUN/syslinux/splash.png" "$c/"
1813 cat > "$c/syslinux.cfg" <<- EOF
1815 MENU TITLE $DIST Boot Menu
1816 MENU BACKGROUND splash.png
1820 # see: https://www.syslinux.org/wiki/index.php/Comboot/menu.c32
1829 MENU HELPMSGENDROW 29
1830 MENU COLOR border 30;44 #40ffffff #a0000000 std
1831 MENU COLOR title 1;36;44 #9033ccff #a0000000 std
1832 MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
1833 MENU COLOR unsel 37;44 #50ffffff #a0000000 std
1834 MENU COLOR help 37;40 #c0ffffff #a0000000 std
1835 MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
1836 MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
1837 MENU COLOR msg07 37;40 #90ffffff #a0000000 std
1838 MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
1841 MENU LABEL $DIST Linux
1842 LINUX $d/vmlinuz-$KERNEL
1843 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1844 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL.img
1846 LABEL ${DIST}fallback
1847 MENU LABEL $DIST Linux Fallback
1848 LINUX $d/vmlinuz-$KERNEL
1849 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1850 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL-fallback.img
1857 EDIT_FILES[bootloader]="/boot/refind_linux.conf"
1858 BCMDS[refind-efi]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1864 cat > $MNT/boot/refind_linux.conf <<- EOF
1865 "$DIST Linux" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1866 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1867 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL.img"
1868 "$DIST Linux Fallback" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1869 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1870 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL-fallback.img"
1872 mkdir -p $MNT/etc/pacman.d/hooks
1873 cat > $MNT/etc/pacman.d/hooks/refind.hook <<- EOF
1880 Description = Updating rEFInd on ESP
1881 When = PostTransaction
1882 Exec = /usr/bin/refind-install
1886 setup_systemd-boot()
1888 EDIT_FILES[bootloader]="/boot/loader/entries/$DIST.conf"
1889 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1890 bootctl --path=/boot install"
1893 prerun_systemd-boot()
1895 mkdir -p $MNT/boot/loader/entries
1896 cat > $MNT/boot/loader/loader.conf <<- EOF
1901 cat > $MNT/boot/loader/entries/$DIST.conf <<- EOF
1903 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1904 initrd /initramfs-$KERNEL.img
1905 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1907 cat > $MNT/boot/loader/entries/$DIST-fallback.conf <<- EOF
1908 title $DIST Linux Fallback
1909 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1910 initrd /initramfs-$KERNEL-fallback.img
1911 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1913 mkdir -p $MNT/etc/pacman.d/hooks
1914 cat > $MNT/etc/pacman.d/hooks/systemd-boot.hook <<- EOF
1921 Description = Updating systemd-boot
1922 When = PostTransaction
1923 Exec = /usr/bin/bootctl update
1925 systemd-machine-id-setup --root="$MNT"
1929 ###############################################################################
1934 msg "Info" "\nGathering device info.\n" 0
1935 is_bg_install || return 1
1939 dlg choice menu "Logical Volume Management" "$_lvmmenu" \
1940 "$_lvmnew" "vgcreate -f, lvcreate -L -n" \
1941 "$_lvmdel" "vgremove -f" \
1942 "$_lvmdelall" "lvrmeove, vgremove, pvremove -f" \
1943 "back" "return to the main menu"
1945 "$_lvmnew") lvm_create ;;
1946 "$_lvmdel") lvm_delgroup && yesno "$_lvmdel" "$_lvmdelask" && vgremove -f "$DEL_VG" >/dev/null 2>&1 ;;
1947 "$_lvmdelall") lvm_del_all ;;
1958 pv="$(pvs -o pv_name --noheading 2>/dev/null)"
1959 v="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
1960 VGROUP="$(vgs -o vg_name --noheading 2>/dev/null)"
1962 if [[ $VGROUP && $v && $pv ]]; then
1963 msg "Logical Volume Management" "\nActivating existing logical volume management (LVM).\n\n" 1
1964 modprobe dm-mod >/dev/null 2>$ERR
1965 errshow 'modprobe dm-mod'
1966 vgscan >/dev/null 2>&1
1967 vgchange -ay >/dev/null 2>&1
1973 VGROUP='' LVM_PARTS='' VGROUP_MB=0
1975 lvm_mkgroup || return 1
1976 local txt="\nThe last (or only) logical volume will automatically use all remaining space in the volume group."
1977 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 -
1978 [[ $VOL_COUNT ]] || return 1
1979 lvm_extra_lvs || return 1
1980 lvm_volume_name "$_lvmlvname\nNOTE: This LV will use up all remaining space in the volume group (${VGROUP_MB}MB)" || return 1
1981 lvcreate -l +100%FREE "$VGROUP" -n "$VNAME" >/dev/null 2>$ERR
1982 errshow "lvcreate -l +100%FREE $VGROUP -n $VNAME" || return 1
1983 LVM='logical volume'; sleep 0.5
1984 txt="\nDone, volume: $VGROUP-$VNAME (${VOLUME_SIZE:-${VGROUP_MB}MB}) has been created.\n"
1985 msg "$_lvmnew (LV:$VOL_COUNT)" "$txt\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE $LVM_PARTS)\n"
1991 local txt="${VGROUP}: ${SIZE}$SIZE_UNIT (${VGROUP_MB}MB remaining).$_lvmlvsize"
1995 dlg VOLUME_SIZE input "$_lvmnew (LV:$VOL_COUNT)" "$txt" ''
1996 if [[ -z $VOLUME_SIZE ]]; then
1998 break # allow bailing with escape or an empty choice
1999 elif (( ${VOLUME_SIZE:0:1} == 0 )); then
2000 ERR_SIZE=1 # size values can't begin with '0'
2002 # walk the string and make sure all but the last char are digits
2003 local lv=$((${#VOLUME_SIZE} - 1))
2004 for (( i=0; i<lv; i++ )); do
2005 [[ ${VOLUME_SIZE:$i:1} =~ [0-9] ]] || { ERR_SIZE=1; break; }
2007 if (( ERR_SIZE != 1 )); then
2008 case ${VOLUME_SIZE:$lv:1} in
2009 [mMgG]) local s=${VOLUME_SIZE:0:$lv} m=$((s * 1000))
2010 case ${VOLUME_SIZE:$lv:1} in
2011 [Gg]) (( m >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - m)) ;;
2012 [Mm]) (( ${VOLUME_SIZE:0:$lv} >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - s)) ;;
2019 if (( ERR_SIZE )); then
2020 msg "Invalid Logical Volume Size" "$_lvmerrlvsize"
2033 until [[ $named ]]; do
2034 lvm_partitions || return 1
2035 lvm_group_name || return 1
2036 yesno "$_lvmnew" "\nConfirm creation of volume group: $VGROUP\n\nwith the following partition(s): $LVM_PARTS\n" && named=true
2039 msg "$_lvmnew" "\nCreating group: $VGROUP\n" 0
2040 vgcreate -f "$VGROUP" $LVM_PARTS >/dev/null 2>$ERR
2041 errshow "vgcreate -f $VGROUP $LVM_PARTS" || return 1
2043 SIZE=$(vgdisplay "$VGROUP" | awk '/VG Size/ { gsub(/[^0-9.]/, ""); print int($0) }')
2044 SIZE_UNIT="$(vgdisplay "$VGROUP" | awk '/VG Size/ { print substr($NF, 0, 1) }')"
2046 if [[ $SIZE_UNIT == 'G' ]]; then
2047 VGROUP_MB=$((SIZE * 1000))
2052 msg "$_lvmnew" "\nVolume group: $VGROUP (${SIZE}$SIZE_UNIT) has been created\n"
2058 pv="$(pvs -o pv_name --noheading 2>/dev/null)"
2059 v="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
2060 VGROUP="$(vgs -o vg_name --noheading 2>/dev/null)"
2062 if [[ $VGROUP || $v || $pv ]]; then
2063 if yesno "$_lvmdelall" "$_lvmdelask"; then
2064 for i in $v; do lvremove -f "/dev/mapper/$i" >/dev/null 2>&1; done
2065 for i in $VGROUP; do vgremove -f "$i" >/dev/null 2>&1; done
2066 for i in $pv; do pvremove -f "$i" >/dev/null 2>&1; done
2070 msg "Delete LVM" "\nNo LVMs to remove...\n" 2
2080 for i in $(lvs --noheadings | awk '{print $2}' | uniq); do
2081 VOL_GROUP_LIST+="$i $(vgdisplay "$i" | awk '/VG Size/ {print $3$4}') "
2084 [[ $VOL_GROUP_LIST ]] || { msg "No Groups" "\nNo volume groups found."; return 1; }
2086 dlg DEL_VG menu "Logical Volume Management" "\nSelect volume group to delete.\n\nAll logical volumes within will also be deleted." $VOL_GROUP_LIST
2092 while (( VOL_COUNT > 1 )); do
2093 lvm_volume_name "$_lvmlvname" && get_lv_size || return 1
2094 lvcreate -L "$VOLUME_SIZE" "$VGROUP" -n "$VNAME" >/dev/null 2>$ERR
2095 errshow "lvcreate -L $VOLUME_SIZE $VGROUP -n $VNAME" || return 1
2096 msg "$_lvmnew (LV:$VOL_COUNT)" "\nDone, logical volume (LV) $VNAME ($VOLUME_SIZE) has been created.\n"
2104 part_find 'part|crypt' || return 1
2105 PARTS="$(awk 'NF > 0 {print $0 " off"}' <<< "$PARTS")"
2106 dlg LVM_PARTS check "$_lvmnew" "\nSelect the partition(s) to use for the physical volume (PV)." $PARTS
2113 until [[ $VGROUP ]]; do
2114 dlg VGROUP input "$_lvmnew" "$_lvmvgname" "mygroup"
2115 if [[ -z $VGROUP ]]; then
2117 elif [[ ${VGROUP:0:1} == "/" || $VGROUP =~ \ |\' ]] || vgdisplay | grep -q "$VGROUP"; then
2118 msg "LVM Name Error" "$_lvmerrvgname"
2128 local txt="$1" default="mainvolume"
2129 (( VOL_COUNT > 1 )) && default="extravolume$VOL_COUNT"
2130 until [[ $VNAME ]]; do
2131 dlg VNAME input "$_lvmnew (LV:$VOL_COUNT)" "\n$txt" "$default"
2132 if [[ -z $VNAME ]]; then
2134 elif [[ ${VNAME:0:1} == "/" || $VNAME =~ \ |\' ]] || lsblk | grep -q "$VNAME"; then
2135 msg "LVM Name Error" "$_lvmerlvname"
2142 ###############################################################################
2148 is_bg_install || return 1
2149 dlg choice menu "LUKS Encryption" "$_luksmenu" \
2150 "$_luksnew" "cryptsetup -q luksFormat" \
2151 "$_luksopen" "cryptsetup open --type luks" \
2152 "$_luksadv" "cryptsetup -q -s -c luksFormat" \
2153 "back" "Return to the main menu"
2156 "$_luksnew") luks_basic || return 1 ;;
2157 "$_luksopen") luks_open || return 1 ;;
2158 "$_luksadv") luks_advanced || return 1 ;;
2166 modprobe -a dm-mod dm_crypt >/dev/null 2>&1
2168 part_find 'part|crypt|lvm' || return 1
2170 if (( COUNT == 1 )); then
2171 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2173 dlg LUKS_PART menu "$_luksopen" "\nSelect which partition to open." $PARTS
2176 [[ $LUKS_PART ]] || return 1
2178 luks_pass "$_luksopen" || return 1
2179 msg "$_luksopen" "\nOpening encrypted partition: $LUKS_NAME\n\nUsing device/volume: $LUKS_PART\n" 0
2180 cryptsetup open --type luks "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2181 errshow "cryptsetup open --type luks $LUKS_PART $LUKS_NAME" || return 1
2182 LUKS='encrypted'; luks_show
2189 local t="$1" op="$2" v='' p='' p2=''
2191 until [[ $LUKS_PASS ]]; do
2195 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " \
2196 --mixedform "\nEnter the password to decrypt $ROOT_PART\n\nThis is needed to create a keyfile." 0 0 0 \
2197 "Password:" 1 1 '' 1 11 "$COLUMNS" 0 1 \
2198 "Password2:" 2 1 '' 2 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
2201 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " --mixedform "$_luksomenu" 0 0 0 \
2202 "Name:" 1 1 "${LUKS_NAME:-cryptroot}" 1 7 "$COLUMNS" 0 0 \
2203 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
2204 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
2208 while read -r line; do
2224 if [[ -z $op && -z $n ]]; then
2225 msg "Name Empty" "\nEncrypted device name cannot be empty.\n\nPlease try again.\n" 2
2226 elif [[ -z $p || "$p" != "$p2" ]]; then
2227 [[ $op ]] || LUKS_NAME="$n"
2228 msg "Password Mismatch" "\nThe passwords entered do not match.\n\nPlease try again.\n" 2
2230 [[ $op ]] || LUKS_NAME="$n"
2241 msg "$_luksnew" "\nEncrypted partition ready for mounting.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$LUKS_PART")\n\n"
2246 modprobe -a dm-mod dm_crypt >/dev/null 2>&1
2248 part_find 'part|lvm' || return 1
2250 if [[ $AUTO_ROOT_PART ]]; then
2251 LUKS_PART="$AUTO_ROOT_PART"
2252 elif (( COUNT == 1 )); then
2253 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2255 dlg LUKS_PART menu "$_luksnew" "\nSelect the partition you want to encrypt." $PARTS
2258 [[ $LUKS_PART ]] || return 1
2259 luks_pass "$_luksnew"
2264 luks_setup || return 1
2265 msg "$_luksnew" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2266 cryptsetup -q luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2>$ERR
2267 errshow "cryptsetup -q luksFormat $LUKS_PART" || return 1
2268 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2269 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2270 LUKS='encrypted'; luks_show
2276 if [[ ! -e $MNT/crypto_keyfile.bin ]]; then
2277 # printf "Creating LUKS keyfile /crypto_keyfile.bin\n"
2279 n="$(lsblk -lno NAME,UUID,TYPE | awk "/$LUKS_UUID/"' && /part|crypt|lvm/ {print $1}')"
2280 local mkkey="dd bs=512 count=8 if=/dev/urandom of=/crypto_keyfile.bin"
2281 mkkey="$mkkey && chmod 000 /crypto_keyfile.bin"
2282 mkkey="$mkkey && cryptsetup luksAddKey /dev/$n /crypto_keyfile.bin <<< '$LUKS_PASS'"
2284 sed -i 's/FILES=()/FILES=(\/crypto_keyfile.bin)/g' $MNT/etc/mkinitcpio.conf 2>$ERR
2294 dlg cipher input "LUKS Encryption" "$_lukskey" "-s 512 -c aes-xts-plain64"
2295 [[ $cipher ]] || return 1
2296 msg "$_luksadv" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2297 cryptsetup -q $cipher luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2>$ERR
2298 errshow "cryptsetup -q $cipher luksFormat $LUKS_PART" || return 1
2299 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2300 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2307 ###############################################################################
2309 # some help avoid repetition and improve usability of some commands
2310 # others are initial setup functions used before reaching the main loop
2314 # does $2 contain $1
2315 [[ "$2" == *"$1"* ]] && printf "on" || printf "off"
2320 # cleanup and exit the installer cleanly with exit code $1
2321 # when ecode is 127 unmount /run/archiso/bootmnt and reboot
2326 if [[ -d $MNT ]] && command cd /; then
2328 if (( ecode == 127 )); then
2329 umount_dir /run/archiso/bootmnt
2340 local var="$1" # assign output from dialog to var
2341 local dlg_t="$2" # dialog type (menu, check, input)
2342 local title="$3" # dialog title
2343 local body="$4" # dialog message
2344 local n=0 # number of items to display
2346 shift 4 # shift off args assigned above
2348 # when passed a large amount of arguments (menu list) adjust menu height
2349 (( ($# / 2) > SHL )) && n=$SHL
2353 menu) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --menu "$body" 0 0 $n "$@" 2>"$ANS" || return 1 ;;
2354 check) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --checklist "$body" 0 0 $n "$@" 2>"$ANS" || return 1 ;;
2357 local def="$1" # assign default value for input
2359 if [[ $1 == 'limit' ]]; then
2360 dialog --backtitle "$DIST Installer - $SYS - v$VER" --max-input 63 --title " $title " --inputbox "$body" 0 0 "$def" 2>"$ANS" || return 1
2362 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --inputbox "$body" 0 0 "$def" 2>"$ANS" || return 1
2366 # if answer file isn't empty read from it into $var
2367 [[ -s "$ANS" ]] && printf -v "$var" "%s" "$(< "$ANS")"
2372 # displays a message dialog
2373 # when more than 2 args the message will disappear after sleep time ($3)
2379 dialog --backtitle "$DIST Installer - $SYS - v$VER" --sleep "$1" --title " $title " --infobox "$body\n" 0 0
2381 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --msgbox "$body\n" 0 0
2387 local title="$1" body="$2" yes='Yes' no='No'
2388 (( $# >= 3 )) && yes="$3"
2389 (( $# >= 4 )) && no="$4"
2391 if (( $# == 5 )); then
2392 dialog --backtitle "$DIST Installer - $SYS - v$VER" --defaultno --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2394 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2400 arch-chroot "$MNT" bash -c "$1"
2405 export PS4='| ${BASH_SOURCE} LINE:${LINENO} FUNC:${FUNCNAME[0]:+ ${FUNCNAME[0]}()} |> '
2414 printf "\n^C caught, cleaning up...\n"
2421 "\e]P0191919" # #191919
2422 "\e]P1D15355" # #D15355
2423 "\e]P2609960" # #609960
2424 "\e]P3FFCC66" # #FFCC66
2425 "\e]P4255A9B" # #255A9B
2426 "\e]P5AF86C8" # #AF86C8
2427 "\e]P62EC8D3" # #2EC8D3
2428 "\e]P7949494" # #949494
2429 "\e]P8191919" # #191919
2430 "\e]P9D15355" # #D15355
2431 "\e]PA609960" # #609960
2432 "\e]PBFF9157" # #FF9157
2433 "\e]PC4E88CF" # #4E88CF
2434 "\e]PDAF86C8" # #AF86C8
2435 "\e]PE2ec8d3" # #2ec8d3
2436 "\e]PFE1E1E1" # #E1E1E1
2439 [[ $TERM == 'linux' ]] && printf "%b" "${colors[@]}" && clear
2444 [ $? -eq 0 ] && return 0
2446 local fatal=0 err=""
2447 err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
2449 (( $1 == 1 )) && { fatal=1; shift; }
2451 local txt="\nThe command exited abnormally:\n\n$1\n\n"
2454 txt+="With the following message:\n\n$err\n\n"
2456 txt+="With no error message:\n\n"
2459 if (( fatal )); then
2460 txt+="Errors at this stage are fatal and the install cannot continue.\n"
2462 txt+="Errors at this stage are non-fatal and can be either fixed or ignored depending on the error.\n"
2464 msg "Install Error" "$txt"
2466 if (( fatal )); then
2467 [[ -r $DBG && $TERM == 'linux' ]] && less "$DBG"
2478 if (( $1 >= 0 )) && ! grep -qw "$MNT" /proc/mounts; then
2479 msg "Not Mounted" "\nPartition(s) must be mounted first.\n" 2
2481 elif [[ $1 -ge 1 && -z $BOOTLDR ]]; then
2482 msg "No Bootloader" "\nBootloader must be selected first.\n" 2
2484 elif [[ $1 -ge 2 && (-z $NEWUSER || -z $USER_PASS) ]]; then
2485 msg "No User" "\nA user must be created first.\n" 2
2487 elif [[ $1 -ge 3 && -z $CONFIG_DONE ]]; then
2488 msg "Not Configured" "\nSystem configuration must be done first.\n" 2
2491 (( i )) # return code
2496 mount | grep -q 'swap' && swapoff -a
2498 [[ -d $dir && "$(mount | grep "on $dir ")" ]] || continue
2499 umount "$dir" 2>/dev/null || { sleep 0.5; umount -f "$dir" 2>/dev/null || umount -l "$dir"; }
2505 msg "Network Connect" "\nVerifying network connection\n" 1
2506 curl -sIN --connect-timeout 5 'https://www.archlinux.org/' | sed '1q' | grep -q '200'
2511 if chk_connect; then
2514 if hash nmtui >/dev/null 2>&1; then
2516 if [[ $TERM == 'linux' ]]; then
2517 printf "%b" "\e]P1191919" "\e]P4191919"
2519 printf "%b" "\e]P1D15355" "\e]P4255a9b"
2532 [[ $RSYNC_PID || $MIRROR_PID ]] || return 0
2533 msg "Install Running" "\nA background install process is currently running.\n" 2
2539 IGNORE_DEV="$(lsblk -lno NAME,MOUNTPOINT | awk '/\/run\/archiso\/bootmnt/ {sub(/[1-9]/, ""); print $1}')"
2541 if [[ $IGNORE_DEV ]]; then
2542 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ && !'"/$IGNORE_DEV/"' {print "/dev/" $1 " " $2}')"
2544 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ {print "/dev/" $1 " " $2}')"
2547 if [[ -z $SYS_DEVS ]]; then
2548 msg "Device Error" "\nNo available devices...\n\nExiting..\n" 2
2553 while read -r line; do
2555 done <<< "$SYS_DEVS"
2562 elif grep -q 'AuthenticAMD' /proc/cpuinfo; then
2564 elif grep -q 'GenuineIntel' /proc/cpuinfo; then
2568 modprobe -q efivarfs >/dev/null 2>&1
2570 _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."
2571 if [[ -d /sys/firmware/efi/efivars ]]; then
2573 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars
2574 _prep+="\n - An EFI boot partition mounted."
2578 _prep+="\n\nOnce finished mounting, a portion of the install can be done in the background while you continue configuring the system:\n"
2579 _prep+="\n - Choose the system bootloader.\n - Create a user and password."
2580 _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."
2583 ###############################################################################
2586 # enable some nicer colours in the linux console
2589 if (( UID != 0 )); then
2590 msg "Not Root" "\nThis installer must be run as root or using sudo.\n\nExiting..\n" 2
2592 elif ! grep -qwm 1 'lm' /proc/cpuinfo; then
2593 msg "Not x86_64 Architecture" "\nThis installer only supports x86_64 architectures.\n\nExiting..\n" 2
2595 elif [[ $1 =~ (-d|--debug) ]]; then
2599 # trap ^C to perform cleanup
2605 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"
2607 select_keymap || { clear; die 0; }
2608 net_connect || { msg "Not Connected" "\nThis installer requires an active internet connection.\n\nExiting..\n" 2; die 1; }
2614 # vim:fdm=marker:fmr={,}