--- /dev/null
+set -Ceu
+SCRIPT_NAME=$0
+cd "$(dirname "${SCRIPT_NAME}")"
+. lib/include.sh
--- /dev/null
+#!/bin/sh
+. "$(dirname "$0")/_lib.sh"
+include NAME_LUKSVG
+include PATH_MNT_CHROOT
+include PATH_PARTITION_LUKSVG
+include await_path
+include check_openable_luksvg
+include check_tools
+include check_partition_mountable
+include chroot_sh
+include close_luksvg
+include mount_privately
+include msg
+include open_luksvg
+include path_vg
+include rbind_mnt
+include unmount_unrbind
+include usage
+
+# inputs to confirm
+usage $# "root-name" "command"
+NAME_ROOT=$1
+COMMAND=$2
+
+# constants derived from changeables
+PATH_VG_ROOT=$(path_vg "${NAME_LUKSVG}")/${NAME_ROOT}
+
+# sanity checks
+check_tools cryptsetup vgchange vgs
+check_partition_mountable "${PATH_PARTITION_LUKSVG}"
+check_openable_luksvg
+
+# mount
+open_luksvg
+await_path "${PATH_VG_ROOT}"
+mount_privately "${PATH_VG_ROOT}" "${PATH_MNT_CHROOT}"
+rbind_mnt
+
+# enact command
+RETURN_CODE=0
+chroot_sh "${COMMAND}" || RETURN_CODE=$?
+
+# clean up mounts
+unmount_unrbind
+close_luksvg
+msg 'Finished! (command exit status: %s)' "${RETURN_CODE}"
+exit "${RETURN_CODE}"
--- /dev/null
+#!/bin/sh
+. "$(dirname "$0")/_lib.sh"
+include DIRNAME_REPO
+include DIRNAME_SCRIPTS
+include FNAME_INITRD
+include FNAME_PROFILE
+include FNAME_VMLINUZ
+include IDX_PARTITION_EFI
+include NAME_DATA
+include NAME_LUKSVG
+include NAME_SWAP
+include PATH_BOOT_DEVICE
+include PATH_DATA
+include PATH_EFI
+include PATH_FIRST_BOOT_PENDING
+include PATH_HOME_ROOT
+include PATH_MNT_CHROOT
+include PATH_PARTITION_LUKSVG
+include await_path
+include check_boot_device_layout
+include check_partition_mountable
+include close_luksvg
+include check_openable_luksvg
+include check_tools
+include chroot_sh
+include create_lv
+include disable_apt_recommends
+include efi_copy_kernel_vmlinuz
+include error
+include msg
+include open_luksvg
+include mount_privately
+include path_vg
+include render_template
+include rbind_mnt
+include retry_until_success
+include unmount_unrbind
+include usage
+
+# constants unlikely to change
+FNAME_NM_CONN=wifi.nmconnection
+FNAME_FSTAB=fstab
+PATH_CRYPTTAB=/etc/crypttab
+PATH_FSTAB="/etc/${FNAME_FSTAB}"
+PATH_HOSTNAME=/etc/hostname
+PATH_HOSTS=/etc/hosts
+PATH_INTERFACES=/etc/network/interfaces
+PATH_NM_CONNECTIONS=/etc/NetworkManager/system-connections
+PATH_RESUME_CONF=/etc/initramfs-tools/conf.d/resume
+
+# constants we might want to change at some point
+DEB_SUITE=trixie
+FNAME_SCRIPT_START=start_root_t490s.sh
+
+# inputs
+usage $# "boot-name"
+NAME_BOOT=$1
+NAME_ROOT="${NAME_BOOT}"
+
+# constants derived from changeables
+PATH_EFI_NAME_BOOT="${PATH_EFI}/${NAME_BOOT}"
+PATH_FIRST_BOOT_SCRIPT="${PATH_DATA}/${DIRNAME_REPO}/${DIRNAME_SCRIPTS}/${FNAME_SCRIPT_START}"
+PATH_MNT_APT_SOURCES="${PATH_MNT_CHROOT}/etc/apt/sources.list"
+PATH_MNT_CRYPTTAB="${PATH_MNT_CHROOT}${PATH_CRYPTTAB}"
+PATH_MNT_FIRST_BOOT_PENDING="${PATH_MNT_CHROOT}${PATH_FIRST_BOOT_PENDING}"
+PATH_MNT_FSTAB="${PATH_MNT_CHROOT}${PATH_FSTAB}"
+PATH_MNT_HOSTNAME="${PATH_MNT_CHROOT}${PATH_HOSTNAME}"
+PATH_MNT_HOSTS="${PATH_MNT_CHROOT}${PATH_HOSTS}"
+PATH_MNT_NM_CONN="${PATH_MNT_CHROOT}${PATH_NM_CONNECTIONS}/${FNAME_NM_CONN}"
+PATH_MNT_NM_CONNECTIONS="${PATH_MNT_CHROOT}${PATH_NM_CONNECTIONS}"
+PATH_MNT_PROFILE="${PATH_MNT_CHROOT}${PATH_HOME_ROOT}/${FNAME_PROFILE}"
+PATH_MNT_RESUME_CONF="${PATH_MNT_CHROOT}${PATH_RESUME_CONF}"
+PATH_VG=$(path_vg "${NAME_LUKSVG}")
+# shellcheck disable=SC2034
+# (used only inside templates/fstab, rendered via render_template)
+PATH_VG_DATA=${PATH_VG}/${NAME_DATA}
+PATH_VG_ROOT=${PATH_VG}/${NAME_ROOT}
+PATH_VG_SWAP=${PATH_VG}/${NAME_SWAP}
+
+# sanity checks
+check_tools cryptsetup debootstrap efibootmgr lvcreate mkfs.ext4 vgchange vgs
+check_boot_device_layout
+check_partition_mountable "${PATH_PARTITION_LUKSVG}"
+check_openable_luksvg
+case "${NAME_BOOT}" in *[!A-Za-z0-9_.-]*|"")
+ error "illegal characters in boot label '${NAME_BOOT}'" ;;
+esac
+[ -e "${PATH_EFI}/${NAME_BOOT}" ]\
+ && error "${PATH_EFI}/${NAME_BOOT} already exists"
+efibootmgr \
+ | sed -n 's/^Boot[0-9A-Fa-f]\{4\}[* ] //p' \
+ | awk '{print $1}' \
+ | grep -Fxq "${NAME_BOOT}"\
+ && error "an EFI boot entry named '${NAME_BOOT}' already exists"
+
+msg 'Your installation choices:'
+msg '- target partition: [ %s ]' "${PATH_PARTITION_LUKSVG}"
+msg '- name for new boot option: [ %s ]' "${NAME_BOOT}"
+
+# set up logical volume and filesystem
+open_luksvg
+create_lv "${NAME_LUKSVG}" "${NAME_ROOT}" 10G
+await_path "${PATH_VG_ROOT}"
+msg 'Creating EXT4 filesystem …'
+mkfs.ext4 -q "${PATH_VG_ROOT}"
+
+# mount and install base
+mount_privately "${PATH_VG_ROOT}" "${PATH_MNT_CHROOT}"
+msg 'Installing Debian Suite "%s" there via debootstrap …' "${DEB_SUITE}"
+debootstrap "${DEB_SUITE}" "${PATH_MNT_CHROOT}"
+rbind_mnt
+
+msg 'Setting up fstab …'
+render_template "${FNAME_FSTAB}" >| "${PATH_MNT_FSTAB}"
+
+msg 'Setting up crypttab …'
+printf '%s %s none luks\n' "${NAME_LUKSVG}" "${PATH_PARTITION_LUKSVG}" \
+ >| "${PATH_MNT_CRYPTTAB}"
+
+msg 'Setting up hostname …'
+printf '%s\n' "${NAME_BOOT}" >| "${PATH_MNT_HOSTNAME}"
+printf '127.0.1.1\t%s\n' "${NAME_BOOT}" >> "${PATH_MNT_HOSTS}"
+
+msg 'Installing first-boot hook into root %s …' "${FNAME_PROFILE}"
+touch "${PATH_MNT_FIRST_BOOT_PENDING}"
+printf '[ -e "%s" ] && sh "%s"\n' \
+ "${PATH_FIRST_BOOT_PENDING}" "${PATH_FIRST_BOOT_SCRIPT}" \
+ >> "${PATH_MNT_PROFILE}"
+
+msg 'For firmware-iwlwifi, enabling non-free-firmware in target sources.list …'
+sed -i 's/ main$/ main non-free-firmware/' "${PATH_MNT_APT_SOURCES}"
+
+disable_apt_recommends "${PATH_MNT_CHROOT}"
+
+msg 'Setting up hibernation resume-from-swap config …'
+mkdir -p "$(dirname "${PATH_MNT_RESUME_CONF}")"
+printf 'RESUME=%s\n' "${PATH_VG_SWAP}" >| "${PATH_MNT_RESUME_CONF}"
+
+msg 'Into chroot environment installing LVM tools, kernel, initrd etc. …'
+chroot_sh "apt-get -qq update"
+chroot_sh \
+ "DEBIAN_FRONTEND=noninteractive apt-get -qq install -y \
+ linux-image-amd64 \
+ cryptsetup cryptsetup-initramfs lvm2 \
+ firmware-iwlwifi network-manager wpasupplicant"
+
+# pre-seed known wifi network into NetworkManager
+msg 'Extracting wifi credentials from %s …' "${PATH_INTERFACES}"
+NAME_WIFI_SSID=$(sed -n 's/^[[:space:]]*wpa-ssid[[:space:]]*//p' \
+ "${PATH_INTERFACES}" | sed 's/[[:space:]]*$//')
+NAME_WIFI_PSK=$(sed -n 's/^[[:space:]]*wpa-psk[[:space:]]*//p' \
+ "${PATH_INTERFACES}" | sed 's/[[:space:]]*$//')
+if [ -z "${NAME_WIFI_SSID}" ] || [ -z "${NAME_WIFI_PSK}" ]; then
+ error "could not extract wifi SSID/PSK from ${PATH_INTERFACES}"
+fi
+msg 'Writing NetworkManager connection profile for "%s" …' \
+ "${NAME_WIFI_SSID}"
+mkdir -p "${PATH_MNT_NM_CONNECTIONS}"
+chmod 700 "${PATH_MNT_NM_CONNECTIONS}"
+render_template "${FNAME_NM_CONN}" >| "${PATH_MNT_NM_CONN}"
+chmod 600 "${PATH_MNT_NM_CONN}"
+
+mkdir "${PATH_EFI_NAME_BOOT}"
+efi_copy_kernel_vmlinuz "${PATH_EFI_NAME_BOOT}" "${PATH_MNT_CHROOT}"
+msg 'EFI setup: adding boot entry %s …' "${NAME_BOOT}"
+efibootmgr \
+ --create \
+ --quiet \
+ --disk "${PATH_BOOT_DEVICE}" \
+ --part "${IDX_PARTITION_EFI}" \
+ --label "${NAME_BOOT}" \
+ --loader "${NAME_BOOT}/${FNAME_VMLINUZ}" \
+ --unicode "root=${PATH_VG_ROOT} ro initrd=${NAME_BOOT}\\${FNAME_INITRD}"
+
+msg 'Setting up root login …'
+retry_until_success chroot_sh "passwd"
+
+# clean up
+unmount_unrbind
+close_luksvg
+msg 'Finished!'
--- /dev/null
+#!/bin/sh
+. "$(dirname "$0")/_lib.sh"
+include DIRNAME_REPO
+include DIRNAME_SCRIPTS
+include PATH_MY_SSH
+include PATH_REPO
+include check_tools
+include msg
+include usage
+
+# constants we might want to change at some point
+FNAME_REPO_TAR=repo.tar
+OPTS_SSH_NEW_HOST="-o StrictHostKeyChecking=accept-new"
+
+# constants derived from changeables
+PATH_REPO_PARENT=$(dirname "${PATH_REPO}")
+RELPATH_SETUP_SCRIPT="${DIRNAME_REPO}/${DIRNAME_SCRIPTS}/start_root_server.sh"
+
+# inputs to confirm
+usage $# "server"
+SERVER=$1
+LOGIN="root@${SERVER}"
+PATH_MY_KNOWN_HOSTS="${PATH_MY_SSH}/known_hosts"
+
+# sanity checks
+check_tools scp ssh ssh-keygen tar
+
+PATH_TEMP=$(mktemp --directory)
+PATH_REPO_TAR="${PATH_TEMP}/${FNAME_REPO_TAR}"
+msg 'Creating tar of repo in temporary directory %s …' "${PATH_TEMP}"
+tar cf "${PATH_REPO_TAR}" -C "${PATH_REPO_PARENT}" "${DIRNAME_REPO}"
+
+msg 'Uploading repo tar to server …'
+[ -e "${PATH_MY_KNOWN_HOSTS}" ]\
+ && ssh-keygen -f "${PATH_MY_KNOWN_HOSTS}" -R "${SERVER}"
+scp ${OPTS_SSH_NEW_HOST} "${PATH_REPO_TAR}" "${LOGIN}:~"
+rm -rf "${PATH_TEMP}"
+
+msg 'Unpacking repo and running setup script …'
+# --no-same-owner owns the files to root, prevening "dubious ownership" when
+# running setup_git_mirror.sh on it later!
+ssh ${OPTS_SSH_NEW_HOST} "${LOGIN}" tar xf "${FNAME_REPO_TAR}" --no-same-owner
+ssh -t ${OPTS_SSH_NEW_HOST} "${LOGIN}" "./${RELPATH_SETUP_SCRIPT}"
--- /dev/null
+DIRNAME_DEV=dev
--- /dev/null
+include PATH_REPO
+
+DIRNAME_REPO=$(basename "${PATH_REPO}")
+
--- /dev/null
+DIRNAME_SCRIPTS=$(basename "$(pwd)")
--- /dev/null
+DIRNAME_SSH=.ssh
+
--- /dev/null
+FNAME_INITRD=initrd.img
--- /dev/null
+FNAME_PROFILE=.profile
--- /dev/null
+FNAME_VMLINUZ=vmlinuz
--- /dev/null
+IDX_PARTITION_EFI=1
--- /dev/null
+NAME_DATA=data
+
--- /dev/null
+NAME_LUKSVG=cryptolvm
+
--- /dev/null
+NAME_SWAP=swap
+
--- /dev/null
+include PATH_DEV
+
+PATH_BOOT_DEVICE="${PATH_DEV}/nvme0n1"
--- /dev/null
+include NAME_DATA
+
+PATH_DATA="/${NAME_DATA}"
+
--- /dev/null
+include DIRNAME_DEV
+
+PATH_DEV="/${DIRNAME_DEV}"
+
--- /dev/null
+PATH_EFI=/boot/efi
--- /dev/null
+include PATH_HOME_ROOT
+
+PATH_FIRST_BOOT_PENDING="${PATH_HOME_ROOT}/.first-boot-pending"
+
--- /dev/null
+PATH_HOME_ROOT=/root
+
--- /dev/null
+PATH_MNT=/mnt
+
--- /dev/null
+include PATH_MNT
+
+PATH_MNT_CHROOT="${PATH_MNT}/chroot"
--- /dev/null
+include DIRNAME_SSH
+
+PATH_MY_SSH="${HOME}/${DIRNAME_SSH}"
+
--- /dev/null
+include IDX_PARTITION_EFI
+include PATH_BOOT_DEVICE
+
+PATH_PARTITION_EFI="${PATH_BOOT_DEVICE}p${IDX_PARTITION_EFI}"
--- /dev/null
+include PATH_BOOT_DEVICE
+
+PATH_PARTITION_LUKSVG="${PATH_BOOT_DEVICE}p3"
+
--- /dev/null
+PATH_REPO=$(cd .. && pwd)
+
--- /dev/null
+include DIRNAME_DEV
+
+TO_RBIND="${DIRNAME_DEV} proc sys"
+
--- /dev/null
+USERNAME=plom
+
--- /dev/null
+include msg
+
+await_path() {
+ local TO_AWAIT=$1
+ msg_nonl 'Waiting for %s to appear …' "${TO_AWAIT}"
+ while [ ! -e "${TO_AWAIT}" ]; do
+ printf " …"
+ sleep 0.5
+ done
+ printf ' there it is!\n'
+}
+
--- /dev/null
+include PATH_BOOT_DEVICE
+include PATH_DEV
+include PATH_EFI
+include PATH_PARTITION_EFI
+include error
+include try_quiet
+
+check_boot_device_layout() {
+ local COUNT_NVME
+ local PATH_PARTITION_RESCUE="${PATH_BOOT_DEVICE}p2"
+ COUNT_NVME=$(find "${PATH_DEV}" -maxdepth 1 -name 'nvme*n[0-9]' | wc -l)
+ [ "${COUNT_NVME}" -eq 1 ]\
+ || error "expected 1 NVMe device in ${PATH_DEV}, found ${COUNT_NVME}"
+ [ -b "${PATH_BOOT_DEVICE}" ]\
+ || error "NVMe device in ${PATH_DEV} not expected ${PATH_BOOT_DEVICE}"
+
+ local COUNT_PARTITIONS
+ COUNT_PARTITIONS=$(find "${PATH_DEV}" -maxdepth 1 \
+ -name "$(basename "${PATH_BOOT_DEVICE}")p[0-9]*" | wc -l)
+ [ "${COUNT_PARTITIONS}" -eq 3 ]\
+ || error "expected 3 partitions on ${PATH_BOOT_DEVICE}, found ${COUNT_PARTITIONS}"
+ local IDX
+ for IDX in 1 2 3; do
+ [ -b "${PATH_BOOT_DEVICE}p${IDX}" ]\
+ || error "missing expected partition ${PATH_BOOT_DEVICE}p${IDX}"
+ done
+
+ try_quiet findmnt --source "${PATH_PARTITION_RESCUE}" --target /\
+ || error "not running from expected rescue partition \
+${PATH_PARTITION_RESCUE} (mounted as /)"
+ try_quiet findmnt --source "${PATH_PARTITION_EFI}" --target "${PATH_EFI}"\
+ || error "expected ${PATH_PARTITION_EFI} mounted at ${PATH_EFI}"
+}
+
--- /dev/null
+include NAME_LUKSVG
+include error
+include path_luks_mapper
+include try_quiet
+
+check_new_luksvg() {
+ local PATH_LUKS_MAPPER
+ PATH_LUKS_MAPPER=$(path_luks_mapper "${NAME_LUKSVG}")
+ try_quiet vgs "${NAME_LUKSVG}"\
+ && error "volume group '${NAME_LUKSVG}' already exists"
+ [ -e "${PATH_LUKS_MAPPER}" ]\
+ && error "${PATH_LUKS_MAPPER} already exists"
+ true
+}
+
--- /dev/null
+include PATH_PARTITION_LUKSVG
+include check_new_luksvg
+include error
+include try_quiet
+
+check_openable_luksvg() {
+ check_new_luksvg
+ try_quiet cryptsetup isLuks "${PATH_PARTITION_LUKSVG}"\
+ || error "${PATH_PARTITION_LUKSVG} not a LUKS container"
+}
+
--- /dev/null
+include error
+include try_quiet
+
+check_partition_mountable() {
+ local PARTITION=$1
+ [ -b "${PARTITION}" ]\
+ || error "${PARTITION} is not a block device"
+ try_quiet findmnt --source "${PARTITION}"\
+ && error "${PARTITION} is already mounted"
+ true
+}
+
--- /dev/null
+include error
+include try_quiet
+
+check_tools() {
+ for CMD in "$@"; do
+ try_quiet command -v "${CMD}"\
+ || error "required tool not found: ${CMD}"
+ done
+}
--- /dev/null
+include PATH_MNT_CHROOT
+
+chroot_sh() {
+ LANG=C.UTF-8 chroot "${PATH_MNT_CHROOT}" /bin/sh -c "$@"
+}
+
--- /dev/null
+include NAME_LUKSVG
+include msg
+
+close_luksvg() {
+ msg 'Deactivating volume group and closing LUKS container …'
+ vgchange -an "${NAME_LUKSVG}"
+ cryptsetup luksClose "${NAME_LUKSVG}"
+}
--- /dev/null
+include msg
+
+create_lv() {
+ local VG=$1
+ local LV=$2
+ local SIZE=$3
+ msg 'Creating logical volume "%s" inside volume group …' "${LV}"
+ lvcreate -L "${SIZE}" -n "${LV}" "${VG}"
+}
+
--- /dev/null
+include msg
+
+die() {
+ msg '%s' "$*" >&2
+ exit 1
+}
--- /dev/null
+include msg
+
+disable_apt_recommends() {
+ local PREFIX=${1:-}
+ local TARGET="${PREFIX}/etc/apt/apt.conf.d/90-no-recommends"
+ msg 'Disabling automatic installation of APT recommends …'
+ printf 'APT::Install-Recommends "false";\n' >| "${TARGET}"
+}
+
--- /dev/null
+include FNAME_INITRD
+include FNAME_VMLINUZ
+include msg
+
+efi_copy_kernel_vmlinuz() {
+ local PATH_EFI_NAME_BOOT=$1
+ local PREFIX=${2:-}
+ msg 'EFI setup: copying kernel and initrd into %s …' "${PATH_EFI_NAME_BOOT}"
+ for FILENAME in "${FNAME_INITRD}" "${FNAME_VMLINUZ}"; do
+ cp "${PREFIX}/${FILENAME}" "${PATH_EFI_NAME_BOOT}/"
+ done
+}
+
--- /dev/null
+include die
+
+error() {
+ die "error: $*"
+}
--- /dev/null
+INCLUDED=""
+
+include() {
+ case " ${INCLUDED} " in
+ *" $1 "*) return 0 ;;
+ esac
+ INCLUDED="${INCLUDED} $1"
+ . "lib/$1.sh"
+}
--- /dev/null
+include FNAME_PROFILE
+include PATH_REPO
+include msg
+
+link_home() {
+ local LOOP_PROFILES='for FILE in ${HOME}/.profile.*; do . "${FILE}"; done'
+ local PATH_PROFILE="${HOME}/${FNAME_PROFILE}"
+ for DIRNAME in any "$1"; do
+ local PATH_SKEL="${PATH_REPO}/home/${DIRNAME}"
+ msg 'Linking %s files into home directory …' "${PATH_SKEL}"
+ find "${PATH_SKEL}" -mindepth 1 -type f -printf '%P\n' \
+ | while IFS= read -r RELPATH; do
+ SRC="${PATH_SKEL}/${RELPATH}"
+ DEST="${HOME}/${RELPATH}"
+ mkdir -p "$(dirname "${DEST}")"
+ if [ -e "${DEST}" ] || [ -L "${DEST}" ]; then
+ msg 'Skipping already-found %s …' "${DEST}"
+ else
+ ln -v -s "${SRC}" "${DEST}"
+ fi
+ done
+ done
+ msg 'Augmenting user %s …' "${FNAME_PROFILE}"
+ # test ensures idempotency
+ grep -qxF "${LOOP_PROFILES}" "${PATH_PROFILE}" 2>/dev/null\
+ || printf '\n%s\n' "${LOOP_PROFILES}" >> "${PATH_PROFILE}"
+}
--- /dev/null
+include msg
+
+mount_privately() {
+ local TO_MOUNT=$1
+ local DEST=$2
+ # to facilitate later unmounting of the chrooted system: isolate our mounts
+ # against propagation to services sandboxed with PrivateMounts=yes (e.g.
+ # systemd-udevd), into whose private namespaces our later umount might fail
+ # to reach for closing their references e.g. into what we'll want to
+ # vgchange -an, only to be blocked by referenced devices claimed as "busy"
+ msg "Privatize script's process' mount namespace …"
+ mount --make-rprivate /
+
+ # mount and install base
+ msg 'Mounting %s at %s …' "${TO_MOUNT}" "${DEST}"
+ mkdir -p "${DEST}"
+ mount "${TO_MOUNT}" "${DEST}"
+}
--- /dev/null
+include msg_nonl
+
+msg() {
+ msg_nonl "$@"
+ printf '\n'
+}
--- /dev/null
+msg_nonl() {
+ printf '[## %s ##] ' "${SCRIPT_NAME}"
+ # shellcheck disable=SC2059
+ # (assume we'll always pass a literal format string)
+ printf -- "$@"
+}
+
--- /dev/null
+include NAME_LUKSVG
+include PATH_PARTITION_LUKSVG
+include msg
+
+open_luksvg() {
+ msg 'Opening LUKS container as "%s" …' "${NAME_LUKSVG}"
+ cryptsetup luksOpen "${PATH_PARTITION_LUKSVG}" "${NAME_LUKSVG}"
+}
+
--- /dev/null
+include PATH_DEV
+
+path_luks_mapper() {
+ printf '%s/mapper/%s' "${PATH_DEV}" "$1"
+}
--- /dev/null
+include PATH_DEV
+
+path_vg() {
+ printf '%s/%s' "${PATH_DEV}" "$1"
+}
+
--- /dev/null
+include PATH_MNT_CHROOT
+include TO_RBIND
+include msg
+
+rbind_mnt() {
+ for NAME in ${TO_RBIND}; do
+ local PATH_NAME="/${NAME}"
+ local SLAVE="${PATH_MNT_CHROOT}${PATH_NAME}"
+ msg 'For working chroot also mounting %s into there …' "${PATH_NAME}"
+ mount --rbind "${PATH_NAME}" "${SLAVE}"
+ mount --make-rslave "${SLAVE}"
+ done
+}
+
--- /dev/null
+include PATH_REPO
+
+render_template() {
+ local PATH_TEMPLATE="${PATH_REPO}/templates/$1"
+ # eval'd instead of just `cat`, so ${...}/$(...) inside the template
+ # get expanded against the calling script's own variables, exactly as
+ # if its content were still an inline heredoc in that script.
+ eval "cat <<RENDER_TEMPLATE_EOF
+$(cat "${PATH_TEMPLATE}")
+RENDER_TEMPLATE_EOF"
+}
--- /dev/null
+include msg
+
+retry_until_success() {
+ until "$@"; do
+ msg 'Command failed, retrying: %s …' "$*"
+ done
+}
+
--- /dev/null
+include DIRNAME_SCRIPTS
+include PATH_REPO
+include USERNAME
+include link_home
+include msg
+include retry_until_success
+include try_quiet
+
+start_root() {
+ local PATH_TO_INSTALL="${PATH_REPO}/to_install/$1"
+ local PATH_SCRIPT_USER="${PATH_REPO}/${DIRNAME_SCRIPTS}/start_user.sh"
+ local TIMEZONE=Europe/Berlin
+ # Assuming read file ends with a newline, has no blank lines, and its
+ # package-name lines contain no whitespace besides that newline.
+ local TO_INSTALL=
+ while read -r LINE; do
+ case "${LINE}" in
+ '#'*) continue ;;
+ esac
+ TO_INSTALL="${TO_INSTALL} ${LINE}"
+ done < "${PATH_TO_INSTALL}"
+ apt-get -y update
+ msg 'Ensuring packages: %s' "${TO_INSTALL}"
+ apt-get -y install ${TO_INSTALL}
+
+ if try_quiet id -u "${USERNAME}"; then
+ msg 'User %s already exists, skipping creation …' "${USERNAME}"
+ else
+ msg 'Setting up user: %s' "${USERNAME}"
+ adduser --disabled-password --comment "" "${USERNAME}"
+ retry_until_success passwd "${USERNAME}"
+ msg 'Running start_user.sh as %s …' "${USERNAME}"
+ su - "${USERNAME}" -c "sh ${PATH_SCRIPT_USER}"
+ fi
+ usermod -a -G sudo "${USERNAME}"
+
+ msg 'Setting system timezone to %s …' "${TIMEZONE}"
+ timedatectl set-timezone "${TIMEZONE}"
+
+ link_home root
+}
--- /dev/null
+try_quiet() {
+ "$@" >/dev/null 2>&1
+}
--- /dev/null
+include PATH_MNT_CHROOT
+include TO_RBIND
+include msg
+
+unmount_unrbind() {
+ msg 'Unmounting chroot environment …'
+ for NAME in ${TO_RBIND}; do
+ umount -R "${PATH_MNT_CHROOT}/${NAME}"
+ done
+ umount "${PATH_MNT_CHROOT}"
+}
+
--- /dev/null
+include die
+
+usage() {
+ local COUNT_INPUTS=$1
+ shift
+ local MSG="usage: ${SCRIPT_NAME}"
+ for PARAMETER in "$@"; do
+ MSG="${MSG} <${PARAMETER}>"
+ done
+ [ "${COUNT_INPUTS}" -eq $# ]\
+ || die "${MSG}"
+}
--- /dev/null
+#!/bin/sh
+. "$(dirname "$0")/_lib.sh"
+include DIRNAME_REPO
+include PATH_REPO
+include USERNAME
+include error
+include msg
+include render_template
+
+# constants we might want to change at some point
+PATH_GIT_BASE=/srv/git
+
+# constants derived from changeables
+FNAME_GIT_DAEMON_UNIT=git-daemon.service
+PATH_GIT_DAEMON_UNIT="/etc/systemd/system/${FNAME_GIT_DAEMON_UNIT}"
+PATH_GIT_MIRROR="${PATH_GIT_BASE}/${DIRNAME_REPO}.git"
+PATH_GIT_MIRROR_EXPORT_OK="${PATH_GIT_MIRROR}/git-daemon-export-ok"
+
+[ -e "${PATH_GIT_MIRROR}" ]\
+ && error "${PATH_GIT_MIRROR} already exists"
+
+msg 'Installing git …'
+apt-get -y update
+apt-get -y install git
+
+msg 'Bare-cloning repo to %s for anonymous serving …' "${PATH_GIT_MIRROR}"
+mkdir -p "${PATH_GIT_BASE}"
+git clone --quiet --bare "${PATH_REPO}" "${PATH_GIT_MIRROR}"
+touch "${PATH_GIT_MIRROR_EXPORT_OK}"
+
+msg 'Own repo to %s so they can update it via ssh …' "${USERNAME}"
+chown -R "${USERNAME}:${USERNAME}" "${PATH_GIT_MIRROR}"
+
+msg 'Writing and enabling git-daemon systemd unit …'
+render_template "${FNAME_GIT_DAEMON_UNIT}" >| "${PATH_GIT_DAEMON_UNIT}"
+systemctl daemon-reload
+systemctl enable --now git-daemon
+
+msg 'Anonymous clone URL: git://<this-server>/%s.git' "${DIRNAME_REPO}"
+msg 'Push updates later with: git push ssh://%s@<this-server>%s' \
+ "${USERNAME}" "${PATH_GIT_MIRROR}"
+msg 'Firewall note: git daemon listens on port 9418/tcp.'
--- /dev/null
+#!/bin/sh
+. "$(dirname "$0")/_lib.sh"
+include NAME_DATA
+include NAME_LUKSVG
+include NAME_SWAP
+include PATH_MNT
+include PATH_DATA
+include PATH_PARTITION_LUKSVG
+include PATH_REPO
+include check_boot_device_layout
+include check_partition_mountable
+include check_new_luksvg
+include check_tools
+include close_luksvg
+include create_lv
+include die
+include error
+include msg
+include msg_nonl
+include open_luksvg
+include mount_privately
+include path_luks_mapper
+include path_vg
+include try_quiet
+include usage
+
+# inputs to confirm
+usage $#
+
+# constants derived from changeables
+PATH_LUKS_MAPPER=$(path_luks_mapper "${NAME_LUKSVG}")
+PATH_MNT_DATA="${PATH_MNT}${PATH_DATA}"
+PATH_VG=$(path_vg "${NAME_LUKSVG}")
+PATH_VG_DATA=${PATH_VG}/${NAME_DATA}
+PATH_VG_SWAP=${PATH_VG}/${NAME_SWAP}
+
+# sanity checks
+check_tools cryptsetup lvcreate mkfs.ext4 mkswap vgchange vgcreate vgs
+check_boot_device_layout
+check_partition_mountable "${PATH_PARTITION_LUKSVG}"
+check_new_luksvg
+try_quiet cryptsetup isLuks "${PATH_PARTITION_LUKSVG}"\
+ && error "${PATH_PARTITION_LUKSVG} is already a LUKS container"
+
+# run inputs by user and ask for confirmation
+msg 'Target partition TO BE ERASED (!): [ %s ]' "${PATH_PARTITION_LUKSVG}"
+msg_nonl 'To continue, type "YES!" (all caps, exclamation mark, no quotes): '
+read -r CONFIRM; [ "${CONFIRM}" = 'YES!' ]\
+ || die 'ABORTED: expected confirmation not given.'
+
+msg 'Encrypting %s as LUKS container …' "${PATH_PARTITION_LUKSVG}"
+cryptsetup luksFormat --batch-mode "${PATH_PARTITION_LUKSVG}"
+open_luksvg
+
+# set up LVM and filesystems
+msg 'Creating volume group "%s" inside LUKS container …' "${NAME_LUKSVG}"
+vgcreate "${NAME_LUKSVG}" "${PATH_LUKS_MAPPER}"
+create_lv "${NAME_LUKSVG}" "${NAME_SWAP}" 64G
+msg 'Configuring as swap area …'
+mkswap "${PATH_VG_SWAP}"
+create_lv "${NAME_LUKSVG}" "${NAME_DATA}" 256G
+msg 'Creating EXT4 filesystem …'
+mkfs.ext4 -q "${PATH_VG_DATA}"
+
+# place repo copy
+mount_privately "${PATH_VG_DATA}" "${PATH_MNT_DATA}"
+msg 'Copying repo …'
+cp -a "${PATH_REPO}" "${PATH_MNT_DATA}"
+
+# clean-up
+msg 'Unmounting …'
+umount "${PATH_MNT_DATA}"
+close_luksvg
+msg 'Finished!'
--- /dev/null
+#!/bin/sh
+. "$(dirname "$0")/_lib.sh"
+include DIRNAME_SSH
+include PATH_MY_SSH
+include USERNAME
+include disable_apt_recommends
+include msg
+include retry_until_success
+include start_root
+
+# constants unlikely to change
+PATH_SSHD_DROPIN=/etc/ssh/sshd_config.d/60-ssh-hardening.conf
+
+# constants derived from changeables
+PATH_HOME_USER="/home/${USERNAME}"
+PATH_USER_SSH="${PATH_HOME_USER}/${DIRNAME_SSH}"
+
+disable_apt_recommends
+start_root server
+
+msg 'Moving ssh access from root to user …'
+mv "${PATH_MY_SSH}" "${PATH_HOME_USER}"
+chown -R "${USERNAME}:${USERNAME}" "${PATH_USER_SSH}"
+
+msg 'Hardening SSH login: no root login, no password auth …'
+printf 'PermitRootLogin no\nPasswordAuthentication no\n' >| "${PATH_SSHD_DROPIN}"
+systemctl reload ssh
+
+msg 'Setting up root password-login …'
+retry_until_success passwd
--- /dev/null
+#!/bin/sh
+. "$(dirname "$0")/_lib.sh"
+include DIRNAME_SCRIPTS
+include PATH_FIRST_BOOT_PENDING
+include PATH_REPO
+include msg
+include start_root
+include render_template
+
+# constants unlikely to change
+PATH_DEFAULT_LOCALE=/etc/default/locale
+PATH_HIBERNATE_OVERRIDE=/etc/systemd/system/systemd-hibernate.service.d/\
+60-poweroff-on-failure.conf
+PATH_HOOK_EFI=/etc/initramfs/post-update.d/update-efi
+PATH_LOGIND_OVERRIDE=/etc/systemd/logind.conf.d/\
+60-poweroff-on-lid-close.conf
+PATH_SYSCTL_PRINTK=/etc/sysctl.d/60-printk-console.conf
+PATH_TLP_THRESH_CONF=/etc/tlp.conf.d/60-thresholds.conf
+PATH_UDEV_RULES=/etc/udev/rules.d
+
+# constants we might want to change at some point
+DIRNAME_TO_COPY=to_copy
+FNAME_SCRIPT_EFI=update_efi.sh
+FNAME_UDEV_RULES_BACKLIGHT=90-backlight.rules
+LOCALE=C.UTF-8
+PRINTK_LEVELS="4 4 1 7"
+TLP_THRESH_START=40
+TLP_THRESH_STOP=80
+
+# constants derived from changeables
+PATH_TO_COPY="${PATH_REPO}/${DIRNAME_TO_COPY}"
+# shellcheck disable=SC2034
+# (used only inside templates/update-efi-hook, rendered via render_template)
+PATH_SCRIPT_EFI="${PATH_REPO}/${DIRNAME_SCRIPTS}/${FNAME_SCRIPT_EFI}"
+
+# before any apt-get call gets a chance to pull in a kernel update of its own …
+msg 'Installing initramfs hook to refresh EFI boot files on kernel updates …'
+mkdir -p "$(dirname "${PATH_HOOK_EFI}")"
+render_template "update-efi-hook" >| "${PATH_HOOK_EFI}"
+chmod +x "${PATH_HOOK_EFI}"
+
+start_root t490s
+
+# C.UTF-8 is built into glibc itself (unlike e.g. en_US.UTF-8), so no
+# "locales" package / locale-gen is needed to make it available — writing
+# it here is enough for it to apply system-wide from the next login on.
+msg 'Setting system locale to %s …' "${LOCALE}"
+printf 'LANG=%s\n' "${LOCALE}" >| "${PATH_DEFAULT_LOCALE}"
+
+msg 'Quieting routine kernel messages on the console …'
+printf 'kernel.printk = %s\n' "${PRINTK_LEVELS}" >| "${PATH_SYSCTL_PRINTK}"
+sysctl -p "${PATH_SYSCTL_PRINTK}"
+
+msg 'Setting TLP battery charge thresholds: start %s%%, stop %s%% …' \
+ "${TLP_THRESH_START}" "${TLP_THRESH_STOP}"
+mkdir -p "$(dirname "${PATH_TLP_THRESH_CONF}")"
+printf 'START_CHARGE_THRESH_BAT0=%s\nSTOP_CHARGE_THRESH_BAT0=%s\n' \
+ "${TLP_THRESH_START}" "${TLP_THRESH_STOP}" >| "${PATH_TLP_THRESH_CONF}"
+tlp start
+
+msg 'Falling back to poweroff on a failed hibernate attempt …'
+mkdir -p "$(dirname "${PATH_HIBERNATE_OVERRIDE}")"
+printf '[Unit]\nOnFailure=poweroff.target\n' >| "${PATH_HIBERNATE_OVERRIDE}"
+systemctl daemon-reload
+
+msg 'Forcing a full poweroff on lid close, in every dock/power state …'
+mkdir -p "$(dirname "${PATH_LOGIND_OVERRIDE}")"
+{
+ printf '[Login]\n'
+ printf '%s=poweroff\n' \
+ HandleLidSwitch HandleLidSwitchExternalPower HandleLidSwitchDocked
+} >| "${PATH_LOGIND_OVERRIDE}"
+# logind only re-reads its config at process start, not via daemon-reload
+systemctl restart systemd-logind
+
+msg 'Making backlight devices available to user-run backlight script …'
+cp "${PATH_TO_COPY}/${FNAME_UDEV_RULES_BACKLIGHT}" "${PATH_UDEV_RULES}/"
+udevadm control --reload-rules
+udevadm trigger --action=add --subsystem-match=backlight
+usermod -a -G video "${USERNAME}"
+
+msg 'Clearing first-boot pending marker …'
+rm -f "${PATH_FIRST_BOOT_PENDING}"
--- /dev/null
+#!/bin/sh
+. "$(dirname "$0")/_lib.sh"
+include link_home
+
+link_home user
--- /dev/null
+#!/bin/sh
+. "$(dirname "$0")/_lib.sh"
+include PATH_PARTITION_EFI
+include check_partition_mountable
+include efi_copy_kernel_vmlinuz
+include msg
+include usage
+
+usage $#
+
+PATH_TEMP=$(mktemp --directory)
+PATH_EFI_NAME_BOOT="${PATH_TEMP}/$(hostname)"
+
+check_partition_mountable "${PATH_PARTITION_EFI}"
+msg 'Mounting EFI partition %s at %s …' "${PATH_PARTITION_EFI}" "${PATH_TEMP}"
+mount "${PATH_PARTITION_EFI}" "${PATH_TEMP}"
+
+efi_copy_kernel_vmlinuz "${PATH_EFI_NAME_BOOT}"
+
+msg 'Unmounting EFI partition …'
+umount "${PATH_TEMP}"
+rmdir "${PATH_TEMP}"
+++ /dev/null
-set -Ceu
-SCRIPT_NAME=$0
-cd "$(dirname "${SCRIPT_NAME}")"
-. lib/include.sh
+++ /dev/null
-#!/bin/sh
-. "$(dirname "$0")/_lib.sh"
-include NAME_LUKSVG
-include PATH_MNT_CHROOT
-include PATH_PARTITION_LUKSVG
-include await_path
-include check_openable_luksvg
-include check_tools
-include check_partition_mountable
-include chroot_sh
-include close_luksvg
-include mount_privately
-include msg
-include open_luksvg
-include path_vg
-include rbind_mnt
-include unmount_unrbind
-include usage
-
-# inputs to confirm
-usage $# "root-name" "command"
-NAME_ROOT=$1
-COMMAND=$2
-
-# constants derived from changeables
-PATH_VG_ROOT=$(path_vg "${NAME_LUKSVG}")/${NAME_ROOT}
-
-# sanity checks
-check_tools cryptsetup vgchange vgs
-check_partition_mountable "${PATH_PARTITION_LUKSVG}"
-check_openable_luksvg
-
-# mount
-open_luksvg
-await_path "${PATH_VG_ROOT}"
-mount_privately "${PATH_VG_ROOT}" "${PATH_MNT_CHROOT}"
-rbind_mnt
-
-# enact command
-RETURN_CODE=0
-chroot_sh "${COMMAND}" || RETURN_CODE=$?
-
-# clean up mounts
-unmount_unrbind
-close_luksvg
-msg 'Finished! (command exit status: %s)' "${RETURN_CODE}"
-exit "${RETURN_CODE}"
+++ /dev/null
-#!/bin/sh
-. "$(dirname "$0")/_lib.sh"
-include DIRNAME_REPO
-include DIRNAME_SCRIPTS
-include FNAME_INITRD
-include FNAME_PROFILE
-include FNAME_VMLINUZ
-include IDX_PARTITION_EFI
-include NAME_DATA
-include NAME_LUKSVG
-include NAME_SWAP
-include PATH_BOOT_DEVICE
-include PATH_DATA
-include PATH_EFI
-include PATH_FIRST_BOOT_PENDING
-include PATH_HOME_ROOT
-include PATH_MNT_CHROOT
-include PATH_PARTITION_LUKSVG
-include await_path
-include check_boot_device_layout
-include check_partition_mountable
-include close_luksvg
-include check_openable_luksvg
-include check_tools
-include chroot_sh
-include create_lv
-include disable_apt_recommends
-include efi_copy_kernel_vmlinuz
-include error
-include msg
-include open_luksvg
-include mount_privately
-include path_vg
-include render_template
-include rbind_mnt
-include retry_until_success
-include unmount_unrbind
-include usage
-
-# constants unlikely to change
-FNAME_NM_CONN=wifi.nmconnection
-FNAME_FSTAB=fstab
-PATH_CRYPTTAB=/etc/crypttab
-PATH_FSTAB="/etc/${FNAME_FSTAB}"
-PATH_HOSTNAME=/etc/hostname
-PATH_HOSTS=/etc/hosts
-PATH_INTERFACES=/etc/network/interfaces
-PATH_NM_CONNECTIONS=/etc/NetworkManager/system-connections
-PATH_RESUME_CONF=/etc/initramfs-tools/conf.d/resume
-
-# constants we might want to change at some point
-DEB_SUITE=trixie
-FNAME_SCRIPT_START=start_root_t490s.sh
-
-# inputs
-usage $# "boot-name"
-NAME_BOOT=$1
-NAME_ROOT="${NAME_BOOT}"
-
-# constants derived from changeables
-PATH_EFI_NAME_BOOT="${PATH_EFI}/${NAME_BOOT}"
-PATH_FIRST_BOOT_SCRIPT="${PATH_DATA}/${DIRNAME_REPO}/${DIRNAME_SCRIPTS}/${FNAME_SCRIPT_START}"
-PATH_MNT_APT_SOURCES="${PATH_MNT_CHROOT}/etc/apt/sources.list"
-PATH_MNT_CRYPTTAB="${PATH_MNT_CHROOT}${PATH_CRYPTTAB}"
-PATH_MNT_FIRST_BOOT_PENDING="${PATH_MNT_CHROOT}${PATH_FIRST_BOOT_PENDING}"
-PATH_MNT_FSTAB="${PATH_MNT_CHROOT}${PATH_FSTAB}"
-PATH_MNT_HOSTNAME="${PATH_MNT_CHROOT}${PATH_HOSTNAME}"
-PATH_MNT_HOSTS="${PATH_MNT_CHROOT}${PATH_HOSTS}"
-PATH_MNT_NM_CONN="${PATH_MNT_CHROOT}${PATH_NM_CONNECTIONS}/${FNAME_NM_CONN}"
-PATH_MNT_NM_CONNECTIONS="${PATH_MNT_CHROOT}${PATH_NM_CONNECTIONS}"
-PATH_MNT_PROFILE="${PATH_MNT_CHROOT}${PATH_HOME_ROOT}/${FNAME_PROFILE}"
-PATH_MNT_RESUME_CONF="${PATH_MNT_CHROOT}${PATH_RESUME_CONF}"
-PATH_VG=$(path_vg "${NAME_LUKSVG}")
-# shellcheck disable=SC2034
-# (used only inside templates/fstab, rendered via render_template)
-PATH_VG_DATA=${PATH_VG}/${NAME_DATA}
-PATH_VG_ROOT=${PATH_VG}/${NAME_ROOT}
-PATH_VG_SWAP=${PATH_VG}/${NAME_SWAP}
-
-# sanity checks
-check_tools cryptsetup debootstrap efibootmgr lvcreate mkfs.ext4 vgchange vgs
-check_boot_device_layout
-check_partition_mountable "${PATH_PARTITION_LUKSVG}"
-check_openable_luksvg
-case "${NAME_BOOT}" in *[!A-Za-z0-9_.-]*|"")
- error "illegal characters in boot label '${NAME_BOOT}'" ;;
-esac
-[ -e "${PATH_EFI}/${NAME_BOOT}" ]\
- && error "${PATH_EFI}/${NAME_BOOT} already exists"
-efibootmgr \
- | sed -n 's/^Boot[0-9A-Fa-f]\{4\}[* ] //p' \
- | awk '{print $1}' \
- | grep -Fxq "${NAME_BOOT}"\
- && error "an EFI boot entry named '${NAME_BOOT}' already exists"
-
-msg 'Your installation choices:'
-msg '- target partition: [ %s ]' "${PATH_PARTITION_LUKSVG}"
-msg '- name for new boot option: [ %s ]' "${NAME_BOOT}"
-
-# set up logical volume and filesystem
-open_luksvg
-create_lv "${NAME_LUKSVG}" "${NAME_ROOT}" 10G
-await_path "${PATH_VG_ROOT}"
-msg 'Creating EXT4 filesystem …'
-mkfs.ext4 -q "${PATH_VG_ROOT}"
-
-# mount and install base
-mount_privately "${PATH_VG_ROOT}" "${PATH_MNT_CHROOT}"
-msg 'Installing Debian Suite "%s" there via debootstrap …' "${DEB_SUITE}"
-debootstrap "${DEB_SUITE}" "${PATH_MNT_CHROOT}"
-rbind_mnt
-
-msg 'Setting up fstab …'
-render_template "${FNAME_FSTAB}" >| "${PATH_MNT_FSTAB}"
-
-msg 'Setting up crypttab …'
-printf '%s %s none luks\n' "${NAME_LUKSVG}" "${PATH_PARTITION_LUKSVG}" \
- >| "${PATH_MNT_CRYPTTAB}"
-
-msg 'Setting up hostname …'
-printf '%s\n' "${NAME_BOOT}" >| "${PATH_MNT_HOSTNAME}"
-printf '127.0.1.1\t%s\n' "${NAME_BOOT}" >> "${PATH_MNT_HOSTS}"
-
-msg 'Installing first-boot hook into root %s …' "${FNAME_PROFILE}"
-touch "${PATH_MNT_FIRST_BOOT_PENDING}"
-printf '[ -e "%s" ] && sh "%s"\n' \
- "${PATH_FIRST_BOOT_PENDING}" "${PATH_FIRST_BOOT_SCRIPT}" \
- >> "${PATH_MNT_PROFILE}"
-
-msg 'For firmware-iwlwifi, enabling non-free-firmware in target sources.list …'
-sed -i 's/ main$/ main non-free-firmware/' "${PATH_MNT_APT_SOURCES}"
-
-disable_apt_recommends "${PATH_MNT_CHROOT}"
-
-msg 'Setting up hibernation resume-from-swap config …'
-mkdir -p "$(dirname "${PATH_MNT_RESUME_CONF}")"
-printf 'RESUME=%s\n' "${PATH_VG_SWAP}" >| "${PATH_MNT_RESUME_CONF}"
-
-msg 'Into chroot environment installing LVM tools, kernel, initrd etc. …'
-chroot_sh "apt-get -qq update"
-chroot_sh \
- "DEBIAN_FRONTEND=noninteractive apt-get -qq install -y \
- linux-image-amd64 \
- cryptsetup cryptsetup-initramfs lvm2 \
- firmware-iwlwifi network-manager wpasupplicant"
-
-# pre-seed known wifi network into NetworkManager
-msg 'Extracting wifi credentials from %s …' "${PATH_INTERFACES}"
-NAME_WIFI_SSID=$(sed -n 's/^[[:space:]]*wpa-ssid[[:space:]]*//p' \
- "${PATH_INTERFACES}" | sed 's/[[:space:]]*$//')
-NAME_WIFI_PSK=$(sed -n 's/^[[:space:]]*wpa-psk[[:space:]]*//p' \
- "${PATH_INTERFACES}" | sed 's/[[:space:]]*$//')
-if [ -z "${NAME_WIFI_SSID}" ] || [ -z "${NAME_WIFI_PSK}" ]; then
- error "could not extract wifi SSID/PSK from ${PATH_INTERFACES}"
-fi
-msg 'Writing NetworkManager connection profile for "%s" …' \
- "${NAME_WIFI_SSID}"
-mkdir -p "${PATH_MNT_NM_CONNECTIONS}"
-chmod 700 "${PATH_MNT_NM_CONNECTIONS}"
-render_template "${FNAME_NM_CONN}" >| "${PATH_MNT_NM_CONN}"
-chmod 600 "${PATH_MNT_NM_CONN}"
-
-mkdir "${PATH_EFI_NAME_BOOT}"
-efi_copy_kernel_vmlinuz "${PATH_EFI_NAME_BOOT}" "${PATH_MNT_CHROOT}"
-msg 'EFI setup: adding boot entry %s …' "${NAME_BOOT}"
-efibootmgr \
- --create \
- --quiet \
- --disk "${PATH_BOOT_DEVICE}" \
- --part "${IDX_PARTITION_EFI}" \
- --label "${NAME_BOOT}" \
- --loader "${NAME_BOOT}/${FNAME_VMLINUZ}" \
- --unicode "root=${PATH_VG_ROOT} ro initrd=${NAME_BOOT}\\${FNAME_INITRD}"
-
-msg 'Setting up root login …'
-retry_until_success chroot_sh "passwd"
-
-# clean up
-unmount_unrbind
-close_luksvg
-msg 'Finished!'
+++ /dev/null
-#!/bin/sh
-. "$(dirname "$0")/_lib.sh"
-include DIRNAME_REPO
-include DIRNAME_SCRIPTS
-include PATH_MY_SSH
-include PATH_REPO
-include check_tools
-include msg
-include usage
-
-# constants we might want to change at some point
-FNAME_REPO_TAR=repo.tar
-OPTS_SSH_NEW_HOST="-o StrictHostKeyChecking=accept-new"
-
-# constants derived from changeables
-PATH_REPO_PARENT=$(dirname "${PATH_REPO}")
-RELPATH_SETUP_SCRIPT="${DIRNAME_REPO}/${DIRNAME_SCRIPTS}/start_root_server.sh"
-
-# inputs to confirm
-usage $# "server"
-SERVER=$1
-LOGIN="root@${SERVER}"
-PATH_MY_KNOWN_HOSTS="${PATH_MY_SSH}/known_hosts"
-
-# sanity checks
-check_tools scp ssh ssh-keygen tar
-
-PATH_TEMP=$(mktemp --directory)
-PATH_REPO_TAR="${PATH_TEMP}/${FNAME_REPO_TAR}"
-msg 'Creating tar of repo in temporary directory %s …' "${PATH_TEMP}"
-tar cf "${PATH_REPO_TAR}" -C "${PATH_REPO_PARENT}" "${DIRNAME_REPO}"
-
-msg 'Uploading repo tar to server …'
-[ -e "${PATH_MY_KNOWN_HOSTS}" ]\
- && ssh-keygen -f "${PATH_MY_KNOWN_HOSTS}" -R "${SERVER}"
-scp ${OPTS_SSH_NEW_HOST} "${PATH_REPO_TAR}" "${LOGIN}:~"
-rm -rf "${PATH_TEMP}"
-
-msg 'Unpacking repo and running setup script …'
-# --no-same-owner owns the files to root, prevening "dubious ownership" when
-# running setup_git_mirror.sh on it later!
-ssh ${OPTS_SSH_NEW_HOST} "${LOGIN}" tar xf "${FNAME_REPO_TAR}" --no-same-owner
-ssh -t ${OPTS_SSH_NEW_HOST} "${LOGIN}" "./${RELPATH_SETUP_SCRIPT}"
+++ /dev/null
-DIRNAME_DEV=dev
+++ /dev/null
-include PATH_REPO
-
-DIRNAME_REPO=$(basename "${PATH_REPO}")
-
+++ /dev/null
-DIRNAME_SCRIPTS=$(basename "$(pwd)")
+++ /dev/null
-DIRNAME_SSH=.ssh
-
+++ /dev/null
-FNAME_INITRD=initrd.img
+++ /dev/null
-FNAME_PROFILE=.profile
+++ /dev/null
-FNAME_VMLINUZ=vmlinuz
+++ /dev/null
-IDX_PARTITION_EFI=1
+++ /dev/null
-NAME_DATA=data
-
+++ /dev/null
-NAME_LUKSVG=cryptolvm
-
+++ /dev/null
-NAME_SWAP=swap
-
+++ /dev/null
-include PATH_DEV
-
-PATH_BOOT_DEVICE="${PATH_DEV}/nvme0n1"
+++ /dev/null
-include NAME_DATA
-
-PATH_DATA="/${NAME_DATA}"
-
+++ /dev/null
-include DIRNAME_DEV
-
-PATH_DEV="/${DIRNAME_DEV}"
-
+++ /dev/null
-PATH_EFI=/boot/efi
+++ /dev/null
-include PATH_HOME_ROOT
-
-PATH_FIRST_BOOT_PENDING="${PATH_HOME_ROOT}/.first-boot-pending"
-
+++ /dev/null
-PATH_HOME_ROOT=/root
-
+++ /dev/null
-PATH_MNT=/mnt
-
+++ /dev/null
-include PATH_MNT
-
-PATH_MNT_CHROOT="${PATH_MNT}/chroot"
+++ /dev/null
-include DIRNAME_SSH
-
-PATH_MY_SSH="${HOME}/${DIRNAME_SSH}"
-
+++ /dev/null
-include IDX_PARTITION_EFI
-include PATH_BOOT_DEVICE
-
-PATH_PARTITION_EFI="${PATH_BOOT_DEVICE}p${IDX_PARTITION_EFI}"
+++ /dev/null
-include PATH_BOOT_DEVICE
-
-PATH_PARTITION_LUKSVG="${PATH_BOOT_DEVICE}p3"
-
+++ /dev/null
-PATH_REPO=$(cd .. && pwd)
-
+++ /dev/null
-include DIRNAME_DEV
-
-TO_RBIND="${DIRNAME_DEV} proc sys"
-
+++ /dev/null
-USERNAME=plom
-
+++ /dev/null
-include msg
-
-await_path() {
- local TO_AWAIT=$1
- msg_nonl 'Waiting for %s to appear …' "${TO_AWAIT}"
- while [ ! -e "${TO_AWAIT}" ]; do
- printf " …"
- sleep 0.5
- done
- printf ' there it is!\n'
-}
-
+++ /dev/null
-include PATH_BOOT_DEVICE
-include PATH_DEV
-include PATH_EFI
-include PATH_PARTITION_EFI
-include error
-include try_quiet
-
-check_boot_device_layout() {
- local COUNT_NVME
- local PATH_PARTITION_RESCUE="${PATH_BOOT_DEVICE}p2"
- COUNT_NVME=$(find "${PATH_DEV}" -maxdepth 1 -name 'nvme*n[0-9]' | wc -l)
- [ "${COUNT_NVME}" -eq 1 ]\
- || error "expected 1 NVMe device in ${PATH_DEV}, found ${COUNT_NVME}"
- [ -b "${PATH_BOOT_DEVICE}" ]\
- || error "NVMe device in ${PATH_DEV} not expected ${PATH_BOOT_DEVICE}"
-
- local COUNT_PARTITIONS
- COUNT_PARTITIONS=$(find "${PATH_DEV}" -maxdepth 1 \
- -name "$(basename "${PATH_BOOT_DEVICE}")p[0-9]*" | wc -l)
- [ "${COUNT_PARTITIONS}" -eq 3 ]\
- || error "expected 3 partitions on ${PATH_BOOT_DEVICE}, found ${COUNT_PARTITIONS}"
- local IDX
- for IDX in 1 2 3; do
- [ -b "${PATH_BOOT_DEVICE}p${IDX}" ]\
- || error "missing expected partition ${PATH_BOOT_DEVICE}p${IDX}"
- done
-
- try_quiet findmnt --source "${PATH_PARTITION_RESCUE}" --target /\
- || error "not running from expected rescue partition \
-${PATH_PARTITION_RESCUE} (mounted as /)"
- try_quiet findmnt --source "${PATH_PARTITION_EFI}" --target "${PATH_EFI}"\
- || error "expected ${PATH_PARTITION_EFI} mounted at ${PATH_EFI}"
-}
-
+++ /dev/null
-include NAME_LUKSVG
-include error
-include path_luks_mapper
-include try_quiet
-
-check_new_luksvg() {
- local PATH_LUKS_MAPPER
- PATH_LUKS_MAPPER=$(path_luks_mapper "${NAME_LUKSVG}")
- try_quiet vgs "${NAME_LUKSVG}"\
- && error "volume group '${NAME_LUKSVG}' already exists"
- [ -e "${PATH_LUKS_MAPPER}" ]\
- && error "${PATH_LUKS_MAPPER} already exists"
- true
-}
-
+++ /dev/null
-include PATH_PARTITION_LUKSVG
-include check_new_luksvg
-include error
-include try_quiet
-
-check_openable_luksvg() {
- check_new_luksvg
- try_quiet cryptsetup isLuks "${PATH_PARTITION_LUKSVG}"\
- || error "${PATH_PARTITION_LUKSVG} not a LUKS container"
-}
-
+++ /dev/null
-include error
-include try_quiet
-
-check_partition_mountable() {
- local PARTITION=$1
- [ -b "${PARTITION}" ]\
- || error "${PARTITION} is not a block device"
- try_quiet findmnt --source "${PARTITION}"\
- && error "${PARTITION} is already mounted"
- true
-}
-
+++ /dev/null
-include error
-include try_quiet
-
-check_tools() {
- for CMD in "$@"; do
- try_quiet command -v "${CMD}"\
- || error "required tool not found: ${CMD}"
- done
-}
+++ /dev/null
-include PATH_MNT_CHROOT
-
-chroot_sh() {
- LANG=C.UTF-8 chroot "${PATH_MNT_CHROOT}" /bin/sh -c "$@"
-}
-
+++ /dev/null
-include NAME_LUKSVG
-include msg
-
-close_luksvg() {
- msg 'Deactivating volume group and closing LUKS container …'
- vgchange -an "${NAME_LUKSVG}"
- cryptsetup luksClose "${NAME_LUKSVG}"
-}
+++ /dev/null
-include msg
-
-create_lv() {
- local VG=$1
- local LV=$2
- local SIZE=$3
- msg 'Creating logical volume "%s" inside volume group …' "${LV}"
- lvcreate -L "${SIZE}" -n "${LV}" "${VG}"
-}
-
+++ /dev/null
-include msg
-
-die() {
- msg '%s' "$*" >&2
- exit 1
-}
+++ /dev/null
-include msg
-
-disable_apt_recommends() {
- local PREFIX=${1:-}
- local TARGET="${PREFIX}/etc/apt/apt.conf.d/90-no-recommends"
- msg 'Disabling automatic installation of APT recommends …'
- printf 'APT::Install-Recommends "false";\n' >| "${TARGET}"
-}
-
+++ /dev/null
-include FNAME_INITRD
-include FNAME_VMLINUZ
-include msg
-
-efi_copy_kernel_vmlinuz() {
- local PATH_EFI_NAME_BOOT=$1
- local PREFIX=${2:-}
- msg 'EFI setup: copying kernel and initrd into %s …' "${PATH_EFI_NAME_BOOT}"
- for FILENAME in "${FNAME_INITRD}" "${FNAME_VMLINUZ}"; do
- cp "${PREFIX}/${FILENAME}" "${PATH_EFI_NAME_BOOT}/"
- done
-}
-
+++ /dev/null
-include die
-
-error() {
- die "error: $*"
-}
+++ /dev/null
-INCLUDED=""
-
-include() {
- case " ${INCLUDED} " in
- *" $1 "*) return 0 ;;
- esac
- INCLUDED="${INCLUDED} $1"
- . "lib/$1.sh"
-}
+++ /dev/null
-include FNAME_PROFILE
-include PATH_REPO
-include msg
-
-link_home() {
- local LOOP_PROFILES='for FILE in ${HOME}/.profile.*; do . "${FILE}"; done'
- local PATH_PROFILE="${HOME}/${FNAME_PROFILE}"
- for DIRNAME in any "$1"; do
- local PATH_SKEL="${PATH_REPO}/home/${DIRNAME}"
- msg 'Linking %s files into home directory …' "${PATH_SKEL}"
- find "${PATH_SKEL}" -mindepth 1 -type f -printf '%P\n' \
- | while IFS= read -r RELPATH; do
- SRC="${PATH_SKEL}/${RELPATH}"
- DEST="${HOME}/${RELPATH}"
- mkdir -p "$(dirname "${DEST}")"
- if [ -e "${DEST}" ] || [ -L "${DEST}" ]; then
- msg 'Skipping already-found %s …' "${DEST}"
- else
- ln -v -s "${SRC}" "${DEST}"
- fi
- done
- done
- msg 'Augmenting user %s …' "${FNAME_PROFILE}"
- # test ensures idempotency
- grep -qxF "${LOOP_PROFILES}" "${PATH_PROFILE}" 2>/dev/null\
- || printf '\n%s\n' "${LOOP_PROFILES}" >> "${PATH_PROFILE}"
-}
+++ /dev/null
-include msg
-
-mount_privately() {
- local TO_MOUNT=$1
- local DEST=$2
- # to facilitate later unmounting of the chrooted system: isolate our mounts
- # against propagation to services sandboxed with PrivateMounts=yes (e.g.
- # systemd-udevd), into whose private namespaces our later umount might fail
- # to reach for closing their references e.g. into what we'll want to
- # vgchange -an, only to be blocked by referenced devices claimed as "busy"
- msg "Privatize script's process' mount namespace …"
- mount --make-rprivate /
-
- # mount and install base
- msg 'Mounting %s at %s …' "${TO_MOUNT}" "${DEST}"
- mkdir -p "${DEST}"
- mount "${TO_MOUNT}" "${DEST}"
-}
+++ /dev/null
-include msg_nonl
-
-msg() {
- msg_nonl "$@"
- printf '\n'
-}
+++ /dev/null
-msg_nonl() {
- printf '[## %s ##] ' "${SCRIPT_NAME}"
- # shellcheck disable=SC2059
- # (assume we'll always pass a literal format string)
- printf -- "$@"
-}
-
+++ /dev/null
-include NAME_LUKSVG
-include PATH_PARTITION_LUKSVG
-include msg
-
-open_luksvg() {
- msg 'Opening LUKS container as "%s" …' "${NAME_LUKSVG}"
- cryptsetup luksOpen "${PATH_PARTITION_LUKSVG}" "${NAME_LUKSVG}"
-}
-
+++ /dev/null
-include PATH_DEV
-
-path_luks_mapper() {
- printf '%s/mapper/%s' "${PATH_DEV}" "$1"
-}
+++ /dev/null
-include PATH_DEV
-
-path_vg() {
- printf '%s/%s' "${PATH_DEV}" "$1"
-}
-
+++ /dev/null
-include PATH_MNT_CHROOT
-include TO_RBIND
-include msg
-
-rbind_mnt() {
- for NAME in ${TO_RBIND}; do
- local PATH_NAME="/${NAME}"
- local SLAVE="${PATH_MNT_CHROOT}${PATH_NAME}"
- msg 'For working chroot also mounting %s into there …' "${PATH_NAME}"
- mount --rbind "${PATH_NAME}" "${SLAVE}"
- mount --make-rslave "${SLAVE}"
- done
-}
-
+++ /dev/null
-include PATH_REPO
-
-render_template() {
- local PATH_TEMPLATE="${PATH_REPO}/templates/$1"
- # eval'd instead of just `cat`, so ${...}/$(...) inside the template
- # get expanded against the calling script's own variables, exactly as
- # if its content were still an inline heredoc in that script.
- eval "cat <<RENDER_TEMPLATE_EOF
-$(cat "${PATH_TEMPLATE}")
-RENDER_TEMPLATE_EOF"
-}
+++ /dev/null
-include msg
-
-retry_until_success() {
- until "$@"; do
- msg 'Command failed, retrying: %s …' "$*"
- done
-}
-
+++ /dev/null
-include DIRNAME_SCRIPTS
-include PATH_REPO
-include USERNAME
-include link_home
-include msg
-include retry_until_success
-include try_quiet
-
-start_root() {
- local PATH_TO_INSTALL="${PATH_REPO}/to_install/$1"
- local PATH_SCRIPT_USER="${PATH_REPO}/${DIRNAME_SCRIPTS}/start_user.sh"
- local TIMEZONE=Europe/Berlin
- # Assuming read file ends with a newline, has no blank lines, and its
- # package-name lines contain no whitespace besides that newline.
- local TO_INSTALL=
- while read -r LINE; do
- case "${LINE}" in
- '#'*) continue ;;
- esac
- TO_INSTALL="${TO_INSTALL} ${LINE}"
- done < "${PATH_TO_INSTALL}"
- apt-get -y update
- msg 'Ensuring packages: %s' "${TO_INSTALL}"
- apt-get -y install ${TO_INSTALL}
-
- if try_quiet id -u "${USERNAME}"; then
- msg 'User %s already exists, skipping creation …' "${USERNAME}"
- else
- msg 'Setting up user: %s' "${USERNAME}"
- adduser --disabled-password --comment "" "${USERNAME}"
- retry_until_success passwd "${USERNAME}"
- msg 'Running start_user.sh as %s …' "${USERNAME}"
- su - "${USERNAME}" -c "sh ${PATH_SCRIPT_USER}"
- fi
- usermod -a -G sudo "${USERNAME}"
-
- msg 'Setting system timezone to %s …' "${TIMEZONE}"
- timedatectl set-timezone "${TIMEZONE}"
-
- link_home root
-}
+++ /dev/null
-try_quiet() {
- "$@" >/dev/null 2>&1
-}
+++ /dev/null
-include PATH_MNT_CHROOT
-include TO_RBIND
-include msg
-
-unmount_unrbind() {
- msg 'Unmounting chroot environment …'
- for NAME in ${TO_RBIND}; do
- umount -R "${PATH_MNT_CHROOT}/${NAME}"
- done
- umount "${PATH_MNT_CHROOT}"
-}
-
+++ /dev/null
-include die
-
-usage() {
- local COUNT_INPUTS=$1
- shift
- local MSG="usage: ${SCRIPT_NAME}"
- for PARAMETER in "$@"; do
- MSG="${MSG} <${PARAMETER}>"
- done
- [ "${COUNT_INPUTS}" -eq $# ]\
- || die "${MSG}"
-}
+++ /dev/null
-#!/bin/sh
-. "$(dirname "$0")/_lib.sh"
-include DIRNAME_REPO
-include PATH_REPO
-include USERNAME
-include error
-include msg
-include render_template
-
-# constants we might want to change at some point
-PATH_GIT_BASE=/srv/git
-
-# constants derived from changeables
-FNAME_GIT_DAEMON_UNIT=git-daemon.service
-PATH_GIT_DAEMON_UNIT="/etc/systemd/system/${FNAME_GIT_DAEMON_UNIT}"
-PATH_GIT_MIRROR="${PATH_GIT_BASE}/${DIRNAME_REPO}.git"
-PATH_GIT_MIRROR_EXPORT_OK="${PATH_GIT_MIRROR}/git-daemon-export-ok"
-
-[ -e "${PATH_GIT_MIRROR}" ]\
- && error "${PATH_GIT_MIRROR} already exists"
-
-msg 'Installing git …'
-apt-get -y update
-apt-get -y install git
-
-msg 'Bare-cloning repo to %s for anonymous serving …' "${PATH_GIT_MIRROR}"
-mkdir -p "${PATH_GIT_BASE}"
-git clone --quiet --bare "${PATH_REPO}" "${PATH_GIT_MIRROR}"
-touch "${PATH_GIT_MIRROR_EXPORT_OK}"
-
-msg 'Own repo to %s so they can update it via ssh …' "${USERNAME}"
-chown -R "${USERNAME}:${USERNAME}" "${PATH_GIT_MIRROR}"
-
-msg 'Writing and enabling git-daemon systemd unit …'
-render_template "${FNAME_GIT_DAEMON_UNIT}" >| "${PATH_GIT_DAEMON_UNIT}"
-systemctl daemon-reload
-systemctl enable --now git-daemon
-
-msg 'Anonymous clone URL: git://<this-server>/%s.git' "${DIRNAME_REPO}"
-msg 'Push updates later with: git push ssh://%s@<this-server>%s' \
- "${USERNAME}" "${PATH_GIT_MIRROR}"
-msg 'Firewall note: git daemon listens on port 9418/tcp.'
+++ /dev/null
-#!/bin/sh
-. "$(dirname "$0")/_lib.sh"
-include NAME_DATA
-include NAME_LUKSVG
-include NAME_SWAP
-include PATH_MNT
-include PATH_DATA
-include PATH_PARTITION_LUKSVG
-include PATH_REPO
-include check_boot_device_layout
-include check_partition_mountable
-include check_new_luksvg
-include check_tools
-include close_luksvg
-include create_lv
-include die
-include error
-include msg
-include msg_nonl
-include open_luksvg
-include mount_privately
-include path_luks_mapper
-include path_vg
-include try_quiet
-include usage
-
-# inputs to confirm
-usage $#
-
-# constants derived from changeables
-PATH_LUKS_MAPPER=$(path_luks_mapper "${NAME_LUKSVG}")
-PATH_MNT_DATA="${PATH_MNT}${PATH_DATA}"
-PATH_VG=$(path_vg "${NAME_LUKSVG}")
-PATH_VG_DATA=${PATH_VG}/${NAME_DATA}
-PATH_VG_SWAP=${PATH_VG}/${NAME_SWAP}
-
-# sanity checks
-check_tools cryptsetup lvcreate mkfs.ext4 mkswap vgchange vgcreate vgs
-check_boot_device_layout
-check_partition_mountable "${PATH_PARTITION_LUKSVG}"
-check_new_luksvg
-try_quiet cryptsetup isLuks "${PATH_PARTITION_LUKSVG}"\
- && error "${PATH_PARTITION_LUKSVG} is already a LUKS container"
-
-# run inputs by user and ask for confirmation
-msg 'Target partition TO BE ERASED (!): [ %s ]' "${PATH_PARTITION_LUKSVG}"
-msg_nonl 'To continue, type "YES!" (all caps, exclamation mark, no quotes): '
-read -r CONFIRM; [ "${CONFIRM}" = 'YES!' ]\
- || die 'ABORTED: expected confirmation not given.'
-
-msg 'Encrypting %s as LUKS container …' "${PATH_PARTITION_LUKSVG}"
-cryptsetup luksFormat --batch-mode "${PATH_PARTITION_LUKSVG}"
-open_luksvg
-
-# set up LVM and filesystems
-msg 'Creating volume group "%s" inside LUKS container …' "${NAME_LUKSVG}"
-vgcreate "${NAME_LUKSVG}" "${PATH_LUKS_MAPPER}"
-create_lv "${NAME_LUKSVG}" "${NAME_SWAP}" 64G
-msg 'Configuring as swap area …'
-mkswap "${PATH_VG_SWAP}"
-create_lv "${NAME_LUKSVG}" "${NAME_DATA}" 256G
-msg 'Creating EXT4 filesystem …'
-mkfs.ext4 -q "${PATH_VG_DATA}"
-
-# place repo copy
-mount_privately "${PATH_VG_DATA}" "${PATH_MNT_DATA}"
-msg 'Copying repo …'
-cp -a "${PATH_REPO}" "${PATH_MNT_DATA}"
-
-# clean-up
-msg 'Unmounting …'
-umount "${PATH_MNT_DATA}"
-close_luksvg
-msg 'Finished!'
+++ /dev/null
-#!/bin/sh
-. "$(dirname "$0")/_lib.sh"
-include DIRNAME_SSH
-include PATH_MY_SSH
-include USERNAME
-include disable_apt_recommends
-include msg
-include retry_until_success
-include start_root
-
-# constants unlikely to change
-PATH_SSHD_DROPIN=/etc/ssh/sshd_config.d/60-ssh-hardening.conf
-
-# constants derived from changeables
-PATH_HOME_USER="/home/${USERNAME}"
-PATH_USER_SSH="${PATH_HOME_USER}/${DIRNAME_SSH}"
-
-disable_apt_recommends
-start_root server
-
-msg 'Moving ssh access from root to user …'
-mv "${PATH_MY_SSH}" "${PATH_HOME_USER}"
-chown -R "${USERNAME}:${USERNAME}" "${PATH_USER_SSH}"
-
-msg 'Hardening SSH login: no root login, no password auth …'
-printf 'PermitRootLogin no\nPasswordAuthentication no\n' >| "${PATH_SSHD_DROPIN}"
-systemctl reload ssh
-
-msg 'Setting up root password-login …'
-retry_until_success passwd
+++ /dev/null
-#!/bin/sh
-. "$(dirname "$0")/_lib.sh"
-include DIRNAME_SCRIPTS
-include PATH_FIRST_BOOT_PENDING
-include PATH_REPO
-include msg
-include start_root
-include render_template
-
-# constants unlikely to change
-PATH_DEFAULT_LOCALE=/etc/default/locale
-PATH_HIBERNATE_OVERRIDE=/etc/systemd/system/systemd-hibernate.service.d/\
-60-poweroff-on-failure.conf
-PATH_HOOK_EFI=/etc/initramfs/post-update.d/update-efi
-PATH_LOGIND_OVERRIDE=/etc/systemd/logind.conf.d/\
-60-poweroff-on-lid-close.conf
-PATH_SYSCTL_PRINTK=/etc/sysctl.d/60-printk-console.conf
-PATH_TLP_THRESH_CONF=/etc/tlp.conf.d/60-thresholds.conf
-PATH_UDEV_RULES=/etc/udev/rules.d
-
-# constants we might want to change at some point
-DIRNAME_TO_COPY=to_copy
-FNAME_SCRIPT_EFI=update_efi.sh
-FNAME_UDEV_RULES_BACKLIGHT=90-backlight.rules
-LOCALE=C.UTF-8
-PRINTK_LEVELS="4 4 1 7"
-TLP_THRESH_START=40
-TLP_THRESH_STOP=80
-
-# constants derived from changeables
-PATH_TO_COPY="${PATH_REPO}/${DIRNAME_TO_COPY}"
-# shellcheck disable=SC2034
-# (used only inside templates/update-efi-hook, rendered via render_template)
-PATH_SCRIPT_EFI="${PATH_REPO}/${DIRNAME_SCRIPTS}/${FNAME_SCRIPT_EFI}"
-
-# before any apt-get call gets a chance to pull in a kernel update of its own …
-msg 'Installing initramfs hook to refresh EFI boot files on kernel updates …'
-mkdir -p "$(dirname "${PATH_HOOK_EFI}")"
-render_template "update-efi-hook" >| "${PATH_HOOK_EFI}"
-chmod +x "${PATH_HOOK_EFI}"
-
-start_root t490s
-
-# C.UTF-8 is built into glibc itself (unlike e.g. en_US.UTF-8), so no
-# "locales" package / locale-gen is needed to make it available — writing
-# it here is enough for it to apply system-wide from the next login on.
-msg 'Setting system locale to %s …' "${LOCALE}"
-printf 'LANG=%s\n' "${LOCALE}" >| "${PATH_DEFAULT_LOCALE}"
-
-msg 'Quieting routine kernel messages on the console …'
-printf 'kernel.printk = %s\n' "${PRINTK_LEVELS}" >| "${PATH_SYSCTL_PRINTK}"
-sysctl -p "${PATH_SYSCTL_PRINTK}"
-
-msg 'Setting TLP battery charge thresholds: start %s%%, stop %s%% …' \
- "${TLP_THRESH_START}" "${TLP_THRESH_STOP}"
-mkdir -p "$(dirname "${PATH_TLP_THRESH_CONF}")"
-printf 'START_CHARGE_THRESH_BAT0=%s\nSTOP_CHARGE_THRESH_BAT0=%s\n' \
- "${TLP_THRESH_START}" "${TLP_THRESH_STOP}" >| "${PATH_TLP_THRESH_CONF}"
-tlp start
-
-msg 'Falling back to poweroff on a failed hibernate attempt …'
-mkdir -p "$(dirname "${PATH_HIBERNATE_OVERRIDE}")"
-printf '[Unit]\nOnFailure=poweroff.target\n' >| "${PATH_HIBERNATE_OVERRIDE}"
-systemctl daemon-reload
-
-msg 'Forcing a full poweroff on lid close, in every dock/power state …'
-mkdir -p "$(dirname "${PATH_LOGIND_OVERRIDE}")"
-{
- printf '[Login]\n'
- printf '%s=poweroff\n' \
- HandleLidSwitch HandleLidSwitchExternalPower HandleLidSwitchDocked
-} >| "${PATH_LOGIND_OVERRIDE}"
-# logind only re-reads its config at process start, not via daemon-reload
-systemctl restart systemd-logind
-
-msg 'Making backlight devices available to user-run backlight script …'
-cp "${PATH_TO_COPY}/${FNAME_UDEV_RULES_BACKLIGHT}" "${PATH_UDEV_RULES}/"
-udevadm control --reload-rules
-udevadm trigger --action=add --subsystem-match=backlight
-usermod -a -G video "${USERNAME}"
-
-msg 'Clearing first-boot pending marker …'
-rm -f "${PATH_FIRST_BOOT_PENDING}"
+++ /dev/null
-#!/bin/sh
-. "$(dirname "$0")/_lib.sh"
-include link_home
-
-link_home user
+++ /dev/null
-#!/bin/sh
-. "$(dirname "$0")/_lib.sh"
-include PATH_PARTITION_EFI
-include check_partition_mountable
-include efi_copy_kernel_vmlinuz
-include msg
-include usage
-
-usage $#
-
-PATH_TEMP=$(mktemp --directory)
-PATH_EFI_NAME_BOOT="${PATH_TEMP}/$(hostname)"
-
-check_partition_mountable "${PATH_PARTITION_EFI}"
-msg 'Mounting EFI partition %s at %s …' "${PATH_PARTITION_EFI}" "${PATH_TEMP}"
-mount "${PATH_PARTITION_EFI}" "${PATH_TEMP}"
-
-efi_copy_kernel_vmlinuz "${PATH_EFI_NAME_BOOT}"
-
-msg 'Unmounting EFI partition …'
-umount "${PATH_TEMP}"
-rmdir "${PATH_TEMP}"