home · contact · privacy
Declutter top directory.
authorPlom Heller <plom@plomlompom.com>
Mon, 7 Sep 2026 03:00:06 +0000 (05:00 +0200)
committerPlom Heller <plom@plomlompom.com>
Mon, 7 Sep 2026 03:00:06 +0000 (05:00 +0200)
14 files changed:
90-backlight.rules [deleted file]
_lib.sh [deleted file]
chrooted_command.sh [deleted file]
install_debian.sh [deleted file]
setup_luksvg.sh [deleted file]
setup_scripts/_lib.sh [new file with mode: 0644]
setup_scripts/chrooted_command.sh [new file with mode: 0755]
setup_scripts/install_debian.sh [new file with mode: 0755]
setup_scripts/setup_luksvg.sh [new file with mode: 0755]
setup_scripts/start_root.sh [new file with mode: 0755]
setup_scripts/start_user.sh [new file with mode: 0755]
start_root.sh [deleted file]
start_user.sh [deleted file]
to_copy/90-backlight.rules [new file with mode: 0644]

diff --git a/90-backlight.rules b/90-backlight.rules
deleted file mode 100644 (file)
index 8adfb73..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-SUBSYSTEM=="backlight", ACTION=="add", \
-    RUN+="/bin/chgrp video $sys$devpath/brightness", \
-    RUN+="/bin/chmod g+w $sys$devpath/brightness"
diff --git a/_lib.sh b/_lib.sh
deleted file mode 100644 (file)
index a4759dc..0000000
--- a/_lib.sh
+++ /dev/null
@@ -1,161 +0,0 @@
-set -Ceu
-SCRIPT_NAME=$0
-cd "$(dirname "${SCRIPT_NAME}")"
-
-# constants unlikely to change
-FNAME_PROFILE=.profile
-NAME_DEV=dev
-PATH_DEV="/${NAME_DEV}"
-PATH_MNT=/mnt
-TO_RBIND="${NAME_DEV} proc sys"
-
-# constants we might want to change at some point
-NAME_DATA=data
-NAME_LUKSVG=cryptolvm
-NAME_SWAP=swap
-PATH_MNT_ROOT="${PATH_MNT}/root"
-
-# constants derived from changeables
-PATH_PROFILE="${HOME}/${FNAME_PROFILE}"
-
-# 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_input_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_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_input_openable_luksvg() {
-    local PARTITION=$1
-    check_new_luksvg
-    try_quiet cryptsetup isLuks "${PARTITION}"\
-        || error "${PARTITION} not a LUKS container"
-}
-
-# helpers: luks open/close
-open_luksvg() {
-    local PARTITION=$1
-    msg 'Opening LUKS container as "%s" …' "${NAME_LUKSVG}"
-    cryptsetup luksOpen "${PARTITION}" "${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 "$@"
-}
-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() {
-    msg 'Augmenting user %s …' "${FNAME_PROFILE}"
-    echo 'alias ls="ls --color=auto"' >> "${PATH_PROFILE}"
-}
diff --git a/chrooted_command.sh b/chrooted_command.sh
deleted file mode 100755 (executable)
index 9c1f74f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-. "$(dirname "$0")/_lib.sh"
-
-# inputs to confirm
-usage $# "partition" "root-name" "command"
-PARTITION=$1
-NAME_ROOT=$2
-COMMAND=$3
-
-# constants derived from changeables
-PATH_VG_ROOT=$(path_vg "${NAME_LUKSVG}")/${NAME_ROOT}
-
-# sanity checks
-check_tools cryptsetup vgchange vgs
-check_input_partition_mountable "${PARTITION}"
-check_input_openable_luksvg "${PARTITION}"
-
-# mount
-open_luksvg "${PARTITION}"
-await_path "${PATH_VG_ROOT}"
-mount_privately "${PATH_VG_ROOT}" "${PATH_MNT_ROOT}"
-rbind_mnt
-
-# enact command
-RC=0
-chroot_sh "${COMMAND}" || RC=$?
-
-# clean up mounts
-unmount_unrbind
-close_luksvg
-msg 'Finished! (command exit status: %s)' "${RC}"
-exit "${RC}"
diff --git a/install_debian.sh b/install_debian.sh
deleted file mode 100755 (executable)
index a8a3330..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-#!/bin/sh
-. "$(dirname "$0")/_lib.sh"
-
-# constants unlikely to change
-FNAME_INITRD=initrd.img
-FNAME_NM_CONN=wifi.nmconnection
-FNAME_VMLINUZ=vmlinuz
-PATH_CRYPTTAB=/etc/crypttab
-PATH_EFI=/boot/efi
-PATH_FSTAB=/etc/fstab
-PATH_INTERFACES=/etc/network/interfaces
-PATH_NM_CONNECTIONS=/etc/NetworkManager/system-connections
-
-# constants we might want to change at some point
-DEB_SUITE=trixie
-IDX_BOOT_PARTITION=1
-PATH_BOOT_DEVICE="${PATH_DEV}/nvme0n1"
-
-# inputs to confirm
-usage $# "partition" "boot-name"
-PARTITION=$1
-NAME_BOOT=$2
-NAME_ROOT="${NAME_BOOT}"
-
-# constants derived from changeables
-PATH_EFI_NAME_BOOT="${PATH_EFI}/${NAME_BOOT}"
-PATH_MNT_APT_SOURCES="${PATH_MNT_ROOT}/etc/apt/sources.list"
-PATH_MNT_CRYPTTAB="${PATH_MNT_ROOT}${PATH_CRYPTTAB}"
-PATH_MNT_FSTAB="${PATH_MNT_ROOT}${PATH_FSTAB}"
-PATH_MNT_NM_CONN="${PATH_MNT_ROOT}${PATH_NM_CONNECTIONS}/${FNAME_NM_CONN}"
-PATH_MNT_NM_CONNECTIONS="${PATH_MNT_ROOT}${PATH_NM_CONNECTIONS}"
-PATH_VG=$(path_vg "${NAME_LUKSVG}")
-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_input_partition_mountable "${PARTITION}"
-check_input_openable_luksvg "${PARTITION}"
-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"
-
-# run inputs by user and ask for confirmation
-msg 'Your installation choices:'
-msg '- target partition: [ %s ]' "${PARTITION}"
-msg '- name for new boot option: [ %s ]' "${NAME_BOOT}"
-
-# set up logival volume and filesystem
-open_luksvg "${PARTITION}"
-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_ROOT}"
-msg 'Installing Debian Suite "%s" there via debootstrap …' "${DEB_SUITE}"
-debootstrap "${DEB_SUITE}" "${PATH_MNT_ROOT}"
-rbind_mnt
-
-# set up minimal fstab
-msg 'Writing fstab …'
-cat <<EOF >| "${PATH_MNT_FSTAB}"
-${PATH_VG_ROOT} / ext4 errors=remount-ro 0 1
-${PATH_VG_DATA} /${NAME_DATA} ext4 errors=remount-ro 0 2
-${PATH_VG_SWAP} none swap sw 0 0
-EOF
-
-# set up crypttab
-msg 'Writing crypttab …'
-printf '%s UUID=%s none luks\n' \
-    "${NAME_LUKSVG}" "$(cryptsetup luksUUID "${PARTITION}")" \
-    >| "${PATH_MNT_CRYPTTAB}"
-
-# enable non-free-firmware component for firmware-iwlwifi below (as debootstrap
-# only enables "main" by default)
-msg 'Enabling non-free-firmware component in target sources.list …'
-sed -i 's/ main$/ main non-free-firmware/' "${PATH_MNT_APT_SOURCES}"
-
-# set up kernel, initrd etc.
-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}"
-cat <<EOF >| "${PATH_MNT_NM_CONN}"
-[connection]
-id=${NAME_WIFI_SSID}
-uuid=$(cat /proc/sys/kernel/random/uuid)
-type=wifi
-
-[wifi]
-mode=infrastructure
-ssid=${NAME_WIFI_SSID}
-
-[wifi-security]
-key-mgmt=wpa-psk
-psk=${NAME_WIFI_PSK}
-
-[ipv4]
-method=auto
-
-[ipv6]
-method=auto
-EOF
-chmod 600 "${PATH_MNT_NM_CONN}"
-
-# install kernel and initrd into EFI tree/vars
-msg 'EFI setup: copying kernel and initrd into %s …' "${PATH_EFI_NAME_BOOT}"
-mkdir "${PATH_EFI_NAME_BOOT}"
-for FILENAME in "${FNAME_INITRD}" "${FNAME_VMLINUZ}"; do
-    cp "${PATH_MNT_ROOT}/${FILENAME}" "${PATH_EFI_NAME_BOOT}/"
-done
-msg 'EFI setup: adding boot entry %s …' "${NAME_BOOT}"
-efibootmgr \
-    --create \
-    --quiet \
-    --disk "${PATH_BOOT_DEVICE}" \
-    --part "${IDX_BOOT_PARTITION}" \
-    --label "${NAME_BOOT}" \
-    --loader "${NAME_BOOT}/${FNAME_VMLINUZ}" \
-    --unicode "root=${PATH_VG_ROOT} ro initrd=${NAME_BOOT}\\${FNAME_INITRD}"
-
-# ask root login at latest possible moment, so that on fails: less left undone
-msg 'Setting up root login …'
-chroot_sh "passwd"
-
-# clean up mounts
-unmount_unrbind
-close_luksvg
-msg 'Finished!'
diff --git a/setup_luksvg.sh b/setup_luksvg.sh
deleted file mode 100755 (executable)
index fcaeabf..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/bin/sh
-. "$(dirname "$0")/_lib.sh"
-
-# inputs to confirm
-usage $# "partition"
-PARTITION=$1
-
-# constants derived from changeables
-PATH_LUKS_MAPPER=$(path_luks_mapper "${NAME_LUKSVG}")
-PATH_MNT_DATA="${PATH_MNT}/${NAME_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_input_partition_mountable "${PARTITION}"
-check_new_luksvg
-try_quiet cryptsetup isLuks "${PARTITION}"\
-    && error "${PARTITION} is already a LUKS container"
-
-# run inputs by user and ask for confirmation
-msg 'Your target partition (WILL BE ERASED!): [ %s ]' "${PARTITION}"
-msg_nonl 'To continue, type "YES!" (all caps, exclamation mark, no quotes): '
-read -r CONFIRM; [ "${CONFIRM}" = 'YES!' ]\
-    || die 'ABORTED: expected confirmation not given.'
-
-# encrypt partition
-msg 'Formatting %s as LUKS container …' "${PARTITION}"
-cryptsetup luksFormat --batch-mode "${PARTITION}"
-open_luksvg "${PARTITION}"
-
-# 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 "$(pwd)" "${PATH_MNT_DATA}"
-
-# clean-up
-msg 'Unmounting …'
-umount "${PATH_MNT_DATA}"
-close_luksvg
-msg 'Finished!'
diff --git a/setup_scripts/_lib.sh b/setup_scripts/_lib.sh
new file mode 100644 (file)
index 0000000..149f046
--- /dev/null
@@ -0,0 +1,162 @@
+set -Ceu
+SCRIPT_NAME=$0
+cd "$(dirname "${SCRIPT_NAME}")"
+
+# constants unlikely to change
+FNAME_PROFILE=.profile
+NAME_DEV=dev
+PATH_DEV="/${NAME_DEV}"
+PATH_MNT=/mnt
+TO_RBIND="${NAME_DEV} proc sys"
+
+# constants we might want to change at some point
+NAME_DATA=data
+NAME_LUKSVG=cryptolvm
+NAME_SWAP=swap
+PATH_MNT_ROOT="${PATH_MNT}/root"
+
+# constants derived from changeables
+PATH_PROFILE="${HOME}/${FNAME_PROFILE}"
+PATH_REPO=$(cd .. && pwd)
+
+# 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_input_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_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_input_openable_luksvg() {
+    local PARTITION=$1
+    check_new_luksvg
+    try_quiet cryptsetup isLuks "${PARTITION}"\
+        || error "${PARTITION} not a LUKS container"
+}
+
+# helpers: luks open/close
+open_luksvg() {
+    local PARTITION=$1
+    msg 'Opening LUKS container as "%s" …' "${NAME_LUKSVG}"
+    cryptsetup luksOpen "${PARTITION}" "${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 "$@"
+}
+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() {
+    msg 'Augmenting user %s …' "${FNAME_PROFILE}"
+    echo 'alias ls="ls --color=auto"' >> "${PATH_PROFILE}"
+}
diff --git a/setup_scripts/chrooted_command.sh b/setup_scripts/chrooted_command.sh
new file mode 100755 (executable)
index 0000000..9c1f74f
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/sh
+. "$(dirname "$0")/_lib.sh"
+
+# inputs to confirm
+usage $# "partition" "root-name" "command"
+PARTITION=$1
+NAME_ROOT=$2
+COMMAND=$3
+
+# constants derived from changeables
+PATH_VG_ROOT=$(path_vg "${NAME_LUKSVG}")/${NAME_ROOT}
+
+# sanity checks
+check_tools cryptsetup vgchange vgs
+check_input_partition_mountable "${PARTITION}"
+check_input_openable_luksvg "${PARTITION}"
+
+# mount
+open_luksvg "${PARTITION}"
+await_path "${PATH_VG_ROOT}"
+mount_privately "${PATH_VG_ROOT}" "${PATH_MNT_ROOT}"
+rbind_mnt
+
+# enact command
+RC=0
+chroot_sh "${COMMAND}" || RC=$?
+
+# clean up mounts
+unmount_unrbind
+close_luksvg
+msg 'Finished! (command exit status: %s)' "${RC}"
+exit "${RC}"
diff --git a/setup_scripts/install_debian.sh b/setup_scripts/install_debian.sh
new file mode 100755 (executable)
index 0000000..a8a3330
--- /dev/null
@@ -0,0 +1,156 @@
+#!/bin/sh
+. "$(dirname "$0")/_lib.sh"
+
+# constants unlikely to change
+FNAME_INITRD=initrd.img
+FNAME_NM_CONN=wifi.nmconnection
+FNAME_VMLINUZ=vmlinuz
+PATH_CRYPTTAB=/etc/crypttab
+PATH_EFI=/boot/efi
+PATH_FSTAB=/etc/fstab
+PATH_INTERFACES=/etc/network/interfaces
+PATH_NM_CONNECTIONS=/etc/NetworkManager/system-connections
+
+# constants we might want to change at some point
+DEB_SUITE=trixie
+IDX_BOOT_PARTITION=1
+PATH_BOOT_DEVICE="${PATH_DEV}/nvme0n1"
+
+# inputs to confirm
+usage $# "partition" "boot-name"
+PARTITION=$1
+NAME_BOOT=$2
+NAME_ROOT="${NAME_BOOT}"
+
+# constants derived from changeables
+PATH_EFI_NAME_BOOT="${PATH_EFI}/${NAME_BOOT}"
+PATH_MNT_APT_SOURCES="${PATH_MNT_ROOT}/etc/apt/sources.list"
+PATH_MNT_CRYPTTAB="${PATH_MNT_ROOT}${PATH_CRYPTTAB}"
+PATH_MNT_FSTAB="${PATH_MNT_ROOT}${PATH_FSTAB}"
+PATH_MNT_NM_CONN="${PATH_MNT_ROOT}${PATH_NM_CONNECTIONS}/${FNAME_NM_CONN}"
+PATH_MNT_NM_CONNECTIONS="${PATH_MNT_ROOT}${PATH_NM_CONNECTIONS}"
+PATH_VG=$(path_vg "${NAME_LUKSVG}")
+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_input_partition_mountable "${PARTITION}"
+check_input_openable_luksvg "${PARTITION}"
+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"
+
+# run inputs by user and ask for confirmation
+msg 'Your installation choices:'
+msg '- target partition: [ %s ]' "${PARTITION}"
+msg '- name for new boot option: [ %s ]' "${NAME_BOOT}"
+
+# set up logival volume and filesystem
+open_luksvg "${PARTITION}"
+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_ROOT}"
+msg 'Installing Debian Suite "%s" there via debootstrap …' "${DEB_SUITE}"
+debootstrap "${DEB_SUITE}" "${PATH_MNT_ROOT}"
+rbind_mnt
+
+# set up minimal fstab
+msg 'Writing fstab …'
+cat <<EOF >| "${PATH_MNT_FSTAB}"
+${PATH_VG_ROOT} / ext4 errors=remount-ro 0 1
+${PATH_VG_DATA} /${NAME_DATA} ext4 errors=remount-ro 0 2
+${PATH_VG_SWAP} none swap sw 0 0
+EOF
+
+# set up crypttab
+msg 'Writing crypttab …'
+printf '%s UUID=%s none luks\n' \
+    "${NAME_LUKSVG}" "$(cryptsetup luksUUID "${PARTITION}")" \
+    >| "${PATH_MNT_CRYPTTAB}"
+
+# enable non-free-firmware component for firmware-iwlwifi below (as debootstrap
+# only enables "main" by default)
+msg 'Enabling non-free-firmware component in target sources.list …'
+sed -i 's/ main$/ main non-free-firmware/' "${PATH_MNT_APT_SOURCES}"
+
+# set up kernel, initrd etc.
+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}"
+cat <<EOF >| "${PATH_MNT_NM_CONN}"
+[connection]
+id=${NAME_WIFI_SSID}
+uuid=$(cat /proc/sys/kernel/random/uuid)
+type=wifi
+
+[wifi]
+mode=infrastructure
+ssid=${NAME_WIFI_SSID}
+
+[wifi-security]
+key-mgmt=wpa-psk
+psk=${NAME_WIFI_PSK}
+
+[ipv4]
+method=auto
+
+[ipv6]
+method=auto
+EOF
+chmod 600 "${PATH_MNT_NM_CONN}"
+
+# install kernel and initrd into EFI tree/vars
+msg 'EFI setup: copying kernel and initrd into %s …' "${PATH_EFI_NAME_BOOT}"
+mkdir "${PATH_EFI_NAME_BOOT}"
+for FILENAME in "${FNAME_INITRD}" "${FNAME_VMLINUZ}"; do
+    cp "${PATH_MNT_ROOT}/${FILENAME}" "${PATH_EFI_NAME_BOOT}/"
+done
+msg 'EFI setup: adding boot entry %s …' "${NAME_BOOT}"
+efibootmgr \
+    --create \
+    --quiet \
+    --disk "${PATH_BOOT_DEVICE}" \
+    --part "${IDX_BOOT_PARTITION}" \
+    --label "${NAME_BOOT}" \
+    --loader "${NAME_BOOT}/${FNAME_VMLINUZ}" \
+    --unicode "root=${PATH_VG_ROOT} ro initrd=${NAME_BOOT}\\${FNAME_INITRD}"
+
+# ask root login at latest possible moment, so that on fails: less left undone
+msg 'Setting up root login …'
+chroot_sh "passwd"
+
+# clean up mounts
+unmount_unrbind
+close_luksvg
+msg 'Finished!'
diff --git a/setup_scripts/setup_luksvg.sh b/setup_scripts/setup_luksvg.sh
new file mode 100755 (executable)
index 0000000..3cbc508
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/sh
+. "$(dirname "$0")/_lib.sh"
+
+# inputs to confirm
+usage $# "partition"
+PARTITION=$1
+
+# constants derived from changeables
+PATH_LUKS_MAPPER=$(path_luks_mapper "${NAME_LUKSVG}")
+PATH_MNT_DATA="${PATH_MNT}/${NAME_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_input_partition_mountable "${PARTITION}"
+check_new_luksvg
+try_quiet cryptsetup isLuks "${PARTITION}"\
+    && error "${PARTITION} is already a LUKS container"
+
+# run inputs by user and ask for confirmation
+msg 'Your target partition (WILL BE ERASED!): [ %s ]' "${PARTITION}"
+msg_nonl 'To continue, type "YES!" (all caps, exclamation mark, no quotes): '
+read -r CONFIRM; [ "${CONFIRM}" = 'YES!' ]\
+    || die 'ABORTED: expected confirmation not given.'
+
+# encrypt partition
+msg 'Formatting %s as LUKS container …' "${PARTITION}"
+cryptsetup luksFormat --batch-mode "${PARTITION}"
+open_luksvg "${PARTITION}"
+
+# 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!'
diff --git a/setup_scripts/start_root.sh b/setup_scripts/start_root.sh
new file mode 100755 (executable)
index 0000000..75d529f
--- /dev/null
@@ -0,0 +1,55 @@
+#!/bin/sh
+. "$(dirname "$0")/_lib.sh"
+
+# constants unlikely to change
+PATH_DEFAULT_LOCALE=/etc/default/locale
+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
+FNAME_UDEV_RULES_BACKLIGHT=90-backlight.rules
+LOCALE=C.UTF-8
+TO_INSTALL="ack man-db ntpsec-ntpdate sudo sway tlp vim-gtk3 wmenu xwayland"
+USERNAME=plom
+PRINTK_LEVELS="4 4 1 7"
+TLP_THRESH_START=40
+TLP_THRESH_STOP=80
+
+# constants derived from changeables
+PATH_TO_COPY="${PATH_REPO}/to_copy"
+
+augment_profile
+
+msg 'Ensuring packages: %s' "${TO_INSTALL}"
+apt-get -y update
+apt-get -y install ${TO_INSTALL}
+
+# 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 '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
+
+msg 'Setting up user: %s' "${USERNAME}"
+adduser --comment "" "${USERNAME}"
+usermod -a -G sudo,video "${USERNAME}"
+
+msg 'Synchronizing clock …'
+ntpdate-debian
diff --git a/setup_scripts/start_user.sh b/setup_scripts/start_user.sh
new file mode 100755 (executable)
index 0000000..be0e919
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+. "$(dirname "$0")/_lib.sh"
+
+# constants we might want to change at some point
+PATH_SKEL_USER="${PATH_REPO}/home_user"
+
+augment_profile
+
+msg 'Linking %s files into home directory …' "${PATH_SKEL_USER}"
+find "${PATH_SKEL_USER}" -mindepth 1 -maxdepth 1\
+    -exec ln -v -s {} "${HOME}/" \;
diff --git a/start_root.sh b/start_root.sh
deleted file mode 100755 (executable)
index 5e00f2e..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/bin/sh
-. "$(dirname "$0")/_lib.sh"
-
-# constants unlikely to change
-PATH_DEFAULT_LOCALE=/etc/default/locale
-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
-FNAME_UDEV_RULES_BACKLIGHT=90-backlight.rules
-LOCALE=C.UTF-8
-TO_INSTALL="ack man-db ntpsec-ntpdate sudo sway tlp vim-gtk3 wmenu xwayland"
-USERNAME=plom
-PRINTK_LEVELS="4 4 1 7"
-TLP_THRESH_START=40
-TLP_THRESH_STOP=80
-
-augment_profile
-
-msg 'Ensuring packages: %s' "${TO_INSTALL}"
-apt-get -y update
-apt-get -y install ${TO_INSTALL}
-
-# 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 'Making backlight devices available to user-run backlight.py script …'
-cp "${FNAME_UDEV_RULES_BACKLIGHT}" "${PATH_UDEV_RULES}/"
-udevadm control --reload-rules
-udevadm trigger --action=add --subsystem-match=backlight
-
-msg 'Setting up user: %s' "${USERNAME}"
-adduser --comment "" "${USERNAME}"
-usermod -a -G sudo,video "${USERNAME}"
-
-msg 'Synchronizing clock …'
-ntpdate-debian
diff --git a/start_user.sh b/start_user.sh
deleted file mode 100755 (executable)
index df49b1b..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-. "$(dirname "$0")/_lib.sh"
-
-# constants we might want to change at some point
-PATH_SKEL_USER="$(pwd)/home_user"
-
-augment_profile
-
-msg 'Linking %s files into home directory …' "${PATH_SKEL_USER}"
-find "${PATH_SKEL_USER}" -mindepth 1 -maxdepth 1\
-    -exec ln -v -s {} "${HOME}/" \;
diff --git a/to_copy/90-backlight.rules b/to_copy/90-backlight.rules
new file mode 100644 (file)
index 0000000..8adfb73
--- /dev/null
@@ -0,0 +1,3 @@
+SUBSYSTEM=="backlight", ACTION=="add", \
+    RUN+="/bin/chgrp video $sys$devpath/brightness", \
+    RUN+="/bin/chmod g+w $sys$devpath/brightness"