#!/bin/sh # ArchSetup - Craig Jennings # License: GNU GPLv3 # Commentary # # There are two levels of errors: # * CRASH: Issues that will halt forward progress, aborting this script. # * ERROR: Issues not serious enough to halt the script. # Both are printed on screen and in the $logfile. # Stderr is also printed to the $logfile for all relevant info. # # This script creates a tmpfs RAM disk for all compilation. This speeds up # building and installing, and all source code no longer exists after reboot. # # # Code # uncomment to stop on any error # set -e ### Constants username="cjennings" password="welcome" # will be changed on first login. :) dwm_repo="https://git.cjennings.net/dwm.git" dmenu_repo="https://git.cjennings.net/dmenu.git" st_repo="https://git.cjennings.net/st.git" slock_repo="https://git.cjennings.net/slock.git" dotfiles_repo="https://git.cjennings.net/dotfiles" dotemacs_repo="https://git.cjennings.net/dotemacs.git" dotfiles_home="/home/$username/.dotfiles" logfile="/var/log/archsetup-$(date +'%Y-%m-%d-%H-%M-%S').log" source_dir="/home/$username/.local/src" # aur/git source goes here packages_before="/var/log/archsetup-preexisting-package-list.txt" packages_after="/var/log/archsetup-post-install-package-list.txt" archsetup_packages="/var/log/archsetup-installed-packages.txt" ### Intro intro() { printf "\n\nArchSetup launched @ %s\n" "$(date +'%D %T')"| tee -a "$logfile" STARTTIME=$(date +%s) errors_encountered=0 # begin with a clean logfile [ -f "$logfile" ] && rm -f "$logfile" touch "$logfile" # count the arch packages before install pacman -Q > "$packages_before" || \ error "crash" "generating pre-install package list" "$?" } ### General Functions # Error error () { # $1 = type ERROR, noted but the script will continue to run. # anything else will produce CRASH, which halts the script # $2 = what was happening (e.g., "adding $username to group $groupname") # $3 = the error code (i.e., "$?") errors_encountered=$((errors_encountered+1)) case "$1" in "error") printf "ERROR: %s failed with error code %s @ %s\n" \ "$2" "$3" "$(date +'%T')" | tee -a "$logfile" return 1; ;; *) printf "CRASH: %s failed with error: %s @ %s. Script halted.\n" \ "$2" "$3" "$(date +'%T')" | tee -a "$logfile" exit 1; ;; esac } # Display display () { # $1 = type (TITLE, ACTION) # $2 = description (answers: "what are you trying to do?") case "$1" in "title") printf "\n##### %s\n" "$2" | tee -a "$logfile" return 1; ;; "subtitle") printf "\n%s\n" "$2" | tee -a "$logfile" ;; "task") printf "...%s @ %s\n" "$2" "$(date +'%T')" | tee -a "$logfile" return 1; ;; *) printf "CRASH: display () called with incorrect arguments.\n" printf "...called %s type, %s action @ %s\n" \ "$1" "$2" "$(date +'%T')" | tee -a "$logfile" exit 1; ;; esac } # Pacman Install pacman_install() { action="installing $1 via pacman" && display "task" "$action" if ! (pacman --noconfirm --needed -S "$1" >> "$logfile" 2>&1); then action="retrying $1" && display "task" "$action" if ! (pacman --noconfirm --needed -S "$1" >> "$logfile" 2>&1); then action="retrying $1 once more" && display "task" "$action" (pacman --noconfirm --needed -S "$1" >> "$logfile" 2>&1) || error "error" "$action" "$?" fi fi } # Git Install git_install() { prog_name="$(basename "$1" .git)" build_dir="$source_dir/$prog_name" action="building & installing $prog_name from source" display "task" "$action" if ! (sudo -u "$username" git clone --depth 1 "$1" "$build_dir" >> "$logfile" 2>&1); then error "error" "cloning source code for $prog_name" "$?" (cd "$build_dir" && sudo -u "$username" git pull --force origin master >> "$logfile" 2>&1) || \ error "error" "pulling source code for $prog_name" "$?" fi (cd "$build_dir" && make install >> "$logfile" 2>&1) || \ error "error" "building $prog_name from source code" "$?" } # AUR Install aur_install() { action="installing $1 via the AUR" && display "task" "$action" if ! (sudo -u "$username" yay -S --noconfirm "$1" >> "$logfile" 2>&1); then action="retrying $1" && display "task" "$action" if ! (sudo -u "$username" yay -S --noconfirm "$1" >> "$logfile" 2>&1); then action="retrying $1 once more" && display "task" "$action" (sudo -u "$username" yay -S --noconfirm "$1" >> "$logfile" 2>&1) || error "error" "$action" "$?" fi fi } # PIP Install pip_install() { [ -x "$(command -v "pip")" ] || pacman_install python-pip action="installing $1 via PIP" && display "task" "$action" (yes | sudo -u "$username" pip install "$1" >> "$logfile" 2>&1) || \ error "error" "$action" "$?" } ### Prerequisites prerequisites() { # why these software packages are 'required' # linux-firmware - ensuring hardware can be detected properly # base_devel - required tools to compile # ca_certificates - for validation of keyrings, etc. # coreutils - comparing package lists # curl - to transfer source code # git - tools required to work with git source respositories # go - required to build yay, the aur installer # ntp - must communicate with other servers in synchronized manner # python - required for python pip installs # stow - places the dotfiles (see: https://bit.ly/41GmysO) # tar - extract unix archives # vi - should things go wrong, we'll need an editor # zsh - we need a shell interpreter for yay; this one's mine display "title" "Prerequisites" display "subtitle" "Bootstrapping" action="ensuring current Arch Linux keyring" && display "task" "$action" (pacman -Syy) >> "$logfile" 2>&1 || error "crash" "$action" "$?" (pacman -S --noconfirm archlinux-keyring) >> "$logfile" 2>&1 || \ error "crash" "$action" "$?" display "task" "verifying Arch Linux keys" (pacman-key --populate archlinux >> "$logfile" 2>&1) || \ error "crash" "verifying Arch Linux keys" "$?" action="refreshing the package cache" && display "task" "$action" (pacman -Syu --noconfirm >> "$logfile" 2>&1) || error "crash" "$action" "$?" display "subtitle" "Required Software" for software in linux-firmware base-devel ca-certificates \ coreutils curl git go ntp openssh python \ stow tar vi zsh; do pacman_install "$software" done display "subtitle" "Environment Configuration" # sync the time on this machine action="synchronizing system time" && display "task" "$action" (ntpdate 0.us.pool.ntp.org >> "$logfile" 2>&1) || error "error" "$action" "$?" action="configuring compiler to use all processor cores" && display "task" "$action" sed -i "s/-j2/-j$(nproc)/;s/^#MAKEFLAGS/MAKEFLAGS/" /etc/makepkg.conf >> "$logfile" 2>&1 # enable pacman concurrent downloads and color action="enabling concurrent downloads" && display "task" "$action" sed -i "s/^#ParallelDownloads.*$/ParallelDownloads = 10/;s/^#Color$/Color/" /etc/pacman.conf action="Package Mirrors" && display "subtitle" "$action" pacman_install reflector action="configuring reflector" && display "task" "$action" (printf ' --connection-timeout 3 \ --download-timeout 3 \ --protocol https \ --age 12 \ --latest 20 \ --score 10 \ --fastest 5 \ --sort score \ --save /etc/pacman.d/mirrorlist ' > /etc/xdg/reflector/reflector.conf >> "$logfile" 2>&1) || \ error "error" "$action" "$?" action="updating repository mirrors" && display "task" "$action" (reflector --connection-timeout 3 \ --download-timeout 3 \ --protocol https \ --age 12 \ --latest 20 \ --score 10 \ --fastest 5 \ --sort score \ --save /etc/pacman.d/mirrorlist > /dev/null 2>&1) action="enabling the reflector timer" && display "task" "$action" (systemctl enable reflector.timer >> "$logfile" 2>&1) || \ error "error" "$action" "$?" action="replacing sudoers file if new package version exists" && display "task" "$action" [ -f /etc/sudoers.pacnew ] && cp /etc/sudoers.pacnew /etc/sudoers >> "$logfile" 2>&1 action="creating a directory to build/install software from git/AUR." (mkdir -p $source_dir) || error "crash" "creating the directory $source_dir" } ### Create User create_user () { display "title" "User Creation" display "task" "checking if user exists" # halt if $username exists ( id -u "$username" >/dev/null 2>&1; ) && \ error "crash" "user '$username' already exists!" # create $username with home, group, shell, password action="creating user and home directory" && display "task" "$action" (useradd -m -G wheel -s /bin/zsh "$username" >> "$logfile" 2>&1) || \ error "crash" "adding user '$username" "$?" display "task" "assigning the password" echo "$username:$password" | chpasswd # any text is allowable! be careful! display "task" "adding to appropriate groups" (usermod -aG \ sys,adm,network,scanner,power,uucp,audio,lp,rfkill,video,storage,optical,users \ "$username" >> "$logfile" 2>&1) || error "crash" "adding $username to groups" "$?" display "task" "configuring shell" # zsh cache required: $username will install via yay; zsh will run those commands mkdir -p "/home/$username/.cache/zsh/" | tee -a "$logfile" # give $username sudo nopasswd rights (required for aur installs) display "task" "granting permissions" (echo "%$username ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers) \ || error "error" "$action" "$?" # mount as ramdisk to speed aur/git build/installs (sudo mount -t tmpfs -o size=4G archsetup $source_dir >> "$logfile" 2>&1) || \ error "crash" "mounting the RAM disk for archsetup" "$?" (chown -R "$username":wheel "$(dirname "$source_dir")" >> "$logfile" 2>&1) || \ error "crash" "changing ownership of $source_dir" "$?" } ### User Customizations user_customizations() { action="User Customizations" && display "title" "$action" action="cloning dotfiles" && display "task" "$action" (git clone --depth 1 $dotfiles_repo "$dotfiles_home" \ >> "$logfile" 2>&1) || error "error" "$action" "$?" action="moving dotfiles into place" && display "task" "$action" (cd "$dotfiles_home" && stow --no-folding --adopt * \ >> "$logfile" 2>&1 ) || error "error" "$action" "$?" action="restoring dotfile versions" && display "task" "$action" (cd "$dotfiles_home" && git restore . \ >> "$logfile" 2>&1 ) || error "error" "$action" "$?" action="creating common directories" && display "task" "$action" # Create default directories and grant permissions { mkdir -p -m 751 /home/$username/code mkdir -p -m 751 /home/$username/documents mkdir -p -m 751 /home/$username/downloads/torrents/complete mkdir -p -m 751 /home/$username/downloads/torrents/incomplete mkdir -p -m 751 /home/$username/downloads/torrents/files mkdir -p -m 751 /home/$username/downloads/ebooks mkdir -p -m 751 /home/$username/music mkdir -p -m 751 /home/$username/projects mkdir -p -m 751 /home/$username/pictures/screenshots mkdir -p -m 751 /home/$username/videos mkdir -p -m 751 /home/$username/vms chown -R $username: /home/$username mkdir -p -m 751 /media/backup mkdir -p -m 751 /media/remote0 mkdir -p -m 751 /media/remote1 mkdir -p -m 751 /media/remote2 chown -R $username: /media } >> "$logfile" 2>&1 } ### AUR Installer aur_installer () { display "title" "AUR Installer" yay_repo="https://aur.archlinux.org/yay.git" build_dir="$source_dir/yay" display "task" "fetching source code for yay" if ! (sudo -u "$username" git clone --depth 1 "$yay_repo" "$build_dir" >> "$logfile" 2>&1); then error "error" "cloning source code for yay" (sudo -u "$username" -D "$build_dir" git pull --force origin master >> "$logfile" 2>&1) || \ error "crash" "changing directories to $build_dir and pulling source code" "$?" fi action="packaging and installing yay"; display "task" "$action" (cd "$build_dir" && sudo -u "$username" makepkg --noconfirm -si >> "$logfile" 2>&1) || \ error "crash" "$action" "$?" } ### Essential Services essential_services() { display "title" "Essential Services" # Randomness display "subtitle" "Randomness" pacman_install rng-tools systemctl enable rngd >> "$logfile" 2>&1 || error "error" "$action" "$?" systemctl start rngd >> "$logfile" 2>&1 || error "error" "$action" "$?" # Networking display "subtitle" "Networking" pacman_install networkmanager # Power display "subtitle" "Power" pacman_install upower systemctl enable upower >> "$logfile" 2>&1 || error "error" "$action" "$?" # Secure Shell display "subtitle" "Secure Shell" pacman_install openssh action="enabling the openssh service to run at boot" && display "task" "$action" systemctl enable sshd >> "$logfile" 2>&1 || error "error" "$action" "$?" action="starting the openssh service" && display "task" "$action" systemctl start sshd >> "$logfile" 2>&1 || error "error" "$action" "$?" # Firewall # deny all connections by default, then allow the following: # http/s : 80/tcp, 443/tcp # tor : 9040,9050,9051,9053,9119/tcp # email : IMAP, IMAPS # mDNS printer discovery : 5353/udp # ssh : ssh # syncthing : 22000/tcp, 22000/udp, 21027/udp # torrents : transmission # calibre content server : 8080/tcp display "subtitle" "Firewall" pacman_install ufw action="configuring ufw to deny by default" && display "task" "$action" ufw default deny incoming >> "$logfile" 2>&1 || error "error" "$action" # note on the numbered protocols # "80,443,8080/tcp" ## http and https traffic # "9040,9050,9051,9053,9119/tcp" ## tor network # "55353/udp" ## DNS # "22000/tcp" "22000/udp" "21027/udp" ## syncthing for protocol in \ "80,443,8080/tcp" \ "9040,9050,9051,9053,9119/tcp" \ "IMAP" "IMAPS" \ "55353/udp" \ "ssh" \ "22000/tcp" "22000/udp" "21027/udp" \ "transmission" \ ; do action="adding ufw rule to allow $protocol" && display "task" "$action" (ufw allow $protocol >> "$logfile" 2>&1) || error "error" "$action" "$?" done action="adding limits to protect from brute force attacks" && display "task" "$action" (ufw limit 22/tcp >> "$logfile" 2>&1 && \ ufw limit 443/tcp >> "$logfile" 2>&1) || \ error "error" "action" action="enabling firewall service to launch on boot" && display "task" "$action" systemctl enable ufw.service >> "$logfile" 2>&1 || error "error" "$action" "$?" action="starting firewall service" && display "task" "$action" systemctl start ufw.service >> "$logfile" 2>&1 || error "error" "$action" "$?" # Service Discovery display "subtitle" "Network Service Discovery" pacman_install nss-mdns # GNU Name Service Switch host name resolution pacman_install avahi # service discovery on a local network using mdns action="configuring avahi" && display "task" "$action" systemctl disable systemd-resolved.service >> "$logfile" 2>&1 || error "error" "$action" "$?" systemctl enable avahi-daemon.service >> "$logfile" 2>&1 || error "error" "$action" "$?" # Job Scheduling display "subtitle" "Job Scheduling" pacman_install cronie action="enabling cronie to launch at boot" && display "task" "$action" systemctl enable cronie >> "$logfile" 2>&1 || error "error" "$action" "$?" pacman_install at action="enabling the batch delayed command scheduler" && display "task" "$action" systemctl enable atd >> "$logfile" 2>&1 || error "error" "$action" "$?" # Package Repository Cache Maintenance display "subtitle" "Package Repository Cache Maintenance" systemctl enable --now paccache.timer >> "$logfile" 2>&1 || error "error" "$action" "$?" # Timeshift-Autosnap display "subtitle" "Snapshot Service" aur_install timeshift-autosnap pacman_install grub-btrfs action="enabling snapshot boot menu updates" && display "task" "$action" systemctl enable grub-btrfsd >> "$logfile" 2>&1 || error "error" "$action" "$?" action="starting snapshot boot menu updates" && display "task" "$action" # starting and stopping service to generate the grub-btrfs config systemctl start grub-btrfsd >> "$logfile" 2>&1 || error "error" "$action" "$?" systemctl stop grub-btrfsd >> "$logfile" 2>&1 || error "error" "$action" "$?" # edit grub-btrfs config for timeshift auto snapshot support sed -i \ 's|ExecStart=/usr/bin/grub-btrfsd --syslog /.snapshots|ExecStart=/usr/bin/grub-btrfsd --syslog --timeshift-auto|' \ /etc/systemd/system/grub-btrfsd.service action="regenerating boot menu" && display "task" "$action" grub-mkconfig -o /boot/grub/grub.cfg >> "$logfile" 2>&1 || error "error" "$action" "$?" } ### Xorg Display Manager xorg() { action="Xorg Display Server Dependencies" && display "subtitle" "$action" pacman_install libglvnd action="Xorg Display Server" && display "subtitle" "$action" for software in xorg-server xorg-xinit xorg-xsetroot \ xsel xorg-xbacklight xf86-input-libinput \ xorg-xdpyinfo xorg-xprop xorg-xwininfo \ xorg-xinput xorg-xkill ; do pacman_install $software done } ### DWM Window Manager dwm() { action="DWM Window Manager Dependencies" && display "subtitle" "$action" for software in coreutils fontconfig freetype2 glibc libx11 libxft libxinerama; do pacman_install $software done; action="DWM Window Manager" && display "subtitle" "$action" git_install $dwm_repo git_install $dmenu_repo git_install $st_repo git_install $slock_repo aur_install pinentry-dmenu # password entry that leverages dmenu } ### Desktop Environment desktop_environment() { display "title" "Desktop Environment" # Fonts action="Fonts" && display "subtitle" "$action" pacman_install noto-fonts-emoji pacman_install ttf-firacode-nerd pacman_install ttf-hack-nerd pacman_install ttf-jetbrains-mono-nerd pacman_install ttf-meslo-nerd pacman_install ttf-nerd-fonts-symbols-mono aur_install ttf-all-the-icons aur_install ttf-lato aur_install ttf-ms-fonts aur_install ttf-ubraille # System Utilities action="System Utilities" && display "subtitle" "$action" pacman_install dmidecode pacman_install dosfstools pacman_install exfat-utils pacman_install lshw pacman_install ntfs-3g pacman_install sshfs pacman_install testdisk pacman_install udisks2 aur_install downgrade aur_install duf aur_install inxi # File Associations action="File/Application Associations" && display "subtitle" "$action" pacman_install perl-file-mimeinfo pacman_install xdg-utils # Authentication Tools action="Authentication Tools" && display "subtitle" "$action" pacman_install gnupg pacman_install polkit pacman_install gnome-keyring # ensure correct permissions on .gpg directory # the colon means the user's group will have perms [ -d /home/"$username"/.gnupg ] || mkdir /home/"$username"/.gnupg chown -R "$username": /home/"$username"/.gnupg find /home/"$username"/.gnupg -type f -exec chmod 600 {} \; find /home/"$username"/.gnupg -type d -exec chmod 700 {} \; # Power Management action="Power Management" && display "subtitle" "$action" pacman_install acpi pacman_install powertop # Audio System action="Audio System" && display "subtitle" "$action" for software in alsa-utils pipewire wireplumber pipewire-pulse \ pipewire-docs pamixer pulsemixer ffmpeg; do pacman_install $software done; # disable the pc speaker beep rmmod pcspkr >> "$logfile" 2>&1 echo "blacklist pcspkr" >/etc/modprobe.d/nobeep.conf >> "$logfile" 2>&1 # Keyboard Shortcut Manager action="Keyboard Shortcut Manager" && display "subtitle" "$action" pacman_install sxhkd # Notifications action="Notification System" && display "subtitle" "$action" pacman_install libnotify pacman_install dunst # Bluetooth Devices action="Bluetooth System" && display "subtitle" "$action" for software in bluez bluez-utils blueman; do pacman_install $software done action="enabling bluetooth to launch at boot" && display "task" "$action" systemctl enable bluetooth.service >> "$logfile" 2>&1 || error "error" "$action" "$?" # Command Line Utilities action="Command Line Utilities" && display "subtitle" "$action" for software in htop mc ncdu tmux fzf zip unzip atool wget detox \ lsof usbutils moreutils; do pacman_install "$software" done; for software in task-spooler speedtest-go gotop-bin rar; do aur_install "$software" done; # Help And Documentation action="Help and Documentation" && display "subtitle" "$action" pacman_install man pacman_install arch-wiki-docs pacman_install tealdeer aur_install cht.sh-git # Sync Services action="Sync Services" && display "subtitle" "$action" pacman_install syncthing systemctl enable syncthing@$username.service >> "$logfile" 2>&1 || error "error" "$action" "$?" # Desktop Environment Utilities action="Desktop Environment Utilities" && display "subtitle" "$action" for software in brightnessctl xautolock network-manager-applet xclip \ conky nitrogen qalculate-gtk; do pacman_install $software done; aur_install python-pulsectl aur_install caffeine-ng aur_install colorpicker # Theme and Cursor action="UI Theme" && display "subtitle" "$action" for software in picom lxappearance gnome-themes-extra gtk-engine-murrine; do pacman_install $software done; for software in vimix-icon-theme vimix-cursors vimix-gtk-themes \ qt5ct adwaita-color-schemes; do aur_install $software done; # Browsers action="Browsers" && display "subtitle" "$action" pacman_install firefox ## TESTING IF NEEDED aur_install librewolf-bin aur_install tor-browser-bin aur_install google-chrome # Install Printing action="Print System" && display "subtitle" "$action" pacman_install cups # the printing service pacman_install cups-pdf # allows printing to pdf pacman_install foomatic-db-engine # generates printer drivers, queues, and jobs pacman_install foomatic-db-ppds # printer driver descriptions pacman_install foomatic-db-nonfree-ppds # non-free printer driver descriptions pacman_install gutenprint # printer driver engine for older computers pacman_install foomatic-db-gutenprint-ppds # gutenprint prebuilt ppd files action="enabling printing service to launch at boot" && display "task" "$action" (systemctl enable cups.service >> "$logfile" 2>&1) || error "error" "$action" "$?" } ### Developer Workstation developer_workstation () { action="Developer Workstation" && display "title" "$action" action="Programming Languages and Utilities" && display "subtitle" "$action" # C pacman_install clang # C/C++ compiler pacman_install cmake # make system pacman_install gdb # the GNU debugger pacman_install splint # C programming static analysis pacman_install valgrind # memory management utility # java pacman_install jdk-openjdk # Java Development Kit pacman_install openjdk-doc # ...and the documentation # Lisps pacman_install guile # GNU Scheme pacman_install sbcl # Steel Bank Common Lisp pacman_install racket # Racket + SICP mit-scheme emulation # Rust pacman_install rust # Rust programming language # Python pacman_install pyright # Python language server pacman_install pyenv # Python environment manager # Shell pacman_install shellcheck # Shell script linter pacman_install shfmt # Shell script formatter # Go pacman_install delve # Go programming language debugger pacman_install go-tools # Go language utilities pacman_install gopls # Go language server pacman_install staticcheck # Go programming language linter # Typescript pacman_install jq # JSON processor pacman_install typescript # Typescript programming language pacman_install nodejs # Node-js JavaScript runtime environment pacman_install npm # Node-js package manager aur_install nvm # Node-js version manager # HTML pacman_install tidy # HTML formatter pacman_install prettier # Multi-language formatter # General Utilities pacman_install meld # Visual diff pacman_install ripgrep # Fast grep utility aur_install the_silver_searcher # Another fast grep utility action="Programming Editors" && display "subtitle" "$action" pacman_install mg # mini emacs pacman_install neovim # mega vi pacman_install pycharm-community-edition # python ide pacman_install code # vscode oss version action="Emacs Dependencies" && display "subtitle" "$action" pacman_install emacs # supporting utilities used by my emacs configuration aur_install exercism-bin # command line tool for exercism.io aur_install isync # email sync aur_install mu # email indexer and utilities aur_install multimarkdown # markdown conversion aur_install proselint # grammar checker aur_install gist # command-line gist poster pacman_install aspell # spell check system pacman_install aspell-en # spell check english files pacman_install fd # a faster find for dired/dirvish pacman_install ffmpegthumbnailer # video previews in dired/dirvish pacman_install imagemagick # image previews for dired/dirvish pacman_install libgccjit # native compilation for Emacs pacman_install mediainfo # generating media info in dired/dirvish pacman_install mpv # video viewer pacman_install mailutils # Emacs' IMAP mail support backend pacman_install msmtp # mail transport for Mu4e pacman_install msmtp-mta # mail transport for Mu4e pacman_install python-lsp-server # python language support pacman_install rlwrap # adds readline support to programs (SBCL-related) pacman_install sdcv # stardict dictionary system pacman_install yt-dlp # video download action="setting up emacs configuration files" && display "task" "$action" (sudo -u "$username" git clone --recurse-submodules $dotemacs_repo /home/$username/.emacs.d >> \ "$logfile" 2>&1) || error "error" "$action" "$?" action="Android Utilities" && display "subtitle" "$action" pacman_install android-file-transfer pacman_install android-tools action="DevOps Utilities" && display "subtitle" "$action" action="installing devops virtualization and automation tools" && display "task" "$action" pacman_install vagrant pacman_install ansible # distrobox related pacman_install podman pacman_install distrobox aur_install boxbuddy aur_install ptyxis # boxes pacman_install gnome-boxes # virtualbox related # ensure headers exist before installing virtualbox*dkms pacman_install linux-headers pacman_install linux-lts-headers pacman_install virtualbox pacman_install virtualbox-guest-iso pacman_install virtualbox-host-dkms # docker action="adding user to vboxusers group" && display "task" "$action" (gpasswd -a $username vboxusers >> "$logfile" 2>&1) || error "error" "$action" "$?" pacman_install docker pacman_install docker-compose action="adding user to docker group" && display "task" "$action" (gpasswd -a $username docker >> "$logfile" 2>&1) || error "error" "$action" "$?" action="enabling docker service to launch on boot" && display "task" "$action" systemctl enable docker.service >> "$logfile" 2>&1 || error "error" "$action" "$?" } ### Supplemental Software supplemental_software() { display "title" "Supplemental Software" # pacman installs pacman_install devtools # tools for arch linux package maintenance pacman_install arandr # xrandr gui for monitor settings pacman_install arch-install-scripts # for making arch installers pacman_install archinstall # the archinstall python program pacman_install aria2 # fast downloader pacman_install bc # arbitrary precision calculator pacman_install calibre # ebook manager/viewer pacman_install dash # posix compliant /bin/sh pacman_install dfc # better display of available space on mounted filesystems pacman_install docx2txt # recovers text from docx files pacman_install entr # run arbitrary commands when files change pacman_install faac # open source mpeg 3 and aac encoder pacman_install faad2 # processes an aac stream pacman_install figlet # words into ascii art pacman_install filezilla # ftp gui pacman_install gparted # disk partition utility pacman_install gst-plugin-pipewire # gstreamer audio plugin for pipewire pacman_install gst-plugins-base # gstreamer base audio plugins pacman_install gst-plugins-good # gstreamer extra audio plugins pacman_install gstreamer # pipeline based multimedia framework pacman_install gucharmap # gui display of character maps pacman_install gzip # compression tool pacman_install handbrake # video transcoder pacman_install ledger # CLI accounting software pacman_install libconfig # library for processing structured config files pacman_install libmad # mpeg audio decoder pacman_install libmpeg2 # library for decoding mpeg video streams pacman_install maim # screenshot utility pacman_install mediainfo # technical and tag information about media files pacman_install mosh # alt SSH terminal with roaming and responsiveness support pacman_install mpc # command line interface to mpd pacman_install mpd # the music player daemon pacman_install ncmpcpp # and mpd client to play music pacman_install neofetch # cli system information tool pacman_install obs-studio # desktop recording software pacman_install obsidian # personal knowledgebase pacman_install odt2txt # converts from open document to text pacman_install p7zip # p7zip compression tool pacman_install pandoc # universal document converter pacman_install perl-image-exiftool # reads/writes exif info for raw photo files pacman_install poppler-glib # poppler-glib document viewer library pacman_install pv # monitor progress of data through pipeline pacman_install ranger # terminal file manager pacman_install rclone # syncs files from gdrive, s3, dropbox, etc. pacman_install signal-desktop # secure messenger pacman_install smartmontools # monitors hard drives pacman_install texlive-meta # latex pacman_install thunderbird # email, calendar, rss feeds pacman_install transmission-cli # bittorrent client pacman_install transmission-remote-gtk # bittorrent client pacman_install unclutter # hides mouse cursor when not being used pacman_install w3m # text based browser pacman_install wavpack # audio compression format pacman_install webkit2gtk # web content engine for GTK pacman_install xcb-util-cursor # calibre dependency (calibre installed manually) pacman_install xdotool # command line xorg automation tool pacman_install xz # general purpose data compression tool pacman_install zathura # document viewer pacman_install zathura-cb # zathura plugin for comics pacman_install zathura-djvu # zathura plugin for djvu books pacman_install zathura-pdf-mupdf # zathura plugin for pdf pacman_install zlib # compression library # aur installs aur_install topgrade # upgrade everything utility aur_install dtrx # extraction tool aur_install figlet-fonts # fonts for figlet aur_install hfsprogs # file system tools for Mac OS aur_install mcomix # image viewer for comic books aur_install nsxiv # image viewer aur_install shell-gpt # gpt in your terminal aur_install tageditor # metadata editor for mkv, webm and related video files aur_install tidal-dl # tidal-dl:tidal as yt-dlp:youtube aur_install ueberzug # allows for displaying images in terminals aur_install tremc # curses interface for transmission aur_install snore-git # sleep with feedback aur_install zsh-fast-syntax-highlighting-git # Optimized and extended zsh-syntax-highlighting } ### Boot-Related silent_boot() { action="Silent Boot" && display "title" "$action" action="removing distro and date/time from initial screen" && display "task" "$action" (cat /dev/null >/etc/issue) || error "error" "$action" "$?" action="preventing kernel messages on the console" && display "task" "$action" (echo "kernel.printk = 3 3 3 3" >/etc/sysctl.d/20-quiet-printk.conf) || \ error "error" "$action" "$?" action="delegating fsck messages from udev to systemd" && display "task" "$action" sed -i "s/.*HOOKS=(base udev autodetect keyboard keymap modconf block filesystems fsck).*/HOOKS=(base systemd autodetect keyboard keymap modconf block filesystems fsck)/" /etc/mkinitcpio.conf || error "error" "running sed on mkinitcpio.conf to hide fsck messages" "$?" mkinitcpio -P >> "$logfile" 2>&1 || error "error" "running mkinitcpio -P to silence fsck messages" "$?" action="instructing systemd to check filesystems" && display "task" "$action" servicefile=/usr/lib/systemd/system/systemd-fsck-root.service [ -f $servicefile ] && echo "StandardOutput=null" >>$servicefile && \ echo "StandardError=journal+console" >>$servicefile servicefile=/usr/lib/systemd/system/systemd-fsck@.service [ -f $servicefile ] && echo "StandardOutput=null" >>$servicefile && \ echo "StandardError=journal+console" >>$servicefile action="removing hostname from login prompt" && display "task" "$action" sed -i "s/--noclear/--nohostname --noclear/g" /usr/lib/systemd/system/getty@.service \ || error "error" "$action" "$?" sed -i "s/--noclear/--nohostname --noclear/g" /usr/lib/systemd/system/container-getty@.service \ || error "error" "$action" "$?" sed -i "s/--noclear/--nohostname --noclear/g" /usr/lib/systemd/system/console-getty.service \ || error "error" "$action" "$?" action="silencing the unneeded and chatty watchdog module" && display "task" "$action" echo "blacklist iTCO_wdt" >/etc/modprobe.d/nowatchdog.conf || error "error" "$action" "$?" # SYSTEMD BOOT: eliminate timeout and silence boot text if [ -f /boot/loader/loader.conf ]; then action="eliminating timeout and silencing boot test on systemd boot" && display "task" "$action" echo "timeout=0" >/boot/loader/loader.conf # the file in this location was named based on the time of the install, so we must use find to identify it. kernelfile=$(find /boot/loader/entries/ -name "*.conf") # hush boot output via kernel parameters sed -i "/.*options root=PARTUUID.*/ s/$/quiet rd.systemd.show_status=auto rd.udev.log_level=2 nvme.noacpi=1 mem_sleep_default=deep nowatchdog/" "$kernelfile" fi # GRUB: reset timeouts and adjust log levels if [ -f /etc/default/grub ]; then action="resetting timeouts and adjusting log levels on grub boot" && display "task" "$action" sed -i "s/.*GRUB_TIMEOUT=.*/GRUB_TIMEOUT=0/g" /etc/default/grub sed -i "s/.*GRUB_DEFAULT=.*/GRUB_DEFAULT=0/g" /etc/default/grub sed -i "s/.*GRUB_RECORDFAIL_TIMEOUT=.*/GRUB_RECORDFAIL_TIMEOUT=$GRUB_TIMEOUT/g" /etc/default/grub sed -i "s/.*GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT=\"rw quiet loglevel=2 rd.systemd.show_status=auto rd.udev.log_level=2 nvme.noacpi=1 mem_sleep_default=deep nowatchdog\"/g" /etc/default/grub grub-mkconfig -o /boot/grub/grub.cfg >> "$logfile" 2>&1 || error "error" "" "$?" fi } ### Outro outro() { action="Cleanup" && display "title" "$action" action="forcing user password change on first login" && display "task" "$action" chage -d 0 "$username" >> "$logfile" 2>&1 || error "error" "$action" "$?" display "subtitle" "Statistics" action="identifying newly installed packages" && display "task" "$action" pacman -Q > "$packages_after" || error "error" "$action" "$?" (comm -13 --nocheck-order "$packages_before" "$packages_after" > "$archsetup_packages") || \ error "error" "$action" "$?" action="comparing timestamps" && display "task" "$action" ENDTIME=$(date +%s) totalsecs=$(($ENDTIME - $STARTTIME)) mins=$(($totalsecs / 60)) secs=$(($totalsecs % 60)) new_packages=$(cat $archsetup_packages | wc -l) printf "\n" printf "Completion time : %s\n" "$(date +'%D %T')" | tee -a "$logfile" printf "Elapsed time : %s minutes, %s seconds\n" $mins $secs | tee -a "$logfile" printf "Errors encountered : %s\n" $errors_encountered | tee -a "$logfile" printf "Log file location : %s\n" "$logfile" printf "Packages installed : %s\n" "$new_packages" printf "\n" printf "Please reboot before working with your new workstation.\n\n" } ### Installation Steps intro # take start stats prerequisites # install software required to install software create_user # create user in wheel with :nopasswd sudo user_customizations # dotfiles aur_installer # install yay (comment out if using zfsarch install first) essential_services # ssh, firewall, printing, etc xorg # display manager dwm # window manager desktop_environment # commonly used applications developer_workstation # development tools and utilities supplemental_software # everything else # silent_boot # make booting a bit less noisy outro # take end stats; show summary exit 0