#!/bin/bash
# BREADCRUMBS:
#
# Audit this whole thing and use it as a forcing function to do clean-up.
# TIP: For configuring wifi from the boot disk, these commands are useful:
#
# iwctl station wlan0 scan
# iwctl station wlan0 get-networks
# iwctl station wlan0 connect <SSID>
#
# The last command will prompt for a password.
# TIP: This command will write out a nice mirror list. Do this before
# bootstrap.
#
# reflector \
# --country 'United States' \
# --age 12 \
# --protocol https \
# --sort rate \
# --save /etc/pacman.d/mirrorlist
#
# This command can take a while and will sometimes emit errors. That's OK.
# Running this can sometimes significantly improve download speeds.
# The script below doesn't handle disk partitioning since that can vary
# depending on the hardware. But the standard thing I do (for non-encrypted
# devices) is:
#
# cfdisk /dev/sda
#
# N.B. /dev/sda is just an example. These days, it's probably /dev/nvme0n1.
#
# Use a GPT partition table. Then create a 2GB boot EFI System Partition.
# And then a Linux system partition using the rest of the space. No swap
# partition. Write it. Then format the partitions:
#
# mkfs.fat -F32 /dev/sda1
# mkfs.ext4 /dev/sda2
#
# Finally, mount the latter above to `/mnt` and the former to `/mnt/boot`:
#
# mount /dev/sda2 /mnt
# mkdir /mnt/boot
# mount /dev/sda1 /mnt/boot
#
# Then you can start the steps below.
# Recommended steps before entering chroot:
#
# encrypt (if encrypting disk, recommended for laptop)
# bootstrap before entering chroot
# installinit
#
# Now enter the chroot:
#
# arch-chroot /mnt
#
# And continue installation using `/arch-install`:
#
# rootinit after entering chroot
# x (if installing graphics)
# pkgs
# xpkgs (if installing graphics)
# bluetoothinit
# andrewinit
# kaitinit
# wifiinit (optional)
# grubinit
#
# At this point, log in as the user created above.
#
# yayinit
# aurpkgs
# aurxpkgs (if installing graphics)
# dhcpcdinit
#
# At this point, reboot to disk, as dealing with GPG off the
# live disk seems to have issues.
#
# gpginit
# homeinit
#
# Now log out and log back in on tty2, then:
#
# xenvinit (if installing graphics)
# pywingoinit (if installing graphics)
# sshinit
# scannerinit
# autologin (for media PCs)
# nasinit (for PCs wanting automatic NAS connection via sshfs)
#
# Time for some manual steps:
#
# Run setup-home-links and add appropriate configs.
# Then run it again.
#
# Then add hostname to relevant scripts in ~/.config and ~/bin. Then add
# ~/.config/ag/startup/wingo-HOST.xinitrc and make it executable.
#
# Then `setup-system-links --dry-run`. Check the output and then run
# `sudo -E setup-system-links`. (Somewhat recently, "secure path" has
# been enabled in sudoers, which makes this annoyingly not work. I've just
# been disabling it.)
INSTALL_DIR=/mnt
encrypt() {
if [ $# != 1 ]; then
echo "Usage: $(basename "$0") encrypt <device>" >&2
exit 1
fi
device="$1"
cryptsetup -y -v luksFormat "$device"
cryptsetup open "$device" cryptroot
echo "partition should be at /dev/mapper/cryptroot"
}
bootstrap() {
pacstrap "$INSTALL_DIR" base base-devel linux linux-firmware
genfstab -U "$INSTALL_DIR" >> "$INSTALL_DIR"/etc/fstab
}
installinit() {
run='curl -fsSL https://burntsushi.net/stuff/arch-install | bash -s -- "$@"'
dest="$INSTALL_DIR"/archlinux-install
echo '#!/usr/bin/env bash' > "$dest"
echo "$run" >> "$INSTALL_DIR"/archlinux-install
chmod +x "$dest"
}
rootinit() {
if [ $# != 1 ]; then
echo "Usage: $(basename "$0") rootinit <hostname>" >&2
exit 1
fi
hostname="$1"
ln -sf /usr/share/zoneinfo/America/New_York /etc/localtime
hwclock --systohc
sed -i 's/^#\(en_US\.UTF-8 .*\)$/\1/g' /etc/locale.gen
locale-gen
echo 'LANG=en_US.UTF-8' > /etc/locale.conf
echo "$hostname" > /etc/hostname
{
echo "127.0.0.1 localhost"
echo "::1 localhost"
echo "127.0.1.1 $hostname.localdomain $hostname"
} >> /etc/hosts
echo 'COMPRESSXZ=(xz -c -z -0 -)' >> /etc/makepkg.conf
echo "set root password:"
passwd
}
x() {
pacman --noconfirm -S xorg xorg-xinit
}
pkgs() {
pacman --noconfirm -S \
zsh \
sudo \
vi \
pkgfile \
alsa-utils vorbis-tools \
aspell aspell-en hunspell hunspell-en_US \
uv python python-pip python-setuptools python-virtualenv bpython \
flake8 \
go go-tools \
rustup rust-analyzer \
grub efibootmgr \
iputils inetutils whois bind-tools dhcpcd \
cups \
shellcheck \
asciidoc \
pdftk \
unzip \
iwd \
cronie openssh openssl sshfs sshuttle gnupg tmux nfs-utils enscript \
docker ffmpeg jq ripgrep yt-dlp fzf \
iotop htop linux-tools pkgfile pwgen pv strace tig time tree valgrind \
vim \
git git-crypt git-absorb tk \
aws-cli s3cmd colordiff curl wget ctags darkhttpd pass rsync \
nodejs yarn \
terminus-font \
words \
keyd \
bash-language-server lua-language-server typescript-language-server
pkgfile --update
systemctl enable keyd
}
xpkgs() {
pacman --noconfirm -Rdd vim
pacman --noconfirm -S \
xterm \
alacritty \
k3b konversation konsole dolphin okular ffmpegthumbs \
qt6ct oxygen oxygen-icons kde-cli-tools \
xbindkeys \
libnotify \
kmix \
dunst \
i3lock \
mpv \
numlockx \
xclip \
xsel \
xdotool \
wmctrl \
scrot \
freerdp \
gvim \
vorbis-tools \
noto-fonts noto-fonts-cjk noto-fonts-emoji noto-fonts-extra \
pipewire-audio pipewire-pulse pipewire-alsa wireplumber \
pamixer pavucontrol \
recordmydesktop \
feh variety \
stalonetray \
firefox
systemctl --user enable wireplumber
}
bluetoothinit() {
pacman --noconfirm -S blueman bluez bluez-utils
systemctl enable bluetooth
}
andrewinit() {
# Use the same group ID on all machines.
sudo groupmod -n users-old users
sudo groupadd -g 100 users
sudo useradd -g users -u 1000 -m -s /bin/zsh \
-G disk,lp,wheel,log,dbus,network,video,audio,optical,storage,scanner,power \
andrew
echo "set andrew password"
sudo passwd andrew
echo "make sure '%wheel ALL=(ALL) NOPASSWD: ALL' is in sudoers"
}
kaitinit() {
sudo useradd -g users -u 1002 -m -s /bin/bash \
-G disk,lp,wheel,log,dbus,network,video,audio,optical,storage,scanner,power \
kait
echo "set kait password"
sudo passwd kait
echo "make sure '%wheel ALL=(ALL) NOPASSWD: ALL' is in sudoers"
}
wifiinit() {
pacman --noconfirm -S networkmanager network-manager-applet
systemctl enable NetworkManager
}
grubinit() {
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=grub
grub-mkconfig -o /boot/grub/grub.cfg
}
yayinit() {
cd /tmp || exit 1
if [ ! -d yay ]; then
git clone https://aur.archlinux.org/yay
fi
cd yay || exit 1
makepkg -fsi --noconfirm
}
aurpkgs() {
# It looks like these need to be manually installed:
#
# brother-mfc-l3770cdw
#
# The AUR packages appear borked.
yay --noconfirm -S \
neovim neovim-plug-git python-pynvim \
brscan4 \
vim-plug-git \
zsh-autosuggestions \
zsh-completions \
zsh-syntax-highlighting \
zsh-fast-syntax-highlighting-git \
dict-wn \
par
}
aurxpkgs() {
yay --noconfirm -S \
dzen2-xft-xpm-xinerama-git \
google-chrome \
1password 1password-cli \
idesk \
gmrun \
naps2-bin \
ttf-hack-nerd \
ttf-dejavu \
ttf-fira-mono \
ttf-mononoki-git \
ttf-roboto \
ttf-ubuntu-font-family
}
dhcpcdinit() {
sudo systemctl enable dhcpcd
}
gpginit() {
import() {
private_key="$1"
fingerprint=$(
gpg \
--pinentry-mode loopback \
--with-colons \
--import-options show-only \
--import "$private_key" \
| awk -F: '$1 == "fpr" {print $10; exit}'
)
# We could consider using `gpg --export-ownertrust` and then
# `gpg --import-ownertrust`. But this way works too.
echo "$fingerprint:6:" | gpg --import-ownertrust
}
rsync \
--archive --recursive --human-readable --partial --inplace --progress \
-e 'ssh -p 7704' \
andrew@home.burntsushi.net:/m/data/andrew/keys/*.key.* /tmp/
import /tmp/jamslam@gmail.com.key.priv
import /tmp/kbrady39@gmail.com.key.priv
}
homeinit() {
cd "$HOME" || exit 1
rustup toolchain install stable
rustup default stable
curl https://burntsushi.net/stuff/setup-home > /tmp/setup-home.sh
sh /tmp/setup-home.sh
if ! [ -d .password-store ]; then
git clone ssh://andrew@home.burntsushi.net:7704/m/git/password-store .password-store
fi
(cd .password-store && "$HOME/bin/configure-git")
mkdir -p .gnupg
{
echo 'default-cache-ttl 86400'
echo 'max-cache-ttl 86400'
} > .gnupg/gpg-agent.conf
}
xenvinit() {
cd "$HOME" || exit 1
# shellcheck disable=SC1091
. "$HOME/bin/x11-go"
go install -v github.com/BurntSushi/wingo/...@latest
go install -v github.com/BurntSushi/gohead/...@latest
git clone https://github.com/BurntSushi/wingo /tmp/wingo
mkdir -p ~/.local/share
cp -a /tmp/wingo/data ~/.local/share/wingo
# Someone seems to have fucked up the KDE/qt6 packages
# on Archlinux, so we need to download this magical file
# in order to make file associations in Dolphin work. WTF.
#
# See: https://old.reddit.com/r/kde/comments/1bd313p/dolphin_not_recognizing_file_associations/l26i3m2/
mkdir -p "$HOME/.config/menus"
url="https://github.com/KDE/plasma-workspace/raw/11e7f5306fa013ec5c2b894a28457dabf5c42bad/menu/desktop/plasma-applications.menu"
curl -L "$url" -o "$HOME/.config/menus/applications.menu"
}
# Split into its own step so that it can be run on its own. When major Python
# upgrades occur, the venv can get fucked up. Unless, I think, when uv does
# installation. :-)
pywingoinit() {
cd "$HOME" || exit 1
rm -rfv "$HOME/.pyx11"
uv venv "$HOME/.pyx11"
# shellcheck disable=SC1091
. "$HOME/.pyx11/bin/activate"
uv pip install git+https://github.com/wingowm/pywingo
}
sshinit() {
sudo systemctl enable sshd
sudo systemctl start sshd
ssh-extract-key burntsushi
}
scannerinit() {
# New color printer.
sudo brsaneconfig4 -a name=BrotherColor model=MFC-L3770CDW ip=192.168.1.151
}
autologin() {
sudo mkdir -p /etc/systemd/system/getty@tty1.service.d
sudo tee /etc/systemd/system/getty@tty1.service.d/override.conf > /dev/null <<EOF
[Service]
ExecStart=
ExecStart=-/usr/bin/agetty --autologin andrew --noclear %I $TERM
EOF
}
nasinit() {
sudo mkdir /m
sudo chown andrew:users /m
systemctl --user enable mount-nas
systemctl --user start mount-nas
cd ~/system/etc/NetworkManager/dispatcher.d/50-mount-nas || exit 1
ln -s run copy:$(myhostname)
}
case "$1" in
encrypt) shift ; encrypt "$@" ;;
bootstrap) shift ; bootstrap "$@" ;;
installinit) shift ; installinit "$@" ;;
rootinit) shift ; rootinit "$@" ;;
x) shift ; x "$@" ;;
pkgs) shift ; pkgs "$@" ;;
xpkgs) shift ; xpkgs "$@" ;;
bluetoothinit) shift ; bluetoothinit "$@" ;;
andrewinit) shift ; andrewinit "$@" ;;
kaitinit) shift ; kaitinit "$@" ;;
wifiinit) shift ; wifiinit "$@" ;;
grubinit) shift ; grubinit "$@" ;;
yayinit) shift ; yayinit "$@" ;;
aurpkgs) shift ; aurpkgs "$@" ;;
aurxpkgs) shift ; aurxpkgs "$@" ;;
homeinit) shift ; homeinit "$@" ;;
xenvinit) shift ; xenvinit "$@" ;;
pywingoinit) shift ; pywingoinit "$@" ;;
dhcpcdinit) shift ; dhcpcdinit "$@" ;;
gpginit) shift ; gpginit "$@" ;;
sshinit) shift ; sshinit "$@" ;;
scannerinit) shift ; scannerinit "$@" ;;
autologin) shift ; autologin "$@" ;;
nasinit) shift ; nasinit "$@" ;;
*)
echo "unrecognized command" >&2
exit 1
;;
esac