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
17 VER="2.0.68" # installer version
18 MNT="/mnt" # install mountpoint
19 ANS="/tmp/ans" # dialog answer file
21 # ------------------------------------------------------ #
22 # When manually mounting your partitions, you need
23 # to set these values to avoid using the mount menu.
24 # ------------------------------------------------------ #
26 # root partition, eg. /dev/sda2
29 # boot partition, required on UEFI eg. /dev/sda1
32 # boot device, used for some bootloaders eg. /dev/sda
35 # bootloader to use, can be:
36 # UEFI: grub, syslinux, efistub, systemd-boot, refind-efi
37 # BIOS: grub, syslinux
40 # directory to mount the boot partition (if any) for most bootloaders
41 # this will need to be 'boot' however a popular one for grub is 'boot/efi'
44 # ------------------------------------------------------ #
46 # bulk default values {
48 # these values will be selected during the install, it is not recommended
49 # to edit them here unless you know what you're doing.
51 SWAP_PART='' # swap partition or file path
52 SWAP_SIZE='' # swap size, only used when creating a swapfile
54 EXMNT='' # holder for additional partitions while mounting
55 EXMNTS='' # when an extra partition is mounted append it's info
57 FONT="ter-i16n" # font used for the linux console
58 HOOKS="shutdown" # list of additional HOOKS to add in /etc/mkinitcpio.conf
60 LOGIN_TYPE='' # login manager can be: lightdm, xinit, ly
61 LOGIN_WM='' # default login session to be placed in ~/.xinitrc
62 LOGINRC='' # login shell rc file, eg. .zprofile, .bash_profile, .profile
63 AUTOLOGIN='' # enable autologin for xinit
65 INSTALL_WMS='' # space separated list of chosen wm/de
67 WM_PKGS='' # list of packages added during wm/de choice (not user edited)
68 PACKAGES='' # list of all packages to install including WM_PKGS (not user edited)
69 USER_PKGS='' # packages selected by the user during install
71 NEWUSER='' # username for the new user
72 USER_PASS='' # new user's password
73 ROOT_PASS='' # root password
75 KERNEL='' # linux kernel, can be: linux, linux-lts, linux-zen, or linux-hardened
76 MYSHELL='' # full path for the shell, eg. /usr/bin/zsh
77 UCODE='' # cpu microcode (if any), can be: amd-ucode, intel-ucode
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 CONFIG_DONE='' # basic configuration is finished
94 FORMATTED='' # partitions we formatted and should allow skipping
95 AUTO_ROOT_PART='' # root value from auto partition
96 AUTO_BOOT_PART='' # boot value from auto partition
98 SEL=0 # currently selected menu item
99 ERR="/tmp/errlog" # error log used internally
100 DBG="/tmp/debuglog" # debug log when passed -d
101 RUN="/run/archiso/bootmnt/arch/boot" # path for live system /boot
102 VM="$(dmesg | grep -i "hypervisor")" # system running in a virtual machine
103 SYS='Unknown' # bios type to be determined: UEFI/BIOS
104 export DIALOGOPTS="--cr-wrap" # see `man dialog`
107 BASE_PKGS="base-devel xorg xorg-drivers sudo git gvfs gtk3 pavucontrol tumbler xdg-user-dirs playerctl "
108 BASE_PKGS+="ffmpeg gstreamer libmad libmatroska gst-libav gst-plugins-base gst-plugins-good scrot"
111 AL_BASE_PKGS="archlabs-skel-base archlabs-fonts archlabs-themes archlabs-icons archlabs-wallpapers archlabs-scripts archlabs-baph"
113 # extras for window managers
114 WM_BASE_PKGS="arandr archlabs-networkmanager-dmenu nitrogen polkit-gnome volumeicon xclip exo laptop-detect "
115 WM_BASE_PKGS+="xdotool compton wmctrl gnome-keyring dunst feh gsimplecal xfce4-power-manager xfce4-settings"
119 # giant ugly variable container :P {
122 SYS_MEM="$(awk '/MemTotal/ {print int($2 / 1024) "M"}' /proc/meminfo)"
124 # locales from /etc/locale.gen
125 LOCALES="$(awk '/\.UTF-8/ {gsub(/# .*|#/, ""); if ($1) {print $1 " - "}}' /etc/locale.gen)"
127 # console keyboard mappings
128 CMAPS="$(find /usr/share/kbd/keymaps -name '*.map.gz' | awk '{gsub(/\.map\.gz|.*\//, ""); print $1 " - "}' | sort)"
131 [[ $LINES ]] || LINES=$(tput lines)
132 [[ $COLUMNS ]] || COLUMNS=$(tput cols)
137 # commands used to install each bootloader, however most get modified during runtime {
139 [refind-efi]='refind-install' # minor modification
140 [grub]='grub-install --recheck --force' # heavily modified
141 [syslinux]='syslinux-install_update -i -a -m' # modified on UEFI
142 [efistub]='efibootmgr -v -d /dev/sda -p 1 -c -l' # heavily modified
143 [systemd-boot]='bootctl --path=/boot install' # not modified
146 # executable name for each wm/de used in ~/.xinitrc {
147 declare -A WM_SESSIONS=(
154 [gnome]='gnome-session'
155 [fluxbox]='startfluxbox'
156 [openbox]='openbox-session'
157 [cinnamon]='cinnamon-session'
160 # packages installed for each wm/de, most are depends of the skel packages {
164 [cinnamon]='gnome-terminal' # doesn't install a terminal on it's own
165 [plasma]='kdebase-meta' # base plasma application set
166 [awesome]='archlabs-skel-awesome' # see deps of archlabs-skel-awesome
167 [bspwm]='archlabs-skel-bspwm' # see deps of archlabs-skel-bspwm
168 [fluxbox]='archlabs-skel-fluxbox' # see deps of archlabs-skel-fluxbox
169 [i3-gaps]='archlabs-skel-i3-gaps' # see deps of archlabs-skel-i3-gaps
170 [openbox]='archlabs-skel-openbox' # see deps of archlabs-skel-openbox
171 [xfce4]='archlabs-skel-xfce4 xfce4-goodies' # see deps of archlabs-skel-xfce4
174 # files offered for editing after install is complete {
175 declare -A EDIT_FILES=(
176 [login]='' # login is populated once we know the username and shell
178 [sudoers]='/etc/sudoers'
179 [crypttab]='/etc/crypttab'
180 [pacman]='/etc/pacman.conf'
181 [console]='/etc/vconsole.conf'
182 [mkinitcpio]='/etc/mkinitcpio.conf'
183 [hostname]='/etc/hostname /etc/hosts'
184 [bootloader]="/boot/loader/entries/$DIST.conf" # ** based on bootloader
185 [locale]='/etc/locale.conf /etc/default/locale'
186 [keyboard]='/etc/X11/xorg.conf.d/00-keyboard.conf /etc/default/keyboard'
189 # mkfs command and flags for filesystem formatting {
194 [ntfs]='mkfs.ntfs -q'
195 [ext2]='mkfs.ext2 -q'
196 [ext3]='mkfs.ext3 -q'
197 [ext4]='mkfs.ext4 -q'
198 [vfat]='mkfs.vfat -F32'
199 [nilfs2]='mkfs.nilfs2 -q'
200 [reiserfs]='mkfs.reiserfs -q'
203 # mount options for each filesystem {
209 [jfs]='discard errors=continue errors=panic nointegrity'
210 [reiserfs]='acl nolog notail replayonly user_xattr off'
211 [ext4]='discard dealloc nofail noacl relatime noatime nobarrier nodelalloc'
212 [xfs]='discard filestreams ikeep largeio noalign nobarrier norecovery noquota wsync'
213 [nilfs2]='discard nobarrier errors=continue errors=panic order=relaxed order=strict norecovery'
214 [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'
217 # packages installed for each login option {
218 declare -A LOGIN_PKGS=(
223 [lightdm]='lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings accountsservice'
226 # extras installed for user selected packages {
227 # if a package requires additional packages that aren't already dependencies
228 # they can be added here eg. [package]="extra"
232 [mupdf]='mupdf-tools'
233 [qt5ct]='qt5-styleplugins'
234 [rxvt-unicode]='urxvt-pearls'
235 [vlc]='qt5ct qt5-styleplugins'
236 [zathura]='zathura-pdf-poppler'
237 [noto-fonts]='noto-fonts-emoji'
238 [cairo-dock]='cairo-dock-plug-ins'
239 [qutebrowser]='qt5ct qt5-styleplugins'
240 [qbittorrent]='qt5ct qt5-styleplugins'
241 [transmission-qt]='qt5ct qt5-styleplugins'
242 [bluez]='bluez-libs bluez-utils bluez-tools bluez-plugins bluez-hid2hci'
243 [kdenlive]='kdebase-meta dvdauthor frei0r-plugins breeze breeze-gtk qt5ct qt5-styleplugins'
248 # dialog text variables
251 # Basics (somewhat in order)
252 _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"
253 _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"
254 _device="\nSelect a device to use from the list below.\n\nDevices (/dev) are the available drives on the system. /sda, /sdb, /sdc ..."
255 _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."
256 _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."
257 _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"
258 _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)."
259 _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."
260 _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."
261 _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."
262 _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"
263 _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."
264 _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."
265 _exmnt="\nWhere do you want the partition mounted?\n\nEnsure the name begins with a slash (/).\nExamples include: /usr, /home, /var, etc."
266 _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."
267 _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."
268 _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"
269 _timez="\nThe time zone is used to set the system clock.\n\nSelect your country or continent from the list below"
270 _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."
271 _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."
272 _login="\nSelect which of your session choices to use for the initial login.\n\nYou can be change this later by editing your ~/.xinitrc"
273 _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"
274 _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."
275 _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."
278 _luksnew="Basic LUKS Encryption"
279 _luksadv="Advanced LUKS Encryption"
280 _luksopen="Open Existing LUKS Partition"
281 _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."
282 _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."
283 _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)."
286 _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."
287 _lvmnew="Create Volume Group and Volume(s)"
288 _lvmdel="Delete an Existing Volume Group"
289 _lvmdelall="Delete ALL Volume Group(s) and Volume(s)"
290 _lvmvgname="\nEnter a name for the volume group (VG) being created from the partition(s) selected."
291 _lvmlvname="\nEnter a name for the logical volume (LV) being created.\n\nThis is similar to setting a label for a partition."
292 _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."
293 _lvmdelask="\nConfirm deletion of volume group(s) and logical volume(s).\n\nDeleting a volume group, will delete all logical volumes within it.\n"
296 _errexpart="\nCannot mount partition due to a problem with the mountpoint.\n\nEnsure it begins with a slash (/) followed by atleast one character.\n"
297 _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"
298 _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"
299 _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"
300 _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"
301 _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"
302 _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"
308 ###############################################################################
310 # main is the entry point which calls functions including outside of its block
311 # once those functions finished they always are returned here with the
312 # exception of install_main(), it exits upon completion
316 (( SEL < 12 )) && (( SEL++ ))
318 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Prepare " --default-item $SEL --cancel-label 'Exit' --menu "$_prep" 0 0 0 \
319 1 "Device tree (optional)" \
320 2 "Partitioning (optional)" \
321 3 "LUKS setup (optional)" \
322 4 "LVM setup (optional)" \
323 5 "Mount partitions" \
324 6 "System bootloader" \
325 7 "User and password" \
326 8 "System configuration" \
327 9 "Select WM/DE (optional)" \
328 10 "Select Packages (optional)" \
329 11 "View configuration (optional)" \
330 12 "Start the installation" 2>"$ANS"
333 [[ -z $WARN && $SEL =~ (2|5) ]] && { msg "Data Warning" "$_warn"; WARN=true; }
336 2) part_menu || (( SEL-- )) ;;
337 3) luks_menu || (( SEL-- )) ;;
338 4) lvm_menu || (( SEL-- )) ;;
339 5) mount_menu || (( SEL-- )) ;;
340 6) prechecks 0 && { select_boot || (( SEL-- )); } ;;
341 7) prechecks 1 && { select_mkuser || (( SEL-- )); } ;;
342 8) prechecks 2 && { select_config || (( SEL-- )); } ;;
343 9) prechecks 3 && { select_sessions || (( SEL-- )); } ;;
344 10) prechecks 3 && { select_packages || (( SEL-- )); } ;;
345 11) prechecks 3 && select_show ;;
346 12) prechecks 3 && install_main ;;
347 *) yesno "Exit" "\nUnmount partitions (if any) and exit the installer?\n" && die 0
353 if [[ $SYS == 'BIOS' ]]; then
354 dlg BOOTLDR menu "BIOS Bootloader" "\nSelect which bootloader to use." \
355 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
356 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network" || return 1
358 dlg BOOTLDR menu "UEFI Bootloader" "\nSelect which bootloader to use." \
359 "systemd-boot" "A simple UEFI boot manager which executes configured EFI images" \
360 "grub" "The Grand Unified Bootloader, standard among many Linux distributions" \
361 "refind-efi" "A UEFI boot manager that aims to be platform neutral and simplify multi-boot" \
362 "efistub" "Boot the kernel image directly (no chainloading support)" \
363 "syslinux" "A collection of boot loaders for booting drives, CDs, or over the network (no chainloading support)" || return 1
370 local pkgs="${USER_PKGS// / } ${PACKAGES// / }"
371 [[ $BOOT_PART ]] && local mnt="/$BOOTDIR"
372 [[ $INSTALL_WMS == *dwm* ]] && pkgs="dwm st dmenu $pkgs"
373 pkgs="${pkgs// / }" pkgs="${pkgs# }"
374 msg "Show Configuration" "
375 ---------- PARTITION CONFIGURATION ------------
377 Root: ${ROOT_PART:-none}
378 Boot: ${BOOT_PART:-${BOOT_DEV:-none}}
380 Swap: ${SWAP_PART:-none}
381 Size: ${SWAP_SIZE:-none}
382 Extra: ${EXMNTS:-${EXMNT:-none}}
383 Hooks: ${HOOKS:-none}
389 ------------ SYSTEM CONFIGURATION -------------
391 Locale: ${MYLOCALE:-none}
392 Keymap: ${KEYMAP:-none}
393 Hostname: ${MYHOST:-none}
394 Timezone: ${ZONE:-none}/${SUBZ:-none}
397 ------------ USER CONFIGURATION ---------------
399 Username: ${NEWUSER:-none}
400 Login Shell: ${MYSHELL:-none}
401 Login Session: ${LOGIN_WM:-none}
402 Autologin: ${AUTOLOGIN:-none}
403 Login Type: ${LOGIN_TYPE:-none}
406 ----------- PACKAGE CONFIGURATION -------------
408 Kernel: ${KERNEL:-none}
409 Bootloader: ${BOOTLDR:-none}
410 Packages: ${pkgs:-none}
416 [[ $INSTALL_WMS ]] || return 0
418 AUTOLOGIN='' # no autologin unless using xinit
420 dlg LOGIN_TYPE menu "Login Management" "\nSelect what kind of login management to use." \
421 "xinit" "Console login without a display manager" \
422 "ly" "TUI display manager with a ncurses-like interface" \
423 "lightdm" "Lightweight display manager with a gtk greeter" \
424 "gdm" "Gnome display manager" \
425 "sddm" "Simple desktop display manager" || return 1
428 ly) EDIT_FILES[login]="/etc/ly/config.ini" ;;
429 gdm|sddm) EDIT_FILES[login]="" ;;
430 lightdm) EDIT_FILES[login]="/etc/lightdm/lightdm.conf /etc/lightdm/lightdm-gtk-greeter.conf" ;;
431 xinit) EDIT_FILES[login]="/home/$NEWUSER/.xinitrc /home/$NEWUSER/.xprofile"
432 if (( $(wc -w <<< "$INSTALL_WMS") > 1 )); then
433 dlg LOGIN_WM menu "Login Management" "$_login" $LOGIN_CHOICES || return 1
434 LOGIN_WM="${WM_SESSIONS[$LOGIN_WM]}"
436 [[ -z $LOGIN_WM ]] && LOGIN_WM="${WM_SESSIONS[${INSTALL_WMS%% *}]}"
437 yesno "Autologin" "$(sed "s|USER|$NEWUSER|g; s|RC|$LOGINRC|g" <<< "$_autologin")" && AUTOLOGIN=true || AUTOLOGIN=''
447 until [[ $CONFIG_DONE ]]; do
449 0) dlg MYSHELL menu "Shell" "\nChoose which shell to use." \
450 /usr/bin/zsh 'A very advanced and programmable command interpreter (shell) for UNIX' \
451 /bin/bash 'The GNU Bourne Again shell, standard in many GNU/Linux distributions' \
452 /usr/bin/mksh 'The MirBSD Korn Shell - an enhanced version of the public domain ksh' || return 1
454 1) dlg MYHOST input "Hostname" "$_hostname" "${DIST,,}" limit || { i=0; continue; } ;;
455 2) dlg MYLOCALE menu "Locale" "$_locale" $LOCALES || { i=1; continue; } ;;
457 until [[ $ZONE && $SUBZ ]]; do
458 dlg ZONE menu "Timezone" "$_timez" America - Australia - Asia - Atlantic - Africa - Europe - Indian - Pacific - Arctic - Antarctica - || break
459 dlg SUBZ menu "Timezone" "$_timesubz" $(awk '/'"$ZONE"'\// {gsub(/'"$ZONE"'\//, ""); print $3 " - "}' /usr/share/zoneinfo/zone.tab | sort) || continue
461 [[ $ZONE && $SUBZ ]] || { i=2; continue; } ;;
462 4) dlg KERNEL menu "Kernel" "\nChoose which kernel to use." \
463 linux 'Vanilla linux kernel and modules, with a few patches applied' \
464 linux-lts 'Long-term support (LTS) linux kernel and modules' \
465 linux-zen 'A effort of kernel hackers to provide the best kernel for everyday systems' \
466 linux-hardened 'A security-focused linux kernel with hardening patches to mitigate exploits' || { i=3; continue; }
470 (( i++ )) # progress through to the next choice
473 case $MYSHELL in *bash) LOGINRC='.bash_profile' ;; *zsh) LOGINRC='.zprofile' ;; *mksh) LOGINRC='.profile' ;; esac
481 local v='' u='' p='' p2='' rp='' rp2=''
483 until [[ $NEWUSER ]]; do
486 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " User " --mixedform "$_user" 0 0 0 \
487 "Username:" 1 1 "$u" 1 11 "$COLUMNS" 0 0 \
488 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
489 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 \
490 "--- Root password, if left empty the user password will be used ---" 6 1 '' 6 68 "$COLUMNS" 0 2 \
491 "Password:" 8 1 '' 8 11 "$COLUMNS" 0 1 \
492 "Password2:" 9 1 '' 9 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
494 while read -r line; do
495 case $i in 0) u="$line" ;; 1) p="$line" ;; 2) p2="$line" ;; 3) rp="$line" ;; 4) rp2="$line" ;; esac
499 # root passwords empty, so use the user passwords
500 [[ -z $rp && -z $rp2 ]] && { rp="$p"; rp2="$p2"; }
502 # make sure a username was entered and that the passwords match
503 if [[ ${#u} -eq 0 || $u =~ \ |\' || $u =~ [^a-z0-9] ]]; then
504 msg "Invalid Username" "\nIncorrect user name.\n\nPlease try again.\n"; u=''
505 elif [[ -z $p ]]; then
506 msg "Empty Password" "\nThe user password cannot be left empty.\n\nPlease try again.\n"
507 elif [[ "$p" != "$p2" ]]; then
508 msg "Password Mismatch" "\nThe user passwords do not match.\n\nPlease try again.\n"
509 elif [[ "$rp" != "$rp2" ]]; then
510 msg "Password Mismatch" "\nThe root passwords do not match.\n\nPlease try again.\n"
522 dlg KEYMAP menu "Keyboard Layout" "$_keymap" \
523 us English cm English gb English au English gh English \
524 za English ng English ca French 'cd' French gn French \
525 tg French fr French de German at German ch German \
526 es Spanish latam Spanish br Portuguese pt Portuguese ma Arabic \
527 sy Arabic ara Arabic ua Ukrainian cz Czech ru Russian \
528 sk Slovak nl Dutch it Italian hu Hungarian cn Chinese \
529 tw Taiwanese vn Vietnamese kr Korean jp Japanese th Thai \
530 la Lao pl Polish se Swedish is Icelandic 'fi' Finnish \
531 dk Danish be Belgian in Indian al Albanian am Armenian \
532 bd Bangla ba Bosnian 'bg' Bulgarian dz Berber mm Burmese \
533 hr Croatian gr Greek il Hebrew ir Persian iq Iraqi \
534 af Afghani fo Faroese ge Georgian ee Estonian kg Kyrgyz \
535 kz Kazakh lt Lithuanian mt Maltese mn Mongolian ro Romanian \
536 no Norwegian rs Serbian si Slovenian tj Tajik lk Sinhala \
537 tr Turkish uz Uzbek ie Irish pk Urdu 'mv' Dhivehi \
538 np Nepali et Amharic sn Wolof ml Bambara tz Swahili \
539 ke Swahili bw Tswana ph Filipino my Malay tm Turkmen \
540 id Indonesian bt Dzongkha lv Latvian md Moldavian mao Maori \
541 by Belarusian az Azerbaijani mk Macedonian kh Khmer epo Esperanto \
542 me Montenegrin || return 1
544 if [[ $CMAPS == *"$KEYMAP"* ]]; then
547 dlg CMAP menu "Console Keymap" "$_vconsole" $CMAPS || return 1
550 if [[ $DISPLAY && $TERM != 'linux' ]]; then
551 setxkbmap "$KEYMAP" >/dev/null 2>&1
553 loadkeys "$CMAP" >/dev/null 2>&1
562 dlg INSTALL_WMS check "Sessions" "$_sessions\n" \
563 openbox "A lightweight, powerful, and highly configurable stacking wm" "$(ofn openbox "${INSTALL_WMS[*]}")" \
564 i3-gaps "A fork of i3wm with more features including gaps" "$(ofn i3-gaps "${INSTALL_WMS[*]}")" \
565 dwm "A dynamic WM for X that manages windows in tiled, floating, or monocle layouts" "$(ofn dwm "${INSTALL_WMS[*]}")" \
566 bspwm "A tiling wm that represents windows as the leaves of a binary tree" "$(ofn bspwm "${INSTALL_WMS[*]}")" \
567 xfce4 "A lightweight and modular desktop environment based on gtk+2/3" "$(ofn xfce4 "${INSTALL_WMS[*]}")" \
568 awesome "A customized Awesome WM session created by @elanapan" "$(ofn awesome "${INSTALL_WMS[*]}")" \
569 fluxbox "A lightweight and highly-configurable window manager" "$(ofn fluxbox "${INSTALL_WMS[*]}")" \
570 plasma "A kde software project currently comprising a full desktop environment" "$(ofn plasma "${INSTALL_WMS[*]}")" \
571 gnome "A desktop environment that aims to be simple and easy to use" "$(ofn gnome "${INSTALL_WMS[*]}")" \
572 cinnamon "A desktop environment combining traditional desktop with modern effects" "$(ofn cinnamon "${INSTALL_WMS[*]}")"
574 [[ $INSTALL_WMS ]] || return 0
576 WM_PKGS="${INSTALL_WMS/dwm/}" # remove dwm from package list
577 WM_PKGS="${WM_PKGS// / }" # remove double spaces
578 WM_PKGS="${WM_PKGS# }" # remove leading space
580 # add archlabs base when choosing any session
581 [[ $WM_PKGS ]] && WM_PKGS+=" $AL_BASE_PKGS"
583 for i in $INSTALL_WMS; do
584 LOGIN_CHOICES+="$i - "
585 [[ ${WM_EXT[$i]} && $WM_PKGS != *"${WM_EXT[$i]}"* ]] && WM_PKGS+=" ${WM_EXT[$i]}"
588 select_login || return 1
590 while IFS=' ' read -r pkg; do
591 [[ $PACKAGES != *"$pkg"* ]] && PACKAGES+=" $pkg"
599 dlg USER_PKGS check " Packages " "$_packages" \
600 abiword "A Fully-featured word processor" "$(ofn abiword "${USER_PKGS[*]}")" \
601 alacritty "A cross-platform, GPU-accelerated terminal emulator" "$(ofn alacritty "${USER_PKGS[*]}")" \
602 atom "An open-source text editor developed by GitHub" "$(ofn atom "${USER_PKGS[*]}")" \
603 audacious "A free and advanced audio player based on GTK+" "$(ofn audacious "${USER_PKGS[*]}")" \
604 audacity "A program that lets you manipulate digital audio waveforms" "$(ofn audacity "${USER_PKGS[*]}")" \
605 blueman "GUI bluetooth device manager" "$(ofn blueman "${USER_PKGS[*]}")" \
606 bluez "Simple CLI based bluetooth support" "$(ofn bluez "${USER_PKGS[*]}")" \
607 cairo-dock "Light eye-candy fully themable animated dock" "$(ofn cairo-dock "${USER_PKGS[*]}")" \
608 calligra "A set of applications for productivity" "$(ofn calligra "${USER_PKGS[*]}")" \
609 chromium "An open-source web browser based on the Blink rendering engine" "$(ofn chromium "${USER_PKGS[*]}")" \
610 clementine "A modern music player and library organizer" "$(ofn clementine "${USER_PKGS[*]}")" \
611 cmus "A small, fast and powerful console music player" "$(ofn cmus "${USER_PKGS[*]}")" \
612 deadbeef "A GTK+ audio player for GNU/Linux" "$(ofn deadbeef "${USER_PKGS[*]}")" \
613 deluge "A BitTorrent client written in python" "$(ofn deluge "${USER_PKGS[*]}")" \
614 docky "Full fledged dock for opening applications and managing windows" "$(ofn docky "${USER_PKGS[*]}")" \
615 emacs "An extensible, customizable, self-documenting real-time display editor" "$(ofn emacs "${USER_PKGS[*]}")" \
616 epiphany "A GNOME web browser based on the WebKit rendering engine" "$(ofn epiphany "${USER_PKGS[*]}")" \
617 evince "A document viewer" "$(ofn evince "${USER_PKGS[*]}")" \
618 evolution "Manage your email, contacts and schedule" "$(ofn evolution "${USER_PKGS[*]}")" \
619 file-roller "Create and modify archives" "$(ofn file-roller "${USER_PKGS[*]}")" \
620 firefox "A popular open-source web browser from Mozilla" "$(ofn firefox "${USER_PKGS[*]}")" \
621 gcolor2 "A simple GTK+2 color selector" "$(ofn gcolor2 "${USER_PKGS[*]}")" \
622 geany "A fast and lightweight IDE" "$(ofn geany "${USER_PKGS[*]}")" \
623 geary "A lightweight email client for the GNOME desktop" "$(ofn geary "${USER_PKGS[*]}")" \
624 gimp "GNU Image Manipulation Program" "$(ofn gimp "${USER_PKGS[*]}")" \
625 gnome-calculator "GNOME Scientific calculator" "$(ofn gnome-calculator "${USER_PKGS[*]}")" \
626 gnome-disk-utility "Disk Management Utility" "$(ofn gnome-disk-utility "${USER_PKGS[*]}")" \
627 gnome-system-monitor "View current processes and monitor system state" "$(ofn gnome-system-monitor "${USER_PKGS[*]}")" \
628 gparted "A GUI frontend for creating and manipulating partition tables" "$(ofn gparted "${USER_PKGS[*]}")" \
629 gpick "Advanced color picker using GTK+ toolkit" "$(ofn gpick "${USER_PKGS[*]}")" \
630 gpicview "Lightweight image viewer" "$(ofn gpicview "${USER_PKGS[*]}")" \
631 guvcview "Capture video from camera devices" "$(ofn guvcview "${USER_PKGS[*]}")" \
632 hexchat "A popular and easy to use graphical IRC client" "$(ofn hexchat "${USER_PKGS[*]}")" \
633 inkscape "Professional vector graphics editor" "$(ofn inkscape "${USER_PKGS[*]}")" \
634 irssi "Modular text mode IRC client" "$(ofn irssi "${USER_PKGS[*]}")" \
635 kdenlive "A popular non-linear video editor for Linux" "$(ofn kdenlive "${USER_PKGS[*]}")" \
636 krita "Edit and paint images" "$(ofn krita "${USER_PKGS[*]}")" \
637 libreoffice-fresh "Full featured office suite" "$(ofn libreoffice-fresh "${USER_PKGS[*]}")" \
638 lollypop "A new music playing application" "$(ofn lollypop "${USER_PKGS[*]}")" \
639 mousepad "A simple text editor" "$(ofn mousepad "${USER_PKGS[*]}")" \
640 mpd "A flexible, powerful, server-side application for playing music" "$(ofn mpd "${USER_PKGS[*]}")" \
641 mpv "A media player based on mplayer" "$(ofn mpv "${USER_PKGS[*]}")" \
642 mupdf "Lightweight PDF and XPS viewer" "$(ofn mupdf "${USER_PKGS[*]}")" \
643 mutt "Small but very powerful text-based mail client" "$(ofn mutt "${USER_PKGS[*]}")" \
644 nautilus "The default file manager for Gnome" "$(ofn nautilus "${USER_PKGS[*]}")" \
645 ncmpcpp "A mpd client and almost exact clone of ncmpc with some new features" "$(ofn ncmpcpp "${USER_PKGS[*]}")" \
646 neovim "A fork of Vim aiming to improve user experience, plugins, and GUIs." "$(ofn neovim "${USER_PKGS[*]}")" \
647 nicotine+ "A graphical client for Soulseek" "$(ofn nicotine+ "${USER_PKGS[*]}")" \
648 noto-fonts "Google Noto fonts" "$(ofn noto-fonts "${USER_PKGS[*]}")" \
649 noto-fonts-cjk "Google Noto CJK fonts (Chinese, Japanese, Korean)" "$(ofn noto-fonts-cjk "${USER_PKGS[*]}")" \
650 obs-studio "Free opensource streaming/recording software" "$(ofn obs-studio "${USER_PKGS[*]}")" \
651 openshot "An open-source, non-linear video editor for Linux" "$(ofn openshot "${USER_PKGS[*]}")" \
652 opera "A Fast and secure, free of charge web browser from Opera Software" "$(ofn opera "${USER_PKGS[*]}")" \
653 pcmanfm "A fast and lightweight file manager based in Lxde" "$(ofn pcmanfm "${USER_PKGS[*]}")" \
654 pidgin "Multi-protocol instant messaging client" "$(ofn pidgin "${USER_PKGS[*]}")" \
655 plank "An elegant, simple, and clean dock" "$(ofn plank "${USER_PKGS[*]}")" \
656 qbittorrent "An advanced BitTorrent client" "$(ofn qbittorrent "${USER_PKGS[*]}")" \
657 qpdfview "A tabbed PDF viewer" "$(ofn qpdfview "${USER_PKGS[*]}")" \
658 qt5ct "GUI for managing Qt based application themes, icons, and fonts" "$(ofn qt5ct "${USER_PKGS[*]}")" \
659 qutebrowser "A keyboard-focused vim-like web browser based on Python and PyQt5" "$(ofn qutebrowser "${USER_PKGS[*]}")" \
660 rhythmbox "A Music playback and management application" "$(ofn rhythmbox "${USER_PKGS[*]}")" \
661 rxvt-unicode "A unicode enabled rxvt-clone terminal emulator" "$(ofn rxvt-unicode "${USER_PKGS[*]}")" \
662 sakura "A terminal emulator based on GTK and VTE" "$(ofn sakura "${USER_PKGS[*]}")" \
663 simple-scan "Simple scanning utility" "$(ofn simple-scan "${USER_PKGS[*]}")" \
664 simplescreenrecorder "A feature-rich screen recorder" "$(ofn simplescreenrecorder "${USER_PKGS[*]}")" \
665 steam "A popular game distribution platform by Valve" "$(ofn steam "${USER_PKGS[*]}")" \
666 surf "A simple web browser based on WebKit2/GTK+" "$(ofn surf "${USER_PKGS[*]}")" \
667 terminator "Terminal emulator that supports tabs and grids" "$(ofn terminator "${USER_PKGS[*]}")" \
668 termite "A minimal VTE-based terminal emulator" "$(ofn termite "${USER_PKGS[*]}")" \
669 thunar "A modern file manager for the Xfce Desktop Environment" "$(ofn thunar "${USER_PKGS[*]}")" \
670 thunderbird "Standalone mail and news reader from mozilla" "$(ofn thunderbird "${USER_PKGS[*]}")" \
671 tilda "A GTK based drop down terminal for Linux and Unix" "$(ofn tilda "${USER_PKGS[*]}")" \
672 tilix "A tiling terminal emulator for Linux using GTK+ 3" "$(ofn tilix "${USER_PKGS[*]}")" \
673 transmission-cli "Free BitTorrent client CLI" "$(ofn transmission-cli "${USER_PKGS[*]}")" \
674 transmission-gtk "GTK+ Front end for transmission" "$(ofn transmission-gtk "${USER_PKGS[*]}")" \
675 transmission-qt "Qt Front end for transmission" "$(ofn transmission-qt "${USER_PKGS[*]}")" \
676 ttf-anonymous-pro "A family fixed-width fonts designed with code in mind" "$(ofn ttf-anonymous-pro "${USER_PKGS[*]}")" \
677 ttf-fira-code "Monospaced font with programming ligatures" "$(ofn ttf-fira-code "${USER_PKGS[*]}")" \
678 ttf-font-awesome "Iconic font designed for Bootstrap" "$(ofn ttf-font-awesome "${USER_PKGS[*]}")" \
679 ttf-hack "A hand groomed typeface based on Bitstream Vera Mono" "$(ofn ttf-hack "${USER_PKGS[*]}")" \
680 vlc "A free and open source cross-platform multimedia player" "$(ofn vlc "${USER_PKGS[*]}")" \
681 weechat "Fast, light and extensible IRC client" "$(ofn weechat "${USER_PKGS[*]}")" \
682 xapps "Common library for X-Apps project" "$(ofn xapps "${USER_PKGS[*]}")" \
683 xarchiver "A GTK+ frontend to various command line archivers" "$(ofn xarchiver "${USER_PKGS[*]}")" \
684 xed "A small and lightweight text editor. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
685 xfce-terminal "A terminal emulator based in the Xfce Desktop Environment" "$(ofn xfce-terminal "${USER_PKGS[*]}")" \
686 xreader "Document viewer for files like PDF and Postscript. X-Apps Project." "$(ofn xed "${USER_PKGS[*]}")" \
687 xterm "The standard terminal emulator for the X window system" "$(ofn xterm "${USER_PKGS[*]}")" \
688 zathura "Minimalistic document viewer" "$(ofn zathura "${USER_PKGS[*]}")"
690 if [[ $USER_PKGS ]]; then # add any needed PKG_EXT to the list
691 for i in $USER_PKGS; do
692 [[ ${PKG_EXT[$i]} && $USER_PKGS != *"${PKG_EXT[$i]}"* ]] && USER_PKGS+=" ${PKG_EXT[$i]}"
699 ###############################################################################
701 # non-essential partitioning helpers called by the user when using the optional
702 # partition menu and selecting a device to edit
706 no_bg_install || return 0
707 local device choice devhash
708 devhash="$(lsblk -f | base64)"
710 part_device || return 1
715 dlg choice menu "Edit Partitions" "$_part" \
716 "auto" "Whole device automatic partitioning" \
717 "shrink" "Shrink an existing ext2/3/4 or ntfs partition to make room for a new partition" \
718 "cfdisk" "Curses based variant of fdisk" \
719 "parted" "GNU partition editor" \
720 "fdisk" "Dialog-driven creation and manipulation of partitions" \
721 "done" "Return to the main menu"
723 if [[ -z $choice || $choice == 'done' ]]; then
725 elif [[ $choice == 'shrink' ]]; then
726 part_shrink "$device"
727 elif [[ $choice == 'auto' ]]; then
728 local root_size txt table boot_fs
729 root_size=$(lsblk -lno SIZE "$device" | awk 'NR == 1 {
732 print ($1 * 1000 - 512) / 1000 "G"
738 txt="\nWARNING:\n\nALL data on $device will be destroyed and the following partitions will be created\n\n- "
739 if [[ $SYS == 'BIOS' ]]; then
740 table="msdos" boot_fs="ext4"
741 txt+="An $boot_fs boot partition with the boot flag enabled (512M)\n- "
743 table="gpt" boot_fs="fat32"
744 txt+="A $boot_fs efi boot partition (512M)\n- "
746 txt+="An ext4 partition using all remaining space ($root_size)\n\nDo you want to continue?\n"
747 yesno "Auto Partition" "$txt" && msg "Info" "\nGathering device info.\n" 1 && part_auto "$device" "$table" "$boot_fs" "$root_size"
754 if [[ $devhash != "$(lsblk -f | base64)" ]]; then
755 msg "Probing Partitions" "\nInforming kernel of partition changes using partprobe\n" 0
756 partprobe >/dev/null 2>&1
757 [[ $choice == 'auto' ]] && return
765 if [[ $IGNORE_DEV ]]; then
766 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk "!/$IGNORE_DEV/"' && /disk|part|lvm|crypt|NAME/')"
768 txt="$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE,MOUNTPOINT | awk '/disk|part|lvm|crypt|NAME/')"
770 msg "Device Tree" "\n\n$txt\n\n"
775 local device="$1" table="$2" boot_fs="$3" size="$4" dev_info=""
776 dev_info="$(parted -s "$device" print)"
778 msg "Auto Partition" "\nRemoving partitions on $device and setting table to $table\n" 1
781 while read -r PART; do
782 parted -s "$device" rm "$PART" >/dev/null 2>&1
783 done <<< "$(awk '/^ [1-9][0-9]?/ {print $1}' <<< "$dev_info" | sort -r)"
785 [[ $(awk '/Table:/ {print $3}' <<< "$dev_info") != "$table" ]] && parted -s "$device" mklabel "$table" >/dev/null 2>&1
787 msg "Auto Partition" "\nCreating a 512M $boot_fs boot partition.\n" 1
788 if [[ $SYS == "BIOS" ]]; then
789 parted -s "$device" mkpart primary "$boot_fs" 1MiB 513MiB >/dev/null 2>&1
791 parted -s "$device" mkpart ESP "$boot_fs" 1MiB 513MiB >/dev/null 2>&1
796 AUTO_BOOT_PART=$(lsblk -lno NAME,TYPE "$device" | awk 'NR==2 {print "/dev/" $1}')
798 if [[ $SYS == "BIOS" ]]; then
799 mkfs.ext4 -q "$AUTO_BOOT_PART" >/dev/null 2>&1
801 mkfs.vfat -F32 "$AUTO_BOOT_PART" >/dev/null 2>&1
804 msg "Auto Partition" "\nCreating a $size ext4 root partition.\n" 0
805 parted -s "$device" mkpart primary ext4 513MiB 100% >/dev/null 2>&1
807 AUTO_ROOT_PART="$(lsblk -lno NAME,TYPE "$device" | awk 'NR==3 {print "/dev/" $1}')"
808 mkfs.ext4 -q "$AUTO_ROOT_PART" >/dev/null 2>&1
810 FORMATTED+="$AUTO_BOOT_PART $AUTO_ROOT_PART "
811 msg "Auto Partition" "\nProcess complete.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$device")\n"
818 local device="$1" fs=""
820 part_find "${device##*/}[^ ]" || return 1
821 (( COUNT == 1 )) && part="$(awk '{print $1}' <<< "${PARTS[@]}" )"
823 if (( COUNT == 1 )) || dlg part menu "Resize" "\nWhich partition on $device do you want to resize?" $PARTS; then
824 fs=$(lsblk -lno FSTYPE "$part")
827 msg "Resize" "\nGathering device size info.\n" 0
829 end=$(parted -s "$device" unit KiB print | awk '/^\s*'"$num"'/ {print $3}') # part size in KiB
830 devsize=$(parted -s "$device" unit KiB print | awk '/Disk '"${device//\//\\/}"':/ {print $3}') # whole device size in KiB
831 mount "$part" $MNT >/dev/null 2>&1; sleep 0.5
832 min=$(df --output=used --block-size=MiB "$part" | awk 'NR == 2 {print int($1) + 256}')
833 max=$(df --output=avail --block-size=MiB "$part" | awk 'NR == 2 {print int($1)}')
836 if dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Resize: $part " --rangebox "$_resize" 17 "$COLUMNS" "$min" "$max" $((max / 2)) 2>$ANS; then
838 size=$((size * 1024))
845 if ntfsresize -fc "$part"; then
846 ntfsresize -ff --size $(( (size * 1024) / 1000 ))k "$part" 2>$ERR # k=10^3 bytes
847 errshow "ntfsresize -f -s $(( (size * 1024) / 1000 ))k $part" || return 1
849 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"
854 e2fsck -f "$part"; sleep 0.5
855 resize2fs -f "$part" ${size}K 2>$ERR # K=2^10 bytes
856 errshow "resize2fs -f $part ${size}K" || return 1
860 parted "$device" resizepart "$num" ${size}KiB || return 1
863 if [[ $devsize == "$end" ]]; then
864 parted -s "$device" mkpart primary ext4 ${size}KiB 100% 2>$ERR
865 errshow "parted -s $device mkpart primary ext4 ${size}KiB 100%" || return 1
867 parted -s "$device" mkpart primary ext4 ${size}KiB ${end}KiB 2>$ERR
868 errshow "parted -s $device mkpart primary ext4 ${size}KiB ${end}KiB" || return 1
870 msg "Resize Complete" "\n$part has been successfully resized to $((size / 1024))M.\n" 1
872 "") msg "No Filesystem" "\nFor unformatted partitions, cfdisk can be used in the partition menu.\n" ;;
873 *) msg "Invalid Filesystem: $fs" "\nResizing only supports ext and ntfs.\n" ;;
878 ###############################################################################
879 # partition management functions
880 # these are helpers for use by other functions to do essential setup/teardown
884 local regexp="$1" err=''
886 # string of partitions as /TYPE/PART SIZE
887 if [[ $IGNORE_DEV ]]; then
888 PARTS="$(lsblk -lno TYPE,NAME,SIZE |
889 awk "/$regexp/"' && !'"/$IGNORE_DEV/"' {
890 sub(/^part/, "/dev/")
891 sub(/^lvm|^crypt/, "/dev/mapper/")
895 PARTS="$(lsblk -lno TYPE,NAME,SIZE |
897 sub(/^part/, "/dev/")
898 sub(/^lvm|^crypt/, "/dev/mapper/")
903 # number of partitions total
905 while read -r line; do
909 # ensure we have enough partitions for the system and action type
911 'part|lvm|crypt') [[ $COUNT -lt 1 || ($SYS == 'UEFI' && $COUNT -lt 2) ]] && err="$_errpart" ;;
912 'part|crypt') (( COUNT < 1 )) && err="$_lvmerr" ;;
913 'part|lvm') (( COUNT < 2 )) && err="$_lukserr" ;;
916 # if there aren't enough partitions show the relevant error message
917 [[ $err ]] && { msg "Not Enough Partitions" "$err" 2; return 1; }
924 if [[ $1 == "$MNT/swapfile" && $SWAP_SIZE ]]; then
925 fallocate -l $SWAP_SIZE "$1" 2>$ERR
926 errshow "fallocate -l $SWAP_SIZE $1"
927 chmod 600 "$1" 2>$ERR
928 errshow "chmod 600 $1"
930 mkswap "$1" >/dev/null 2>$ERR
932 swapon "$1" >/dev/null 2>$ERR
939 local part="$1" mountp="${MNT}$2" fs=""
940 fs="$(lsblk -lno FSTYPE "$part")"
943 if [[ $fs && ${FS_OPTS[$fs]} && $part != "$BOOT_PART" ]] && select_mntopts "$fs"; then
944 mount -o "$MNT_OPTS" "$part" "$mountp" >/dev/null 2>&1
946 mount "$part" "$mountp" >/dev/null 2>&1
949 part_mountconf "$part" "$mountp" || return 1
957 local part="$1" fs="$2" delay="$3"
959 msg "Format" "\nFormatting $part as $fs\n" 0
960 ${FS_CMDS[$fs]} "$part" >/dev/null 2>$ERR
961 errshow "${FS_CMDS[$fs]} $part" || return 1
968 if [[ $DEV_COUNT -eq 1 && $SYS_DEVS ]]; then
969 DEVICE="$(awk '{print $1}' <<< "$SYS_DEVS")"
970 elif (( DEV_COUNT > 1 )); then
972 dlg DEVICE menu "Boot Device" "\nSelect the device to use for bootloader install." $SYS_DEVS
974 dlg DEVICE menu "Select Device" "$_device" $SYS_DEVS
976 [[ $DEVICE ]] || return 1
977 elif [[ $DEV_COUNT -lt 1 && ! $1 ]]; then
978 msg "Device Error" "\nNo available devices.\n\nExiting..\n" 2
982 [[ $1 ]] && BOOT_DEV="$DEVICE"
989 BOOT_DEV="${BOOT_PART%[1-9]}"
990 BOOT_PART_NUM="${BOOT_PART: -1}"
991 [[ $BOOT_PART = /dev/nvme* ]] && BOOT_DEV="${BOOT_PART%p[1-9]}"
992 if [[ $SYS == 'UEFI' ]]; then
993 parted -s $BOOT_DEV set $BOOT_PART_NUM esp on >/dev/null 2>&1
995 parted -s $BOOT_DEV set $BOOT_PART_NUM boot on >/dev/null 2>&1
1002 local part="$1" devs=""
1003 devs="$(lsblk -lno NAME,FSTYPE,TYPE)"
1005 # Identify if $part is LUKS+LVM, LVM+LUKS, LVM alone, or LUKS alone
1006 if lsblk -lno TYPE "$part" | grep -q 'crypt'; then
1008 LUKS_NAME="${part#/dev/mapper/}"
1009 for dev in $(awk '/lvm/ && /crypto_LUKS/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
1010 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1011 LUKS_DEV="$LUKS_DEV cryptdevice=$dev:$LUKS_NAME"
1012 LVM='logical volume'
1016 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
1017 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1018 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
1019 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
1023 elif lsblk -lno TYPE "$part" | grep -q 'lvm'; then
1024 LVM='logical volume'
1025 VNAME="${part#/dev/mapper/}"
1026 for dev in $(awk '/crypt/ && /lvm2_member/ {print "/dev/mapper/"$1}' <<< "$devs" | uniq); do
1027 if lsblk -lno NAME "$dev" | grep -q "$VNAME"; then
1028 LUKS_NAME="${dev/\/dev\/mapper\//}"
1032 for dev in $(awk '/part/ && /crypto_LUKS/ {print "/dev/"$1}' <<< "$devs" | uniq); do
1033 if lsblk -lno NAME "$dev" | grep -q "$LUKS_NAME"; then
1034 LUKS_UUID="$(lsblk -lno UUID,TYPE,FSTYPE "$dev" | awk '/part/ && /crypto_LUKS/ {print $1}')"
1035 LUKS_DEV="$LUKS_DEV cryptdevice=UUID=$LUKS_UUID:$LUKS_NAME"
1046 if (( COUNT > 0 )); then
1047 PARTS="$(sed "/${pt//\//\\/}/d" <<< "$PARTS")"
1055 if grep -qw "$1" /proc/mounts; then
1056 msg "Mount Success" "\nPartition $1 mounted at $2\n" 1
1060 msg "Mount Fail" "\nPartition $1 failed to mount at $2\n" 2
1065 ###############################################################################
1067 # mount_menu is the entry point which calls all other functions
1068 # once finished it returns to the main menu: main()
1072 msg "Info" "\nGathering device info.\n" 0
1073 no_bg_install || return 0
1076 part_find 'part|lvm|crypt' || { SEL=2; return 1; }
1078 [[ $LUKS && $LUKS_PART ]] && part_countdec $LUKS_PART
1079 [[ $LVM && $LVM_PARTS ]] && part_countdec $LVM_PARTS
1081 select_root_partition || return 1
1083 if [[ $SYS == 'UEFI' ]]; then
1084 select_efi_partition || { BOOT_PART=''; return 1; }
1085 elif (( COUNT > 0 )); then
1086 select_boot_partition || { BOOT_PART=''; return 1; }
1089 if [[ $BOOT_PART ]]; then
1090 part_mount "$BOOT_PART" "/$BOOTDIR" && SEP_BOOT=true || return 1
1094 select_swap || return 1
1095 select_extra_partitions || return 1
1103 dlg SWAP_PART menu "Swap Setup" "\nSelect whether to use a swapfile, swap partition, or none." \
1104 "none" "Don't allocate any swap space" \
1105 "swapfile" "Allocate $SYS_MEM at /swapfile" \
1108 if [[ -z $SWAP_PART || $SWAP_PART == "none" ]]; then
1111 elif [[ $SWAP_PART == "swapfile" ]]; then
1113 until [[ ${SWAP_SIZE:0:1} =~ [1-9] && ${SWAP_SIZE: -1} =~ (M|G) ]]; do
1114 (( 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
1115 dlg SWAP_SIZE input "Swap Setup" "$_swapsize" "$SYS_MEM" || { SWAP_PART=''; SWAP_SIZE=''; return 1; }
1118 part_swap "$MNT/$SWAP_PART"
1119 SWAP_PART="/$SWAP_PART"
1120 elif [[ $PARTS == *"$SWAP_PART"* ]]; then
1121 part_swap $SWAP_PART
1122 part_countdec $SWAP_PART
1123 SWAP_SIZE="$(lsblk -lno SIZE $SWAP_PART)"
1133 local fs="$1" opts=''
1134 local title="${fs^} Mount Options"
1136 for i in ${FS_OPTS[$fs]}; do
1140 until [[ $MNT_OPTS ]]; do
1141 dlg MNT_OPTS check "$title" "$_mount" $opts
1142 [[ $MNT_OPTS ]] || return 1
1143 MNT_OPTS="${MNT_OPTS// /,}"
1144 yesno "$title" "\nConfirm the following options: $MNT_OPTS\n" || MNT_OPTS=''
1153 until [[ $EXMNT ]]; do
1154 dlg EXMNT input "Extra Mount $part" "$_exmnt" "/" || return 1
1155 if [[ ${EXMNT:0:1} != "/" || ${#EXMNT} -le 1 || $EXMNT =~ \ |\' || $EXMNTS == *"$EXMNT"* ]]; then
1156 msg "Mountpoint Error" "$_errexpart"
1165 local part="$1" fs='' cur=''
1166 local txt="\nSelect which filesystem to use for: $part\n\nDefault: ext4"
1167 cur="$(lsblk -lno FSTYPE "$part" 2>/dev/null)"
1170 if [[ $cur && ($part != "$ROOT_PART" || $FORMATTED == *"$part"*) ]]; then
1171 dlg fs menu "Filesystem" "$txt\nCurrent: $cur" skip - ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1173 dlg fs menu "Filesystem" "$txt" ext4 - ext3 - ext2 - vfat - ntfs - f2fs - jfs - xfs - nilfs2 - reiserfs - || return 1
1175 [[ $fs == 'skip' ]] && return 0
1176 yesno "Filesystem" "\nFormat $part as $fs?\n" || fs=''
1178 part_format "$part" "$fs"
1181 select_efi_partition()
1183 if [[ $AUTO_BOOT_PART ]]; then
1184 msg "EFI Boot Partition" "\nUsing partition created during automatic format.\n" 2
1185 BOOT_PART="$AUTO_BOOT_PART"; return 0 # were done here
1187 local pts size dev isize bsize ptcount=0
1189 # walk partition list and skip ones that are too small/big for boot
1190 while read -r dev size; do
1191 size_t="${size: -1:1}" # size type eg. K, M, G, T
1192 isize=${size:0:-1} # remove trailing size type character
1193 isize=${isize%.*} # remove any decimal (round down)
1194 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1197 if (( ptcount == 1 )); then
1198 msg "EFI Boot Partition" "\nOnly one partition available that meets size requirements.\n" 1
1199 BOOT_PART="$(awk 'NF > 0 {print $1}' <<< "$pts")"
1201 dlg BOOT_PART menu "EFI Partition" "$_uefi" $pts
1205 [[ $BOOT_PART ]] || return 1
1207 if grep -q 'fat' <<< "$(fsck -N "$BOOT_PART")"; then
1208 local txt="\nIMPORTANT:\n\nThe EFI partition $BOOT_PART $_format"
1209 if yesno "Format EFI Partition" "$txt" "Format $BOOT_PART" "Skip Formatting" 1; then
1210 part_format "$BOOT_PART" "vfat" 2
1213 part_format "$BOOT_PART" "vfat" 2
1219 select_boot_partition()
1221 if [[ $AUTO_BOOT_PART && ! $LVM ]]; then
1222 msg "BIOS Boot Partition" "\nUsing partition created during automatic format.\n" 2
1223 BOOT_PART="$AUTO_BOOT_PART"; return 0 # were done here
1225 local pts size dev isize bsize ptcount=0
1227 # walk partition list and skip ones that are too small/big for boot
1228 while read -r dev size; do
1229 size_t="${size: -1:1}" # size type eg. K, M, G, T
1230 isize=${size:0:-1} # remove trailing size type character
1231 isize=${isize%.*} # remove any decimal (round down)
1232 [[ $size_t =~ [KT] || ($size_t == 'G' && $isize -gt 2) || ($size_t == 'M' && $isize -lt 100) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1235 if [[ $LUKS && ! $LVM ]]; then
1236 dlg BOOT_PART menu "Boot Partition" "$_biosluks" $pts
1237 [[ $BOOT_PART ]] || return 1
1239 dlg BOOT_PART menu "Boot Partition" "$_bios" "skip" "don't use a separate boot" $pts
1240 [[ -z $BOOT_PART || $BOOT_PART == "skip" ]] && { BOOT_PART=''; return 0; }
1244 if grep -q 'ext[34]' <<< "$(fsck -N "$BOOT_PART")"; then
1245 local txt="\nIMPORTANT:\n\nThe boot partition $BOOT_PART $_format"
1246 if yesno "Format Boot Partition" "$txt" "Format $BOOT_PART" "Skip Formatting" 1; then
1247 part_format "$BOOT_PART" "ext4" 2
1250 part_format "$BOOT_PART" "ext4" 2
1255 select_root_partition()
1257 if [[ $AUTO_ROOT_PART && -z $LVM && -z $LUKS ]]; then
1258 ROOT_PART="$AUTO_ROOT_PART"
1259 msg "Select Root Partition (/)" "\nUsing partition created during automatic format.\n" 2
1260 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1261 return 0 # we're done here
1263 local pts size dev isize bsize ptcount=0
1265 # walk partition list and skip ones that are too small for / (root)
1266 while read -r dev size; do
1267 size_t="${size: -1:1}" # size type eg. K, M, G, T
1268 isize=${size:0:-1} # remove trailing size type character
1269 isize=${isize%.*} # remove any decimal (round down)
1270 [[ $size_t =~ [MK] || ($size_t == 'G' && $isize -lt 4) ]] || { pts+="$dev $size "; (( ptcount++ )); }
1273 if (( ptcount == 1 )); then # only one available device
1274 msg "Select Root Partition (/)" "\nOnly one partition available that meets size requirements.\n" 2
1275 ROOT_PART="$(awk 'NR==1 {print $1}' <<< "$pts")"
1277 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
1280 [[ $ROOT_PART ]] || return 1
1282 select_filesystem "$ROOT_PART" || { ROOT_PART=''; return 1; }
1283 part_mount "$ROOT_PART" || { ROOT_PART=''; return 1; }
1288 select_extra_partitions()
1292 # walk partition list and skip ones that are too small to be usable
1293 while read -r dev size; do
1294 [[ ${size: -1:1} =~ [KM] ]] && part_countdec "$dev"
1297 while (( COUNT > 0 )); do
1299 dlg part menu 'Mount Extra' "$_expart" 'done' 'finish mounting step' $PARTS || break
1300 if [[ $part == 'done' ]]; then
1302 elif select_filesystem "$part" && select_mountpoint && part_mount "$part" "$EXMNT"; then
1303 EXMNTS+="$part: $EXMNT "
1304 [[ $EXMNT == '/usr' && $HOOKS != *usr* ]] && HOOKS="usr $HOOKS"
1312 ###############################################################################
1314 # main is the entry point which calls all other install functions, once
1315 # complete it shows a dialog to edit files on the new system before reboot
1322 genfstab -U $MNT >$MNT/etc/fstab 2>$ERR
1323 errshow 1 "genfstab -U $MNT >$MNT/etc/fstab"
1324 [[ -f $MNT/swapfile ]] && sed -i "s~${MNT}~~" $MNT/etc/fstab
1328 chrun "hwclock --systohc --utc" || chrun "hwclock --systohc --utc --directisa"
1331 chrun "chown -Rf $NEWUSER:users /home/$NEWUSER"
1334 dlg choice menu "Finalization" "$_edit" \
1335 finished "exit the installer and reboot" \
1336 keyboard "${EDIT_FILES[keyboard]}" \
1337 console "${EDIT_FILES[console]}" \
1338 locale "${EDIT_FILES[locale]}" \
1339 hostname "${EDIT_FILES[hostname]}" \
1340 sudoers "${EDIT_FILES[sudoers]}" \
1341 mkinitcpio "${EDIT_FILES[mkinitcpio]}" \
1342 fstab "${EDIT_FILES[fstab]}" \
1343 crypttab "${EDIT_FILES[crypttab]}" \
1344 bootloader "${EDIT_FILES[bootloader]}" \
1345 pacman "${EDIT_FILES[pacman]}" \
1346 login "${EDIT_FILES[login]}"
1348 if [[ -z $choice || $choice == 'finished' ]]; then
1349 [[ $DEBUG == true && -r $DBG ]] && $EDITOR $DBG
1353 for f in ${EDIT_FILES[$choice]}; do
1354 [[ -e ${MNT}$f ]] && exists+=" ${MNT}$f"
1356 if [[ $exists ]]; then
1359 msg "File Missing" "\nThe file(s) selected do not exist:\n\n${EDIT_FILES[$choice]}\n"
1367 if kill -0 "$RSYNC_PID" 2>/dev/null || kill -0 "$MIRROR_PID" 2>/dev/null; then
1368 printf "\nOne or more background install processes are still running, grabbing their output...\n" && cat /tmp/bg_out
1369 while kill -0 "$RSYNC_PID" 2>/dev/null || kill -0 "$MIRROR_PID" 2>/dev/null; do
1374 unset RSYNC_PID MIRROR_PID
1376 rm -rf $MNT/etc/mkinitcpio-archiso.conf
1377 find $MNT/usr/lib/initcpio -name 'archiso*' -type f -delete
1378 sed -i 's/volatile/auto/g' $MNT/etc/systemd/journald.conf
1379 find $MNT/boot -name '*-ucode.img' -delete
1381 if [[ $DIST != "ArchLabs" ]]; then
1382 for f in $MNT/etc/{lsb-release,os-release}; do
1383 sed -i "s/ArchLabs/$DIST/g" $MNT/etc/{lsb-release,os-release}
1388 find $MNT/etc/X11/xorg.conf.d/ -name '*.conf' -delete
1389 elif lspci | grep ' VGA ' | grep -q 'Intel'; then
1390 echo "Creating Intel VGA Tear Free config /etc/X11/xorg.conf.d/20-intel.conf"
1391 cat > $MNT/etc/X11/xorg.conf.d/20-intel.conf <<- EOF
1393 Identifier "Intel Graphics"
1395 Option "TearFree" "true"
1400 [[ -e /run/archiso/sfs/airootfs && $KERNEL == 'linux' ]] && cp -vf $RUN/x86_64/vmlinuz $MNT/boot/vmlinuz-linux
1402 cp -fv /etc/resolv.conf $MNT/etc/
1403 [[ -e /etc/NetworkManager/system-connections ]] && cp -rvf /etc/NetworkManager/system-connections $MNT/etc/NetworkManager/
1405 echo "LANG=$MYLOCALE" > $MNT/etc/locale.conf
1406 cp -f $MNT/etc/locale.conf $MNT/etc/default/locale
1407 sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; s/#${MYLOCALE}/${MYLOCALE}/g" $MNT/etc/locale.gen
1409 chrun "ln -svf /usr/share/zoneinfo/$ZONE/$SUBZ /etc/localtime"
1411 cat > $MNT/etc/X11/xorg.conf.d/00-keyboard.conf <<- EOF
1412 # Use localectl(1) to instruct systemd-localed to update it.
1413 Section "InputClass"
1414 Identifier "system-keyboard"
1415 MatchIsKeyboard "on"
1416 Option "XkbLayout" "$KEYMAP"
1420 cat > $MNT/etc/default/keyboard <<- EOF
1421 # KEYBOARD CONFIGURATION FILE
1422 # Consult the keyboard(5) manual page.
1429 printf "KEYMAP=%s\nFONT=%s\n" "$CMAP" "$FONT" > $MNT/etc/vconsole.conf
1430 echo "$MYHOST" > $MNT/etc/hostname
1431 cat > $MNT/etc/hosts <<- EOF
1434 ::1 localhost ip6-localhost ip6-loopback
1435 ff02::1 ip6-allnodes
1436 ff02::2 ip6-allrouters
1442 echo "Installing $BOOTLDR"
1444 if [[ $ROOT_PART == /dev/mapper* ]]; then
1445 ROOT_PART_ID="$ROOT_PART"
1447 local uuid_type="UUID"
1448 [[ $BOOTLDR =~ (systemd-boot|refind-efi|efistub) ]] && uuid_type="PARTUUID"
1449 ROOT_PART_ID="$uuid_type=$(blkid -s $uuid_type -o value $ROOT_PART)"
1452 if [[ $SYS == 'UEFI' ]]; then
1453 # remove our old install and generic BOOT/ dir
1454 find $MNT/$BOOTDIR/EFI/ -maxdepth 1 -mindepth 1 -iname "$DIST" -type d -delete
1455 find $MNT/$BOOTDIR/EFI/ -maxdepth 1 -mindepth 1 -iname 'BOOT' -type d -delete
1459 chrun "${BCMDS[$BOOTLDR]}" 2>$ERR
1460 errshow 1 "${BCMDS[$BOOTLDR]}"
1462 if [[ -d $MNT/hostrun ]]; then
1463 # cleanup the bind mounts we made earlier for the grub-probe module
1464 umount_dir $MNT/hostrun/{udev,lvm}
1465 rm -rf $MNT/hostrun >/dev/null 2>&1
1468 if [[ $SYS == 'UEFI' ]]; then
1469 # some UEFI firmware requires a generic esp/BOOT/BOOTX64.EFI
1470 mkdir -pv $MNT/$BOOTDIR/EFI/BOOT
1472 grub) cp -fv $MNT/$BOOTDIR/EFI/$DIST/grubx64.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI ;;
1473 syslinux) cp -rf $MNT/$BOOTDIR/EFI/syslinux/* $MNT/$BOOTDIR/EFI/BOOT/ && cp -f $MNT/$BOOTDIR/EFI/syslinux/syslinux.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI ;;
1474 refind-efi) sed -i '/#extra_kernel_version_strings/ c extra_kernel_version_strings linux-hardened,linux-zen,linux-lts,linux' $MNT/$BOOTDIR/EFI/refind/refind.conf
1475 cp -fv $MNT/$BOOTDIR/EFI/refind/refind_x64.efi $MNT/$BOOTDIR/EFI/BOOT/BOOTX64.EFI ;;
1484 rm -f $MNT/root/.zshrc # remove welcome message from root zshrc
1486 chrun "chpasswd <<< 'root:$ROOT_PASS'" 2>$ERR
1487 errshow 1 "set root password"
1488 if [[ $MYSHELL != "/usr/bin/zsh" ]]; then # root uses zsh by default, change it if something else was chosen
1489 chrun "usermod -s $MYSHELL root" 2>$ERR
1490 errshow 1 "usermod -s $MYSHELL root"
1491 # copy the default mkshrc to /root if mksh was picked
1492 [[ $MYSHELL == '/usr/bin/mksh' ]] && cp -fv $MNT/etc/skel/.mkshrc $MNT/root/.mkshrc
1495 echo "Creating new user $NEWUSER and setting password"
1496 local groups='audio,floppy,log,network,rfkill,scanner,storage,optical,power,wheel'
1498 chrun "useradd -m -u 1000 -g users -G $groups -s $MYSHELL $NEWUSER" 2>$ERR
1499 errshow 1 "useradd -m -u 1000 -g users -G $groups -s $MYSHELL $NEWUSER"
1500 chrun "chpasswd <<< '$NEWUSER:$USER_PASS'" 2>$ERR
1501 errshow 1 "set $NEWUSER password"
1503 [[ $INSTALL_WMS == *dwm* ]] && install_suckless
1504 [[ $WM_PKGS == *xfce* ]] && echo 'volumeicon &' >> $MNT/home/$NEWUSER/.xprofile
1506 # remove some commands from ~/.xprofile when using KDE or Gnome as the login session
1507 if [[ $LOGIN_WM =~ (startkde|gnome-session) || ($LOGIN_TYPE =~ (lightdm|ly) && $WM_PKGS =~ (plasma|gnome)) ]]; then
1508 sed -i '/super/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1509 sed -i '/nitrogen/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1510 sed -i '/compton/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile
1513 # create user home directories (Music, Documents, Downloads, etc..)
1514 chrun 'xdg-user-dirs-update'
1521 local serv="$MNT/etc/systemd/system/getty@tty1.service.d"
1522 echo "Setting up $LOGIN_TYPE"
1524 ly|sddm|gdm|lightdm)
1525 rm -rf "$serv" "$MNT/home/$NEWUSER/.xinitrc"
1526 chrun "systemctl enable $LOGIN_TYPE.service" 2>$ERR
1527 errshow 1 "systemctl enable $LOGIN_TYPE.service"
1528 if [[ $LOGIN_TYPE == 'lightdm' ]]; then
1529 cat > $MNT/etc/lightdm/lightdm-gtk-greeter.conf <<- EOF
1531 default-user-image=/usr/share/icons/ArchLabs-Dark/64x64/places/distributor-logo-archlabs.png
1532 background=/usr/share/backgrounds/archlabs/archlabs.jpg
1533 theme-name=Adwaita-dark
1534 icon-theme-name=Adwaita
1535 font-name=DejaVu Sans Mono 11
1536 position=30%,end 50%,end
1541 if [[ $INSTALL_WMS ]]; then
1542 sed -i "/exec/ c exec ${LOGIN_WM}" "$MNT/home/$NEWUSER/.xinitrc"
1543 elif [[ -e $MNT/home/$NEWUSER/.xinitrc ]]; then
1544 sed -i '/exec/d' "$MNT/home/$NEWUSER/.xinitrc"
1547 if [[ $AUTOLOGIN ]]; then
1548 sed -i "s/root/${NEWUSER}/g" $serv/autologin.conf
1549 cat > "$MNT/home/$NEWUSER/$LOGINRC" <<- EOF
1550 # automatically run startx when logging in on tty1
1551 [ -z \$DISPLAY ] && [ \$XDG_VTNR -eq 1 ] && exec startx
1562 local rmpkg="archlabs-installer "
1563 local inpkg="$BASE_PKGS ${LOGIN_PKGS[$LOGIN_TYPE]} $PACKAGES $USER_PKGS "
1566 *zsh) inpkg+="zsh-completions " ;;
1567 *mksh) inpkg+="mksh " rmpkg+="zsh " ;;
1568 *bash) inpkg+="bash-completion " rmpkg+="zsh " ;;
1571 # using a different kernel, remove the stock one
1572 [[ $KERNEL != 'linux' ]] && inpkg+="$KERNEL " rmpkg+="linux "
1574 # don't install extras on dwm only installs
1575 if [[ $INSTALL_WMS != 'dwm' ]]; then
1576 # gnome, plasma, and cinnamon have their own superkey bind and ksuperkey conflicts
1577 [[ $INSTALL_WMS =~ ^(plasma|gnome|cinnamon)$ ]] || inpkg+="archlabs-ksuperkey "
1578 # window manager only packages
1579 [[ $INSTALL_WMS =~ (openbox|bspwm|i3-gaps|fluxbox) ]] && inpkg+="$WM_BASE_PKGS "
1581 inpkg+="arandr nitrogen polkit-gnome xclip xdotool compton gnome-keyring dunst feh "
1584 # update first to avoid issues
1585 chrun "pacman -Syyu --noconfirm"
1587 # remove the packages we don't want on the installed system
1588 [[ $rmpkg ]] && chrun "pacman -Rnsc $rmpkg --noconfirm"
1590 # reinstalling iputils fixes the network issue for non-root users
1591 chrun "pacman -S iputils $UCODE --noconfirm"
1593 # install the packages chosen throughout the install
1594 chrun "pacman -S $inpkg --needed --noconfirm" 2>$ERR
1595 errshow 1 "pacman -S $inpkg --needed --noconfirm"
1597 # bootloader packages
1598 if [[ $BOOTLDR == 'grub' ]]; then
1599 [[ $SYS == 'UEFI' ]] && local efib="efibootmgr"
1600 chrun "pacman -S os-prober grub $efib --needed --noconfirm" 2>$ERR
1601 errshow 1 "pacman -S os-prober grub $efib --needed --noconfirm"
1602 elif [[ $BOOTLDR == 'refind-efi' ]]; then
1603 chrun "pacman -S refind-efi efibootmgr --needed --noconfirm" 2>$ERR
1604 errshow 1 "pacman -S refind-efi efibootmgr --needed --noconfirm"
1605 elif [[ $SYS == 'UEFI' ]]; then
1606 chrun "pacman -S efibootmgr --needed --noconfirm" 2>$ERR
1607 errshow 1 "pacman -S efibootmgr --needed --noconfirm"
1610 # allow members of the wheel group to run commands as root
1611 sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" $MNT/etc/sudoers
1618 mkdir -pv "$MNT/home/$NEWUSER/suckless"
1620 for i in dwm dmenu st; do
1621 if chrun "git clone https://git.suckless.org/$i /home/$NEWUSER/suckless/$i"; then
1622 chrun "cd /home/$NEWUSER/suckless/$i; make PREFIX=/usr install; make clean; rm config.h"
1624 printf "failed to clone %s repo\n" "$i"
1629 install_mkinitcpio()
1632 [[ $LUKS ]] && add="encrypt"
1633 [[ $LVM ]] && { [[ $add ]] && add+=" lvm2" || add+="lvm2"; }
1634 sed -i "s/block filesystems/block ${add} filesystems ${HOOKS}/g" $MNT/etc/mkinitcpio.conf
1635 chrun "mkinitcpio -p $KERNEL" 2>$ERR
1636 errshow 1 "mkinitcpio -p $KERNEL"
1639 install_mirrorlist()
1641 local mfile="$1" # output mirrorlist file
1643 if hash reflector >/dev/null 2>&1; then
1644 reflector --verbose --score 80 -l 40 -f 5 --sort rate --save "$mfile"
1645 elif hash rankmirrors >/dev/null 2>&1; then
1646 echo "Sorting mirrorlist"
1647 local key="access_key=5f29642060ab983b31fdf4c2935d8c56"
1648 ip_add="$(curl -fsSL "http://api.ipstack.com/check&?$key&fields=ip" | python -c "import sys, json; print(json.load(sys.stdin)['ip'])")"
1649 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'])")"
1650 if [[ "$country" ]]; then
1651 if [[ $country =~ (CA|US) ]]; then
1652 # use both CA and US mirrors for CA or US countries
1653 mirror="https://www.archlinux.org/mirrorlist/?country=US&country=CA&use_mirror_status=on"
1654 elif [[ $country =~ (AU|NZ) ]]; then
1655 # use both AU and NZ mirrors for AU or NZ countries
1656 mirror="https://www.archlinux.org/mirrorlist/?country=AU&country=NZ&use_mirror_status=on"
1658 mirror="https://www.archlinux.org/mirrorlist/?country=${country}&use_mirror_status=on"
1660 else # no country code so just grab all mirrors, will be a very slow sort but we don't have other options
1661 mirror="https://www.archlinux.org/mirrorlist/?country=all&use_mirror_status=on"
1663 curl -fsSL "$mirror" | sed -e 's/^#Server/Server/' -e '/^#/d' | rankmirrors -n 6 - >"$mfile"
1669 install_background()
1671 msg "Background Install" "\nInstall will now begin in the background\n" 1
1672 rsync -a /run/archiso/sfs/airootfs/ $MNT/ &
1674 ( install_mirrorlist "$MNT/etc/pacman.d/mirrorlist" >>/tmp/bg_out 2>&1 ) &
1676 # end the background processes before exiting
1677 trap "kill $RSYNC_PID $MIRROR_PID 2>/dev/null" EXIT
1680 ###############################################################################
1682 # prerun_* set up the configs needed before actually running the commands
1683 # setup_* are run after selecting a bootloader and build the command used later
1684 # they can also be used for further user input as these run before control is taken away
1688 EDIT_FILES[bootloader]="/etc/default/grub"
1690 if [[ $SYS == 'BIOS' ]]; then
1691 [[ $BOOT_DEV ]] || { part_device 1 || return 1; }
1692 BCMDS[grub]="grub-install --recheck --force --target=i386-pc $BOOT_DEV"
1694 BCMDS[grub]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1695 grub-install --recheck --force --target=x86_64-efi --efi-directory=/$BOOTDIR --bootloader-id=$DIST"
1696 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1699 BCMDS[grub]="mkdir -p /run/udev /run/lvm &&
1700 mount --bind /hostrun/udev /run/udev &&
1701 mount --bind /hostrun/lvm /run/lvm &&
1703 grub-mkconfig -o /boot/grub/grub.cfg &&
1704 sleep 1 && umount /run/udev /run/lvm"
1711 sed -i "s/GRUB_DISTRIBUTOR=.*/GRUB_DISTRIBUTOR=\"${DIST}\"/g; s/GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"\"/g" $MNT/etc/default/grub
1713 if [[ $LUKS_DEV ]]; then
1714 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
1715 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"
1718 if [[ $SYS == 'BIOS' && $LVM && -z $SEP_BOOT ]]; then
1719 sed -i "s/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g" $MNT/etc/default/grub 2>$ERR
1720 errshow 1 "sed -i 's/GRUB_PRELOAD_MODULES=.*/GRUB_PRELOAD_MODULES=\"lvm\"/g' $MNT/etc/default/grub"
1723 # setup for os-prober module
1724 mkdir -p /run/{lvm,udev} $MNT/hostrun/{lvm,udev}
1725 mount --bind /run/lvm $MNT/hostrun/lvm
1726 mount --bind /run/udev $MNT/hostrun/udev
1733 EDIT_FILES[bootloader]=""
1738 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1739 efibootmgr -v -d $BOOT_DEV -p $BOOT_PART_NUM -c -L '${DIST} Linux' -l /vmlinuz-${KERNEL} \
1740 -u 'root=$ROOT_PART_ID rw $([[ $UCODE ]] && printf 'initrd=\%s.img ' "$UCODE")initrd=\initramfs-${KERNEL}.img'"
1745 if [[ $SYS == 'BIOS' ]]; then
1746 EDIT_FILES[bootloader]="/boot/syslinux/syslinux.cfg"
1748 EDIT_FILES[bootloader]="/boot/EFI/syslinux/syslinux.cfg"
1749 BCMDS[syslinux]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1750 efibootmgr -v -c -d $BOOT_DEV -p $BOOT_PART_NUM -l /EFI/syslinux/syslinux.efi -L $DIST"
1756 local c="$MNT/boot/syslinux" s="/usr/lib/syslinux/bios" d=".."
1757 [[ $SYS == 'UEFI' ]] && { c="$MNT/boot/EFI/syslinux"; s="/usr/lib/syslinux/efi64/"; d=''; }
1759 mkdir -pv "$c" && cp -rfv $s/* "$c/"
1760 cat > "$c/syslinux.cfg" <<- EOF
1763 MENU TITLE $DIST Boot Menu
1768 MENU LABEL $DIST Linux
1769 LINUX $d/vmlinuz-$KERNEL
1770 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1771 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL.img
1773 LABEL ${DIST}fallback
1774 MENU LABEL $DIST Linux Fallback
1775 LINUX $d/vmlinuz-$KERNEL
1776 APPEND root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1777 INITRD $([[ $UCODE ]] && printf "%s" "$d/$UCODE.img,")$d/initramfs-$KERNEL-fallback.img
1784 EDIT_FILES[bootloader]="/boot/refind_linux.conf"
1785 BCMDS[refind-efi]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1791 cat > $MNT/boot/refind_linux.conf <<- EOF
1792 "$DIST Linux" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1793 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1794 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL.img"
1795 "$DIST Linux Fallback" "root=$ROOT_PART_ID $([[ $LUKS_DEV ]] &&
1796 printf "%s " "$LUKS_DEV")rw add_efi_memmap $([[ $UCODE ]] &&
1797 printf "initrd=%s " "/$UCODE.img")initrd=/initramfs-$KERNEL-fallback.img"
1799 mkdir -p $MNT/etc/pacman.d/hooks
1800 cat > $MNT/etc/pacman.d/hooks/refind.hook <<- EOF
1807 Description = Updating rEFInd on ESP
1808 When = PostTransaction
1809 Exec = /usr/bin/refind-install
1813 setup_systemd-boot()
1815 EDIT_FILES[bootloader]="/boot/loader/entries/$DIST.conf"
1816 BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1
1817 bootctl --path=/boot install"
1820 prerun_systemd-boot()
1822 mkdir -p $MNT/boot/loader/entries
1823 cat > $MNT/boot/loader/loader.conf <<- EOF
1828 cat > $MNT/boot/loader/entries/$DIST.conf <<- EOF
1830 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1831 initrd /initramfs-$KERNEL.img
1832 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1834 cat > $MNT/boot/loader/entries/$DIST-fallback.conf <<- EOF
1835 title $DIST Linux Fallback
1836 linux /vmlinuz-${KERNEL}$([[ $UCODE ]] && printf "\ninitrd %s" "/$UCODE.img")
1837 initrd /initramfs-$KERNEL-fallback.img
1838 options root=$ROOT_PART_ID $([[ $LUKS_DEV ]] && printf "%s " "$LUKS_DEV")rw
1840 mkdir -p $MNT/etc/pacman.d/hooks
1841 cat > $MNT/etc/pacman.d/hooks/systemd-boot.hook <<- EOF
1848 Description = Updating systemd-boot
1849 When = PostTransaction
1850 Exec = /usr/bin/bootctl update
1852 systemd-machine-id-setup --root="$MNT"
1856 ###############################################################################
1861 msg "Info" "\nGathering device info.\n" 0
1862 no_bg_install || return 1
1866 dlg choice menu "Logical Volume Management" "$_lvmmenu" \
1867 "$_lvmnew" "vgcreate -f, lvcreate -L -n" \
1868 "$_lvmdel" "vgremove -f" \
1869 "$_lvmdelall" "lvrmeove, vgremove, pvremove -f" \
1870 "Back" "Return to the main menu"
1872 "$_lvmnew") lvm_create && break ;;
1873 "$_lvmdel") lvm_delgroup && yesno "$_lvmdel" "$_lvmdelask" && vgremove -f "$DEL_VG" >/dev/null 2>&1 ;;
1874 "$_lvmdelall") lvm_del_all ;;
1885 pv="$(pvs -o pv_name --noheading 2>/dev/null)"
1886 v="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
1887 VGROUP="$(vgs -o vg_name --noheading 2>/dev/null)"
1889 if [[ $VGROUP && $v && $pv ]]; then
1890 msg "LVM Setup" "\nActivating existing logical volume management.\n" 0
1891 modprobe dm-mod >/dev/null 2>$ERR
1892 errshow 'modprobe dm-mod'
1893 vgscan >/dev/null 2>&1
1894 vgchange -ay >/dev/null 2>&1
1900 VGROUP='' LVM_PARTS='' VGROUP_MB=0
1902 lvm_mkgroup || return 1
1903 local txt="\nThe last (or only) logical volume will automatically use all remaining space in the volume group."
1904 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 -
1905 [[ $VOL_COUNT ]] || return 1
1906 lvm_extra_lvs || return 1
1907 lvm_volume_name "$_lvmlvname\nNOTE: This LV will use up all remaining space in the volume group (${VGROUP_MB}MB)" || return 1
1908 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating volume $VNAME from remaining space in $VGROUP\n" 0
1909 lvcreate -l +100%FREE "$VGROUP" -n "$VNAME" >/dev/null 2>$ERR
1910 errshow "lvcreate -l +100%FREE $VGROUP -n $VNAME" || return 1
1911 LVM='logical volume'; sleep 0.5
1912 txt="\nDone, volume: $VGROUP-$VNAME (${VOLUME_SIZE:-${VGROUP_MB}MB}) has been created.\n"
1913 msg "$_lvmnew (LV:$VOL_COUNT)" "$txt\n$(lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE $LVM_PARTS)\n"
1919 local txt="${VGROUP}: ${SIZE}$SIZE_UNIT (${VGROUP_MB}MB remaining).$_lvmlvsize"
1923 dlg VOLUME_SIZE input "$_lvmnew (LV:$VOL_COUNT)" "$txt" ''
1924 if [[ -z $VOLUME_SIZE ]]; then
1926 break # allow bailing with escape or an empty choice
1927 elif (( ${VOLUME_SIZE:0:1} == 0 )); then
1928 ERR_SIZE=1 # size values can't begin with '0'
1930 # walk the string and make sure all but the last char are digits
1931 local lv=$((${#VOLUME_SIZE} - 1))
1932 for (( i=0; i<lv; i++ )); do
1933 [[ ${VOLUME_SIZE:$i:1} =~ [0-9] ]] || { ERR_SIZE=1; break; }
1935 if (( ERR_SIZE != 1 )); then
1936 case ${VOLUME_SIZE:$lv:1} in
1937 [mMgG]) local s=${VOLUME_SIZE:0:$lv} m=$((s * 1000))
1938 case ${VOLUME_SIZE:$lv:1} in
1939 [Gg]) (( m >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - m)) ;;
1940 [Mm]) (( ${VOLUME_SIZE:0:$lv} >= VGROUP_MB )) && ERR_SIZE=1 || VGROUP_MB=$((VGROUP_MB - s)) ;;
1947 if (( ERR_SIZE )); then
1948 msg "Invalid Logical Volume Size" "$_lvmerrlvsize"
1961 until [[ $named ]]; do
1962 lvm_partitions || return 1
1963 lvm_group_name || return 1
1964 yesno "$_lvmnew" "\nCreate volume group: $VGROUP\n\nusing these partition(s): $LVM_PARTS\n" && named=true
1967 msg "$_lvmnew" "\nCreating volume group: $VGROUP\n" 0
1968 vgcreate -f "$VGROUP" $LVM_PARTS >/dev/null 2>$ERR
1969 errshow "vgcreate -f $VGROUP $LVM_PARTS" || return 1
1971 SIZE=$(vgdisplay "$VGROUP" | awk '/VG Size/ { gsub(/[^0-9.]/, ""); print int($0) }')
1972 SIZE_UNIT="$(vgdisplay "$VGROUP" | awk '/VG Size/ { print substr($NF, 0, 1) }')"
1974 if [[ $SIZE_UNIT == 'G' ]]; then
1975 VGROUP_MB=$((SIZE * 1000))
1980 msg "$_lvmnew" "\nVolume group $VGROUP (${SIZE}$SIZE_UNIT) successfully created\n"
1986 pv="$(pvs -o pv_name --noheading 2>/dev/null)"
1987 v="$(lvs -o vg_name,lv_name --noheading --separator - 2>/dev/null)"
1988 VGROUP="$(vgs -o vg_name --noheading 2>/dev/null)"
1990 if [[ $VGROUP || $v || $pv ]]; then
1991 if yesno "$_lvmdelall" "$_lvmdelask"; then
1992 for i in $v; do lvremove -f "/dev/mapper/$i" >/dev/null 2>&1; done
1993 for i in $VGROUP; do vgremove -f "$i" >/dev/null 2>&1; done
1994 for i in $pv; do pvremove -f "$i" >/dev/null 2>&1; done
1998 msg "Delete LVM" "\nNo LVMs to remove...\n" 2
2008 for i in $(lvs --noheadings | awk '{print $2}' | uniq); do
2009 VOL_GROUP_LIST+="$i $(vgdisplay "$i" | awk '/VG Size/ {print $3$4}') "
2012 [[ $VOL_GROUP_LIST ]] || { msg "No Groups" "\nNo volume groups found."; return 1; }
2014 dlg DEL_VG menu "Logical Volume Management" "\nSelect volume group to delete.\n\nAll logical volumes within will also be deleted." $VOL_GROUP_LIST
2020 while (( VOL_COUNT > 1 )); do
2021 lvm_volume_name "$_lvmlvname" && lvm_lv_size || return 1
2022 msg "$_lvmnew (LV:$VOL_COUNT)" "\nCreating a $VOLUME_SIZE volume $VNAME in $VGROUP\n" 0
2023 lvcreate -L "$VOLUME_SIZE" "$VGROUP" -n "$VNAME" >/dev/null 2>$ERR
2024 errshow "lvcreate -L $VOLUME_SIZE $VGROUP -n $VNAME" || return 1
2025 msg "$_lvmnew (LV:$VOL_COUNT)" "\nDone, logical volume (LV) $VNAME ($VOLUME_SIZE) has been created.\n"
2033 part_find 'part|crypt' || return 1
2034 PARTS="$(awk 'NF > 0 {print $0 " off"}' <<< "$PARTS")"
2035 dlg LVM_PARTS check "$_lvmnew" "\nSelect the partition(s) to use for the physical volume (PV)." $PARTS
2042 until [[ $VGROUP ]]; do
2043 dlg VGROUP input "$_lvmnew" "$_lvmvgname" "lvgroup"
2044 if [[ -z $VGROUP ]]; then
2046 elif [[ ${VGROUP:0:1} == "/" || $VGROUP =~ \ |\' ]] || vgdisplay | grep -q "$VGROUP"; then
2047 msg "LVM Name Error" "$_lvmerrvgname"
2057 local txt="$1" default="mainvolume"
2058 (( VOL_COUNT > 1 )) && default="extvolume$VOL_COUNT"
2059 until [[ $VNAME ]]; do
2060 dlg VNAME input "$_lvmnew (LV:$VOL_COUNT)" "\n$txt" "$default"
2061 if [[ -z $VNAME ]]; then
2063 elif [[ ${VNAME:0:1} == "/" || $VNAME =~ \ |\' ]] || lsblk | grep -q "$VNAME"; then
2064 msg "LVM Name Error" "$_lvmerlvname"
2071 ###############################################################################
2077 no_bg_install || return 1
2078 dlg choice menu "LUKS Encryption" "$_luksmenu" \
2079 "$_luksnew" "cryptsetup -q luksFormat" \
2080 "$_luksopen" "cryptsetup open --type luks" \
2081 "$_luksadv" "cryptsetup -q -s -c luksFormat" \
2082 "Back" "Return to the main menu"
2085 "$_luksnew") luks_basic || return 1 ;;
2086 "$_luksopen") luks_open || return 1 ;;
2087 "$_luksadv") luks_advanced || return 1 ;;
2095 modprobe -a dm-mod dm_crypt >/dev/null 2>&1
2097 part_find 'part|crypt|lvm' || return 1
2099 if (( COUNT == 1 )); then
2100 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2102 dlg LUKS_PART menu "$_luksopen" "\nSelect which partition to open." $PARTS
2105 [[ $LUKS_PART ]] || return 1
2107 luks_pass "$_luksopen" || return 1
2108 msg "$_luksopen" "\nOpening encrypted partition: $LUKS_NAME\n\nUsing device/volume: $LUKS_PART\n" 0
2109 cryptsetup open --type luks "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2110 errshow "cryptsetup open --type luks $LUKS_PART $LUKS_NAME" || return 1
2111 LUKS='encrypted'; luks_show
2118 local t="$1" op="$2" v='' p='' p2=''
2120 until [[ $LUKS_PASS ]]; do
2124 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " \
2125 --mixedform "\nEnter the password to decrypt $ROOT_PART\n\nThis is needed to create a keyfile." 0 0 0 \
2126 "Password:" 1 1 '' 1 11 "$COLUMNS" 0 1 \
2127 "Password2:" 2 1 '' 2 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
2130 dialog --insecure --backtitle "$DIST Installer - $SYS - v$VER" --separator $'\n' --title " $t " --mixedform "$_luksomenu" 0 0 0 \
2131 "Name:" 1 1 "${LUKS_NAME:-cryptroot}" 1 7 "$COLUMNS" 0 0 \
2132 "Password:" 2 1 '' 2 11 "$COLUMNS" 0 1 \
2133 "Password2:" 3 1 '' 3 12 "$COLUMNS" 0 1 2>"$ANS" || return 1
2137 while read -r line; do
2153 if [[ -z $op && -z $n ]]; then
2154 msg "Name Empty" "\nEncrypted device name cannot be empty.\n\nPlease try again.\n" 2
2155 elif [[ -z $p || "$p" != "$p2" ]]; then
2156 [[ $op ]] || LUKS_NAME="$n"
2157 msg "Password Mismatch" "\nThe passwords entered do not match.\n\nPlease try again.\n" 2
2159 [[ $op ]] || LUKS_NAME="$n"
2170 msg "$_luksnew" "\nEncrypted partition ready for mounting.\n\n$(lsblk -o NAME,MODEL,SIZE,TYPE,FSTYPE "$LUKS_PART")\n\n"
2175 modprobe -a dm-mod dm_crypt >/dev/null 2>&1
2177 part_find 'part|lvm' || return 1
2179 if [[ $AUTO_ROOT_PART ]]; then
2180 LUKS_PART="$AUTO_ROOT_PART"
2181 elif (( COUNT == 1 )); then
2182 LUKS_PART="$(awk 'NF > 0 {print $1}' <<< "$PARTS")"
2184 dlg LUKS_PART menu "$_luksnew" "\nSelect the partition you want to encrypt." $PARTS
2187 [[ $LUKS_PART ]] || return 1
2188 luks_pass "$_luksnew"
2193 luks_setup || return 1
2194 msg "$_luksnew" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2195 cryptsetup -q luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2>$ERR
2196 errshow "cryptsetup -q luksFormat $LUKS_PART" || return 1
2197 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2198 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2199 LUKS='encrypted'; luks_show
2207 dlg cipher input "LUKS Encryption" "$_lukskey" "-s 512 -c aes-xts-plain64"
2208 [[ $cipher ]] || return 1
2209 msg "$_luksadv" "\nCreating encrypted partition: $LUKS_NAME\n\nDevice or volume used: $LUKS_PART\n" 0
2210 cryptsetup -q $cipher luksFormat "$LUKS_PART" <<< "$LUKS_PASS" 2>$ERR
2211 errshow "cryptsetup -q $cipher luksFormat $LUKS_PART" || return 1
2212 cryptsetup open "$LUKS_PART" "$LUKS_NAME" <<< "$LUKS_PASS" 2>$ERR
2213 errshow "cryptsetup open $LUKS_PART $LUKS_NAME" || return 1
2220 ###############################################################################
2222 # some help avoid repetition and improve usability of some commands
2223 # others are initial setup functions used before reaching the main loop
2227 [[ "$2" == *"$1"* ]] && printf "on" || printf "off"
2232 # cleanup and exit the installer cleanly with exit code $1
2233 # when ecode is 127 unmount /run/archiso/bootmnt and reboot
2238 if [[ -d $MNT ]] && command cd /; then
2240 if (( ecode == 127 )); then
2241 umount_dir /run/archiso/bootmnt
2252 local var="$1" # assign output from dialog to var
2253 local dlg_t="$2" # dialog type (menu, check, input)
2254 local title="$3" # dialog title
2255 local body="$4" # dialog message
2256 local n=0 # number of items to display for menu and check dialogs
2258 shift 4 # shift off args assigned above
2260 # adjust n when passed a large list
2261 local l=$((LINES - 20))
2262 (( ($# / 2) > l )) && n=$l
2266 menu) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --menu "$body" 0 0 $n "$@" 2>"$ANS" || return 1 ;;
2267 check) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --checklist "$body" 0 0 $n "$@" 2>"$ANS" || return 1 ;;
2270 local def="$1" # assign default value for input
2272 if [[ $1 == 'limit' ]]; then
2273 dialog --backtitle "$DIST Installer - $SYS - v$VER" --max-input 63 --title " $title " --inputbox "$body" 0 0 "$def" 2>"$ANS" || return 1
2275 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --inputbox "$body" 0 0 "$def" 2>"$ANS" || return 1
2279 # if answer file isn't empty read from it into $var
2280 [[ -s "$ANS" ]] && printf -v "$var" "%s" "$(< "$ANS")"
2285 # displays a message dialog
2286 # when more than 2 args the message will disappear after sleep time ($3)
2292 dialog --backtitle "$DIST Installer - $SYS - v$VER" --sleep "$1" --title " $title " --infobox "$body\n" 0 0
2294 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --msgbox "$body\n" 0 0
2300 select_keymap || { clear; die 0; }
2301 net_connect || { msg "Not Connected" "\nRunning live requires an active internet connection.\n\nExiting..\n" 2; die 1; }
2303 pacman -Syyu --noconfirm || die 1
2304 pacman -S $AL_BASE_PKGS $WM_BASE_PKGS xorg-xinit xorg-server --needed --noconfirm || die 1
2306 dwm) pacman -S git --needed --noconfirm || die 1
2307 mkdir -pv /root/suckless
2308 for i in dwm dmenu st; do
2309 git clone https://git.suckless.org/$i /root/suckless/$i && cd /root/suckless/$i && make PREFIX=/usr install
2311 i3-gaps|oepnbox|fluxbox|bspwm|xfce4|gnome|plasma|cinnamon|awesome) pacman -S "$1" ${WM_EXT[$1]} xterm --needed --noconfirm ;;
2312 *) echo "error: invalid session for -l, --live, see -h, --help"; die 1 ;;
2314 pacman -Scc --noconfirm # these get back some space
2315 rm -rf /var/cache/pacman/pkg/*
2316 cp -rfT /etc/skel /root || die 1
2317 sed -i "/exec/ c exec ${WM_SESSIONS[$1]}" /root/.xinitrc
2324 local title="$1" body="$2" yes='Yes' no='No'
2325 (( $# >= 3 )) && yes="$3"
2326 (( $# >= 4 )) && no="$4"
2328 if (( $# == 5 )); then
2329 dialog --backtitle "$DIST Installer - $SYS - v$VER" --defaultno --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2331 dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0
2337 arch-chroot "$MNT" bash -c "$1"
2342 export PS4='| ${BASH_SOURCE} LINE:${LINENO} FUNC:${FUNCNAME[0]:+ ${FUNCNAME[0]}()} |> '
2351 printf "\n^C caught, cleaning up...\n"
2358 "\e]P0191919" # #191919
2359 "\e]P1D15355" # #D15355
2360 "\e]P2609960" # #609960
2361 "\e]P3FFCC66" # #FFCC66
2362 "\e]P4255A9B" # #255A9B
2363 "\e]P5AF86C8" # #AF86C8
2364 "\e]P62EC8D3" # #2EC8D3
2365 "\e]P7949494" # #949494
2366 "\e]P8191919" # #191919
2367 "\e]P9D15355" # #D15355
2368 "\e]PA609960" # #609960
2369 "\e]PBFF9157" # #FF9157
2370 "\e]PC4E88CF" # #4E88CF
2371 "\e]PDAF86C8" # #AF86C8
2372 "\e]PE2ec8d3" # #2ec8d3
2373 "\e]PFE1E1E1" # #E1E1E1
2376 [[ $TERM == 'linux' ]] && printf "%b" "${colors[@]}" && clear
2381 [ $? -eq 0 ] && return 0
2383 local fatal=0 err=""
2384 err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")"
2386 (( $1 == 1 )) && { fatal=1; shift; }
2389 local txt+="\nThe command exited abnormally:\n\n$1\n\nWith the following message:\n\n$err\n\n"
2391 local txt+="\nThe command exited abnormally:\n\n$1\n\nWith no error message:\n\n"
2394 if (( fatal )); then
2395 msg "Install Error" "${txt}Errors at this stage are fatal and the install cannot continue.\n"
2396 [[ -r $DBG && $TERM == 'linux' ]] && less "$DBG"
2400 msg "Install Error" "${txt}Errors at this stage are non-fatal and can be either fixed or ignored depending on the error.\n"
2408 if (( $1 >= 0 )) && ! grep -qw "$MNT" /proc/mounts; then
2409 msg "Not Mounted" "\nPartition(s) must be mounted first.\n" 2
2411 elif [[ $1 -ge 1 && -z $BOOTLDR ]]; then
2412 msg "No Bootloader" "\nBootloader must be selected first.\n" 2
2414 elif [[ $1 -ge 2 && (-z $NEWUSER || -z $USER_PASS) ]]; then
2415 msg "No User" "\nA user must be created first.\n" 2
2417 elif [[ $1 -ge 3 && -z $CONFIG_DONE ]]; then
2418 msg "Not Configured" "\nSystem configuration must be done first.\n" 2
2421 (( i )) # return code
2426 mount | grep -q 'swap' && swapoff -a
2428 [[ -d $dir && "$(mount | grep "on $dir ")" ]] || continue
2429 umount "$dir" 2>/dev/null || { sleep 0.5; umount -f "$dir" 2>/dev/null || umount -l "$dir"; }
2435 msg "Network Connect" "\nVerifying network connection\n" 1
2436 curl -sIN --connect-timeout 5 'https://www.archlinux.org/' | sed '1q' | grep -q '200'
2441 if chk_connect; then
2443 elif hash nmtui >/dev/null 2>&1; then
2445 if [[ $TERM == 'linux' ]]; then
2446 printf "%b" "\e]P1191919" "\e]P4191919"
2448 printf "%b" "\e]P1D15355" "\e]P4255a9b"
2453 elif hash wifi-menu >dev/null 2>&1; then
2463 [[ $RSYNC_PID || $MIRROR_PID ]] || return 0
2464 msg "Install Running" "\nA background install process is currently running.\n" 2
2470 IGNORE_DEV="$(lsblk -lno NAME,MOUNTPOINT | awk '/\/run\/archiso\/bootmnt/ {sub(/[1-9]/, ""); print $1}')"
2472 if [[ $IGNORE_DEV ]]; then
2473 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ && !'"/$IGNORE_DEV/"' {print "/dev/" $1 " " $2}')"
2475 SYS_DEVS="$(lsblk -lno NAME,SIZE,TYPE | awk '/disk/ {print "/dev/" $1 " " $2}')"
2478 if [[ -z $SYS_DEVS ]]; then
2479 msg "Device Error" "\nNo available devices...\n\nExiting..\n" 2
2484 while read -r line; do
2486 done <<< "$SYS_DEVS"
2493 elif grep -q 'AuthenticAMD' /proc/cpuinfo; then
2495 elif grep -q 'GenuineIntel' /proc/cpuinfo; then
2499 modprobe -q efivarfs >/dev/null 2>&1
2501 _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."
2502 if [[ -d /sys/firmware/efi/efivars ]]; then
2504 grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars
2505 _prep+="\n - An EFI boot partition mounted."
2509 _prep+="\n\nOnce finished mounting, a portion of the install can be done in the background while you continue configuring the system:\n"
2510 _prep+="\n - Choose the system bootloader.\n - Create a user and password."
2511 _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."
2514 ###############################################################################
2517 # enable some nicer colours in the linux console
2520 if (( UID != 0 )); then
2521 msg "Not Root" "\nThis installer must be run as root or using sudo.\n\nExiting..\n" 2
2523 elif ! grep -qwm 1 'lm' /proc/cpuinfo; then
2524 msg "Not x86_64 Architecture" "\nThis installer only supports x86_64 architectures.\n\nExiting..\n" 2
2526 elif [[ $1 =~ (-h|--help) ]]; then
2528 usage: $0 [-hdl] [session]
2531 -h, --help print this message and exit
2532 -d, --debug enable debugging and log to $DBG
2533 -l, --live install and setup a live session
2536 i3-gaps - A fork of i3wm with more features including gaps
2537 openbox - A lightweight, powerful, and highly configurable stacking wm
2538 dwm - A dynamic WM for X that manages windows in tiled, floating, or monocle layouts
2539 awesome - A customized Awesome WM session created by @elanapan
2540 bspwm - A tiling wm that represents windows as the leaves of a binary tree
2541 fluxbox - A lightweight and highly-configurable window manager
2542 gnome - A desktop environment that aims to be simple and easy to use
2543 cinnamon - A desktop environment combining traditional desktop with modern effects
2544 plasma - A kde software project currently comprising a full desktop environment
2545 xfce4 - A lightweight and modular desktop environment based on gtk+2/3
2547 elif [[ $1 =~ (-d|--debug) ]]; then
2549 elif [[ $1 =~ (-l|--live) ]]; then
2553 # trap ^C to perform cleanup
2559 msg "Welcome to the $DIST Installer" "\nThis will help you get $DIST installed and setup on your system.\n\nIf you are unsure about a section the default option will be listed or\nthe first selected item will be the default.\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"
2561 select_keymap || { clear; die 0; }
2562 net_connect || { msg "Not Connected" "\nThis installer requires an active internet connection.\n\nExiting..\n" 2; die 1; }
2569 # vim:fdm=marker:fmr={,}