Machines without @factory fell back to a degraded reset that kept the current system and only wiped user state. Turn them away with an explanation instead, and drop the degraded staging path. The first-boot worker still honors a wipe-degraded marker so a reset staged by an older version finishes its scrub rather than handing the machine over with the seller's accounts intact. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
169 lines
5.6 KiB
Bash
Executable File
169 lines
5.6 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# omarchy:summary=First-boot worker that finishes an omarchy-system-factory-reset reset
|
|
# omarchy:requires-sudo=true
|
|
# omarchy:hidden=true
|
|
|
|
# Runs once, early on the first boot after omarchy-system-factory-reset, via
|
|
# omarchy-system-factory-reset-finish.service (armed by /var/lib/omarchy/provisioning/wipe-pending).
|
|
# Ordered before home.mount/var-log.mount so @home and @log can be dropped and
|
|
# recreated as empty subvolumes instead of rm -rf'd file by file.
|
|
#
|
|
# The root is already a fresh clone of @factory (staged by
|
|
# omarchy-system-factory-reset); this deletes the previous root (@omarchy-old-*),
|
|
# recreates @home/@log, and repairs /.snapshots. A reset staged by an older
|
|
# Omarchy on a machine without @factory (wipe-degraded) kept its root instead,
|
|
# and is scrubbed in place here.
|
|
|
|
set -uo pipefail
|
|
|
|
PROVISIONING_DIR=/var/lib/omarchy/provisioning
|
|
TOP_MNT=/run/omarchy-system-factory-reset-finish-top
|
|
|
|
[[ -f $PROVISIONING_DIR/wipe-pending ]] || exit 0
|
|
|
|
if (( EUID != 0 )); then
|
|
echo "Error: omarchy-system-factory-reset-finish must run as root" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# This runs before var-log.mount, so a log file under /var/log would be
|
|
# shadowed (and @log is recreated below anyway). stdout goes to the journal,
|
|
# which is volatile in /run this early and flushed into the fresh @log later.
|
|
echo "=== Omarchy factory wipe started: $(date '+%Y-%m-%d %H:%M:%S') ==="
|
|
|
|
log() {
|
|
echo "factory-wipe: $1"
|
|
}
|
|
|
|
root_device() {
|
|
findmnt -no SOURCE / | sed 's/\[.*\]//'
|
|
}
|
|
|
|
abort() {
|
|
# Keep wipe-pending so the wipe retries next boot, and so provisioning stays
|
|
# gated (it refuses to create a user on a half-wiped system).
|
|
log "$1 — aborting; the wipe will retry on the next boot"
|
|
umount "$TOP_MNT" 2>/dev/null || true
|
|
rmdir "$TOP_MNT" 2>/dev/null || true
|
|
exit 1
|
|
}
|
|
|
|
delete_subvolume() {
|
|
local path="$1"
|
|
[[ -d $path ]] || return 0
|
|
|
|
if ! btrfs subvolume delete --recursive "$path" 2>/dev/null; then
|
|
# Older btrfs-progs without --recursive: delete nested subvolumes deepest
|
|
# first, then the subvolume itself.
|
|
local nested
|
|
nested=$(btrfs subvolume list -o "$path" 2>/dev/null | awk '{print $NF}')
|
|
if [[ -n $nested ]]; then
|
|
local sub
|
|
while IFS= read -r sub; do
|
|
delete_subvolume "$TOP_MNT/${sub#<FS_TREE>/}"
|
|
done <<<"$nested"
|
|
fi
|
|
btrfs subvolume delete "$path"
|
|
fi
|
|
}
|
|
|
|
recreate_subvolume() {
|
|
local name="$1"
|
|
delete_subvolume "$TOP_MNT/$name"
|
|
btrfs subvolume create "$TOP_MNT/$name"
|
|
}
|
|
|
|
# Only for a reset staged by an Omarchy that still had the degraded path: the
|
|
# current system was kept, so accounts and identity are scrubbed in place here
|
|
# instead of arriving pre-scrubbed in the factory clone. Reachable when a
|
|
# degraded reset was staged, the reboot deferred, and this worker updated in
|
|
# between — the reset must still finish, or provisioning hands the machine over
|
|
# with the seller's accounts intact.
|
|
scrub_legacy_degraded_state() {
|
|
log "degraded reset: scrubbing user accounts and machine identity in place"
|
|
|
|
local user
|
|
for user in $(awk -F: '$3 >= 1000 && $3 < 60000 { print $1 }' /etc/passwd); do
|
|
log "removing user $user"
|
|
rm -rf "/var/lib/fprint/$user" # enrolled fingerprints outlive userdel
|
|
userdel "$user" 2>/dev/null || abort "could not remove user $user"
|
|
done
|
|
|
|
rm -f /etc/ssh/ssh_host_*
|
|
rm -f /etc/NetworkManager/system-connections/*
|
|
rm -rf /var/lib/NetworkManager/* /var/lib/tailscale /var/lib/iwd
|
|
rm -f /var/lib/sddm/state.conf /etc/sddm.conf.d/autologin.conf
|
|
|
|
# Fresh machine identity from the next boot on.
|
|
systemd-id128 new >/etc/machine-id 2>/dev/null || :>/etc/machine-id
|
|
|
|
# The kept root still carries its accumulated snapper snapshots (nested under
|
|
# /.snapshots); a factory clone loses them with the old root.
|
|
local snapshot
|
|
for snapshot in /.snapshots/*/snapshot; do
|
|
[[ -d $snapshot ]] || continue
|
|
delete_subvolume "$snapshot"
|
|
rm -rf "$(dirname "$snapshot")"
|
|
done
|
|
}
|
|
|
|
repair_snapshots_dir() {
|
|
# A snapshot of @ carries /.snapshots only as a plain empty directory
|
|
# (nested subvolumes are not part of snapshots). Snapper needs it to be a
|
|
# subvolume again.
|
|
if [[ -d /.snapshots ]] && ! btrfs subvolume show /.snapshots >/dev/null 2>&1; then
|
|
rm -rf /.snapshots
|
|
fi
|
|
if [[ ! -d /.snapshots ]]; then
|
|
btrfs subvolume create /.snapshots
|
|
chmod 750 /.snapshots
|
|
fi
|
|
}
|
|
|
|
main() {
|
|
local device
|
|
device=$(root_device)
|
|
if [[ -z $device ]]; then
|
|
log "could not determine the btrfs root device; aborting"
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p "$TOP_MNT"
|
|
if ! mount -o subvolid=5 "$device" "$TOP_MNT"; then
|
|
log "could not mount the btrfs top level from $device; aborting"
|
|
exit 1
|
|
fi
|
|
|
|
[[ -f $PROVISIONING_DIR/wipe-degraded ]] && scrub_legacy_degraded_state
|
|
|
|
local old
|
|
for old in "$TOP_MNT"/@omarchy-old-*; do
|
|
[[ -d $old ]] || continue
|
|
log "deleting previous system root $(basename "$old")"
|
|
delete_subvolume "$old" || abort "could not delete $(basename "$old")"
|
|
done
|
|
|
|
# A wipe that cannot recreate @home has not wiped anything — the seller's
|
|
# data would survive a "successful" factory reset.
|
|
log "recreating @home and @log"
|
|
recreate_subvolume @home || abort "could not recreate @home"
|
|
recreate_subvolume @log || abort "could not recreate @log"
|
|
|
|
repair_snapshots_dir
|
|
|
|
umount "$TOP_MNT"
|
|
rmdir "$TOP_MNT" 2>/dev/null || true
|
|
|
|
log "trimming free space"
|
|
fstrim -a 2>/dev/null || true
|
|
|
|
rm -f "$PROVISIONING_DIR/wipe-pending" "$PROVISIONING_DIR/wipe-degraded"
|
|
rm -f /etc/systemd/system/sysinit.target.wants/omarchy-system-factory-reset-finish.service
|
|
rm -f /etc/systemd/system/omarchy-system-factory-reset-finish.service
|
|
|
|
log "factory wipe complete"
|
|
}
|
|
|
|
main
|