set -Ceu
SCRIPT_NAME=$0
cd "$(dirname "${SCRIPT_NAME}")"
-
-# constants unlikely to change
-DIRNAME_DEV=dev
-DIRNAME_SSH=.ssh
-FNAME_FIRST_BOOT_PENDING=.first-boot-pending
-FNAME_INITRD=initrd.img
-FNAME_PROFILE=.profile
-FNAME_VMLINUZ=vmlinuz
-PATH_DEV="/${DIRNAME_DEV}"
-PATH_EFI=/boot/efi
-PATH_MNT=/mnt
-TO_RBIND="${DIRNAME_DEV} proc sys"
-
-# constants we might want to change at some point
-IDX_PARTITION_EFI=1
-IDX_PARTITION_LUKSVG=3
-IDX_PARTITION_RESCUE=2
-NAME_BOOT_DEVICE=nvme0n1
-NAME_DATA=data
-NAME_LUKSVG=cryptolvm
-NAME_SWAP=swap
-PATH_APT_NORECOMMENDS=/etc/apt/apt.conf.d/90-no-recommends
-PATH_MNT_ROOT="${PATH_MNT}/root"
-TIMEZONE=Europe/Berlin
-USERNAME=plom
-
-# constants derived from changeables
-PATH_BOOT_DEVICE="${PATH_DEV}/${NAME_BOOT_DEVICE}"
-PATH_FIRST_BOOT_PENDING="/root/${FNAME_FIRST_BOOT_PENDING}"
-PATH_MY_SSH="${HOME}/${DIRNAME_SSH}"
-PATH_PARTITION_EFI="${PATH_BOOT_DEVICE}p${IDX_PARTITION_EFI}"
-PATH_PARTITION_LUKSVG="${PATH_BOOT_DEVICE}p${IDX_PARTITION_LUKSVG}"
-PATH_PARTITION_RESCUE="${PATH_BOOT_DEVICE}p${IDX_PARTITION_RESCUE}"
-PATH_PROFILE="${HOME}/${FNAME_PROFILE}"
-PATH_REPO=$(cd .. && pwd)
-PATH_SCRIPTS="${PATH_REPO}/setup_scripts"
-DIRNAME_REPO=$(basename "${PATH_REPO}")
-PATH_TEMPLATES="${PATH_REPO}/templates"
-
-# path constructors
-path_luks_mapper() {
- printf '%s/mapper/%s' "${PATH_DEV}" "$1"
-}
-path_vg() {
- printf '%s/%s' "${PATH_DEV}" "$1"
-}
-
-# helpers: logging, testing, failing basics
-msg_nonl() {
- printf '[## %s ##] ' "${SCRIPT_NAME}"
- # shellcheck disable=SC2059
- # (assume we'll always pass a literal format string)
- printf -- "$@"
-}
-msg() {
- msg_nonl "$@"
- printf '\n'
-}
-die() {
- msg '%s' "$*" >&2
- exit 1
-}
-error() {
- die "error: $*"
-}
-try_quiet() {
- "$@" >/dev/null 2>&1
-}
-
-# helpers: more involved testing
-check_tools() {
- for CMD in "$@"; do
- try_quiet command -v "${CMD}"\
- || error "required tool not found: ${CMD}"
- done
-}
-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
-}
-check_boot_device_layout() {
- local COUNT_NVME
- 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}"
-}
-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
-}
-check_openable_luksvg() {
- check_new_luksvg
- try_quiet cryptsetup isLuks "${PATH_PARTITION_LUKSVG}"\
- || error "${PATH_PARTITION_LUKSVG} not a LUKS container"
-}
-
-# helpers: luks open/close
-open_luksvg() {
- msg 'Opening LUKS container as "%s" …' "${NAME_LUKSVG}"
- cryptsetup luksOpen "${PATH_PARTITION_LUKSVG}" "${NAME_LUKSVG}"
-}
-close_luksvg() {
- msg 'Deactivating volume group and closing LUKS container …'
- vgchange -an "${NAME_LUKSVG}"
- cryptsetup luksClose "${NAME_LUKSVG}"
-}
-
-# helpers: mount/unmount root
-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}"
-}
-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'
-}
-rbind_mnt() {
- for NAME in ${TO_RBIND}; do
- local PATH_NAME="/${NAME}"
- local SLAVE="${PATH_MNT_ROOT}${PATH_NAME}"
- msg 'For working chroot also mounting %s into there …' "${PATH_NAME}"
- mount --rbind "${PATH_NAME}" "${SLAVE}"
- mount --make-rslave "${SLAVE}"
- done
-}
-unmount_unrbind() {
- msg 'Unmounting chroot environment …'
- for NAME in ${TO_RBIND}; do
- umount -R "${PATH_MNT_ROOT}/${NAME}"
- done
- umount "${PATH_MNT_ROOT}"
-}
-
-# helpers: miscellaneous
-chroot_sh() {
- LANG=C.UTF-8 chroot "${PATH_MNT_ROOT}" /bin/sh -c "$@"
-}
-retry_until_success() {
- until "$@"; do
- msg 'Command failed, retrying: %s …' "$*"
- done
-}
-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}"
-}
-usage() {
- local COUNT_INPUTS=$1
- shift
- local MSG="usage: ${SCRIPT_NAME}"
- for PARAMETER in "$@"; do
- MSG="${MSG} <${PARAMETER}>"
- done
- [ "${COUNT_INPUTS}" -eq $# ]\
- || die "${MSG}"
-}
-augment_profile() {
- local ALIAS_LS='alias ls="ls --color=auto"'
- msg 'Augmenting user %s …' "${FNAME_PROFILE}"
- # test ensures idempotency
- grep -qxF "${ALIAS_LS}" "${PATH_PROFILE}" 2>/dev/null\
- || echo "${ALIAS_LS}" >> "${PATH_PROFILE}"
-}
-start_root() {
- local TARGET=$1
-
- # 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_REPO}/to_install/${TARGET}"
- 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_SCRIPTS}/start_user.sh"
- fi
- usermod -a -G sudo "${USERNAME}"
-
- msg 'Setting system timezone to %s …' "${TIMEZONE}"
- timedatectl set-timezone "${TIMEZONE}"
-
- augment_profile
-}
-disable_apt_recommends() {
- local PREFIX=${1:-}
- local TARGET="${PREFIX}${PATH_APT_NORECOMMENDS}"
- msg 'Disabling automatic installation of APT recommends …'
- printf 'APT::Install-Recommends "false";\n' >| "${TARGET}"
-}
-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
-}
-render_template() {
- local PATH_TEMPLATE=$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"
-}
#!/bin/sh
. "$(dirname "$0")/_lib.sh"
+. lib/NAME_LUKSVG.sh
+. lib/PATH_MNT_CHROOT.sh
+. lib/PATH_PARTITION_LUKSVG.sh
+. lib/await_path.sh
+. lib/check_openable_luksvg.sh
+. lib/check_tools.sh
+. lib/check_partition_mountable.sh
+. lib/chroot_sh.sh
+. lib/close_luksvg.sh
+. lib/mount_privately.sh
+. lib/msg.sh
+. lib/open_luksvg.sh
+. lib/path_vg.sh
+. lib/rbind_mnt.sh
+. lib/unmount_unrbind.sh
+. lib/usage.sh
# inputs to confirm
usage $# "root-name" "command"
# mount
open_luksvg
await_path "${PATH_VG_ROOT}"
-mount_privately "${PATH_VG_ROOT}" "${PATH_MNT_ROOT}"
+mount_privately "${PATH_VG_ROOT}" "${PATH_MNT_CHROOT}"
rbind_mnt
# enact command
#!/bin/sh
. "$(dirname "$0")/_lib.sh"
+. lib/DIRNAME_REPO.sh
+. lib/DIRNAME_SCRIPTS.sh
+. lib/FNAME_INITRD.sh
+. lib/FNAME_PROFILE.sh
+. lib/FNAME_VMLINUZ.sh
+. lib/IDX_PARTITION_EFI.sh
+. lib/NAME_DATA.sh
+. lib/NAME_LUKSVG.sh
+. lib/NAME_SWAP.sh
+. lib/PATH_BOOT_DEVICE.sh
+. lib/PATH_DATA.sh
+. lib/PATH_EFI.sh
+. lib/PATH_FIRST_BOOT_PENDING.sh
+. lib/PATH_HOME_ROOT.sh
+. lib/PATH_MNT_CHROOT.sh
+. lib/PATH_PARTITION_LUKSVG.sh
+. lib/await_path.sh
+. lib/check_boot_device_layout.sh
+. lib/check_partition_mountable.sh
+. lib/close_luksvg.sh
+. lib/check_openable_luksvg.sh
+. lib/check_tools.sh
+. lib/chroot_sh.sh
+. lib/create_lv.sh
+. lib/disable_apt_recommends.sh
+. lib/efi_copy_kernel_vmlinuz.sh
+. lib/error.sh
+. lib/msg.sh
+. lib/open_luksvg.sh
+. lib/mount_privately.sh
+. lib/path_vg.sh
+. lib/render_template.sh
+. lib/rbind_mnt.sh
+. lib/retry_until_success.sh
+. lib/unmount_unrbind.sh
+. lib/usage.sh
# constants unlikely to change
FNAME_NM_CONN=wifi.nmconnection
+FNAME_FSTAB=fstab
PATH_CRYPTTAB=/etc/crypttab
-PATH_FSTAB=/etc/fstab
+PATH_FSTAB="/etc/${FNAME_FSTAB}"
PATH_HOSTNAME=/etc/hostname
PATH_HOSTS=/etc/hosts
PATH_INTERFACES=/etc/network/interfaces
# constants we might want to change at some point
DEB_SUITE=trixie
+FNAME_SCRIPT_START=start_root_t490s.sh
# inputs
usage $# "boot-name"
# constants derived from changeables
PATH_EFI_NAME_BOOT="${PATH_EFI}/${NAME_BOOT}"
-PATH_FIRST_BOOT_SCRIPT="/${NAME_DATA}/${PATH_SCRIPTS}//start_root_t490s.sh"
-PATH_MNT_APT_SOURCES="${PATH_MNT_ROOT}/etc/apt/sources.list"
-PATH_MNT_CRYPTTAB="${PATH_MNT_ROOT}${PATH_CRYPTTAB}"
-PATH_MNT_FIRST_BOOT_PENDING="${PATH_MNT_ROOT}${PATH_FIRST_BOOT_PENDING}"
-PATH_MNT_FSTAB="${PATH_MNT_ROOT}${PATH_FSTAB}"
-PATH_MNT_HOSTNAME="${PATH_MNT_ROOT}${PATH_HOSTNAME}"
-PATH_MNT_HOSTS="${PATH_MNT_ROOT}${PATH_HOSTS}"
-PATH_MNT_NM_CONN="${PATH_MNT_ROOT}${PATH_NM_CONNECTIONS}/${FNAME_NM_CONN}"
-PATH_MNT_NM_CONNECTIONS="${PATH_MNT_ROOT}${PATH_NM_CONNECTIONS}"
-PATH_MNT_PROFILE="${PATH_MNT_ROOT}/root/${FNAME_PROFILE}"
+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_VG=$(path_vg "${NAME_LUKSVG}")
# shellcheck disable=SC2034
# (used only inside templates/fstab, rendered via render_template)
mkfs.ext4 -q "${PATH_VG_ROOT}"
# mount and install base
-mount_privately "${PATH_VG_ROOT}" "${PATH_MNT_ROOT}"
+mount_privately "${PATH_VG_ROOT}" "${PATH_MNT_CHROOT}"
msg 'Installing Debian Suite "%s" there via debootstrap …' "${DEB_SUITE}"
-debootstrap "${DEB_SUITE}" "${PATH_MNT_ROOT}"
+debootstrap "${DEB_SUITE}" "${PATH_MNT_CHROOT}"
rbind_mnt
msg 'Setting up fstab …'
-render_template "${PATH_TEMPLATES}/fstab" >| "${PATH_MNT_FSTAB}"
+render_template "${FNAME_FSTAB}" >| "${PATH_MNT_FSTAB}"
msg 'Setting up crypttab …'
printf '%s %s none luks\n' "${NAME_LUKSVG}" "${PATH_PARTITION_LUKSVG}" \
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_ROOT}"
+disable_apt_recommends "${PATH_MNT_CHROOT}"
msg 'Into chroot environment installing LVM tools, kernel, initrd etc. …'
chroot_sh "apt-get -qq update"
"${NAME_WIFI_SSID}"
mkdir -p "${PATH_MNT_NM_CONNECTIONS}"
chmod 700 "${PATH_MNT_NM_CONNECTIONS}"
-render_template "${PATH_TEMPLATES}/wifi.nmconnection" >| "${PATH_MNT_NM_CONN}"
+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_ROOT}"
+efi_copy_kernel_vmlinuz "${PATH_EFI_NAME_BOOT}" "${PATH_MNT_CHROOT}"
msg 'EFI setup: adding boot entry %s …' "${NAME_BOOT}"
efibootmgr \
--create \
#!/bin/sh
. "$(dirname "$0")/_lib.sh"
+. lib/DIRNAME_REPO.sh
+. lib/DIRNAME_SCRIPTS.sh
+. lib/PATH_MY_SSH.sh
+. lib/PATH_REPO.sh
+. lib/check_tools.sh
+. lib/msg.sh
+. lib/usage.sh
# constants we might want to change at some point
FNAME_REPO_TAR=repo.tar
# constants derived from changeables
PATH_REPO_PARENT=$(dirname "${PATH_REPO}")
-PATH_SETUP_SCRIPT="./${PATH_SCRIPTS}/start_root_server.sh"
+RELPATH_SETUP_SCRIPT="${DIRNAME_REPO}/${DIRNAME_SCRIPTS}/start_root_server.sh"
# inputs to confirm
usage $# "server"
SERVER=$1
-TARGET="root@${SERVER}"
+LOGIN="root@${SERVER}"
PATH_MY_KNOWN_HOSTS="${PATH_MY_SSH}/known_hosts"
# sanity checks
tar cf "${PATH_REPO_TAR}" -C "${PATH_REPO_PARENT}" "${DIRNAME_REPO}"
msg 'Uploading repo tar to server …'
-if [ -e "${PATH_MY_KNOWN_HOSTS}" ]; then
- ssh-keygen -f "${PATH_MY_KNOWN_HOSTS}" -R "${SERVER}"
-fi
-scp ${OPTS_SSH_NEW_HOST} "${PATH_REPO_TAR}" "${TARGET}:~"
+[ -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} "${TARGET}" tar xf "${FNAME_REPO_TAR}" --no-same-owner
-ssh -t ${OPTS_SSH_NEW_HOST} "${TARGET}" "${PATH_SETUP_SCRIPT}"
+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_CHROOT=chroot
--- /dev/null
+DIRNAME_DEV=dev
--- /dev/null
+. lib/PATH_REPO.sh
+
+DIRNAME_REPO=$(basename "${PATH_REPO}")
+
--- /dev/null
+DIRNAME_SCRIPTS=$(basename "$(dirname "${SCRIPT_NAME}")")
+
--- /dev/null
+DIRNAME_SSH=.ssh
+
--- /dev/null
+FNAME_FIRST_BOOT_PENDING=.first-boot-pending
+
--- /dev/null
+FNAME_INITRD=initrd.img
--- /dev/null
+FNAME_PROFILE=.profile
--- /dev/null
+FNAME_VMLINUZ=vmlinuz
--- /dev/null
+IDX_PARTITION_EFI=1
--- /dev/null
+IDX_PARTITION_LUKSVG=3
--- /dev/null
+IDX_PARTITION_RESCUE=2
+
--- /dev/null
+NAME_BOOT_DEVICE=nvme0n1
+
--- /dev/null
+NAME_DATA=data
+
--- /dev/null
+NAME_LUKSVG=cryptolvm
+
--- /dev/null
+NAME_SWAP=swap
+
--- /dev/null
+. lib/NAME_BOOT_DEVICE.sh
+. lib/PATH_DEV.sh
+
+PATH_BOOT_DEVICE="${PATH_DEV}/${NAME_BOOT_DEVICE}"
--- /dev/null
+. lib/NAME_DATA.sh
+
+PATH_DATA="/${NAME_DATA}"
+
--- /dev/null
+. lib/DIRNAME_DEV.sh
+
+PATH_DEV="/${DIRNAME_DEV}"
+
--- /dev/null
+PATH_EFI=/boot/efi
--- /dev/null
+. lib/FNAME_FIRST_BOOT_PENDING.sh
+. lib/PATH_HOME_ROOT.sh
+
+PATH_FIRST_BOOT_PENDING="${PATH_HOME_ROOT}/${FNAME_FIRST_BOOT_PENDING}"
+
--- /dev/null
+PATH_HOME_ROOT=/root
+
--- /dev/null
+PATH_MNT=/mnt
+
--- /dev/null
+. lib/DIRNAME_CHROOT.sh
+. lib/PATH_MNT.sh
+
+PATH_MNT_CHROOT="${PATH_MNT}/${DIRNAME_CHROOT}"
--- /dev/null
+. lib/DIRNAME_SSH.sh
+
+PATH_MY_SSH="${HOME}/${DIRNAME_SSH}"
+
--- /dev/null
+. lib/IDX_PARTITION_EFI.sh
+. lib/PATH_BOOT_DEVICE.sh
+
+PATH_PARTITION_EFI="${PATH_BOOT_DEVICE}p${IDX_PARTITION_EFI}"
--- /dev/null
+. lib/IDX_PARTITION_LUKSVG.sh
+. lib/PATH_BOOT_DEVICE.sh
+
+PATH_PARTITION_LUKSVG="${PATH_BOOT_DEVICE}p${IDX_PARTITION_LUKSVG}"
+
--- /dev/null
+. lib/IDX_PARTITION_RESCUE.sh
+. lib/PATH_BOOT_DEVICE.sh
+
+PATH_PARTITION_RESCUE="${PATH_BOOT_DEVICE}p${IDX_PARTITION_RESCUE}"
+
--- /dev/null
+. lib/FNAME_PROFILE.sh
+
+PATH_PROFILE="${HOME}/${FNAME_PROFILE}"
+
--- /dev/null
+PATH_REPO=$(cd .. && pwd)
+
--- /dev/null
+TIMEZONE=Europe/Berlin
--- /dev/null
+. lib/DIRNAME_DEV.sh
+
+TO_RBIND="${DIRNAME_DEV} proc sys"
+
--- /dev/null
+USERNAME=plom
+
--- /dev/null
+. lib/FNAME_PROFILE.sh
+. lib/PATH_PROFILE.sh
+. lib/msg.sh
+
+augment_profile() {
+ local ALIAS_LS='alias ls="ls --color=auto"'
+ msg 'Augmenting user %s …' "${FNAME_PROFILE}"
+ # test ensures idempotency
+ grep -qxF "${ALIAS_LS}" "${PATH_PROFILE}" 2>/dev/null\
+ || echo "${ALIAS_LS}" >> "${PATH_PROFILE}"
+}
+
--- /dev/null
+. lib/msg.sh
+
+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
+. lib/PATH_BOOT_DEVICE.sh
+. lib/PATH_DEV.sh
+. lib/PATH_EFI.sh
+. lib/PATH_PARTITION_EFI.sh
+. lib/PATH_PARTITION_RESCUE.sh
+. lib/error.sh
+. lib/try_quiet.sh
+
+check_boot_device_layout() {
+ local COUNT_NVME
+ 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
+. lib/NAME_LUKSVG.sh
+. lib/error.sh
+. lib/path_luks_mapper.sh
+. lib/try_quiet.sh
+
+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
+. lib/PATH_PARTITION_LUKSVG.sh
+. lib/check_new_luksvg.sh
+. lib/error.sh
+. lib/try_quiet.sh
+
+check_openable_luksvg() {
+ check_new_luksvg
+ try_quiet cryptsetup isLuks "${PATH_PARTITION_LUKSVG}"\
+ || error "${PATH_PARTITION_LUKSVG} not a LUKS container"
+}
+
--- /dev/null
+. lib/error.sh
+. lib/try_quiet.sh
+
+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
+. lib/error.sh
+. lib/try_quiet.sh
+
+check_tools() {
+ for CMD in "$@"; do
+ try_quiet command -v "${CMD}"\
+ || error "required tool not found: ${CMD}"
+ done
+}
--- /dev/null
+. lib/PATH_MNT_CHROOT.sh
+
+chroot_sh() {
+ LANG=C.UTF-8 chroot "${PATH_MNT_CHROOT}" /bin/sh -c "$@"
+}
+
--- /dev/null
+. lib/NAME_LUKSVG.sh
+. lib/msg.sh
+
+close_luksvg() {
+ msg 'Deactivating volume group and closing LUKS container …'
+ vgchange -an "${NAME_LUKSVG}"
+ cryptsetup luksClose "${NAME_LUKSVG}"
+}
--- /dev/null
+. lib/msg.sh
+
+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
+. lib/msg.sh
+
+die() {
+ msg '%s' "$*" >&2
+ exit 1
+}
--- /dev/null
+. lib/msg.sh
+
+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
+. lib/FNAME_INITRD.sh
+. lib/FNAME_VMLINUZ.sh
+. lib/msg.sh
+
+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
+. lib/die.sh
+
+error() {
+ die "error: $*"
+}
--- /dev/null
+. lib/msg.sh
+
+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
+. lib/msg_nonl.sh
+
+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
+. lib/NAME_LUKSVG.sh
+. lib/PATH_PARTITION_LUKSVG.sh
+. lib/msg.sh
+
+open_luksvg() {
+ msg 'Opening LUKS container as "%s" …' "${NAME_LUKSVG}"
+ cryptsetup luksOpen "${PATH_PARTITION_LUKSVG}" "${NAME_LUKSVG}"
+}
+
--- /dev/null
+. lib/PATH_DEV.sh
+
+path_luks_mapper() {
+ printf '%s/mapper/%s' "${PATH_DEV}" "$1"
+}
--- /dev/null
+. lib/PATH_DEV.sh
+
+path_vg() {
+ printf '%s/%s' "${PATH_DEV}" "$1"
+}
+
--- /dev/null
+. lib/PATH_MNT_CHROOT.sh
+. lib/TO_RBIND.sh
+. lib/msg.sh
+
+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
+. lib/PATH_REPO.sh
+
+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
+. lib/msg.sh
+
+retry_until_success() {
+ until "$@"; do
+ msg 'Command failed, retrying: %s …' "$*"
+ done
+}
+
--- /dev/null
+. lib/DIRNAME_SCRIPTS.sh
+. lib/PATH_REPO.sh
+. lib/TIMEZONE.sh
+. lib/USERNAME.sh
+. lib/augment_profile.sh
+. lib/msg.sh
+. lib/retry_until_success.sh
+. lib/try_quiet.sh
+
+start_root() {
+ local PATH_TO_INSTALL="${PATH_REPO}/to_install/$1"
+ local PATH_SCRIPT_USER="${PATH_REPO}/${DIRNAME_SCRIPTS}/start_user.sh"
+ # 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}"
+
+ augment_profile
+}
--- /dev/null
+try_quiet() {
+ "$@" >/dev/null 2>&1
+}
--- /dev/null
+. lib/PATH_MNT_CHROOT.sh
+. lib/TO_RBIND.sh
+. lib/msg.sh
+
+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
+. lib/die.sh
+
+usage() {
+ local COUNT_INPUTS=$1
+ shift
+ local MSG="usage: ${SCRIPT_NAME}"
+ for PARAMETER in "$@"; do
+ MSG="${MSG} <${PARAMETER}>"
+ done
+ [ "${COUNT_INPUTS}" -eq $# ]\
+ || die "${MSG}"
+}
#!/bin/sh
. "$(dirname "$0")/_lib.sh"
+. lib/DIRNAME_REPO.sh
+. lib/PATH_REPO.sh
+. lib/USERNAME.sh
+. lib/error.sh
+. lib/msg.sh
+. lib/render_template.sh
# constants we might want to change at some point
PATH_GIT_BASE=/srv/git
# constants derived from changeables
-PATH_GIT_DAEMON_UNIT=/etc/systemd/system/git-daemon.service
+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_TEMPLATE_GIT_DAEMON="${PATH_TEMPLATES}/git-daemon.service"
+PATH_GIT_MIRROR_EXPORT_OK="${PATH_GIT_MIRROR}/git-daemon-export-ok"
[ -e "${PATH_GIT_MIRROR}" ]\
&& error "${PATH_GIT_MIRROR} already exists"
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}/git-daemon-export-ok"
+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 "${PATH_TEMPLATE_GIT_DAEMON}" >| "${PATH_GIT_DAEMON_UNIT}"
+render_template "${FNAME_GIT_DAEMON_UNIT}" >| "${PATH_GIT_DAEMON_UNIT}"
systemctl daemon-reload
systemctl enable --now git-daemon
#!/bin/sh
. "$(dirname "$0")/_lib.sh"
+. lib/NAME_DATA.sh
+. lib/NAME_LUKSVG.sh
+. lib/NAME_SWAP.sh
+. lib/PATH_MNT.sh
+. lib/PATH_DATA.sh
+. lib/PATH_PARTITION_LUKSVG.sh
+. lib/check_boot_device_layout.sh
+. lib/check_partition_mountable.sh
+. lib/check_new_luksvg.sh
+. lib/check_tools.sh
+. lib/close_luksvg.sh
+. lib/create_lv.sh
+. lib/die.sh
+. lib/error.sh
+. lib/msg.sh
+. lib/msg_nonl.sh
+. lib/open_luksvg.sh
+. lib/mount_privately.sh
+. lib/path_vg.sh
+. lib/try_quiet.sh
# inputs to confirm
usage $#
# constants derived from changeables
PATH_LUKS_MAPPER=$(path_luks_mapper "${NAME_LUKSVG}")
-PATH_MNT_DATA="${PATH_MNT}/${NAME_DATA}"
+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}
#!/bin/sh
. "$(dirname "$0")/_lib.sh"
+. lib/DIRNAME_SSH.sh
+. lib/PATH_MY_SSH.sh
+. lib/USERNAME.sh
+. lib/disable_apt_recommends.sh
+. lib/msg.sh
+. lib/retry_until_success.sh
+. lib/start_root.sh
# constants unlikely to change
PATH_SSHD_DROPIN=/etc/ssh/sshd_config.d/60-ssh-hardening.conf
#!/bin/sh
. "$(dirname "$0")/_lib.sh"
+. lib/DIRNAME_SCRIPTS.sh
+. lib/PATH_FIRST_BOOT_PENDING.sh
+. lib/PATH_REPO.sh
+. lib/msg.sh
+. lib/start_root.sh
+. lib/render_template.sh
# constants unlikely to change
PATH_DEFAULT_LOCALE=/etc/default/locale
-PATH_HOOK_UPDATE_EFI=/etc/initramfs/post-update.d/update-efi
+PATH_HOOK_EFI=/etc/initramfs/post-update.d/update-efi
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_STOP=80
# constants derived from changeables
-PATH_TO_COPY="${PATH_REPO}/to_copy"
+PATH_TO_COPY="${PATH_REPO}/${DIRNAME_TO_COPY}"
# shellcheck disable=SC2034
# (used only inside templates/update-efi-hook, rendered via render_template)
-PATH_UPDATE_EFI_SCRIPT="${PATH_SCRIPTS}/update_efi.sh"
+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_UPDATE_EFI}")"
-render_template "${PATH_TEMPLATES}/update-efi-hook" >| "${PATH_HOOK_UPDATE_EFI}"
-chmod +x "${PATH_HOOK_UPDATE_EFI}"
+mkdir -p "$(dirname "${PATH_HOOK_EFI}")"
+render_template "update-efi-hook" >| "${PATH_HOOK_EFI}"
+chmod +x "${PATH_HOOK_EFI}"
start_root t490s
#!/bin/sh
. "$(dirname "$0")/_lib.sh"
+. lib/PATH_REPO.sh
+. lib/augment_profile.sh
+. lib/msg.sh
# constants we might want to change at some point
-PATH_SKEL_USER="${PATH_REPO}/home_user"
+DIRNAME_HOME_USER=home_user
+
+# constants derived from changeables
+PATH_SKEL_USER="${PATH_REPO}/${DIRNAME_HOME_USER}"
augment_profile
msg 'Linking %s files into home directory …' "${PATH_SKEL_USER}"
#!/bin/sh
. "$(dirname "$0")/_lib.sh"
+. lib/PATH_PARTITION_EFI.sh
+. lib/check_partition_mountable.sh
+. lib/efi_copy_kernel_vmlinuz.sh
+. lib/msg.sh
+. lib/usage.sh
usage $#
${PATH_VG_ROOT} / ext4 errors=remount-ro 0 1
-${PATH_VG_DATA} /${NAME_DATA} ext4 errors=remount-ro 0 2
+${PATH_VG_DATA} ${PATH_DATA} ext4 errors=remount-ro 0 2
${PATH_VG_SWAP} none swap sw 0 0
#!/bin/sh
-exec "${PATH_UPDATE_EFI_SCRIPT}"
+exec "${PATH_SCRIPT_EFI}"