diff --git a/archlabs-installer b/archlabs-installer index 905de66..8877cbc 100755 --- a/archlabs-installer +++ b/archlabs-installer @@ -5,7 +5,7 @@ # Some ideas and code reworked from other resources # AIF, Cnichi, Calamares, Arch Wiki.. Credit where credit is due -VER="2.0.47" # installer version +VER="2.0.48" # installer version DIST="ArchLabs" # linux distributor MNT="/mnt" # install mountpoint ANS="/tmp/ans" # dialog answer file @@ -420,9 +420,9 @@ select_login() fi if [[ $LOGIN_TYPE == 'lightdm' ]]; then + AUTOLOGIN='' LOGIN_PKGS="lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings accountsservice" EDIT_FILES[login]="/etc/lightdm/lightdm.conf /etc/lightdm/lightdm-gtk-greeter.conf" - AUTOLOGIN='' else if (( WM_NUM == 1 )); then LOGIN_WM="${WM_SESSIONS[$INSTALL_WMS]}" @@ -431,7 +431,10 @@ select_login() LOGIN_WM="${WM_SESSIONS[$LOGIN_WM]}" fi - local txt="\nDo you want autologin enabled for $NEWUSER?\n\nIf so the following two files will be created (disable autologin by removing them):\n\n - /home/$NEWUSER/$LOGINRC (this runs startx when logging in on tty1)\n - /etc/systemd/system/getty@tty1.service.d/autologin.conf (this logs in $NEWUSER without a password)\n" + local txt="\nDo you want autologin enabled for $NEWUSER?\n\n" + txt+="If so the following two files will be created (disable autologin by removing them):\n\n" + txt+="- /home/$NEWUSER/$LOGINRC (run startx when logging in on tty1)\n" + txt+="- /etc/systemd/system/getty@tty1.service.d/autologin.conf (login $NEWUSER without password)\n" yesno "Autologin" "$txt" && AUTOLOGIN=true || AUTOLOGIN='' LOGIN_PKGS="xorg-xinit" EDIT_FILES[login]="/home/$NEWUSER/.xinitrc /home/$NEWUSER/.xprofile" @@ -714,7 +717,7 @@ select_packages() part_menu() { - check_background_install || return 0 + is_bg_install || return 0 local device choice devhash devhash="$(lsblk -f | base64)" umount_dir $MNT @@ -935,7 +938,7 @@ part_shrink() mount "$part" $MNT >/dev/null 2>&1; sleep 0.5 min=$(df --output=used --block-size=MiB "$part" | awk 'NR == 2 {print int($1) + 256}') max=$(df --output=avail --block-size=MiB "$part" | awk 'NR == 2 {print int($1)}') - umount $MNT >/dev/null 2>&1 + umount_dir $MNT tput cnorm if dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " Resize: $part " --rangebox "$_resize" 17 "$COLUMNS" "$min" "$max" $((max / 2)) 2>$ANS; then size=$(< "$ANS") @@ -1087,7 +1090,7 @@ part_mountconf() select_menu() { - check_background_install || return 0 + is_bg_install || return 0 lvm_detect umount_dir $MNT part_find 'part|lvm|crypt' || { SEL=2; return 1; } @@ -1342,7 +1345,7 @@ install_base() done trap - EXIT unset RSYNC_PID MIRROR_PID - elif [[ -d /run/archiso/sfs/airootfs/etc/skel ]]; then + elif hash rsync >/dev/null 2>&1 && [[ -d /run/archiso/sfs/airootfs/etc/skel ]]; then rsync -ahv /run/archiso/sfs/airootfs/ $MNT/ 2>$ERR errshow 1 "rsync -ahv /run/archiso/sfs/airootfs/ $MNT/" install_mirrorlist "$MNT/etc/pacman.d/mirrorlist" @@ -1429,8 +1432,10 @@ install_boot() fi if [[ $SYS == 'UEFI' ]]; then + # our old installs find $MNT/$BOOTDIR/EFI/ -maxdepth 1 -mindepth 1 -iname "$DIST" -type d -delete - find $MNT/$BOOTDIR/EFI/ -maxdepth 1 -mindepth 1 -iname 'boot' -type d -delete + # generic BOOT/ dir + find $MNT/$BOOTDIR/EFI/ -maxdepth 1 -mindepth 1 -iname 'BOOT' -type d -delete fi prerun_$BOOTLDR @@ -1438,8 +1443,8 @@ install_boot() errshow 1 "${BCMDS[$BOOTLDR]}" if [[ -d $MNT/hostrun ]]; then - umount $MNT/hostrun/udev >/dev/null 2>&1 - umount $MNT/hostrun/lvm >/dev/null 2>&1 + # cleanup the bind mounts we made earlier for the grub-probe module + umount_dir $MNT/hostrun/{udev,lvm} rm -rf $MNT/hostrun >/dev/null 2>&1 fi @@ -1464,10 +1469,11 @@ install_user() { chrun "chpasswd <<< 'root:$ROOT_PASS'" 2>$ERR errshow 1 "set root password" - if [[ $MYSHELL != *zsh ]]; then + if [[ $MYSHELL != "/usr/bin/zsh" ]]; then + # root uses zsh by default, change it if something else was chosen chrun "usermod -s $MYSHELL root" 2>$ERR errshow 1 "usermod -s $MYSHELL root" - [[ $MYSHELL == "/usr/bin/mksh" ]] && cp -fv $MNT/etc/skel/.mkshrc /root/.mkshrc + cp -fv $MNT/etc/skel/.mkshrc $MNT/root/.mkshrc fi local groups='audio,autologin,floppy,log,network,rfkill,scanner,storage,optical,power,wheel' @@ -1487,9 +1493,10 @@ install_user() [[ $INSTALL_WMS == *dwm* ]] && install_suckless [[ $INSTALL_WMS == *awesome* ]] && install_awesome + [[ $WM_PKGS == *xfce* ]] && echo 'volumeicon &' >> $MNT/home/$NEWUSER/.xprofile # remove some commands from ~/.xprofile when using KDE or Gnome as the login session - if [[ $LOGIN_WM =~ (startkde|gnome-session) ]]; then + if [[ $LOGIN_WM =~ (startkde|gnome-session) || ($LOGIN_TYPE == 'lightdm' && $WM_PKGS =~ (plasma|gnome)) ]]; then sed -i '/super/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile sed -i '/nitrogen/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile sed -i '/al-compositor/d' $MNT/home/$NEWUSER/.xprofile $MNT/root/.xprofile @@ -1516,11 +1523,12 @@ install_xinit() # sourced by ${MYSHELL##*/} when used as a login shell # automatically run startx when logging in on tty1 -[[ -z \$DISPLAY && \$XDG_VTNR -eq 1 ]] && exec startx -- vt1 +if [ -z \$DISPLAY ] && [ \$XDG_VTNR -eq 1 ]; then + exec startx +fi EOF else rm -rf $SERVICE - rm -rf $MNT/home/$NEWUSER/.{profile,zprofile,bash_profile} fi } @@ -1552,6 +1560,8 @@ EOF install_awesome() { + # downloads and sets up @elenapan's awesome WM config hosted on github + if chrun "git clone https://github.com/elenapan/archlabs-awesome /home/$NEWUSER/archlabs-awesome"; then cp -rT "/mnt/home/$NEWUSER/archlabs-awesome" "/mnt/home/$NEWUSER" cp -rT "/mnt/home/$NEWUSER/archlabs-awesome" /mnt/etc/skel @@ -1574,20 +1584,38 @@ install_packages() rm -f "$MNT/usr/bin/archlabs-installer" fi + # add extras or missed packages gathered throughout the install [[ $UCODE ]] && inpkg+=" $UCODE" - [[ $MYSHELL == *mksh ]] && inpkg+=" mksh" [[ $KERNEL == 'linux' ]] || { inpkg+=" $KERNEL"; rmpkg+=" linux"; } - [[ $inpkg =~ (term|urxvt|tilix|alacritty|sakura|tilda|plasma|cinnamon) || $INSTALL_WMS == *dwm* ]] || inpkg+=" xterm" - [[ $MYSHELL == '/usr/bin/zsh' ]] && inpkg+=" zsh-completions" + [[ $MYSHELL == "/usr/bin/mksh" ]] && inpkg+=" mksh" + if [[ $MYSHELL == '/usr/bin/zsh' ]]; then + inpkg+=" zsh-completions" + else + rmpkg+=" zsh" + fi + + # packages only installed for certain WM/DE [[ $INSTALL_WMS =~ ^(plasma|gnome|cinnamon)$ ]] || inpkg+=" archlabs-ksuperkey" [[ $INSTALL_WMS =~ (openbox|bspwm|i3-gaps|dwm|fluxbox) ]] && inpkg+=" $WM_BASE_PKGS" + # ensure a terminal gets installed + [[ $inpkg =~ (term|urxvt|tilix|alacritty|sakura|tilda|plasma|cinnamon) || $INSTALL_WMS == *dwm* ]] || inpkg+=" xterm" + + # update fully first to avoid issues chrun "pacman -Syyu --noconfirm" + + # remove packages we no longer want [[ $rmpkg ]] && chrun "pacman -Rns $rmpkg --noconfirm" + + # for some reason the user has "no network" after install even though the + # system is connected, reinstalling iputils fixes it chrun "pacman -S iputils --noconfirm" + + # install all the packages chosen throughout the install chrun "pacman -S $inpkg --needed --noconfirm" 2>$ERR errshow 1 "pacman -S $inpkg --needed --noconfirm" + # extras for bootloaders if [[ $BOOTLDR == 'grub' ]]; then if [[ $SYS == 'BIOS' ]]; then chrun "pacman -S grub os-prober --needed --noconfirm" 2>$ERR @@ -1603,13 +1631,16 @@ install_packages() chrun "pacman -S efibootmgr --needed --noconfirm" 2>$ERR errshow 1 "pacman -S efibootmgr --needed --noconfirm" fi + sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" $MNT/etc/sudoers + return 0 } install_suckless() { mkdir -pv $MNT/home/$NEWUSER/suckless + for i in dwm dmenu st; do if chrun "git clone https://git.suckless.org/$i /home/$NEWUSER/suckless/$i"; then chrun "cd /home/$NEWUSER/suckless/$i; make PREFIX=/usr install; make clean; rm config.h" @@ -1642,17 +1673,15 @@ install_mkinitcpio() install_mirrorlist() { - mfile="$1" + local mfile="$1" # output mirrorlist file if hash reflector >/dev/null 2>&1; then reflector --score 120 -l 50 -f 5 --sort rate --save "$mfile" elif hash rankmirrors >/dev/null 2>&1; then ip_add="$(curl -fsSL "http://api.ipstack.com/check&?access_key=5f29642060ab983b31fdf4c2935d8c56&fields=ip" | python -c "import sys, json; print(json.load(sys.stdin)['ip'])")" - country="$(curl -fsSL "http://api.ipstack.com/${ip_add}?access_key=5f29642060ab983b31fdf4c2935d8c56&fields=country_code" | python -c "import sys, json; print(json.load(sys.stdin)['country_code'])")" - if [[ "$country" ]]; then if [[ $country =~ (CA|US) ]]; then mirror="https://www.archlinux.org/mirrorlist/?country=US&country=CA&use_mirror_status=on" @@ -1665,7 +1694,7 @@ install_mirrorlist() mirror="https://www.archlinux.org/mirrorlist/?country=all&use_mirror_status=on" fi - curl -fsSL "$mirror" | sed -e 's/^#Server/Server/' -e '/^#/d' | rankmirrors -n 6 - >/etc/pacman.d/mirrorlist + curl -fsSL "$mirror" | sed -e 's/^#Server/Server/' -e '/^#/d' | rankmirrors -n 6 - >"$mfile" fi return 0 @@ -1674,12 +1703,13 @@ install_mirrorlist() install_background() { if [[ -d /run/archiso/sfs/airootfs/etc/skel ]] && grep -qw "$MNT" /proc/mounts && (grep -qw "$MNT/$BOOTDIR" /proc/mounts || [[ $SYS == 'BIOS' && -z $LUKS ]]); then - yesno "Background Install" "\nSome parts of the install can be done in the background now, base unpack, mirrorlist sort, system update, and base packages.\n\nDo you want to start the background process?\n" || return 0 + yesno "Background Install" "\nBegin install in the background?\n" || return 0 rsync -a /run/archiso/sfs/airootfs/ $MNT/ & RSYNC_PID=$! - ( install_mirrorlist "$MNT/etc/pacman.d/mirrorlist" && chrun "pacman -Syyu $BASE_PKGS --needed --noconfirm" >> /tmp/bg_out 2>&1 ) & + ( install_mirrorlist "$MNT/etc/pacman.d/mirrorlist"; chrun "pacman -Syyu $BASE_PKGS --needed --noconfirm" >> /tmp/bg_out 2>&1 ) & MIRROR_PID=$! - trap "kill $RSYNC_PID 2>/dev/null; kill $MIRROR_PID 2>/dev/null" EXIT + # end the background processes before exiting + trap "kill $RSYNC_PID $MIRROR_PID 2>/dev/null" EXIT fi return 0 } @@ -1695,9 +1725,9 @@ setup_grub() [[ $BOOT_DEV ]] || { part_device 1 || return 1; } BCMDS[grub]="grub-install --recheck --force --target=i386-pc $BOOT_DEV" else - if [[ $ROOT_PART == */dev/mapper/* && -z $LVM && -z $LUKS_PASS ]]; then - luks_pass "$_luksopen" 1 || return 1 - fi + # if [[ $ROOT_PART == */dev/mapper/* && -z $LVM && -z $LUKS_PASS ]]; then + # luks_pass "$_luksopen" 1 || return 1 + # fi BCMDS[grub]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1 grub-install --recheck --force --target=x86_64-efi --efi-directory=/$BOOTDIR --bootloader-id=$DIST" grep -q /sys/firmware/efi/efivars /proc/mounts || mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1 @@ -1731,8 +1761,7 @@ prerun_grub() fi # setup for os-prober module - mkdir -p /run/{lvm,udev} - mkdir -p $MNT/hostrun/{lvm,udev} + mkdir -p /run/{lvm,udev} $MNT/hostrun/{lvm,udev} mount --bind /run/lvm $MNT/hostrun/lvm mount --bind /run/udev $MNT/hostrun/udev @@ -1749,7 +1778,6 @@ prerun_efistub() BCMDS[systemd-boot]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1 efibootmgr -v -d $BOOT_DEV -p $BOOT_PART_NUM -c -L '${DIST} Linux' -l /vmlinuz-${KERNEL} \ -u 'root=$ROOT_PART_ID rw $([[ $UCODE ]] && printf 'initrd=\%s.img ' "$UCODE")initrd=\initramfs-${KERNEL}.img'" - return 0 } setup_syslinux() @@ -1760,7 +1788,6 @@ setup_syslinux() EDIT_FILES[bootloader]="/boot/EFI/syslinux/syslinux.cfg" BCMDS[syslinux]="mount -t efivarfs efivarfs /sys/firmware/efi/efivars >/dev/null 2>&1 efibootmgr -v -c -d $BOOT_DEV -p $BOOT_PART_NUM -l /EFI/syslinux/syslinux.efi -L $DIST" - fi } @@ -1902,7 +1929,7 @@ EOF lvm_menu() { - check_background_install || return 1 + is_bg_install || return 1 lvm_detect local choice dlg choice menu "Logical Volume Management" "$_lvmmenu" \ @@ -2113,7 +2140,7 @@ lvm_volume_name() luks_menu() { local choice - check_background_install || return 1 + is_bg_install || return 1 dlg choice menu "LUKS Encryption" "$_luksmenu" \ "$_luksnew" "cryptsetup -q luksFormat" \ "$_luksopen" "cryptsetup open --type luks" \ @@ -2282,28 +2309,20 @@ ofn() die() { - local exitcode="$1" + local ecode="$1" + trap - INT - trap - TSTP tput cnorm if [[ -d $MNT ]] && command cd /; then umount_dir $MNT - if (( exitcode == 127 )); then - umount -l /run/archiso/bootmnt + if (( ecode == 127 )); then + umount_dir /run/archiso/bootmnt sleep 0.5 - systemctl -i reboot + reboot -f fi fi - - # restore custom linux console 0-15 colors when not rebooting - if [[ $TERM == 'linux' ]]; then - colors=("\e]P0191919" "\e]P1D15355" "\e]P2609960" "\e]P3FFCC66" - "\e]P4255A9B" "\e]P5AF86C8" "\e]P62EC8D3" "\e]P7949494" "\e]P8191919" "\e]P9D15355" - "\e]PA609960" "\e]PBFF9157" "\e]PC4E88CF" "\e]PDAF86C8" "\e]PE2ec8d3" "\e]PFE1E1E1") - printf "%b" "${colors[@]}" && clear && unset col - fi - - exit "$exitcode" + termcol + exit "$ecode" } dlg() @@ -2314,12 +2333,8 @@ dlg() tput civis case "$dialog_type" in - menu) - dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --menu "$body" 0 0 $n "$@" 2>"$ANS" || return 1 - ;; - check) - dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --checklist "$body" 0 0 $n "$@" 2>"$ANS" || return 1 - ;; + menu) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --menu "$body" 0 0 $n "$@" 2>"$ANS" || return 1 ;; + check) dialog --backtitle "$DIST Installer - $SYS - v$VER" --title " $title " --checklist "$body" 0 0 $n "$@" 2>"$ANS" || return 1 ;; input) tput cnorm local def="$1" @@ -2348,8 +2363,8 @@ msg() yesno() { local title="$1" body="$2" yes='Yes' no='No' - (( $# >= 3 )) && local yes="$3" - (( $# >= 4 )) && local no="$4" + (( $# >= 3 )) && yes="$3" + (( $# >= 4 )) && no="$4" tput civis if (( $# == 5 )); then dialog --backtitle "$DIST Installer - $SYS - v$VER" --defaultno --title " $title " --yes-label "$yes" --no-label "$no" --yesno "$body\n" 0 0 @@ -2381,6 +2396,7 @@ sigint() print4() { local str="$*" + if [[ $COLUMNS -ge 110 && ${#str} -gt $((COLUMNS - 30)) ]]; then str="$(awk '{ i = 2; p1 = p2 = p3 = p4 = ""; p1 = $1; q = int(NF / 4) @@ -2396,14 +2412,39 @@ print4() fi } +termcol() +{ + local colors=( + "\e]P0191919" # #191919 + "\e]P1D15355" # #D15355 + "\e]P2609960" # #609960 + "\e]P3FFCC66" # #FFCC66 + "\e]P4255A9B" # #255A9B + "\e]P5AF86C8" # #AF86C8 + "\e]P62EC8D3" # #2EC8D3 + "\e]P7949494" # #949494 + "\e]P8191919" # #191919 + "\e]P9D15355" # #D15355 + "\e]PA609960" # #609960 + "\e]PBFF9157" # #FF9157 + "\e]PC4E88CF" # #4E88CF + "\e]PDAF86C8" # #AF86C8 + "\e]PE2ec8d3" # #2ec8d3 + "\e]PFE1E1E1" # #E1E1E1 + ) + + [[ $TERM == 'linux' ]] && printf "%b" "${colors[@]}" && clear +} + errshow() { - exit_code="$?" - (( exit_code == 0 )) && return 0 + [ $? -eq 0 ] && return 0 local fatal=0 err="" err="$(sed 's/[^[:print:]]//g; s/\[[0-9\;:]*\?m//g; s/==> //g; s/] ERROR:/]\nERROR:/g' "$ERR")" + (( $1 == 1 )) && { fatal=1; shift; } + local txt="\nThe command exited abnormally:\n\n$1\n\n" if [[ $err ]]; then @@ -2412,15 +2453,14 @@ errshow() txt+="With no error message:\n\n" fi - if (( fatal == 1 )); then + if (( fatal )); then txt+="Errors at this stage are fatal and the install cannot continue.\n" else txt+="Errors at this stage are non-fatal and can be either fixed or ignored depending on the error.\n" fi - msg "Install Error" "$txt" - if (( fatal == 1 )); then + if (( fatal )); then [[ -r $DBG && $TERM == 'linux' ]] && less "$DBG" die 1 fi @@ -2437,31 +2477,31 @@ load_bcm() prechecks() { - if [[ $1 -ge 0 ]] && ! grep -qw "$MNT" /proc/mounts; then + local i=1 + + if (( $1 >= 0 )) && ! grep -qw "$MNT" /proc/mounts; then msg "Not Mounted" "\nPartition(s) must be mounted first.\n" 2 - SEL=4 - return 1 + SEL=4 i=0 elif [[ $1 -ge 1 && -z $BOOTLDR ]]; then msg "No Bootloader" "\nBootloader must be selected first.\n" 2 - SEL=5 - return 1 + SEL=5 i=0 elif [[ $1 -ge 2 && (-z $NEWUSER || -z $USER_PASS) ]]; then msg "No User" "\nA user must be created first.\n" 2 - SEL=6 - return 1 + SEL=6 i=0 elif [[ $1 -ge 3 && -z $CONFIG_DONE ]]; then msg "Not Configured" "\nSystem configuration must be done first.\n" 2 - SEL=7 - return 1 + SEL=7 i=0 fi - return 0 + (( i )) # return code } umount_dir() { - swapoff -a - [[ -d $1 ]] && umount -R "$1" >/dev/null 2>&1 - return 0 + mount | grep -q 'swap' && swapoff -a + for dir; do + [[ -d $dir ]] || continue + umount "$dir" 2>/dev/null || { sleep 0.5; umount -f "$dir" 2>/dev/null || umount -l "$dir"; } + done } chk_connect() @@ -2477,9 +2517,13 @@ net_connect() else if hash nmtui >/dev/null 2>&1; then tput civis - [[ $TERM == 'linux' ]] && printf "%b" "\e]P1191919" "\e]P4191919" - nmtui-connect - [[ $TERM == 'linux' ]] && printf "%b" "\e]P1D15355" "\e]P4255a9b" + if [[ $TERM == 'linux' ]]; then + printf "%b" "\e]P1191919" "\e]P4191919" + nmtui-connect + printf "%b" "\e]P1D15355" "\e]P4255a9b" + else + nmtui-connect + fi chk_connect else return 1 @@ -2487,6 +2531,13 @@ net_connect() fi } +is_bg_install() +{ + [[ $RSYNC_PID || $MIRROR_PID ]] || return 0 + msg "Install Running" "\nA background install process is currently running.\n" 2 + return 1 +} + system_devices() { IGNORE_DEV="$(lsblk -lno NAME,MOUNTPOINT | awk '/\/run\/archiso\/bootmnt/ {sub(/[1-9]/, ""); print $1}')" @@ -2533,16 +2584,12 @@ system_identify() _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." } -check_background_install() -{ - [[ $RSYNC_PID || $MIRROR_PID ]] || return 0 - msg "Install Running" "\nA background install process is currently running.\n" 2 - return 1 -} - ############################################################################### # entry point +# enable some nicer colours in the linux console +termcol + if (( UID != 0 )); then msg "Not Root" "\nThis installer must be run as root or using sudo.\n\nExiting..\n" 2 die 1