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 system /boot
115 VM="$(dmesg | grep -i "hypervisor")" # system running in a virtual machine
116 SYS='Unknown' # bios type to be determined: UEFI/BIOS
118 export DIALOGOPTS="--cr-wrap" # see `man dialog`
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)
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 {
167 [cinnamon]='gnome-terminal' # doesn't install a terminal on it's own
168 [plasma]='kdebase-meta' # base plasma application set
169 [awesome]='archlabs-skel-awesome' # see deps of archlabs-skel-awesome
170 [bspwm]='archlabs-skel-bspwm' # see deps of archlabs-skel-bspwm
171 [fluxbox]='archlabs-skel-fluxbox' # see deps of archlabs-skel-fluxbox
172 [i3-gaps]='archlabs-skel-i3-gaps' # see deps of archlabs-skel-i3-gaps
173 [openbox]='archlabs-skel-openbox' # see deps of archlabs-skel-openbox
174 [xfce4]='archlabs-skel-xfce4 xfce4-goodies' # see deps of archlabs-skel-xfce4
177 # files offered for editing after install is complete {
178 declare -A EDIT_FILES=(
179 [login]='' # login is populated once we know the username and shell
181 [sudoers]='/etc/sudoers'
182 [crypttab]='/etc/crypttab'
183 [pacman]='/etc/pacman.conf'
184 [console]='/etc/vconsole.conf'
185 [mkinitcpio]='/etc/mkinitcpio.conf'
186 [hostname]='/etc/hostname /etc/hosts'
187 [bootloader]="/boot/loader/entries/$DIST.conf"
188 [locale]='/etc/locale.conf /etc/default/locale'
189 [keyboard]='/etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard'
192 # mkfs command and flags for filesystem formatting {
197 [ntfs]='mkfs.ntfs -q'
198 [ext2]='mkfs.ext2 -q'
199 [ext3]='mkfs.ext3 -q'
200 [ext4]='mkfs.ext4 -q'
201 [vfat]='mkfs.vfat -F32'
202 [nilfs2]='mkfs.nilfs2 -q'
203 [reiserfs]='mkfs.reiserfs -q'
206 # mount options for each filesystem {
212 [jfs]='discard errors=continue errors=panic nointegrity'
213 [reiserfs]='acl nolog notail replayonly user_xattr off'
214 [ext4]='discard dealloc nofail noacl relatime noatime nobarrier nodelalloc'
215 [xfs]='discard filestreams ikeep largeio noalign nobarrier norecovery noquota wsync'
216 [nilfs2]='discard nobarrier errors=continue errors=panic order=relaxed order=strict norecovery'
217 [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'
220 # packages installed for each login option {
221 declare -A LOGIN_PKGS=(
226 [lightdm]='lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings accountsservice'
229 # extras installed for user selected packages {
230 # if a package requires additional packages that aren't already dependencies
231 # they can be added here eg. [package]="extra"
235 [mupdf]='mupdf-tools'
236 [qt5ct]='qt5-styleplugins'
237 [vlc]='qt5ct qt5-styleplugins'
238 [zathura]='zathura-pdf-poppler'
239 [noto-fonts]='noto-fonts-emoji'
240 [cairo-dock]='cairo-dock-plug-ins'
241 [qutebrowser]='qt5ct qt5-styleplugins'
242 [qbittorrent]='qt5ct qt5-styleplugins'
243 [transmission-qt]='qt5ct qt5-styleplugins'
244 [bluez]='bluez-libs bluez-utils bluez-tools bluez-plugins bluez-hid2hci'
245 [kdenlive]='kdebase-meta dvdauthor frei0r-plugins breeze breeze-gtk qt5ct qt5-styleplugins'
250 # dialog text variables
253 # Basics (somewhat in order)
254 _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"
255 _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"
256 _device="\nSelect a device to use from the list below.\n\nDevices (/dev) are the available drives on the system. /sda, /sdb, /sdc ..."
257 _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."
258 _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."
259 _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"
260 _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)."
261 _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."
262 _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."
263 _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."
264 _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"
265 _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."
266 _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."
267 _exmnt="\nWhere do you want the partition mounted?\n\nEnsure the name begins with a slash (/).\nExamples include: /usr, /home, /var, etc."
268 _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."
269 _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."
270 _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"
271 _timez="\nThe time zone is used to set the system clock.\n\nSelect your country or continent from the list below"
272 _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."
273 _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."
274 _login="\nSelect which of your session choices to use for the initial login.\n\nYou can be change this later by editing your ~/.xinitrc"
275 _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"
276 _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."
277 _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."
280 _luksnew="Basic LUKS Encryption"
281 _luksadv="Advanced LUKS Encryption"
282 _luksopen="Open Existing LUKS Partition"
283 _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."
284 _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."
285 _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)."
288 _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."
289 _lvmnew="Create Volume Group and Volume(s)"
290 _lvmdel="Delete an Existing Volume Group"
291 _lvmdelall="Delete ALL Volume Group(s) and Volume(s)"
292 _lvmvgname="\nEnter a name for the volume group (VG) being created from the partition(s) selected."
293 _lvmlvname="\nEnter a name for the logical volume (LV) being created.\n\nThis is similar to setting a label for a partition."
294 _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."
295 _lvmdelask="\nConfirm deletion of volume group(s) and logical volume(s).\n\nDeleting a volume group, will delete all logical volumes within it.\n"
298 _errexpart="\nCannot mount partition due to a problem with the mountpoint.\n\nEnsure it begins with a slash (/) followed by atleast one character.\n"
299 _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"
300 _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"
301 _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"
302 _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"
303 _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"
304 _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"
310 ###############################################################################
312 # main is the entry point which calls functions including outside of its block
313 # once those functions finished they always are returned here with the
314 # exception of install_main(), it exits upon completion
318 (( SEL < 12 )) && (( SEL++ ))
320 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Prepare " --default-item $SEL --cancel-label 'Exit' --menu "$_prep" 0 0 0 \
321 1 "Device tree (optional)" \
322 2 "Partitioning (optional)" \
323 3 "LUKS setup (optional)" \
324 4 "LVM setup (optional)" \
325 5 "Mount partitions" \
326 6 "System bootloader" \
327 7 "User and password" \
328 8 "System configuration" \
329 9 "Select WM/DE (optional)" \
330 10 "Select Packages (optional)" \
331 11 "View configuration (optional)" \
332 12 "Start the installation" 2>"$ANS"
335 [[ -z $WARN && $SEL =~ (2|5) ]] && { msg "Data Warning" "$_warn"; WARN=true; }
338 2) part_menu || (( SEL-- )) ;;
339 3) luks_menu || (( SEL-- )) ;;
340 4) lvm_menu || (( SEL-- )) ;;
341 5) mount_menu || (( SEL-- )) ;;
342 6) prechecks 0 && { select_boot || (( SEL-- )); } ;;
343 7) prechecks 1 && { select_mkuser || (( SEL-- )); } ;;
344 8) prechecks 2 && { select_config || (( SEL-- )); } ;;
345 9) prechecks 3 && { select_sessions || (( SEL-- )); } ;;
346 10) prechecks 3 && { select_packages || (( SEL-- )); } ;;
347 11) prechecks 3 && select_show ;;
348 12) prechecks 3 && install_main ;;
349 *) yesno "Exit" "\nUnmount partitions (if any) and exit the installer?\n" && die 0
355 if [[ $SYS == 'BIOS' ]]; then
356 dlg BOOTLDR menu "BIOS Bootloader" "\nSelect which bootloader to use." \
357 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
358 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network" || return 1
360 dlg BOOTLDR menu "UEFI Bootloader" "\nSelect which bootloader to use." \
361 "systemd-boot" "A simple UEFI boot manager which executes configured EFI images" \
362 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
363 "refind-efi" "A UEFI boot manager that aims to be platform neutral and simplify multi-boot" \
364 "efistub" "Boot the kernel image directly (no chainloading support)" \
365 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network (no chainloading support)" || return 1
372 local pkgs="${USER_PKGS// / } ${PACKAGES// / }"
373 [[ $BOOT_PART ]] && local mnt="/$BOOTDIR"
374 [[ $INSTALL_WMS == *dwm* ]] && pkgs="dwm st dmenu $pkgs"
375 pkgs="${pkgs// / }" pkgs="${pkgs# }"
376 msg "Show Configuration" "
377 ---------- PARTITION CONFIGURATION ------------
379 Root: ${ROOT_PART:-none}
380 Boot: ${BOOT_PART:-${BOOT_DEV:-none}}
382 Swap: ${SWAP_PART:-none}
383 Size: ${SWAP_SIZE:-none}
384 Extra: ${EXMNTS:-${EXMNT:-none}}
385 Hooks: ${HOOKS:-none}
391 ------------ SYSTEM CONFIGURATION -------------
393 Locale: ${MYLOCALE:-none}
394 Keymap: ${KEYMAP:-none}
395 Hostname: ${MYHOST:-none}
396 Timezone: ${ZONE:-none}/${SUBZ:-none}
399 ------------ USER CONFIGURATION ---------------
401 Username: ${NEWUSER:-none}
402 Login Shell: ${MYSHELL:-none}
403 Login Session: ${LOGIN_WM:-none}
404 Autologin: ${AUTOLOGIN:-none}
405 Login Type: ${LOGIN_TYPE:-none}
408 ----------- PACKAGE CONFIGURATION -------------
410 Kernel: ${KERNEL:-none}
411 Bootloader: ${BOOTLDR:-none}
412 Packages: ${pkgs:-none}
418 [[ $INSTALL_WMS ]] || return 0
420 AUTOLOGIN='' # no autologin unless using xinit
422 if [[ -z $LOGIN_TYPE ]]; then
423 dlg LOGIN_TYPE menu "Login Management" "\nSelect what kind of login management to use." \
424 "xinit" "Console login without a display manager" \
425 "ly" "TUI display manager with a ncurses-like interface" \
426 "lightdm" "Lightweight display manager with a gtk greeter" \
427 "gdm" "Gnome display manager" \
428 "sddm" "Simple desktop display manager" || return 1
432 ly) EDIT_FILES[login]="/etc/ly/config.ini" ;;
433 gdm|sddm) EDIT_FILES[login]="" ;;
434 lightdm) EDIT_FILES[login]="/etc/lightdm/lightdm.conf /etc/lightdm/lightdm-gtk-greeter.conf" ;;
435 xinit) EDIT_FILES[login]="/home/$NEWUSER/.xinitrc /home/$NEWUSER/.xprofile"
436 if (( $(wc -w <<< "$INSTALL_WMS") > 1 )); then
437 dlg LOGIN_WM menu "Login Management" "$_login" $LOGIN_CHOICES || return 1
438 LOGIN_WM="${WM_SESSIONS[$LOGIN_WM]}"
440 [[ -z $LOGIN_WM ]] && LOGIN_WM="${WM_SESSIONS[${INSTALL_WMS%% *}]}"
441 yesno "Autologin" "$(sed "s|USER|$NEWUSER|g; s|RC|$LOGINRC|g" <<< "$_autologin")" && AUTOLOGIN=true || AUTOLOGIN=''
451 until [[ $CONFIG_DONE ]]; do
453 0) dlg MYSHELL menu "Shell" "\nChoose which shell to use." \
454 /usr/bin/zsh 'A very advanced and programmable command interpreter (shell) for UNIX' \
455 /bin/bash 'The GNU Bourne Again shell, standard in many GNU/Linux distributions' \
456 /usr/bin/mksh 'The MirBSD Korn Shell - an enhanced version of the public domain ksh' || return 1
458 1) dlg MYHOST input "Hostname" "$_hostname" "${DIST,,}" limit || { i=0; continue; } ;;
459 2) dlg MYLOCALE menu "Locale" "$_locale" $LOCALES || { i=1; continue; } ;;
461 until [[ $ZONE && $SUBZ ]]; do
462 dlg ZONE menu "Timezone" "$_timez" America - Australia - Asia - Atlantic - Africa - Europe - Indian - Pacific - Arctic - Antarctica - || break
463 dlg SUBZ menu "Timezone" "$_timesubz" $(awk '/'"$ZONE"'\// {gsub(/'"$ZONE"'\//, ""); print $3 " - "}' /usr/share/zoneinfo/zone.tab | sort) || continue
465 [[ $ZONE && $SUBZ ]] || { i=2; continue; } ;;
466 4) dlg KERNEL menu "Kernel" "\nChoose which kernel to use." \
467 linux 'Vanilla linux kernel and modules, with a few patches applied' \
468 linux-lts 'Long-term support (LTS) linux kernel and modules' \
469 linux-zen 'A effort of kernel hackers to provide the best kernel for everyday systems' \
470 linux-hardened 'A security-focused linux kernel with hardening patches to mitigate exploits' || { i=3; continue; }
474 (( i++ )) # progress through to the next choice
477 case $MYSHELL in *bash) LOGINRC='.bash_profile' ;; *zsh) LOGINRC='.zprofile' ;; *mksh) LOGINRC='.profile' ;; esac
485 local v='' u='' p='' p2='' rp='' rp2=''
487 until [[ $NEWUSER ]]; do
490 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " User " --mixedform "$_user" 0 0 0 \
491 "Username:" 1 1 "$u" 1 11 "$COLUMNS" 0 0 \
492 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
493 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 \
494 "--- Root password, if left empty the user password will be used ---" 6 1 '' 6 68 "$COLUMNS" 0 2 \
495 "Password:" 8 1 '' 8 11 "$COLUMNS" 0 1 \
496 "Password2:" 9 1 '' 9 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
498 while read -r line; do
499 case $i in 0) u="$line" ;; 1) p="$line" ;; 2) p2="$line" ;; 3) rp="$line" ;; 4) rp2="$line" ;; esac
503 # root passwords empty, so use the user passwords
504 [[ -z $rp && -z $rp2 ]] && { rp="$p"; rp2="$p2"; }
506 # make sure a username was entered and that the passwords match
507 if [[ ${#u} -eq 0 || $u =~ \ |\' || $u =~ [^a-z0-9] ]]; then
508 msg "Invalid Username" "\nIncorrect user name.\n\nPlease try again.\n"; u=''
509 elif [[ -z $p ]]; then
510 msg "Empty Password" "\nThe user password cannot be left empty.\n\nPlease try again.\n"
511 elif [[ "$p" != "$p2" ]]; then
512 msg "Password Mismatch" "\nThe user passwords do not match.\n\nPlease try again.\n"
513 elif [[ "$rp" != "$rp2" ]]; then
514 msg "Password Mismatch" "\nThe root passwords do not match.\n\nPlease try again.\n"
526 dlg KEYMAP menu "Keyboard Layout" "$_keymap" \
527 us English cm English gb English au English gh English \
528 za English ng English ca French 'cd' French gn French \
529 tg French fr French de German at German ch German \
530 es Spanish latam Spanish br Portuguese pt Portuguese ma Arabic \
531 sy Arabic ara Arabic ua Ukrainian cz Czech ru Russian \
532 sk Slovak nl Dutch it Italian hu Hungarian cn Chinese \
533 tw Taiwanese vn Vietnamese kr Korean jp Japanese th Thai \
534 la Lao pl Polish se Swedish is Icelandic 'fi' Finnish \
535 dk Danish be Belgian in Indian al Albanian am Armenian \
536 bd Bangla ba Bosnian 'bg' Bulgarian dz Berber mm Burmese \
537 hr Croatian gr Greek il Hebrew ir Persian iq Iraqi \
538 af Afghani fo Faroese ge Georgian ee Estonian kg Kyrgyz \
539 kz Kazakh lt Lithuanian mt Maltese mn Mongolian ro Romanian \
540 no Norwegian rs Serbian si Slovenian tj Tajik lk Sinhala \
541 tr Turkish uz Uzbek ie Irish pk Urdu 'mv' Dhivehi \
542 np Nepali et Amharic sn Wolof ml Bambara tz Swahili \
543 ke Swahili bw Tswana ph Filipino my Malay tm Turkmen \
544 id Indonesian bt Dzongkha lv Latvian md Moldavian mao Maori \
545 by Belarusian az Azerbaijani mk Macedonian kh Khmer epo Esperanto \
546 me Montenegrin || return 1
548 if [[ $CMAPS == *"$KEYMAP"* ]]; then
551 dlg CMAP menu "Console Keymap" "$_vconsole" $CMAPS || return 1
554 if [[ $DISPLAY && $TERM != 'linux' ]]; then
555 setxkbmap "$KEYMAP" >/dev/null 2>&1
557 loadkeys "$CMAP" >/dev/null 2>&1
567 dlg INSTALL_WMS check "Sessions" "$_sessions\n" \
568 i3-gaps "A fork of i3wm with more features including gaps" "$(ofn i3-gaps "${INSTALL_WMS[*]}")" \
569 openbox "A lightweight, powerful, and highly configurable stacking wm" "$(ofn openbox "${INSTALL_WMS[*]}")" \
570 awesome "A customized Awesome WM session created by @elanapan" "$(ofn awesome "${INSTALL_WMS[*]}")" \
571 dwm "A dynamic WM for X that manages windows in tiled, floating, or monocle layouts" "$(ofn dwm "${INSTALL_WMS[*]}")" \
572 bspwm "A tiling wm that represents windows as the leaves of a binary tree" "$(ofn bspwm "${INSTALL_WMS[*]}")" \
573 fluxbox "A lightweight and highly-configurable window manager" "$(ofn fluxbox "${INSTALL_WMS[*]}")" \
574 gnome "A desktop environment that aims to be simple and easy to use" "$(ofn gnome "${INSTALL_WMS[*]}")" \
575 cinnamon "A desktop environment combining traditional desktop with modern effects" "$(ofn cinnamon "${INSTALL_WMS[*]}")" \
576 plasma "A kde software project currently comprising a full desktop environment" "$(ofn plasma "${INSTALL_WMS[*]}")" \
577 xfce4 "A lightweight and modular desktop environment based on gtk+2/3" "$(ofn xfce4 "${INSTALL_WMS[*]}")"
579 [[ $INSTALL_WMS ]] || return 0
581 WM_PKGS="${INSTALL_WMS/dwm/}" # remove dwm from package list
582 WM_PKGS="${WM_PKGS// / }" # remove double spaces
583 WM_PKGS="${WM_PKGS# }" # remove leading space
585 # add archlabs base when choosing any session
586 [[ $WM_PKGS ]] && WM_PKGS+=" $AL_BASE_PKGS"
588 for i in $INSTALL_WMS; do
589 LOGIN_CHOICES+="$i - "
590 [[ ${WM_EXT[$i]} && $WM_PKGS != *"${WM_EXT[$i]}"* ]] && WM_PKGS+=" ${WM_EXT[$i]}"
593 select_login || return 1
595 while IFS=' ' read -r pkg; do
596 [[ $PACKAGES != *"$pkg"* ]] && PACKAGES+=" $pkg"
604 dlg USER_PKGS check " Packages " "$_packages" \
605 abiword "A Fully-featured word processor" "$(ofn abiword "${USER_PKGS[*]}")" \
606 alacritty "A cross-platform, GPU-accelerated terminal emulator" "$(ofn alacritty "${USER_PKGS[*]}")" \
607 atom "An open-source text editor developed by GitHub" "$(ofn atom "${USER_PKGS[*]}")" \
608 audacious "A free and advanced audio player based on GTK+" "$(ofn audacious "${USER_PKGS[*]}")" \
609 audacity "A program that lets you manipulate digital audio waveforms" "$(ofn audacity "${USER_PKGS[*]}")" \
610 blueman "GUI bluetooth device manager" "$(ofn blueman "${USER_PKGS[*]}")" \
611 bluez "Simple CLI based bluetooth support" "$(ofn bluez "${USER_PKGS[*]}")" \
612 cairo-dock "Light eye-candy fully themable animated dock" "$(ofn cairo-dock "${USER_PKGS[*]}")" \
613 calligra "A set of applications for productivity" "$(ofn calligra "${USER_PKGS[*]}")" \
614 chromium "An open-source web browser based on the Blink rendering engine" "$(ofn chromium "${USER_PKGS[*]}")" \
615 clementine "A modern music player and library organizer" "$(ofn clementine "${USER_PKGS[*]}")" \
616 cmus "A small, fast and powerful console music player" "$(ofn cmus "${USER_PKGS[*]}")" \
617 deadbeef "A GTK+ audio player for GNU/Linux" "$(ofn deadbeef "${USER_PKGS[*]}")" \
618 deluge "A BitTorrent client written in python" "$(ofn deluge "${USER_PKGS[*]}")" \
619 docky "Full fledged dock for opening applications and managing windows" "$(ofn docky "${USER_PKGS[*]}")" \
620 emacs "An extensible, customizable, self-documenting real-time display editor" "$(ofn emacs "${USER_PKGS[*]}")" \
621 epiphany "A GNOME web browser based on the WebKit rendering engine" "$(ofn epiphany "${USER_PKGS[*]}")" \
622 evince "A document viewer" "$(ofn evince "${USER_PKGS[*]}")" \
623 evolution "Manage your email, contacts and schedule" "$(ofn evolution "${USER_PKGS[*]}")" \
624 file-roller "Create and modify archives" "$(ofn file-roller "${USER_PKGS[*]}")" \
625 firefox "A popular open-source web browser from Mozilla" "$(ofn firefox "${USER_PKGS[*]}")" \
626 gcolor2 "A simple GTK+2 color selector" "$(ofn gcolor2 "${USER_PKGS[*]}")" \
627 geany "A fast and lightweight IDE" "$(ofn geany "${USER_PKGS[*]}")" \
628 geary "A lightweight email client for the GNOME desktop" "$(ofn geary "${USER_PKGS[*]}")" \
629 gimp "GNU Image Manipulation Program" "$(ofn gimp "${USER_PKGS[*]}")" \
630 gnome-calculator "GNOME Scientific calculator" "$(ofn gnome-calculator "${USER_PKGS[*]}")" \
631 gnome-disk-utility "Disk Management Utility" "$(ofn gnome-disk-utility "${USER_PKGS[*]}")" \
632 gnome-system-monitor "View current processes and monitor system state" "$(ofn gnome-system-monitor "${USER_PKGS[*]}")" \
633 gparted "A GUI frontend for creating and manipulating partition tables" "$(ofn gparted "${USER_PKGS[*]}")" \
634 gpick "Advanced color picker using GTK+ toolkit" "$(ofn gpick "${USER_PKGS[*]}")" \
635 gpicview "Lightweight image viewer" "$(ofn gpicview "${USER_PKGS[*]}")" \
636 guvcview "Capture video from camera devices" "$(ofn guvcview "${USER_PKGS[*]}")" \
637 hexchat "A popular and easy to use graphical IRC client" "$(ofn hexchat "${USER_PKGS[*]}")" \
638 inkscape "Professional vector graphics editor" "$(ofn inkscape "${USER_PKGS[*]}")" \
639 irssi "Modular text mode IRC client" "$(ofn irssi "${USER_PKGS[*]}")" \
640 kdenlive "A popular non-linear video editor for Linux" "$(ofn kdenlive "${USER_PKGS[*]}")" \
641 krita "Edit and paint images" "$(ofn krita "${USER_PKGS[*]}")" \
642 libreoffice-fresh "Full featured office suite" "$(ofn libreoffice-fresh "${USER_PKGS[*]}")" \
643 lollypop "A new music playing application" "$(ofn lollypop "${USER_PKGS[*]}")" \
644 mousepad "A simple text editor" "$(ofn mousepad "${USER_PKGS[*]}")" \
645 mpd "A flexible, powerful, server-side application for playing music" "$(ofn mpd "${USER_PKGS[*]}")" \
646 mpv "A media player based on mplayer" "$(ofn mpv "${USER_PKGS[*]}")" \
647 mupdf "Lightweight PDF and XPS viewer" "$(ofn mupdf "${USER_PKGS[*]}")" \
648 mutt "Small but very powerful text-based mail client" "$(ofn mutt "${USER_PKGS[*]}")" \
649 nautilus "The default file manager for Gnome" "$(ofn nautilus "${USER_PKGS[*]}")" \
650 ncmpcpp "A mpd client and almost exact clone of ncmpc with some new features" "$(ofn ncmpcpp "${USER_PKGS[*]}")" \
651 neovim "A fork of Vim aiming to improve user experience, plugins, and GUIs." "$(ofn neovim "${USER_PKGS[*]}")" \
652 nicotine+ "A graphical client for Soulseek" "$(ofn nicotine+ "${USER_PKGS[*]}")" \
653 noto-fonts "Google Noto fonts" "$(ofn noto-fonts "${USER_PKGS[*]}")" \
654 noto-fonts-cjk "Google Noto CJK fonts (Chinese, Japanese, Korean)" "$(ofn noto-fonts-cjk "${USER_PKGS[*]}")" \
655 obs-studio "Free opensource streaming/recording software" "$(ofn obs-studio "${USER_PKGS[*]}")" \
656 openshot "An open-source, non-linear video editor for Linux" "$(ofn openshot "${USER_PKGS[*]}")" \
657 opera "A Fast and secure, free of charge web browser from Opera Software" "$(ofn opera "${USER_PKGS[*]}")" \
658 pcmanfm "A fast and lightweight file manager based in Lxde" "$(ofn pcmanfm "${USER_PKGS[*]}")" \
659 pidgin "Multi-protocol instant messaging client" "$(ofn pidgin "${USER_PKGS[*]}")" \
660 plank "An elegant, simple, and clean dock" "$(ofn plank "${USER_PKGS[*]}")" \
661 qbittorrent "An advanced BitTorrent client" "$(ofn qbittorrent "${USER_PKGS[*]}")" \
662 qpdfview "A tabbed PDF viewer" "$(ofn qpdfview "${USER_PKGS[*]}")" \
663 qt5ct "GUI for managing Qt based application themes, icons, and fonts" "$(ofn qt5ct "${USER_PKGS[*]}")" \
664 qutebrowser "A keyboard-focused vim-like web browser based on Python and PyQt5" "$(ofn qutebrowser "${USER_PKGS[*]}")" \
665 rhythmbox "A Music playback and management application" "$(ofn rhythmbox "${USER_PKGS[*]}")" \
666 rxvt-unicode "A unicode enabled rxvt-clone terminal emulator" "$(ofn rxvt-unicode "${USER_PKGS[*]}")" \
667 sakura "A terminal emulator based on GTK and VTE" "$(ofn sakura "${USER_PKGS[*]}")" \
668 simple-scan "Simple scanning utility" "$(ofn simple-scan "${USER_PKGS[*]}")" \
669 simplescreenrecorder "A feature-rich screen recorder" "$(ofn simplescreenrecorder "${USER_PKGS[*]}")" \
670 steam "A popular game distribution platform by Valve" "$(ofn steam "${USER_PKGS[*]}")" \
671 surf "A simple web browser based on WebKit2/GTK+" "$(ofn surf "${USER_PKGS[*]}")" \
672 terminator "Terminal emulator that supports tabs and grids" "$(ofn terminator "${USER_PKGS[*]}")" \
673 termite "A minimal VTE-based terminal emulator" "$(ofn termite "${USER_PKGS[*]}")" \
674 thunar "A modern file manager for the Xfce Desktop Environment" "$(ofn thunar "${USER_PKGS[*]}")" \
675 thunderbird "Standalone mail and news reader from mozilla" "$(ofn thunderbird "${USER_PKGS[*]}")" \
676 tilda "A GTK based drop down terminal for Linux and Unix" "$(ofn tilda "${USER_PKGS[*]}")" \
677 tilix "A tiling terminal emulator for Linux using GTK+ 3" "$(ofn tilix "${USER_PKGS[*]}")" \
678 transmission-cli "Free BitTorrent client CLI" "$(ofn transmission-cli "${USER_PKGS[*]}")" \
679 transmission-gtk "GTK+ Front end for transmission" "$(ofn transmission-gtk "${USER_PKGS[*]}")" \
680 transmission-qt "Qt Front end for transmission" "$(ofn transmission-qt "${USER_PKGS[*]}")" \
681 ttf-anonymous-pro "A family fixed-width fonts designed with code in mind" "$(ofn ttf-anonymous-pro "${USER_PKGS[*]}")" \
682 ttf-fira-code "Monospaced font with programming ligatures" "$(ofn ttf-fira-code "${USER_PKGS[*]}")" \
683 ttf-font-awesome "Iconic font designed for Bootstrap" "$(ofn ttf-font-awesome "${USER_PKGS[*]}")" \
684 ttf-hack "A hand groomed typeface based on Bitstream Vera Mono" "$(ofn ttf-hack "${USER_PKGS[*]}")" \
685 vlc "A free and open source cross-platform multimedia player" "$(ofn vlc "${USER_PKGS[*]}")" \
686 weechat "Fast, light and extensible IRC client" "$(ofn weechat "${USER_PKGS[*]}")" \
687 xapps "Common library for X-Apps project" "$(ofn xapps "${USER_PKGS[*]}")" \
688 xarchiver "A GTK+ frontend to various command line archivers" "$(ofn xarchiver "${USER_PKGS[*]}")" \
689 xed "A small and lightweight text editor. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
690 xfce-terminal "A terminal emulator based in the Xfce Desktop Environment" "$(ofn xfce-terminal "${USER_PKGS[*]}")" \
691 xreader "Document viewer for files like PDF and Postscript. X-Apps Project." "$(ofn xed "${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 no_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" && msg "Info" "\nGathering device info.\n" 1 && part_auto "$device" "$table" "$boot_fs" "$root_size"
770 if [[ $devhash != "$(lsblk -f | base64)" ]]; then
771 msg "Probing Partitions" "\nInforming kernel of partition changes using partprobe\n" 0
772 partprobe >/dev/null 2>&1
773 [[ $choice == 'auto' ]] && return
781 if [[ $IGNORE_DEV ]]; then
782 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk "!/$IGNORE_DEV/"' && /disk|part|lvm|crypt|NAME/')"
784 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk '/disk|part|lvm|crypt|NAME/')"
786 msg "Device Tree" "\n\n$txt\n\n"
791 local device="$1" table="$2" boot_fs="$3" size="$4" dev_info=""
792 dev_info="$(parted -s "$device" print)"
794 msg "Auto Partition" "\nRemoving partitions on $device and setting table to $table\n" 1
797 while read -r PART; do
798 parted -s "$device" rm "$PART" >/dev/null 2>&1
799 done <<< "$(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r)"
801 [[ $(awk '/Table:/ {print $3}' <<< "$dev_info") != "$table" ]] && parted -s "$device" mklabel "$table" >/dev/null 2>&1
803 msg "Auto Partition" "\nCreating a 512M $boot_fs boot partition.\n" 1
804 if [[ $SYS == "BIOS" ]]; then
805 parted -s "$device" mkpart primary "$boot_fs" 1MiB 513MiB >/dev/null 2>&1
807 parted -s "$device" mkpart ESP "$boot_fs" 1MiB 513MiB >/dev/null 2>&1
812 AUTO_BOOT_PART=$(lsblk -lno NAME,TYPE "$device" | awk 'NR==2 {print "/dev/" $1}')
814 if [[ $SYS == "BIOS" ]]; then
815 mkfs.ext4 -q "$AUTO_BOOT_PART" >/dev/null 2>&1
817 mkfs.vfat -F32 "$AUTO_BOOT_PART" >/dev/null 2>&1
820 msg "Auto Partition" "\nCreating a $size ext4 root partition.\n" 0
821 parted -s "$device" mkpart primary ext4 513MiB 100% >/dev/null 2>&1
823 AUTO_ROOT_PART="$(lsblk -lno NAME,TYPE "$device" | awk 'NR==3 {print "/dev/" $1}')"
824 mkfs.ext4 -q "$AUTO_ROOT_PART" >/dev/null 2>&1
826 FORMATTED+="$AUTO_BOOT_PART $AUTO_ROOT_PART "
827 msg "Auto Partition" "\nProcess complete.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$device")\n"
834 local device="$1" fs=""
836 part_find "${device##*/}[^ ]" || return 1
837 (( COUNT == 1 )) && part="$(awk '{print $1}' <<< "${PARTS[@]}" )"
839 if (( COUNT == 1 )) || dlg part menu "Resize" "\nWhich partition on $device do you want to resize?" $PARTS; then
840 fs=$(lsblk -lno FSTYPE "$part")
843 msg "Resize" "\nGathering device size info.\n" 0
845 end=$(parted -s "$device" unit KiB print | awk '/^\s*'"$num"'/ {print $3}') # part size in KiB
846 devsize=$(parted -s "$device" unit KiB print | awk '/Disk '"${device//\//\\/}"':/ {print $3}') # whole device size in KiB
847 mount "$part" $MNT >/dev/null 2>&1; sleep 0.5
848 min=$(df --output=used --block-size=MiB "$part" | awk 'NR == 2 {print int($1) + 256}')
849 max=$(df --output=avail --block-size=MiB "$part" | awk 'NR == 2 {print int($1)}')
852 if dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Resize: $part " --rangebox "$_resize" 17 "$COLUMNS" "$min" "$max" $((max / 2)) 2>$ANS; then
854 size=$((size * 1024))
861 if ntfsresize -fc "$part"; then
862 ntfsresize -ff --size $(( (size * 1024) / 1000 ))k "$part" 2>$ERR # k=10^3 bytes
863 errshow "ntfsresize -f -s $(( (size * 1024) / 1000 ))k $part" || return 1
865 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"
870 e2fsck -f "$part"; sleep 0.5
871 resize2fs -f "$part" ${size}K 2>$ERR # K=2^10 bytes
872 errshow "resize2fs -f $part ${size}K" || return 1
876 parted "$device" resizepart "$num" ${size}KiB || return 1
879 if [[ $devsize == "$end" ]]; then
880 parted -s "$device" mkpart primary ext4 ${size}KiB 100% 2>$ERR
881 errshow "parted -s $device mkpart primary ext4 ${size}KiB 100%" || return 1
883 parted -s "$device" mkpart primary ext4 ${size}KiB ${end}KiB 2>$ERR
884 errshow "parted -s $device mkpart primary ext4 ${size}KiB ${end}KiB" || return 1
886 msg "Resize Complete" "\n$part has been successfully resized to $((size / 1024))M.\n" 1
888 "") msg "No Filesystem" "\nFor unformatted partitions, cfdisk can be used in the partition menu.\n" ;;
889 *) msg "Invalid Filesystem: $fs" "\nResizing only supports ext and ntfs.\n" ;;
894 ###############################################################################
895 # partition management functions
896 # these are helpers for use by other functions to do essential setup/teardown
900 local regexp="$1" err=''
902 # string of partitions as /TYPE/PART SIZE
903 if [[ $IGNORE_DEV ]]; then
904 PARTS="$(lsblk -lno TYPE,NAME,SIZE |
905 awk "/$regexp/"' && !'"/$IGNORE_DEV/"' {
906 sub(/^part/, "/dev/")
907 sub(/^lvm|^crypt/, "/dev/mapper/")
911 PARTS="$(lsblk -lno TYPE,NAME,SIZE |
913 sub(/^part/, "/dev/")
914 sub(/^lvm|^crypt/, "/dev/mapper/")
919 # number of partitions total
921 while read -r line; do
925 # ensure we have enough partitions for the system and action type
927 'part|lvm|crypt') [[ $COUNT -lt 1 || ($SYS == 'UEFI' && $COUNT -lt 2) ]] && err="$_errpart" ;;
928 'part|crypt') (( COUNT < 1 )) && err="$_lvmerr" ;;
929 'part|lvm') (( COUNT < 2 )) && err="$_lukserr" ;;
932 # if there aren't enough partitions show the relevant error message
933 [[ $err ]] && { msg "Not Enough Partitions" "$err" 2; return 1; }
940 if [[ $1 == "$MNT/swapfile" && $SWAP_SIZE ]]; then
941 fallocate -l $SWAP_SIZE "$1" 2>$ERR
942 errshow "fallocate -l $SWAP_SIZE $1"
943 chmod 600 "$1" 2>$ERR
944 errshow "chmod 600 $1"
946 mkswap "$1" >/dev/null 2>$ERR
948 swapon "$1" >/dev/null 2>$ERR
955 local part="$1" mountp="${MNT}$2" fs=""
956 fs="$(lsblk -lno FSTYPE "$part")"
959 if [[ $fs && ${FS_OPTS[$fs]} && $part != "$BOOT_PART" ]] && select_mntopts "$fs"; then
960 mount -o "$MNT_OPTS" "$part" "$mountp" >/dev/null 2>&1
962 mount "$part" "$mountp" >/dev/null 2>&1
965 part_mountconf "$part" "$mountp" || return 1
973 local part="$1" fs="$2" delay="$3"
975 msg "Format" "\nFormatting $part as $fs\n" 0
976 ${FS_CMDS[$fs]} "$part" >/dev/null 2>$ERR
977 errshow "${FS_CMDS[$fs]} $part" || return 1
984 if [[ $DEV_COUNT -eq 1 && $SYS_DEVS ]]; then
985 DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
986 elif (( DEV_COUNT > 1 )); then
988 dlg DEVICE menu "Boot Device" "\nSelect the device to use for bootloader install." $SYS_DEVS
990 dlg DEVICE menu "Select Device" "$_device" $SYS_DEVS
992 [[ $DEVICE ]] || return 1
993 elif [[ $DEV_COUNT -lt 1 && ! $1 ]]; then
994 msg "Device Error" "\nNo available devices.\n\nExiting..\n" 2
998 [[ $1 ]] && BOOT_DEV="$DEVICE"
1005 BOOT_DEV="${BOOT_PART%[1-9]}"
1006 BOOT_PART_NUM="${BOOT_PART: -1}"
1007 [[ $BOOT_PART = /dev/nvme* ]] && BOOT_DEV="${BOOT_PART%p[1-9]}"
1008 if [[ $SYS == 'UEFI' ]]; then
1009 parted -s $BOOT_DEV set $BOOT_PART_NUM esp on >/dev/null 2>&1
1011 parted -s $BOOT_DEV set $BOOT_PART_NUM boot on >/dev/null 2>&1
1018 local part="$1" devs=""
1019 devs="$(lsblk -lno NAME,FSTYPE,TYPE)"
1021 # Identify if $part is LUKS+LVM, LVM+LUKS, LVM alone, or LUKS alone
1022 if lsblk -lno TYPE "$part" | grep -q 'crypt'; then
1024 LUKS_NAME="${part#/dev/mapper/}"
1026 for dev in $(awk '/lvm/ && /crypto_LUKS/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
1027 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1028 LUKS_DEV="$LUKS_DEV cryptdevice=$dev:$LUKS_NAME"
1029 LVM='logical volume'
1034 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
1035 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1036 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
1037 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
1042 elif lsblk -lno TYPE "$part" | grep -q 'lvm'; then
1043 LVM='logical volume'
1044 VNAME="${part#/dev/mapper/}"
1046 for dev in $(awk '/crypt/ && /lvm2_member/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
1047 if lsblk -lno NAME "$dev" | grep -q "$VNAME"; then
1048 LUKS_NAME="${dev/\/dev\/mapper\//}"
1053 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
1054 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1055 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
1056 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
1067 if (( COUNT > 0 )); then
1068 PARTS="$(sed "/${pt//\//\\/}/d" <<< "$PARTS")"
1076 if grep -qw "$1" /proc/mounts; then
1077 msg "Mount Success" "\nPartition $1 mounted at $2\n" 1
1081 msg "Mount Fail" "\nPartition $1 failed to mount at $2\n" 2
1086 ###############################################################################
1088 # mount_menu is the entry point which calls all other functions
1089 # once finished it returns to the main menu: main()
1093 msg "Info" "\nGathering device info.\n" 0
1094 no_bg_install || return 0
1097 part_find 'part|lvm|crypt' || { SEL=2; return 1; }
1099 [[ $LUKS && $LUKS_PART ]] && part_countdec $LUKS_PART
1100 [[ $LVM && $LVM_PARTS ]] && part_countdec $LVM_PARTS
1102 select_root_partition || return 1
1104 if [[ $SYS == 'UEFI' ]]; then
1105 select_efi_partition || { BOOT_PART=''; return 1; }
1106 elif (( COUNT > 0 )); then
1107 select_boot_partition || { BOOT_PART=''; return 1; }
1110 if [[ $BOOT_PART ]]; then
1111 part_mount "$BOOT_PART" "/$BOOTDIR" && SEP_BOOT=true || return 1
1115 select_swap || return 1
1116 select_extra_partitions || return 1
1124 dlg SWAP_PART menu "Swap Setup" "\nSelect whether to use a swapfile, swap partition, or none." \
1125 "none" "Don't allocate any swap space" \
1126 "swapfile" "Allocate $SYS_MEM at /swapfile" \
1129 if [[ -z $SWAP_PART || $SWAP_PART == "none" ]]; then
1132 elif [[ $SWAP_PART == "swapfile" ]]; then
1134 until [[ ${SWAP_SIZE:0:1} =~ [1-9] && ${SWAP_SIZE: -1} =~ (M|G) ]]; do
1135 (( 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
1136 dlg SWAP_SIZE input "Swap Setup" "$_swapsize" "$SYS_MEM" || { SWAP_PART=''; SWAP_SIZE=''; return 1; }
1139 part_swap "$MNT/$SWAP_PART"
1140 SWAP_PART="/$SWAP_PART"
1141 elif [[ $PARTS == *"$SWAP_PART"* ]]; then
1142 part_swap $SWAP_PART
1143 part_countdec $SWAP_PART
1144 SWAP_SIZE="$(lsblk -lno SIZE $SWAP_PART)"
1154 local fs="$1" opts=''
1155 local title="${fs^} Mount Options"
1157 for i in ${FS_OPTS[$fs]}; do
1161 until [[ $MNT_OPTS ]]; do
1162 dlg MNT_OPTS check "$title" "$_mount" $opts
1163 [[ $MNT_OPTS ]] || return 1
1164 MNT_OPTS="${MNT_OPTS// /,}"
1165 yesno "$title" "\nConfirm the following options: $MNT_OPTS\n" || MNT_OPTS=''
1174 until [[ $EXMNT ]]; do
1175 dlg EXMNT input "Extra Mount $part" "$_exmnt" "/" || return 1
1176 if [[ ${EXMNT:0:1} != "/" || ${#EXMNT} -le 1 || $EXMNT =~ \ |\' || $EXMNTS == *"$EXMNT"* ]]; then
1177 msg "Mountpoint Error" "$_errexpart"
1186 local part="$1" fs='' cur=''
1187 local txt="\nSelect which filesystem to use for: $part\n\nDefault: ext4"
1188 cur="$(lsblk -lno FSTYPE "$part" 2>/dev/null)"
1191 if [[ $cur && ($part != "$ROOT_PART" || $FORMATTED == *"$part"*) ]]; then
1192 dlg fs menu "Filesystem" "$txt\nCurrent: $cur" skip - ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1194 dlg fs menu "Filesystem" "$txt" ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1196 [[ $fs == 'skip' ]] && return 0
1197 yesno "Filesystem" "\nFormat $part as $fs?\n" || fs=''
1199 part_format "$part" "$fs"
1202 select_efi_partition()
1204 if [[ $AUTO_BOOT_PART ]]; then
1205 msg "EFI Boot Partition" "\nUsing partition created during automatic format.\n" 2
1206 BOOT_PART="$AUTO_BOOT_PART"; return 0 # were done here
1208 local pts size dev isize bsize ptcount=0
1210 # walk partition list and skip ones that are too small/big for boot
1211 while read -r dev size; do
1212 size_t="${size: -1:1}" # size type eg. K, M, G, T
1213 isize=${size:0:-1} # remove trailing size type character
1214 isize=${isize%.*} # remove any decimal (round down)
1215 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1218 if (( ptcount == 1 )); then
1219 msg "EFI Boot Partition" "\nOnly one partition available that meets size requirements.\n" 1
1220 BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")"
1222 dlg BOOT_PART menu "EFI Partition" "$_uefi" $pts
1226 [[ $BOOT_PART ]] || return 1
1228 if grep -q 'fat' <<< "$(fsck -N "$BOOT_PART")"; then
1229 local txt="\nIMPORTANT:\n\nThe EFI partition $BOOT_PART $_format"
1230 if yesno "Format EFI Partition" "$txt" "Format $BOOT_PART" "Skip Formatting" 1; then
1231 part_format "$BOOT_PART" "vfat" 2
1234 part_format "$BOOT_PART" "vfat" 2
1240 select_boot_partition()
1242 if [[ $AUTO_BOOT_PART && ! $LVM ]]; then
1243 msg "BIOS Boot Partition" "\nUsing partition created during automatic format.\n" 2
1244 BOOT_PART="$AUTO_BOOT_PART"; return 0 # were done here
1246 local pts size dev isize bsize ptcount=0
1248 # walk partition list and skip ones that are too small/big for boot
1249 while read -r dev size; do
1250 size_t="${size: -1:1}" # size type eg. K, M, G, T
1251 isize=${size:0:-1} # remove trailing size type character
1252 isize=${isize%.*} # remove any decimal (round down)
1253 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1256 if [[ $LUKS && ! $LVM ]]; then
1257 dlg BOOT_PART menu "Boot Partition" "$_biosluks" $pts
1258 [[ $BOOT_PART ]] || return 1
1260 dlg BOOT_PART menu "Boot Partition" "$_bios" "skip" "don't use a separate boot" $pts
1261 [[ -z $BOOT_PART || $BOOT_PART == "skip" ]] && { BOOT_PART=''; return 0; }
1265 if grep -q 'ext[34]' <<< "$(fsck -N "$BOOT_PART")"; then
1266 local txt="\nIMPORTANT:\n\nThe boot partition $BOOT_PART $_format"
1267 if yesno "Format Boot Partition" "$txt" "Format $BOOT_PART" "Skip Formatting" 1; then
1268 part_format "$BOOT_PART" "ext4" 2
1271 part_format "$BOOT_PART" "ext4" 2
1276 select_root_partition()
1278 if [[ $AUTO_ROOT_PART && -z $LVM && -z $LUKS ]]; then
1279 ROOT_PART="$AUTO_ROOT_PART"
1280 msg "Select Root Partition (/)" "\nUsing partition created during automatic format.\n" 2
1281 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1282 return 0 # we're done here
1284 local pts size dev isize bsize ptcount=0
1286 # walk partition list and skip ones that are too small for / (root)
1287 while read -r dev size; do
1288 size_t="${size: -1:1}" # size type eg. K, M, G, T
1289 isize=${size:0:-1} # remove trailing size type character
1290 isize=${isize%.*} # remove any decimal (round down)
1291 [[ $size_t =~ [MK] || ($size_t == 'G' && $isize -lt 4) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1294 if (( ptcount == 1 )); then # only one available device
1295 msg "Select Root Partition (/)" "\nOnly one partition available that meets size requirements.\n" 2
1296 ROOT_PART="$(awk 'NR==1 {print $1}' <<< "$pts")"
1298 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
1301 [[ $ROOT_PART ]] || return 1
1303 select_filesystem "$ROOT_PART" || { ROOT_PART=''; return 1; }
1304 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1309 select_extra_partitions()
1313 # walk partition list and skip ones that are too small to be usable
1314 while read -r dev size; do
1315 [[ ${size: -1:1} =~ [KM] ]] && part_countdec "$dev"
1318 while (( COUNT > 0 )); do
1320 dlg part menu 'Mount Extra' "$_expart" 'done' 'finish mounting step' $PARTS || break
1321 if [[ $part == 'done' ]]; then
1323 elif select_filesystem "$part" && select_mountpoint && part_mount "$part" "$EXMNT"; then
1324 EXMNTS+="$part: $EXMNT "
1325 [[ $EXMNT == '/usr' && $HOOKS != *usr* ]] && HOOKS="usr $HOOKS"
1333 ###############################################################################
1335 # main is the entry point which calls all other install functions, once
1336 # complete it shows a dialog to edit files on the new system before reboot
1343 genfstab -U $MNT >$MNT/etc/fstab 2>$ERR
1344 errshow 1 "genfstab -U $MNT >$MNT/etc/fstab"
1345 [[ -f $MNT/swapfile ]] && sed -i "s~${MNT}~~" $MNT/etc/fstab
1349 chrun "hwclock --systohc --utc" || chrun "hwclock --systohc --utc --directisa"
1352 chrun "chown -Rf $NEWUSER:users /home/$NEWUSER"
1355 dlg choice menu "Finalization" "$_edit" \
1356 finished "exit the installer and reboot" \
1357 keyboard "${EDIT_FILES[keyboard]}" \
1358 console "${EDIT_FILES[console]}" \
1359 locale "${EDIT_FILES[locale]}" \
1360 hostname "${EDIT_FILES[hostname]}" \
1361 sudoers "${EDIT_FILES[sudoers]}" \
1362 mkinitcpio "${EDIT_FILES[mkinitcpio]}" \
1363 fstab "${EDIT_FILES[fstab]}" \
1364 crypttab "${EDIT_FILES[crypttab]}" \
1365 bootloader "${EDIT_FILES[bootloader]}" \
1366 pacman "${EDIT_FILES[pacman]}" \
1367 login "${EDIT_FILES[login]}"
1369 if [[ -z $choice || $choice == 'finished' ]]; then
1370 [[ $DEBUG == true && -r $DBG ]] && vim $DBG
1374 for f in ${EDIT_FILES[$choice]}; do
1375 [[ -e ${MNT}$f ]] && exists+=" ${MNT}$f"
1377 if [[ $exists ]]; then
1380 msg "File Missing" "\nThe file(s) selected do not exist:\n\n${EDIT_FILES[$choice]}\n"
1388 if kill -0 "$RSYNC_PID" 2>/dev/null || kill -0 "$MIRROR_PID" 2>/dev/null; then
1389 printf "\nOne or more background install processes are still running, grabbing their output...\n" && cat /tmp/bg_out
1390 while kill -0 "$RSYNC_PID" 2>/dev/null || kill -0 "$MIRROR_PID" 2>/dev/null; do
1395 unset RSYNC_PID MIRROR_PID
1397 rm -rf $MNT/etc/mkinitcpio-archiso.conf
1398 find $MNT/usr/lib/initcpio -name 'archiso*' -type f -delete
1399 sed -i 's/volatile/auto/g' $MNT/etc/systemd/journald.conf
1400 find $MNT/boot -name '*-ucode.img' -delete
1402 if [[ $DIST != "ArchLabs" ]]; then
1403 for f in $MNT/etc/{lsb-release,os-release}; do
1404 sed -i "s/ArchLabs/$DIST/g" $MNT/etc/{lsb-release,os-release}
1409 find $MNT/etc/X11/xorg.conf.d/ -name '*.conf' -delete
1410 elif lspci | grep ' VGA ' | grep -q 'Intel'; then
1411 cat > $MNT/etc/X11/xorg.conf.d/20-intel.conf <<- EOF
1413 Identifier "Intel Graphics"
1415 Option "TearFree" "true"
1420 [[ -e /run/archiso/sfs/airootfs && $KERNEL == 'linux' ]] && cp -vf $RUN/x86_64/vmlinuz $MNT/boot/vmlinuz-linux
1422 cp -fv /etc/resolv.conf $MNT/etc/
1423 [[ -e /etc/NetworkManager/system-connections ]] && cp -rvf /etc/NetworkManager/system-connections $MNT/etc/NetworkManager/
1425 echo "LANG=$MYLOCALE" > $MNT/etc/locale.conf
1426 cp -f $MNT/etc/locale.conf $MNT/etc/default/locale
1427 sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${MYLOCALE}/${MYLOCALE}/g" $MNT/etc/locale.gen
1429 chrun "ln -svf /usr/share/zoneinfo/$ZONE/$SUBZ /etc/localtime"
1431 cat > $MNT/etc/X11/xorg.conf.d/00-keyboard.conf <<- EOF
1432 # Use localectl(1) to instruct systemd-localed to update it.
1433 Section "InputClass"
1434 Identifier "system-keyboard"
1435 MatchIsKeyboard "on"
1436 Option "XkbLayout" "$KEYMAP"
1440 cat > $MNT/etc/default/keyboard <<- EOF
1441 # KEYBOARD CONFIGURATION FILE
1442 # Consult the keyboard(5) manual page.
1449 printf "KEYMAP=%s\nFONT=%s\n" "$CMAP" "$FONT" > $MNT/etc/vconsole.conf
1450 echo "$MYHOST" > $MNT/etc/hostname
1451 cat > $MNT/etc/hosts <<- EOF
1454 ::1 localhost ip6-localhost ip6-loopback
1455 ff02::1 ip6-allnodes
1456 ff02::2 ip6-allrouters
1462 echo "Installing $BOOTLDR"
1464 if [[ $ROOT_PART == /dev/mapper* ]]; then
1465 ROOT_PART_ID="$ROOT_PART"
1467 local uuid_type="UUID"
1468 [[ $BOOTLDR =~ (systemd-boot|refind-efi|efistub) ]] && uuid_type="PARTUUID"
1469 ROOT_PART_ID="$uuid_type=$(blkid -s $uuid_type -o value $ROOT_PART)"
1472 if [[ $SYS == 'UEFI' ]]; then
1473 # remove our old install and generic BOOT/ dir
1474 find $MNT/$BOOTDIR/EFI/ -maxdepth 1 -mindepth 1 -iname "$DIST" -type d -delete
1475 find $MNT/$BOOTDIR/EFI/ -maxdepth 1 -mindepth 1 -iname 'BOOT' -type d -delete
1479 chrun "${BCMDS[$BOOTLDR]}" 2>$ERR
1480 errshow 1 "${BCMDS[$BOOTLDR]}"
1482 if [[ -d $MNT/hostrun ]]; then
1483 # cleanup the bind mounts we made earlier for the grub-probe module
1484 umount_dir $MNT/hostrun/{udev,lvm}
1485 rm -rf $MNT/hostrun >/dev/null 2>&1
1488 if [[ $SYS == 'UEFI' ]]; then
1489 # some UEFI firmware requires a generic esp/BOOT/BOOTX64.EFI
1490 mkdir -pv $MNT/$BOOTDIR/EFI/BOOT
1491 if [[ $BOOTLDR == 'grub' ]]; then
1492 cp -fv $MNT/$BOOTDIR/EFI/$DIST/grubx64.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI
1493 elif [[ $BOOTLDR == 'syslinux' ]]; then
1494 cp -rf $MNT/$BOOTDIR/EFI/syslinux/* $MNT/$BOOTDIR/EFI/BOOT/
1495 cp -f $MNT/$BOOTDIR/EFI/syslinux/syslinux.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI
1496 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1497 sed -i '/#extra_kernel_version_strings/ c extra_kernel_version_strings linux-hardened,linux-zen,linux-lts,linux' $MNT/$BOOTDIR/EFI/refind/refind.conf
1498 cp -fv $MNT/$BOOTDIR/EFI/refind/refind_x64.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI
1507 echo "Creating new user $NEWUSER and setting password"
1508 rm -f $MNT/root/.zshrc # remove welcome message from root zshrc
1510 chrun "chpasswd <<< 'root:$ROOT_PASS'" 2>$ERR
1511 errshow 1 "set root password"
1512 if [[ $MYSHELL != "/usr/bin/zsh" ]]; then # root uses zsh by default, change it if something else was chosen
1513 chrun "usermod -s $MYSHELL root" 2>$ERR
1514 errshow 1 "usermod -s $MYSHELL root"
1515 # copy the default mkshrc to /root if mksh was picked
1516 [[ $MYSHELL == '/usr/bin/mksh' ]] && cp -fv $MNT/etc/skel/.mkshrc $MNT/root/.mkshrc
1519 local groups='audio,floppy,log,network,rfkill,scanner,storage,optical,power,wheel'
1521 chrun "useradd -m -u 1000 -g users -G $groups -s $MYSHELL $NEWUSER" 2>$ERR
1522 errshow 1 "useradd -m -u 1000 -g users -G $groups -s $MYSHELL $NEWUSER"
1523 chrun "chpasswd <<< '$NEWUSER:$USER_PASS'" 2>$ERR
1524 errshow 1 "set $NEWUSER password"
1526 # if neovim was picked copy vim configs to ~/.config/nvim
1527 if [[ $USER_PKGS == *neovim* ]]; then
1528 mkdir -p $MNT/home/$NEWUSER/.config/nvim
1529 cp -fv $MNT/home/$NEWUSER/.vimrc $MNT/home/$NEWUSER/.config/nvim/init.vim
1530 cp -rfv $MNT/home/$NEWUSER/.vim/colors $MNT/home/$NEWUSER/.config/nvim/colors
1533 [[ $INSTALL_WMS == *dwm* ]] && install_suckless
1535 [[ $WM_PKGS == *xfce* ]] && echo 'volumeicon &' >> $MNT/home/$NEWUSER/.xprofile
1537 # remove some commands from ~/.xprofile when using KDE or Gnome as the login session
1538 if [[ $LOGIN_WM =~ (startkde|gnome-session) || ($LOGIN_TYPE =~ (lightdm|ly) && $WM_PKGS =~ (plasma|gnome)) ]]; then
1539 sed -i '/super/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1540 sed -i '/nitrogen/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1541 sed -i '/compton/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1544 # create user home directories (Music, Documents, Downloads, etc..)
1545 chrun 'xdg-user-dirs-update'
1552 local serv="$MNT/etc/systemd/system/getty@tty1.service.d"
1554 echo "Setting up $LOGIN_TYPE"
1557 ly|sddm|gdm|lightdm)
1558 rm -rf "$serv" "$MNT/home/$NEWUSER/.xinitrc"
1559 chrun "systemctl enable $LOGIN_TYPE.service" 2>$ERR
1560 errshow 1 "systemctl enable $LOGIN_TYPE.service"
1561 if [[ $LOGIN_TYPE == 'lightdm' ]]; then
1562 cat > $MNT/etc/lightdm/lightdm-gtk-greeter.conf <<- EOF
1564 default-user-image=/usr/share/icons/ArchLabs-Dark/64x64/places/distributor-logo-archlabs.png
1565 background=/usr/share/backgrounds/archlabs/archlabs.jpg
1566 theme-name=Adwaita-dark
1567 icon-theme-name=Adwaita
1568 font-name=DejaVu Sans Mono 11
1569 position=30%,end 50%,end
1574 if [[ $INSTALL_WMS ]]; then
1575 sed -i "/exec/ c exec ${LOGIN_WM}" "$MNT/home/$NEWUSER/.xinitrc"
1576 elif [[ -e $MNT/home/$NEWUSER/.xinitrc ]]; then
1577 sed -i '/exec/d' "$MNT/home/$NEWUSER/.xinitrc"
1580 if [[ $AUTOLOGIN ]]; then
1581 sed -i "s/root/${NEWUSER}/g" $serv/autologin.conf
1582 cat > "$MNT/home/$NEWUSER/$LOGINRC" <<- EOF
1583 # automatically run startx when logging in on tty1
1584 [ -z \$DISPLAY ] && [ \$XDG_VTNR -eq 1 ] && exec startx
1595 local rmpkg="archlabs-installer "
1596 local inpkg="$BASE_PKGS ${LOGIN_PKGS[$LOGIN_TYPE]} $PACKAGES $USER_PKGS "
1598 # add extra packages chosen throughout the install
1599 if [[ $MYSHELL == '/usr/bin/zsh' ]]; then
1600 inpkg+="zsh-completions "
1603 [[ $MYSHELL == '/usr/bin/mksh' ]] && inpkg+="mksh "
1606 # using a different kernel, remove the stock one
1607 if [[ $KERNEL != 'linux' ]]; then
1612 # gnome, plasma, and cinnamon have their own superkey bind and ksuperkey conflicts
1613 [[ $INSTALL_WMS =~ ^(plasma|gnome|cinnamon)$ ]] || inpkg+="archlabs-ksuperkey "
1615 # window manager only packages
1616 [[ $INSTALL_WMS =~ (openbox|bspwm|i3-gaps|dwm|fluxbox) ]] && inpkg+="$WM_BASE_PKGS "
1618 # ensure a terminal gets installed if one wasn't chosen or a DE that installs one
1619 [[ $inpkg =~ (term|urxvt|tilix|alacritty|sakura|tilda|plasma|cinnamon) || $INSTALL_WMS == *dwm* ]] || inpkg+="xterm "
1621 # update first to avoid issues
1622 chrun "pacman -Syyu --noconfirm"
1624 # remove the packages we don't want on the installed system
1625 [[ $rmpkg ]] && chrun "pacman -Rnsc $rmpkg --noconfirm"
1627 # reinstalling iputils fixes the network issue for non-root users
1628 chrun "pacman -S iputils $UCODE --noconfirm"
1630 # install the packages chosen throughout the install
1631 chrun "pacman -S $inpkg --needed --noconfirm" 2>$ERR
1632 errshow 1 "pacman -S $inpkg --needed --noconfirm"
1634 # bootloader packages
1635 if [[ $BOOTLDR == 'grub' ]]; then
1636 [[ $SYS == 'UEFI' ]] && local efib="efibootmgr"
1637 chrun "pacman -S os-prober grub $efib --needed --noconfirm" 2>$ERR
1638 errshow 1 "pacman -S os-prober grub $efib --needed --noconfirm"
1639 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1640 chrun "pacman -S refind-efi efibootmgr --needed --noconfirm" 2>$ERR
1641 errshow 1 "pacman -S refind-efi efibootmgr --needed --noconfirm"
1642 elif [[ $SYS == 'UEFI' ]]; then
1643 chrun "pacman -S efibootmgr --needed --noconfirm" 2>$ERR
1644 errshow 1 "pacman -S efibootmgr --needed --noconfirm"
1647 # allow members of the wheel group to run commands as root
1648 sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" $MNT/etc/sudoers
1655 mkdir -pv "$MNT/home/$NEWUSER/suckless"
1657 for i in dwm dmenu st; do
1658 if chrun "git clone https://git.suckless.org/$i /home/$NEWUSER/suckless/$i"; then
1659 chrun "cd /home/$NEWUSER/suckless/$i; make PREFIX=/usr install; make clean; rm config.h"
1661 printf "failed to clone %s repo\n" "$i"
1665 if [[ -x $MNT/usr/bin/dwm ]]; then
1666 printf "To configure dwm edit %s\n" "/home/$NEWUSER/suckless/dwm/config.h"
1667 printf "You can then recompile it with 'sudo make clean install'\n"
1672 install_mkinitcpio()
1676 # luks keyfile creation
1677 # currently not used due to not prompting for passphrase on startup
1678 # [[ $LUKS_UUID && $LUKS_PASS && $SYS == 'UEFI' && $BOOTLDR == 'grub' ]] && luks_keyfile
1680 [[ $LUKS ]] && add="encrypt"
1681 [[ $LVM ]] && { [[ $add ]] && add+=" lvm2" || add+="lvm2"; }
1682 sed -i "s/block filesystems/block ${add} filesystems ${HOOKS}/g" $MNT/etc/mkinitcpio.conf
1683 chrun "mkinitcpio -p $KERNEL" 2>$ERR
1684 errshow 1 "mkinitcpio -p $KERNEL"
1687 install_mirrorlist()
1689 local mfile="$1" # output mirrorlist file
1691 if hash reflector >/dev/null 2>&1; then
1692 reflector --verbose --score 80 -l 40 -f 5 --sort rate --save "$mfile"
1693 elif hash rankmirrors >/dev/null 2>&1; then
1694 echo "Sorting mirrorlist"
1695 local key="access_key=5f29642060ab983b31fdf4c2935d8c56"
1696 ip_add="$(curl -fsSL "http://api.ipstack.com/check&?$key&fields=ip" | python -c "import sys, json; print(json.load(sys.stdin)['ip'])")"
1697 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'])")"
1698 if [[ "$country" ]]; then
1699 if [[ $country =~ (CA|US) ]]; then
1700 # use both CA and US mirrors for CA or US countries
1701 mirror="https://www.archlinux.org/mirrorlist/?country=US&country=CA&use_mirror_status=on"
1702 elif [[ $country =~ (AU|NZ) ]]; then
1703 # use both AU and NZ mirrors for AU or NZ countries
1704 mirror="https://www.archlinux.org/mirrorlist/?country=AU&country=NZ&use_mirror_status=on"
1706 mirror="https://www.archlinux.org/mirrorlist/?country=${country}&use_mirror_status=on"
1708 else # no country code so just grab all mirrors, will be a very slow sort but we don't have other options
1709 mirror="https://www.archlinux.org/mirrorlist/?country=all&use_mirror_status=on"
1711 curl -fsSL "$mirror" | sed -e 's/^#Server/Server/' -e '/^#/d' | rankmirrors -n 6 - >"$mfile"
1717 install_background()
1719 msg "Background Install" "\nInstall will now begin in the background?\n" 2
1720 rsync -a /run/archiso/sfs/airootfs/ $MNT/ &
1722 ( install_mirrorlist "$MNT/etc/pacman.d/mirrorlist" >>/tmp/bg_out 2>&1 ) &
1724 # end the background processes before exiting
1725 trap "kill $RSYNC_PID $MIRROR_PID 2>/dev/null" EXIT
1728 ###############################################################################
1730 # prerun_* set up the configs needed before actually running the commands
1731 # setup_* are run after selecting a bootloader and build the command used later
1732 # they can also be used for further user input as these run before control is taken away
1736 EDIT_FILES[bootloader]="/etc/default/grub"
1738 if [[ $SYS == 'BIOS' ]]; then
1739 [[ $BOOT_DEV ]] || { part_device 1 || return 1; }
1740 BCMDS[grub]="grub-install --recheck --force --target=i386-pc $BOOT_DEV"
1742 # since we're not using the keyfile this is dead code
1743 # if [[ $ROOT_PART == */dev/mapper/* && -z $LVM && -z $LUKS_PASS ]]; then
1744 # luks_pass "$_luksopen" 1 || return 1
1746 BCMDS[grub]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1747 grub-install --recheck --force --target=x86_64-efi --efi-directory=/$BOOTDIR --bootloader-id=$DIST"
1748 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1751 BCMDS[grub]="mkdir -p /run/udev /run/lvm &&
1752 mount --bind /hostrun/udev /run/udev &&
1753 mount --bind /hostrun/lvm /run/lvm &&
1755 grub-mkconfig -o /boot/grub/grub.cfg &&
1756 sleep 1 && umount /run/udev /run/lvm"
1763 sed -i "s/GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR=\"${DIST}\"/g; s/GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"\"/g" $MNT/etc/default/grub
1765 if [[ $LUKS_DEV ]]; then
1766 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
1767 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"
1770 if [[ $SYS == 'BIOS' && $LVM && -z $SEP_BOOT ]]; then
1771 sed -i "s/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g" $MNT/etc/default/grub 2>$ERR
1772 errshow 1 "sed -i 's/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g' $MNT/etc/default/grub"
1775 # setup for os-prober module
1776 mkdir -p /run/{lvm,udev} $MNT/hostrun/{lvm,udev}
1777 mount --bind /run/lvm $MNT/hostrun/lvm
1778 mount --bind /run/udev $MNT/hostrun/udev
1785 EDIT_FILES[bootloader]=""
1790 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1791 efibootmgr -v -d $BOOT_DEV -p $BOOT_PART_NUM -c -L '${DIST} Linux' -l /vmlinuz-${KERNEL} \
1792 -u 'root=$ROOT_PART_ID rw $([[ $UCODE ]] && printf 'initrd=\%s.img ' "$UCODE")initrd=\initramfs-${KERNEL}.img'"
1797 if [[ $SYS == 'BIOS' ]]; then
1798 EDIT_FILES[bootloader]="/boot/syslinux/syslinux.cfg"
1800 EDIT_FILES[bootloader]="/boot/EFI/syslinux/syslinux.cfg"
1801 BCMDS[syslinux]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1802 efibootmgr -v -c -d $BOOT_DEV -p $BOOT_PART_NUM -l /EFI/syslinux/syslinux.efi -L $DIST"
1808 local c="$MNT/boot/syslinux" s="/usr/lib/syslinux/bios" d=".."
1809 [[ $SYS == 'UEFI' ]] && { c="$MNT/boot/EFI/syslinux"; s="/usr/lib/syslinux/efi64/"; d=''; }
1811 mkdir -pv "$c" && cp -rfv $s/* "$c/" && cp -f "$RUN/syslinux/splash.png" "$c/"
1812 cat > "$c/syslinux.cfg" <<- EOF
1814 MENU TITLE $DIST Boot Menu
1815 MENU BACKGROUND splash.png
1819 # see: https://www.syslinux.org/wiki/index.php/Comboot/menu.c32
1828 MENU HELPMSGENDROW 29
1829 MENU COLOR border 30;44 #40ffffff #a0000000 std
1830 MENU COLOR title 1;36;44 #9033ccff #a0000000 std
1831 MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
1832 MENU COLOR unsel 37;44 #50ffffff #a0000000 std
1833 MENU COLOR help 37;40 #c0ffffff #a0000000 std
1834 MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
1835 MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
1836 MENU COLOR msg07 37;40 #90ffffff #a0000000 std
1837 MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
1840 MENU LABEL $DIST Linux
1841 LINUX $d/vmlinuz-$KERNEL
1842 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1843 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL.img
1845 LABEL ${DIST}fallback
1846 MENU LABEL $DIST Linux Fallback
1847 LINUX $d/vmlinuz-$KERNEL
1848 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1849 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL-fallback.img
1856 EDIT_FILES[bootloader]="/boot/refind_linux.conf"
1857 BCMDS[refind-efi]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1863 cat > $MNT/boot/refind_linux.conf <<- EOF
1864 "$DIST Linux" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1865 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1866 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL.img"
1867 "$DIST Linux Fallback" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1868 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1869 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL-fallback.img"
1871 mkdir -p $MNT/etc/pacman.d/hooks
1872 cat > $MNT/etc/pacman.d/hooks/refind.hook <<- EOF
1879 Description = Updating rEFInd on ESP
1880 When = PostTransaction
1881 Exec = /usr/bin/refind-install
1885 setup_systemd-boot()
1887 EDIT_FILES[bootloader]="/boot/loader/entries/$DIST.conf"
1888 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1889 bootctl --path=/boot install"
1892 prerun_systemd-boot()
1894 mkdir -p $MNT/boot/loader/entries
1895 cat > $MNT/boot/loader/loader.conf <<- EOF
1900 cat > $MNT/boot/loader/entries/$DIST.conf <<- EOF
1902 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1903 initrd /initramfs-$KERNEL.img
1904 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1906 cat > $MNT/boot/loader/entries/$DIST-fallback.conf <<- EOF
1907 title $DIST Linux Fallback
1908 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1909 initrd /initramfs-$KERNEL-fallback.img
1910 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1912 mkdir -p $MNT/etc/pacman.d/hooks
1913 cat > $MNT/etc/pacman.d/hooks/systemd-boot.hook <<- EOF
1920 Description = Updating systemd-boot
1921 When = PostTransaction
1922 Exec = /usr/bin/bootctl update
1924 systemd-machine-id-setup --root="$MNT"
1928 ###############################################################################
1933 msg "Info" "\nGathering device info.\n" 0
1934 no_bg_install || return 1
1938 dlg choice menu "Logical Volume Management" "$_lvmmenu" \
1939 "$_lvmnew" "vgcreate -f, lvcreate -L -n" \
1940 "$_lvmdel" "vgremove -f" \
1941 "$_lvmdelall" "lvrmeove, vgremove, pvremove -f" \
1942 "back" "return to the main menu"
1944 "$_lvmnew") lvm_create ;;
1945 "$_lvmdel") lvm_delgroup && yesno "$_lvmdel" "$_lvmdelask" && vgremove -f "$DEL_VG" >/dev/null 2>&1 ;;
1946 "$_lvmdelall") lvm_del_all ;;
1957 pv="$(pvs -o pv_name --noheading 2>/dev/null)"
1958 v="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
1959 VGROUP="$(vgs -o vg_name --noheading 2>/dev/null)"
1961 if [[ $VGROUP && $v && $pv ]]; then
1962 msg "Logical Volume Management" "\nActivating existing logical volume management (LVM).\n\n" 1
1963 modprobe dm-mod >/dev/null 2>$ERR
1964 errshow 'modprobe dm-mod'
1965 vgscan >/dev/null 2>&1
1966 vgchange -ay >/dev/null 2>&1
1972 VGROUP='' LVM_PARTS='' VGROUP_MB=0
1974 lvm_mkgroup || return 1
1975 local txt="\nThe last (or only) logical volume will automatically use all remaining space in the volume group."
1976 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 -
1977 [[ $VOL_COUNT ]] || return 1
1978 lvm_extra_lvs || return 1
1979 lvm_volume_name "$_lvmlvname\nNOTE: This LV will use up all remaining space in the volume group (${VGROUP_MB}MB)" || return 1
1980 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating volume $VNAME from remaining space in $VGROUP\n" 0
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" "\nCreate volume group: $VGROUP\n\nusing these partition(s): $LVM_PARTS\n" && named=true
2039 msg "$_lvmnew" "\nCreating volume 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) successfully 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" && lvm_lv_size || return 1
2094 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating a $VOLUME_SIZE volume $VNAME in $VGROUP\n" 0
2095 lvcreate -L "$VOLUME_SIZE" "$VGROUP" -n "$VNAME" >/dev/null 2>$ERR
2096 errshow "lvcreate -L $VOLUME_SIZE $VGROUP -n $VNAME" || return 1
2097 msg "$_lvmnew (LV:$VOL_COUNT)" "\nDone, logical volume (LV) $VNAME ($VOLUME_SIZE) has been created.\n"
2105 part_find 'part|crypt' || return 1
2106 PARTS="$(awk 'NF > 0 {print $0 " off"}' <<< "$PARTS")"
2107 dlg LVM_PARTS check "$_lvmnew" "\nSelect the partition(s) to use for the physical volume (PV)." $PARTS
2114 until [[ $VGROUP ]]; do
2115 dlg VGROUP input "$_lvmnew" "$_lvmvgname" "lvgroup"
2116 if [[ -z $VGROUP ]]; then
2118 elif [[ ${VGROUP:0:1} == "/" || $VGROUP =~ \ |\' ]] || vgdisplay | grep -q "$VGROUP"; then
2119 msg "LVM Name Error" "$_lvmerrvgname"
2129 local txt="$1" default="mainvolume"
2130 (( VOL_COUNT > 1 )) && default="extvolume$VOL_COUNT"
2131 until [[ $VNAME ]]; do
2132 dlg VNAME input "$_lvmnew (LV:$VOL_COUNT)" "\n$txt" "$default"
2133 if [[ -z $VNAME ]]; then
2135 elif [[ ${VNAME:0:1} == "/" || $VNAME =~ \ |\' ]] || lsblk | grep -q "$VNAME"; then
2136 msg "LVM Name Error" "$_lvmerlvname"
2143 ###############################################################################
2149 no_bg_install || return 1
2150 dlg choice menu "LUKS Encryption" "$_luksmenu" \
2151 "$_luksnew" "cryptsetup -q luksFormat" \
2152 "$_luksopen" "cryptsetup open --type luks" \
2153 "$_luksadv" "cryptsetup -q -s -c luksFormat" \
2154 "back" "Return to the main menu"
2157 "$_luksnew") luks_basic || return 1 ;;
2158 "$_luksopen") luks_open || return 1 ;;
2159 "$_luksadv") luks_advanced || return 1 ;;
2167 modprobe -a dm-mod dm_crypt >/dev/null 2>&1
2169 part_find 'part|crypt|lvm' || return 1
2171 if (( COUNT == 1 )); then
2172 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2174 dlg LUKS_PART menu "$_luksopen" "\nSelect which partition to open." $PARTS
2177 [[ $LUKS_PART ]] || return 1
2179 luks_pass "$_luksopen" || return 1
2180 msg "$_luksopen" "\nOpening encrypted partition: $LUKS_NAME\n\nUsing device/volume: $LUKS_PART\n" 0
2181 cryptsetup open --type luks "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2182 errshow "cryptsetup open --type luks $LUKS_PART $LUKS_NAME" || return 1
2183 LUKS='encrypted'; luks_show
2190 local t="$1" op="$2" v='' p='' p2=''
2192 until [[ $LUKS_PASS ]]; do
2196 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " \
2197 --mixedform "\nEnter the password to decrypt $ROOT_PART\n\nThis is needed to create a keyfile." 0 0 0 \
2198 "Password:" 1 1 '' 1 11 "$COLUMNS" 0 1 \
2199 "Password2:" 2 1 '' 2 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
2202 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " --mixedform "$_luksomenu" 0 0 0 \
2203 "Name:" 1 1 "${LUKS_NAME:-cryptroot}" 1 7 "$COLUMNS" 0 0 \
2204 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
2205 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
2209 while read -r line; do
2225 if [[ -z $op && -z $n ]]; then
2226 msg "Name Empty" "\nEncrypted device name cannot be empty.\n\nPlease try again.\n" 2
2227 elif [[ -z $p || "$p" != "$p2" ]]; then
2228 [[ $op ]] || LUKS_NAME="$n"
2229 msg "Password Mismatch" "\nThe passwords entered do not match.\n\nPlease try again.\n" 2
2231 [[ $op ]] || LUKS_NAME="$n"
2242 msg "$_luksnew" "\nEncrypted partition ready for mounting.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$LUKS_PART")\n\n"
2247 modprobe -a dm-mod dm_crypt >/dev/null 2>&1
2249 part_find 'part|lvm' || return 1
2251 if [[ $AUTO_ROOT_PART ]]; then
2252 LUKS_PART="$AUTO_ROOT_PART"
2253 elif (( COUNT == 1 )); then
2254 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2256 dlg LUKS_PART menu "$_luksnew" "\nSelect the partition you want to encrypt." $PARTS
2259 [[ $LUKS_PART ]] || return 1
2260 luks_pass "$_luksnew"
2265 luks_setup || return 1
2266 msg "$_luksnew" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2267 cryptsetup -q luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2>$ERR
2268 errshow "cryptsetup -q luksFormat $LUKS_PART" || return 1
2269 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2270 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2271 LUKS='encrypted'; luks_show
2277 if [[ ! -e $MNT/crypto_keyfile.bin ]]; then
2278 # printf "Creating LUKS keyfile /crypto_keyfile.bin\n"
2280 n="$(lsblk -lno NAME,UUID,TYPE | awk "/$LUKS_UUID/"' && /part|crypt|lvm/ {print $1}')"
2281 local mkkey="dd bs=512 count=8 if=/dev/urandom of=/crypto_keyfile.bin"
2282 mkkey="$mkkey && chmod 000 /crypto_keyfile.bin"
2283 mkkey="$mkkey && cryptsetup luksAddKey /dev/$n /crypto_keyfile.bin <<< '$LUKS_PASS'"
2285 sed -i 's/FILES=()/FILES=(\/crypto_keyfile.bin)/g' $MNT/etc/mkinitcpio.conf 2>$ERR
2295 dlg cipher input "LUKS Encryption" "$_lukskey" "-s 512 -c aes-xts-plain64"
2296 [[ $cipher ]] || return 1
2297 msg "$_luksadv" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2298 cryptsetup -q $cipher luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2>$ERR
2299 errshow "cryptsetup -q $cipher luksFormat $LUKS_PART" || return 1
2300 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2301 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2308 ###############################################################################
2310 # some help avoid repetition and improve usability of some commands
2311 # others are initial setup functions used before reaching the main loop
2315 # does $2 contain $1
2316 [[ "$2" == *"$1"* ]] && printf "on" || printf "off"
2321 # cleanup and exit the installer cleanly with exit code $1
2322 # when ecode is 127 unmount /run/archiso/bootmnt and reboot
2327 if [[ -d $MNT ]] && command cd /; then
2329 if (( ecode == 127 )); then
2330 umount_dir /run/archiso/bootmnt
2341 local var="$1" # assign output from dialog to var
2342 local dlg_t="$2" # dialog type (menu, check, input)
2343 local title="$3" # dialog title
2344 local body="$4" # dialog message
2345 local n=0 # number of items to display for menu and check dialogs
2347 shift 4 # shift off args assigned above
2349 # adjust $n when passed a large list
2350 local l=$((LINES - 20))
2351 (( ($# / 2) > l )) && n=$l
2355 menu) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --menu "$body" 0 0 $n "$@" 2>"$ANS" || return 1 ;;
2356 check) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --checklist "$body" 0 0 $n "$@" 2>"$ANS" || return 1 ;;
2359 local def="$1" # assign default value for input
2361 if [[ $1 == 'limit' ]]; then
2362 dialog --backtitle "$DIST Installer - $SYS - v$VER" --max-input 63 --title " $title " --inputbox "$body" 0 0 "$def" 2>"$ANS" || return 1
2364 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --inputbox "$body" 0 0 "$def" 2>"$ANS" || return 1
2368 # if answer file isn't empty read from it into $var
2369 [[ -s "$ANS" ]] && printf -v "$var" "%s" "$(< "$ANS")"
2374 # displays a message dialog
2375 # when more than 2 args the message will disappear after sleep time ($3)
2381 dialog --backtitle "$DIST Installer - $SYS - v$VER" --sleep "$1" --title " $title " --infobox "$body\n" 0 0
2383 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --msgbox "$body\n" 0 0
2389 local title="$1" body="$2" yes='Yes' no='No'
2390 (( $# >= 3 )) && yes="$3"
2391 (( $# >= 4 )) && no="$4"
2393 if (( $# == 5 )); then
2394 dialog --backtitle "$DIST Installer - $SYS - v$VER" --defaultno --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2396 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2402 arch-chroot "$MNT" bash -c "$1"
2407 export PS4='| ${BASH_SOURCE} LINE:${LINENO} FUNC:${FUNCNAME[0]:+ ${FUNCNAME[0]}()} |> '
2416 printf "\n^C caught, cleaning up...\n"
2423 "\e]P0191919" # #191919
2424 "\e]P1D15355" # #D15355
2425 "\e]P2609960" # #609960
2426 "\e]P3FFCC66" # #FFCC66
2427 "\e]P4255A9B" # #255A9B
2428 "\e]P5AF86C8" # #AF86C8
2429 "\e]P62EC8D3" # #2EC8D3
2430 "\e]P7949494" # #949494
2431 "\e]P8191919" # #191919
2432 "\e]P9D15355" # #D15355
2433 "\e]PA609960" # #609960
2434 "\e]PBFF9157" # #FF9157
2435 "\e]PC4E88CF" # #4E88CF
2436 "\e]PDAF86C8" # #AF86C8
2437 "\e]PE2ec8d3" # #2ec8d3
2438 "\e]PFE1E1E1" # #E1E1E1
2441 [[ $TERM == 'linux' ]] && printf "%b" "${colors[@]}" && clear
2446 [ $? -eq 0 ] && return 0
2448 local fatal=0 err=""
2449 err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
2451 (( $1 == 1 )) && { fatal=1; shift; }
2453 local txt="\nThe command exited abnormally:\n\n$1\n\n"
2456 txt+="With the following message:\n\n$err\n\n"
2458 txt+="With no error message:\n\n"
2461 if (( fatal )); then
2462 txt+="Errors at this stage are fatal and the install cannot continue.\n"
2464 txt+="Errors at this stage are non-fatal and can be either fixed or ignored depending on the error.\n"
2466 msg "Install Error" "$txt"
2468 if (( fatal )); then
2469 [[ -r $DBG && $TERM == 'linux' ]] && less "$DBG"
2480 if (( $1 >= 0 )) && ! grep -qw "$MNT" /proc/mounts; then
2481 msg "Not Mounted" "\nPartition(s) must be mounted first.\n" 2
2483 elif [[ $1 -ge 1 && -z $BOOTLDR ]]; then
2484 msg "No Bootloader" "\nBootloader must be selected first.\n" 2
2486 elif [[ $1 -ge 2 && (-z $NEWUSER || -z $USER_PASS) ]]; then
2487 msg "No User" "\nA user must be created first.\n" 2
2489 elif [[ $1 -ge 3 && -z $CONFIG_DONE ]]; then
2490 msg "Not Configured" "\nSystem configuration must be done first.\n" 2
2493 (( i )) # return code
2498 mount | grep -q 'swap' && swapoff -a
2500 [[ -d $dir && "$(mount | grep "on $dir ")" ]] || continue
2501 umount "$dir" 2>/dev/null || { sleep 0.5; umount -f "$dir" 2>/dev/null || umount -l "$dir"; }
2507 msg "Network Connect" "\nVerifying network connection\n" 1
2508 curl -sIN --connect-timeout 5 'https://www.archlinux.org/' | sed '1q' | grep -q '200'
2513 if chk_connect; then
2516 if hash nmtui >/dev/null 2>&1; then
2518 if [[ $TERM == 'linux' ]]; then
2519 printf "%b" "\e]P1191919" "\e]P4191919"
2521 printf "%b" "\e]P1D15355" "\e]P4255a9b"
2534 [[ $RSYNC_PID || $MIRROR_PID ]] || return 0
2535 msg "Install Running" "\nA background install process is currently running.\n" 2
2541 IGNORE_DEV="$(lsblk -lno NAME,MOUNTPOINT | awk '/\/run\/archiso\/bootmnt/ {sub(/[1-9]/, ""); print $1}')"
2543 if [[ $IGNORE_DEV ]]; then
2544 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ && !'"/$IGNORE_DEV/"' {print "/dev/" $1 " " $2}')"
2546 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ {print "/dev/" $1 " " $2}')"
2549 if [[ -z $SYS_DEVS ]]; then
2550 msg "Device Error" "\nNo available devices...\n\nExiting..\n" 2
2555 while read -r line; do
2557 done <<< "$SYS_DEVS"
2564 elif grep -q 'AuthenticAMD' /proc/cpuinfo; then
2566 elif grep -q 'GenuineIntel' /proc/cpuinfo; then
2570 modprobe -q efivarfs >/dev/null 2>&1
2572 _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."
2573 if [[ -d /sys/firmware/efi/efivars ]]; then
2575 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars
2576 _prep+="\n - An EFI boot partition mounted."
2580 _prep+="\n\nOnce finished mounting, a portion of the install can be done in the background while you continue configuring the system:\n"
2581 _prep+="\n - Choose the system bootloader.\n - Create a user and password."
2582 _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."
2585 ###############################################################################
2588 # enable some nicer colours in the linux console
2591 if (( UID != 0 )); then
2592 msg "Not Root" "\nThis installer must be run as root or using sudo.\n\nExiting..\n" 2
2594 elif ! grep -qwm 1 'lm' /proc/cpuinfo; then
2595 msg "Not x86_64 Architecture" "\nThis installer only supports x86_64 architectures.\n\nExiting..\n" 2
2597 elif [[ $1 =~ (-d|--debug) ]]; then
2601 # trap ^C to perform cleanup
2607 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"
2609 select_keymap || { clear; die 0; }
2610 net_connect || { msg "Not Connected" "\nThis installer requires an active internet connection.\n\nExiting..\n" 2; die 1; }
2616 # vim:fdm=marker:fmr={,}