archlinux/functions/chroot
2025-11-22 23:15:27 +00:00

728 lines
18 KiB
Bash
Executable file

#!/usr/bin/env bash
revision=0.1a
set -a
set -E
echo
# Environment variables
tee -a /etc/environment >/dev/null <<- environment
EDITOR=vim
SUDO_EDITOR=vim
environment
# Global bashrc
tee -a /etc/skel/.bashrc >/dev/null <<- 'bashglobal'
# Source bash functions
if [ -d ~/.local/functions ]
then
for file in $(find ~/.local/functions -type f)
do
. ${file}
done
fi
# Add local functions folder to path
export PATH=${PATH}:${HOME}/.local/bin:/zfs/bin:/opt/local/bin
export SUDO_PROMPT=$'\a'"$(tput rev)[sudo] password for %p:$(tput sgr0)"' '
# Colored prompts
alias diff='diff --color=auto'
alias ip='ip -color=auto'
export LESS='-R --use-color -Dd+r$Du+b$'
# Adjust terminal upon window resize
shopt -s checkwinsize
# Auto cd into directory
shopt -s autocd
# Enable tab complete for sudo
complete -c -f sudo
# Ignore duplicate and whitespace history entries
export HISTCONTROL=ignoreboth
#
# ~/.bash_aliases
#
# ZFS/btrfs
alias zfs='sudo zfs'
alias zpool='sudo zpool'
alias btrfs='sudo btrfs'
# Shutdown reboot
alias poweroff='sudo poweroff'
alias reboot='sudo reboot'
# Text editors
alias v='vim'
alias sv='sudo vim'
# Clear bash history
alias clearhistory='rm ${HISTFILE}; history -c -w'
# Miscellanous pacman
alias orphans='sudo pacman -Rcns $(pacman -Qtdq)'
alias unlockpacman='sudo rm /var/lib/pacman/db.lck && sudo pacman -Syyu'
# Rsync
alias rsync='rsync -v -h --progress --info=progress2 --partial --append-verify'
# --log-file=
# --remove-source-files
#
# ~/.bash_functions
#
# Pacman tools
function installer
{
/opt/local/bin/cacheserver
sudo pacman -S ${@}
echo
}
function uninstall
{
sudo pacman -Rcns ${@}
echo
}
function mirrors
{
echo
sudo reflector --country CA,US --age 24 --latest 20 --protocol https --fastest 25 --sort rate --save /etc/pacman.d/mirrorlist
echo
cat /etc/pacman.d/mirrorlist
echo
}
function syur
{
/opt/local/bin/syu &&
reboot
}
function syup
{
/opt/local/bin/syu &&
poweroff
}
# Update bash
function update-bash
{
vim ~/.bashrc &&
source ~/.bashrc
}
bashglobal
# Root bashrc
rsync -a /etc/skel/.bashrc ~/
mkdir -p ~/.local/functions/
cat > ~/.local/functions/bashrc <<- 'bashrc'
#!/usr/bin/env bash
# Root shell color
PS1="$(tput setaf 1)[\u@\h \W \$?]\$$(tput sgr0) "
# Colored prompts
alias ll='ls --color=auto -l -a -h'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
# Disable history
unset HISTFILE
rm -f ${HISTFILE}
history -c -w
bashrc
# Locale
sed '/#en_US.UTF-8 UTF-8/ s/#//' -i /etc/locale.gen
locale-gen >/dev/null
echo 'LANG=en_US.UTF-8' >>/etc/locale.conf
say as heading 'Locale configured'
# Time zone
if ls -l /dev/disk/* | grep -q 'VBOX\|virtio\|QEMU'
then
ln -s -f $(find /usr/share/zoneinfo/ | shuf -n 1) /etc/localtime
else
ln -s -f /usr/share/zoneinfo/UTC /etc/localtime
fi
hwclock --systohc --utc
say as heading 'Time zone configured'
# Hostname
echo ${hostname} >/etc/hostname
cat >>/etc/hosts <<HOSTS
127.0.0.1 localhost
127.0.1.1 ${hostname}
HOSTS
say as heading 'Hostname configured'
# User and superuser
useradd -m -g users -G wheel -s /usr/bin/bash ${username} || die 'User account creation has failed'
printf '%s\n' "${userpass}" "${userpass}" | passwd ${username} >/dev/null 2>&1
unset userpass userpass2
# Disable root account
passwd -l root >/dev/null 2>&1
# Sudoers
install -m 0440 /dev/stdin /etc/sudoers.d/01-DEFAULTS <<- DEFAULTS
Defaults passwd_timeout=0
Defaults timestamp_type=global
Defaults insults
DEFAULTS
install -m 0440 /dev/stdin /etc/sudoers.d/02-COMMANDS <<- COMMANDS
Cmnd_Alias POWER = /usr/bin/poweroff, /usr/bin/reboot
Cmnd_Alias ZFS = /usr/bin/zfs, /usr/bin/zpool
Cmnd_Alias BTRFS = /usr/bin/btrfs, /usr/bin/timeshift, /usr/bin/timeshift-gtk, /usr/bin/timeshift-launcher
Cmnd_Alias QEMU = /usr/bin/virsh, /usr/bin/qemu-system-x86_64, /usr/bin/virt-install
Cmnd_Alias FAIL2BAN = /usr/bin/fail2ban-client
Cmnd_Alias ARCHISO = /opt/local/bin/mkairgap, /opt/local/bin/mkiso
Cmnd_Alias PACMAN = /usr/bin/pacman -Sy
Cmnd_Alias IPTABLES = /usr/bin/iptables, /usr/bin/iptables-save
Cmnd_Alias MISC = /usr/bin/rsync
COMMANDS
install -m 0440 /dev/stdin /etc/sudoers.d/03-WHEEL <<- WHEEL
%wheel ALL=(ALL:ALL) ALL
%wheel ALL=(ALL:ALL) NOPASSWD: POWER, ZFS, BTRFS, QEMU, FAIL2BAN, ARCHISO, PACMAN, IPTABLES, MISC
WHEEL
install -m 0440 /dev/stdin /etc/sudoers.d/.zz-NOPASSWD <<- NOPASSWD
Defaults:${username} !authenticate
NOPASSWD
case ${filesystem} in
zfs)
# ZFS setup
zpool set cachefile=/etc/zfs/zpool.cache zroot
zgenhostid $(hostid)
# ZFS files
touch /zfs/snapshot-syu
chown ${username}:users /zfs/snapshot-syu
# Trim zroot monthly
cat >/etc/systemd/system/zfs-trim@.timer <<- 'TRIM'
[Unit]
Description=Monthly zpool trim on %i
[Timer]
OnCalendar=monthly
AccuracySec=1h
Persistent=true
[Install]
WantedBy=multi-user.target
TRIM
cat >/etc/systemd/system/zfs-trim@.service <<- 'TRIM'
[Unit]
Description=zpool trim on %i
Documentation=man:zpool-trim(8)
Requires=zfs.target
After=zfs.target
ConditionACPower=true
ConditionPathIsDirectory=/sys/module/zfs
[Service]
Nice=19
IOSchedulingClass=idle
KillSignal=SIGINT
ExecStart=/bin/sh -c '\
if /usr/bin/zpool status %i | grep "trimming"; then\
exec /usr/bin/zpool wait -t trim %i;\
else exec /usr/bin/zpool trim -w %i; fi'
ExecStop=-/bin/sh -c '/usr/bin/zpool trim -s %i 2>/dev/null || true'
[Install]
WantedBy=multi-user.target
TRIM
# Scrub zroot monthly
cat >/etc/systemd/system/zfs-scrub@.timer <<- 'SCRUB'
[Unit]
Description=Monthly zpool scrub on %i
[Timer]
OnCalendar=monthly
AccuracySec=1h
Persistent=true
[Install]
WantedBy=multi-user.target
SCRUB
cat >/etc/systemd/system/zfs-scrub@.service <<- 'SCRUB'
[Unit]
Description=zpool scrub on %i
[Service]
Nice=19
IOSchedulingClass=idle
KillSignal=SIGINT
ExecStart=/usr/bin/zpool scrub %i
[Install]
WantedBy=multi-user.target
SCRUB
# Pre and Post update backup hooks
cat >/etc/pacman.d/hooks/00-syu_pre.hook <<- pre
[Trigger]
Type = Path
Operation = Upgrade
Operation = Install
Operation = Remove
Target = usr/lib/modules/*/vmlinuz
Target = usr/lib/initcpio/*
Target = usr/lib/firmware/*
Target = usr/src/*/dkms.conf
[Action]
Description = Creating pre zroot snapshot...
When = PreTransaction
Exec = /usr/bin/bash -c 'zfs snapshot zroot/ROOT@pre-\$(cat /zfs/snapshot-syu)'
AbortOnFail
pre
cat >/etc/pacman.d/hooks/55-bootbackup_pre.hook <<- pre
[Trigger]
Operation = Upgrade
Operation = Install
Operation = Remove
Type = Path
Target = usr/lib/modules/*/vmlinuz
Target = usr/lib/initcpio/*
Target = usr/lib/firmware/*
Target = usr/src/*/dkms.conf
[Action]
Depends = rsync
Description = Backing up pre /boot...
When = PreTransaction
Exec = /usr/bin/bash -c 'mount /boot; rsync -a --mkpath --delete /boot/ "/.boot/\$(cat /zfs/snapshot-syu)_pre"/'
AbortOnFail
pre
cat >/etc/pacman.d/hooks/95-bootbackup_post.hook <<- post
[Trigger]
Operation = Upgrade
Operation = Install
Operation = Remove
Type = Path
Target = usr/lib/modules/*/vmlinuz
Target = usr/lib/initcpio/*
Target = usr/lib/firmware/*
Target = usr/src/*/dkms.conf
[Action]
Depends = rsync
Description = Backing up post /boot...
When = PostTransaction
Exec = /usr/bin/bash -c 'rsync -a --mkpath --delete /boot/ "/.boot/\$(cat /zfs/snapshot-syu)_post"/'
post
cat >/etc/pacman.d/hooks/zz-syu_post.hook <<- post
[Trigger]
Type = Path
Operation = Upgrade
Operation = Install
Operation = Remove
Target = usr/lib/modules/*/vmlinuz
Target = usr/lib/initcpio/*
Target = usr/lib/firmware/*
Target = usr/src/*/dkms.conf
[Action]
Description = Creating post zroot snapshot...
When = PostTransaction
Exec = /usr/bin/bash -c 'zfs snapshot zroot/ROOT@post-\$(cat /zfs/snapshot-syu)'
post
# Custom pacman wrapper
install /dev/stdin /opt/local/bin/syu <<- syu
#!/usr/bin/env bash
set -e
mirrorlist=
# Enable or disable pacman cache server
/opt/local/bin/cacheserver
# Fetch latest mirrors
sudo curl --fail --silent \${mirrorlist} -o /etc/pacman.d/mirrorlist
# Record current time
echo \$(date "+%Y-%m-%d-%H:%M:%S") >/zfs/snapshot-syu
# Check for new packages and continue if found
newpkg+=(\$(checkupdates --nocolor | awk '{print \$1}'))
if [ "\${newpkg}" ]
then
# Sync pacman dbs
sudo pacman --ask 4 -Sy >/dev/null
# Check zfs-linux kernel dependency
zfslinux=\$(pacman -Si zfs-${linux_kernel} | grep "Depends On" | sed "s|.*${linux_kernel}=||")
linux=\$(pacman -Si ${linux_kernel} | grep "Version" | awk '{print \$3}')
if [ \${zfslinux} != \${linux} ]
then
archzfs="--ignore zfs-utils,zfs-${linux_kernel},${linux_kernel}"
fi
# Update archlinux-keyring first
if [[ \${newpkg[@]} =~ "archlinux-keyring" ]]
then
sudo pacman --ask 4 -S archlinux-keyring
echo
fi
# Perform update if dependencies are satisfied
if sudo pacman --ask 4 -Syu \${archzfs} --needed
then
echo
sudo pacdiff
exit 0
fi
fi
syu
;;
*)
case ${filesystem} in
btrfs)
# Pre and post update backup hooks
cat >/etc/pacman.d/hooks/00-syu_pre.hook <<- pre
[Trigger]
Type = Path
Operation = Upgrade
Operation = Install
Operation = Remove
Target = usr/lib/modules/*/vmlinuz
Target = usr/lib/initcpio/*
Target = usr/lib/firmware/*
Target = usr/src/*/dkms.conf
[Action]
Depends = timeshift
Description = Creating pre root snapshot...
When = PreTransaction
Exec = /usr/bin/bash -c 'timeshift --create --comments "pre_\$(date "+%Y-%m-%d-%H:%M:%S")" >/dev/null'
AbortOnFail
pre
cat >/etc/pacman.d/hooks/55-bootbackup_pre.hook <<- pre
[Trigger]
Operation = Upgrade
Operation = Install
Operation = Remove
Type = Path
Target = usr/lib/modules/*/vmlinuz
Target = usr/lib/initcpio/*
Target = usr/lib/firmware/*
Target = usr/src/*/dkms.conf
[Action]
Depends = rsync
Description = Backing up pre /boot...
When = PreTransaction
Exec = /usr/bin/bash -c 'rsync -a --mkpath --delete --exclude 'header.img' /boot/ "/.boot/\$(date "+%Y-%m-%d-%H:%M:%S")_pre"/'
AbortOnFail
pre
cat >/etc/pacman.d/hooks/95-bootbackup_post.hook <<- post
[Trigger]
Operation = Upgrade
Operation = Install
Operation = Remove
Type = Path
Target = usr/lib/modules/*/vmlinuz
Target = usr/lib/initcpio/*
Target = usr/lib/firmware/*
Target = usr/src/*/dkms.conf
[Action]
Depends = rsync
Description = Backing up post /boot...
When = PostTransaction
Exec = /usr/bin/bash -c 'rsync -a --mkpath --delete --exclude 'header.img' /boot/ "/.boot/\$(date "+%Y-%m-%d-%H:%M:%S")_post"/'
post
cat >/etc/pacman.d/hooks/zz-syu_post.hook <<- post
[Trigger]
Type = Path
Operation = Upgrade
Operation = Install
Operation = Remove
Target = usr/lib/modules/*/vmlinuz
Target = usr/lib/initcpio/*
Target = usr/lib/firmware/*
Target = usr/src/*/dkms.conf
[Action]
Depends = timeshift
Description = Creating post root snapshot...
When = PostTransaction
Exec = /usr/bin/bash -c 'timeshift --create --comments "post_\$(date "+%Y-%m-%d-%H:%M:%S")" >/dev/null'
post
install /dev/stdin /usr/local/bin/timeshift-gui <<- 'timeshift'
#!/bin/sh
pkexec env WAYLAND_DISPLAY="$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" XDG_RUNTIME_DIR=/run/user/0 timeshift-launcher
timeshift
;;
esac
# Custom pacman wrapper
install /dev/stdin /opt/local/bin/syu <<- syu
#!/usr/bin/env bash
set -e
mirrorlist=
# Enable or disable pacman cache server
/opt/local/bin/cacheserver
# Fetch latest mirrors
sudo curl --fail --silent \${mirrorlist} -o /etc/pacman.d/mirrorlist
# Check for new packages and continue if found
newpkg+=(\$(checkupdates --nocolor | awk '{print \$1}'))
if [ "\${newpkg}" ]
then
# Update archlinux-keyring first
if [[ \${newpkg[@]} =~ "archlinux-keyring" ]]
then
sudo pacman --ask 4 -S archlinux-keyring
echo
fi
# Perform update if dependencies are satisfied
if sudo pacman --ask 4 -Syu --needed
then
echo
sudo pacdiff
exit 0
fi
fi
syu
;;
esac
echo
# /opt/local/bin/cacheserver
install /dev/stdin /opt/local/bin/cacheserver <<- 'cacheserver'
#!/usr/bin/env bash
set -e
# Enable cacheserver if active
cacheserver=
port=
scheme=
if [ -z ${cacheserver} ]
then
exit 1
fi
if nc -z -4 -w 3 ${cacheserver} ${port:-80} >/dev/null 2>&1
then
if grep -q "CacheServer" /etc/pacman.conf
then
sudo sed "/CacheServer/ s/^\(#\)*//g" -i /etc/pacman.conf
else
sudo sed "/^\[core\]$\|^\[extra\]$\|^\[myvezfs\]$/a CacheServer = ${scheme:-http}://${cacheserver}:${port:-80}" -i /etc/pacman.conf
fi
else
sudo sed "/CacheServer/ s/^/#/g" -i /etc/pacman.conf
fi
cacheserver
if ls -l /dev/disk/* | grep -q 'VBOX\|virtio\|QEMU'
then
sed -e "/^cacheserver=/c cacheserver=192.168.122.1" \
-e "/^port=/c port=9090" \
-i /opt/local/bin/cacheserver
/opt/local/bin/cacheserver
fi
# mkinitcpio
say as heading 'Regenerating cpio image'
mkinitcpio -P
echo
# Install GRUB
if [[ ${arch} = [3567] ]]
then
say as heading 'Installing GRUB'
grub-install --target=x86_64-efi --bootloader-id="Arch Linux (${hostname})" --efi-directory=/boot/efi --recheck || die 'Grub installation failed'
grub-mkconfig -o /boot/grub/grub.cfg
echo
fi
# Sysctl custom settings
cat >/etc/sysctl.d/99-sysctl.conf <<- SYSCTL
net.core.netdev_max_backlog = 16384
net.core.somaxconn = 8192
net.core.rmem_default = 1048576
net.core.rmem_max = 16777216
net.core.wmem_default = 1048576
net.core.wmem_max = 16777216
net.core.optmem_max = 65536
net.ipv4.tcp_rmem = 4096 1048576 2097152
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.udp_rmem_min = 8192
net.ipv4.udp_wmem_min = 8192
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_timestamps = 0
net.core.default_qdisc = cake
net.ipv4.tcp_congestion_control = bbr
vm.swappiness=10
vm.vfs_cache_pressure=50
SYSCTL
# iptables
cat >/etc/iptables/userinput.rules <<- IPTABLES
## User input
# SSH port
-A INPUT -p tcp -m tcp --dport ${port:-22} -j ACCEPT -m comment --comment "SSH Port"
## Simple Firewall
IPTABLES
sed "/OUTPUT ACCEPT/r /etc/iptables/userinput.rules" /etc/iptables/simple_firewall.rules >/etc/iptables/iptables.rules
# zram
echo 'zram' >/etc/modules-load.d/zram.conf
echo 'options zram num_devices=1' >/etc/modprobe.d/zram.conf
echo 'KERNEL=="zram0", ATTR{comp_algorithm}="lz4", ATTR{disksize}="512M" RUN="/usr/bin/mkswap /dev/zram0", TAG+="systemd"' >/etc/udev/rules.d/99-zram.rules
echo '/dev/zram0 none swap defaults 0 0' >>/etc/fstab
# Configure ssh and ssh_config.d/10-global.conf
ssh-keygen -q \
-t ed25519 \
-P "" \
-C "${USER}@${hostname}" \
-f ~/.ssh/id_ed25519
mkdir ~/.ssh/sockets/
cat >/etc/ssh/sshd_config.d/10-sshd.conf <<- sshd
PermitRootLogin no
PasswordAuthentication no
AuthenticationMethods publickey
sshd
cat >/etc/ssh/ssh_config.d/10-global.conf <<- 'sshconfig'
# Preferred ciphers
Ciphers aes128-gcm@openssh.com,aes256-gcm@openssh.com,chacha20-poly1305@openssh.com
# Only use ipv4
AddressFamily inet
# Multiplex
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 10m
# Ease up on local area network devices
Host 192.168.*
StrictHostKeyChecking no
UserKnownHostsFile=/dev/null
LogLevel Error
sshconfig
# Polkit
mkdir -p /etc/polkit-1/rules.d/
cat >/etc/polkit-1/rules.d/49-nopasswd_global.rules <<- 'polkit'
/* Allow members of the wheel group to execute any actions
* without password authentication, similar to "sudo NOPASSWD:"
*/
polkit.addRule(function(action, subject) {
if (subject.isInGroup("wheel")) {
return polkit.Result.YES;
}
});
polkit
# Persistent journal logging
mkdir -p /etc/systemd/journald.conf.d/
cat >/etc/systemd/journald.conf.d/zz-journald.conf <<- eof
[Journal]
Storage=persistent
eof
# makepkg
mkdir -p /etc/makepkg.conf.d/
cat >/etc/makepkg.conf.d/zz-makepkg.conf <<- makepkg
PKGEXT=".pkg.tar"
MAKEFLAGS="--jobs=$(nproc)"
COMPRESSZST=(zstd -c -T0 --auto-threads=logical -)
makepkg
# Virtual machine settings
if ls -l /dev/disk/* | grep -q 'VBOX\|virtio\|QEMU'
then
mv /etc/sudoers.d/.zz-NOPASSWD /etc/sudoers.d/zz-NOPASSWD
fi
##
## Hooks
##
# paccache
cat >/etc/pacman.d/hooks/zz-paccache.hook <<- paccache
[Trigger]
Operation = Upgrade
Operation = Install
Operation = Remove
Type = Package
Target = *
[Action]
Description = Cleaning pacman cache...
When = PostTransaction
Exec = /usr/bin/paccache --remove
paccache
# locale.gen.pacnew hook
install /dev/stdin /opt/local/hooks/localegen <<- hook
#!/usr/bin/env bash
if [ -f /etc/locale.gen.pacnew ]
then
sed '/#en_US.UTF-8 UTF-8/ s/#//' -i /etc/locale.gen.pacnew
mv /etc/locale.gen.pacnew /etc/locale.gen
locale-gen >/dev/null
fi
hook
# locale.gen.pacnew hook
cat >/etc/pacman.d/hooks/100-localegen.hook <<- localegen
[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = glibc
[Action]
Description = Fixing locale.gen
When = PostTransaction
Exec = /opt/local/hooks/localegen
localegen
# iptables
cat >/etc/pacman.d/hooks/100-iptables.rules.hook <<iptables
[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = iptables-nft
[Action]
Description = Fixing iptables rules
When = PostTransaction
Exec = /opt/local/hooks/iptables.rules
iptables
install /dev/stdin /opt/local/hooks/iptables.rules <<hook
#!/usr/bin/env bash
if [ -f /etc/iptables/iptables.rules.pacsave ]
then
sed "/OUTPUT ACCEPT/r /etc/iptables/userinput.rules" /etc/iptables/simple_firewall.rules >/etc/iptables/iptables.rules
rm /etc/iptables/iptables.rules.pacsave
fi
hook
su ${username} <<- "user"
curl --fail --silent https://git.myvelabs.com/lab/archlinux/raw/branch/master/functions/user -o /tmp/user
bash /tmp/user
user