overlay: atomic CLI tools for v0.7+ (bootc upgrade, postinstall, doctor)
A3 inline (agent failed on API). Three CLIs ported / written for the
v0.7+ atomic system:
veilor-update — rewritten on bootc upgrade (was dnf upgrade --refresh).
Pre-checks bootc status, pauses auditd while staging, prints summary
and offers reboot. Returns 0/1/2/3 per legacy contract.
veilor-postinstall (NEW) — first-login TUI run via
veilor-postinstall.service oneshot. Asks once for keyboard, locale,
hostname, GPU drivers, package presets (dev/media/homelab),
bluetooth, USBGuard snapshot, then invokes veilor-doctor. Writes
/var/lib/veilor/postinstall-complete and self-disables on success.
veilor-doctor — Updates section rewritten to parse `bootc status
--json` (with jq) when available, falls back to dnf history /
check-update for legacy v0.5.x kickstart-installed systems.
Plus systemd units:
- veilor-postinstall.service (oneshot on graphical.target, gated on
absence of done-marker, runs on tty1)
- veilor-doctor.service + .timer (weekly drift check)
This commit is contained in:
parent
61fec5e1a9
commit
606806f82f
6 changed files with 300 additions and 67 deletions
7
overlay/etc/systemd/system/veilor-doctor.service
Normal file
7
overlay/etc/systemd/system/veilor-doctor.service
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
[Unit]
|
||||||
|
Description=veilor-doctor — system health + drift check
|
||||||
|
After=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/bin/veilor-doctor --quiet
|
||||||
10
overlay/etc/systemd/system/veilor-doctor.timer
Normal file
10
overlay/etc/systemd/system/veilor-doctor.timer
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
[Unit]
|
||||||
|
Description=veilor-doctor weekly drift check
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar=weekly
|
||||||
|
Persistent=true
|
||||||
|
RandomizedDelaySec=30m
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
17
overlay/etc/systemd/system/veilor-postinstall.service
Normal file
17
overlay/etc/systemd/system/veilor-postinstall.service
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
[Unit]
|
||||||
|
Description=veilor-os one-time post-install TUI (first login)
|
||||||
|
After=graphical.target
|
||||||
|
ConditionPathExists=!/var/lib/veilor/postinstall-complete
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/bin/veilor-postinstall
|
||||||
|
StandardInput=tty
|
||||||
|
StandardOutput=tty
|
||||||
|
StandardError=journal
|
||||||
|
TTYPath=/dev/tty1
|
||||||
|
TTYReset=yes
|
||||||
|
TTYVHangup=yes
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=graphical.target multi-user.target
|
||||||
|
|
@ -147,23 +147,44 @@ PUBLIC_IP=$(curl -s --max-time 3 ifconfig.me 2>/dev/null || echo "")
|
||||||
|| check Network public_ip fail "lookup timed out"
|
|| check Network public_ip fail "lookup timed out"
|
||||||
|
|
||||||
# ── 5. Updates ──────────────────────────────────────────────────────
|
# ── 5. Updates ──────────────────────────────────────────────────────
|
||||||
LAST_DNF=$(sudo -n dnf history list 2>/dev/null \
|
# v0.7+ atomic — bootc replaces dnf as the update channel. Parse
|
||||||
| awk 'NR==4 {for(i=4;i<NF;i++)printf "%s ", $i; print $NF; exit}')
|
# `bootc status --json` for the booted deployment + staged/cached image
|
||||||
[[ -n $LAST_DNF ]] && check Updates last_dnf pass "$LAST_DNF" \
|
# age. Fall back to dnf history if bootc not present (legacy v0.5.x).
|
||||||
|| check Updates last_dnf pass "(unknown — try \`sudo dnf history\`)"
|
if have bootc; then
|
||||||
|
BOOTC_JSON=$(sudo -n bootc status --json 2>/dev/null || echo "")
|
||||||
# `dnf check-update` exits 100 if updates available, 0 if not.
|
if [[ -n $BOOTC_JSON ]] && have jq; then
|
||||||
sudo -n dnf check-update -q >/dev/null 2>&1
|
BOOTED_IMG=$(jq -r '.status.booted.image.image.image // "unknown"' <<<"$BOOTC_JSON")
|
||||||
RC=$?
|
BOOTED_DIGEST=$(jq -r '.status.booted.image.imageDigest // ""' <<<"$BOOTC_JSON")
|
||||||
case $RC in
|
check Updates booted_image pass "${BOOTED_IMG}@${BOOTED_DIGEST:0:12}"
|
||||||
0) check Updates pending pass "system up-to-date" ;;
|
STAGED=$(jq -r '.status.staged.image.image.image // ""' <<<"$BOOTC_JSON")
|
||||||
100)
|
if [[ -n $STAGED ]]; then
|
||||||
AVAIL=$(sudo -n dnf check-update -q 2>/dev/null \
|
check Updates staged_image fail "staged: $STAGED — reboot to apply"
|
||||||
| awk 'NF>=3 && $1!~/^Last/ {n++} END {print n+0}')
|
else
|
||||||
check Updates pending fail "${AVAIL} update(s) available — run \`veilor-update\`"
|
check Updates staged_image pass "no staged update"
|
||||||
;;
|
fi
|
||||||
*) check Updates pending fail "dnf check-update returned $RC (need sudo?)" ;;
|
else
|
||||||
esac
|
check Updates bootc_state pass "bootc present (jq missing — install for richer detail)"
|
||||||
|
fi
|
||||||
|
elif have dnf; then
|
||||||
|
# Legacy v0.5.x kickstart-installed system.
|
||||||
|
LAST_DNF=$(sudo -n dnf history list 2>/dev/null \
|
||||||
|
| awk 'NR==4 {for(i=4;i<NF;i++)printf "%s ", $i; print $NF; exit}')
|
||||||
|
[[ -n $LAST_DNF ]] && check Updates last_dnf pass "$LAST_DNF" \
|
||||||
|
|| check Updates last_dnf pass "(unknown — try \`sudo dnf history\`)"
|
||||||
|
sudo -n dnf check-update -q >/dev/null 2>&1
|
||||||
|
RC=$?
|
||||||
|
case $RC in
|
||||||
|
0) check Updates pending pass "system up-to-date" ;;
|
||||||
|
100)
|
||||||
|
AVAIL=$(sudo -n dnf check-update -q 2>/dev/null \
|
||||||
|
| awk 'NF>=3 && $1!~/^Last/ {n++} END {print n+0}')
|
||||||
|
check Updates pending fail "${AVAIL} update(s) available — run \`veilor-update\`"
|
||||||
|
;;
|
||||||
|
*) check Updates pending fail "dnf check-update returned $RC (need sudo?)" ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
check Updates channel fail "neither bootc nor dnf available"
|
||||||
|
fi
|
||||||
|
|
||||||
# ── 6. veilor services ──────────────────────────────────────────────
|
# ── 6. veilor services ──────────────────────────────────────────────
|
||||||
for unit in veilor-firstboot.service veilor-modules-lock.service; do
|
for unit in veilor-firstboot.service veilor-modules-lock.service; do
|
||||||
|
|
|
||||||
178
overlay/usr/local/bin/veilor-postinstall
Executable file
178
overlay/usr/local/bin/veilor-postinstall
Executable file
|
|
@ -0,0 +1,178 @@
|
||||||
|
#!/usr/bin/bash
|
||||||
|
# veilor-postinstall — first-login TUI on v0.7+ atomic systems.
|
||||||
|
#
|
||||||
|
# Runs ONCE on first SDDM login via the user-mode systemd unit
|
||||||
|
# `veilor-postinstall.service`. Asks the operator for the small set
|
||||||
|
# of decisions we deliberately defer from install time:
|
||||||
|
# - keyboard / locale
|
||||||
|
# - hostname override
|
||||||
|
# - GPU drivers (NVIDIA layered via rpm-ostree, mesa = no-op)
|
||||||
|
# - package preset (dev / media / homelab — additive, opt-out)
|
||||||
|
# - bluetooth opt-in
|
||||||
|
# - USBGuard policy snapshot
|
||||||
|
# - veilor-doctor first run
|
||||||
|
# Writes /var/lib/veilor/postinstall-complete on success and disables
|
||||||
|
# its own autostart unit. Idempotent: safe to re-run.
|
||||||
|
#
|
||||||
|
# Style: gum if present, plain bash read fallback. No decorative ASCII.
|
||||||
|
|
||||||
|
set -uo pipefail
|
||||||
|
export TERM="${TERM:-linux}"
|
||||||
|
|
||||||
|
STATE_DIR=/var/lib/veilor
|
||||||
|
DONE_MARKER="$STATE_DIR/postinstall-complete"
|
||||||
|
LOG=/var/log/veilor-postinstall.log
|
||||||
|
|
||||||
|
have() { command -v "$1" >/dev/null 2>&1; }
|
||||||
|
GUM=$(have gum && echo gum || echo "")
|
||||||
|
|
||||||
|
# Always log + tee to stdout for live progress.
|
||||||
|
mkdir -p "$STATE_DIR" 2>/dev/null || true
|
||||||
|
exec > >(tee -a "$LOG") 2>&1
|
||||||
|
|
||||||
|
if [[ -e $DONE_MARKER && ${1:-} != "--force" ]]; then
|
||||||
|
echo "veilor-postinstall already ran (marker: $DONE_MARKER). Pass --force to re-run."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Wrappers ────────────────────────────────────────────────────────
|
||||||
|
choose() {
|
||||||
|
local header=$1; shift
|
||||||
|
if [[ -n $GUM ]]; then
|
||||||
|
gum choose --header "$header" "$@"
|
||||||
|
else
|
||||||
|
echo
|
||||||
|
echo "$header"
|
||||||
|
local i=1
|
||||||
|
for opt in "$@"; do printf ' %d) %s\n' "$i" "$opt"; ((i++)); done
|
||||||
|
local n
|
||||||
|
read -rp " choice (1-$#): " n
|
||||||
|
[[ $n -ge 1 && $n -le $# ]] || return 1
|
||||||
|
eval "echo \${$n}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ask() {
|
||||||
|
local prompt=$1 default=${2:-}
|
||||||
|
if [[ -n $GUM ]]; then
|
||||||
|
gum input --header "$prompt" --value "$default"
|
||||||
|
else
|
||||||
|
local v
|
||||||
|
read -rp "$prompt [$default] " v
|
||||||
|
echo "${v:-$default}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
confirm() {
|
||||||
|
local prompt=$1
|
||||||
|
if [[ -n $GUM ]]; then
|
||||||
|
gum confirm "$prompt" && return 0 || return 1
|
||||||
|
else
|
||||||
|
read -rp "$prompt [y/N] " y
|
||||||
|
[[ ${y,,} == y* ]]
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
say() {
|
||||||
|
if [[ -n $GUM ]]; then
|
||||||
|
gum style --foreground 212 --bold "$1"
|
||||||
|
else
|
||||||
|
printf '\n=== %s ===\n' "$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Need root for several actions; re-exec under sudo if not root.
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
say "veilor-postinstall: sudo required"
|
||||||
|
exec sudo -E bash "$0" "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
say "veilor-postinstall — one-time setup"
|
||||||
|
echo " This runs once. Each step is skippable. Defaults are sane."
|
||||||
|
echo
|
||||||
|
|
||||||
|
# ── 1. Keyboard layout ──────────────────────────────────────────────
|
||||||
|
KB=$(choose "Keyboard layout" us gb de fr es ru "skip") || KB=skip
|
||||||
|
if [[ $KB != skip ]]; then
|
||||||
|
localectl set-keymap "$KB" 2>/dev/null || true
|
||||||
|
echo " [OK] keymap = $KB"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 2. Locale ───────────────────────────────────────────────────────
|
||||||
|
LOC=$(choose "Locale" en_US.UTF-8 en_GB.UTF-8 de_DE.UTF-8 fr_FR.UTF-8 "skip") || LOC=skip
|
||||||
|
if [[ $LOC != skip ]]; then
|
||||||
|
localectl set-locale LANG="$LOC" 2>/dev/null || true
|
||||||
|
echo " [OK] locale = $LOC"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 3. Hostname ─────────────────────────────────────────────────────
|
||||||
|
HN=$(ask "Hostname" "veilor")
|
||||||
|
if [[ -n $HN && $HN != $(hostnamectl --static 2>/dev/null) ]]; then
|
||||||
|
hostnamectl set-hostname "$HN"
|
||||||
|
echo " [OK] hostname = $HN"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 4. GPU drivers ──────────────────────────────────────────────────
|
||||||
|
GPU=$(choose "GPU drivers" "Skip (use mesa defaults)" "NVIDIA proprietary (akmod-nvidia)" "Intel/AMD mesa (no-op)") || GPU=skip
|
||||||
|
case "$GPU" in
|
||||||
|
*NVIDIA*)
|
||||||
|
say "Layering NVIDIA driver — this takes a few minutes"
|
||||||
|
rpm-ostree install --idempotent akmod-nvidia xorg-x11-drv-nvidia-cuda \
|
||||||
|
&& echo " [OK] NVIDIA driver layered (reboot to use)" \
|
||||||
|
|| echo " [WARN] NVIDIA layer failed; check rpm-ostree status"
|
||||||
|
;;
|
||||||
|
*) echo " (skipped GPU layering)" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# ── 5. Package presets (multi-select) ───────────────────────────────
|
||||||
|
say "Package presets — pick any combination (skip = none)"
|
||||||
|
PRESET_DEV="git tmux vim-enhanced htop podman skopeo"
|
||||||
|
PRESET_MEDIA="vlc obs-studio"
|
||||||
|
PRESET_HOMELAB="wireguard-tools jq yq tmux"
|
||||||
|
|
||||||
|
PICKED=()
|
||||||
|
confirm "Install dev preset? ($PRESET_DEV)" && PICKED+=($PRESET_DEV) || true
|
||||||
|
confirm "Install media preset? ($PRESET_MEDIA)" && PICKED+=($PRESET_MEDIA) || true
|
||||||
|
confirm "Install homelab preset? ($PRESET_HOMELAB)" && PICKED+=($PRESET_HOMELAB) || true
|
||||||
|
if (( ${#PICKED[@]} > 0 )); then
|
||||||
|
# de-dupe
|
||||||
|
UNIQ=$(printf '%s\n' "${PICKED[@]}" | sort -u | tr '\n' ' ')
|
||||||
|
say "Layering: $UNIQ"
|
||||||
|
rpm-ostree install --idempotent $UNIQ \
|
||||||
|
&& echo " [OK] preset packages layered (reboot to use)" \
|
||||||
|
|| echo " [WARN] preset layer failed; check rpm-ostree status"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 6. Bluetooth ────────────────────────────────────────────────────
|
||||||
|
if confirm "Enable Bluetooth?"; then
|
||||||
|
systemctl enable --now bluetooth.service 2>/dev/null || true
|
||||||
|
echo " [OK] bluetooth enabled"
|
||||||
|
else
|
||||||
|
echo " (skipped bluetooth)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 7. USBGuard snapshot ────────────────────────────────────────────
|
||||||
|
say "USBGuard policy snapshot"
|
||||||
|
echo " Plug in EVERY USB device you trust right now (keyboard,"
|
||||||
|
echo " mouse, dock, yubikey, etc.) before continuing."
|
||||||
|
if confirm "Snapshot current USB devices into the allowlist?"; then
|
||||||
|
usbguard generate-policy > /etc/usbguard/rules.conf \
|
||||||
|
&& echo " [OK] policy written to /etc/usbguard/rules.conf" \
|
||||||
|
|| echo " [WARN] generate-policy failed"
|
||||||
|
systemctl restart usbguard 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 8. veilor-doctor ────────────────────────────────────────────────
|
||||||
|
if confirm "Run veilor-doctor now?"; then
|
||||||
|
veilor-doctor || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Done ────────────────────────────────────────────────────────────
|
||||||
|
date -u +"%Y-%m-%dT%H:%M:%SZ" > "$DONE_MARKER"
|
||||||
|
say "veilor-postinstall complete"
|
||||||
|
echo " Marker written: $DONE_MARKER"
|
||||||
|
echo " Disabling autostart unit so this never runs again."
|
||||||
|
systemctl --user --global disable veilor-postinstall.service 2>/dev/null || true
|
||||||
|
systemctl disable veilor-postinstall.service 2>/dev/null || true
|
||||||
|
echo
|
||||||
|
echo " If you layered any packages or drivers, reboot to activate."
|
||||||
|
|
@ -1,25 +1,22 @@
|
||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
# veilor-update — system update wrapper.
|
# veilor-update — atomic update wrapper for v0.7+ (bootc + rpm-ostree).
|
||||||
# Wraps `dnf upgrade --refresh` + `flatpak update` behind a single command.
|
#
|
||||||
# User-facing CLI shipped in /usr/local/bin/. v0.6 ergonomic tooling.
|
# Wraps `bootc upgrade` + flatpak update behind a single command.
|
||||||
|
# Pre-checks rollback availability, pauses auditd while staging the
|
||||||
|
# new image, prints a clear post-state summary, and offers reboot.
|
||||||
#
|
#
|
||||||
# Exit codes:
|
# Exit codes:
|
||||||
# 0 success
|
# 0 success (with or without pending reboot)
|
||||||
# 1 dnf failed
|
# 1 bootc upgrade failed
|
||||||
# 2 flatpak failed (dnf still ran successfully)
|
# 2 flatpak failed (bootc still ran successfully)
|
||||||
# 3 no network
|
# 3 no network
|
||||||
#
|
|
||||||
# Uses `gum` for spinner output if present, falls back to plain stdout.
|
|
||||||
|
|
||||||
set -uo pipefail
|
set -uo pipefail
|
||||||
|
|
||||||
# ── Helpers ─────────────────────────────────────────────────────────
|
|
||||||
have() { command -v "$1" >/dev/null 2>&1; }
|
have() { command -v "$1" >/dev/null 2>&1; }
|
||||||
|
|
||||||
GUM=$(have gum && echo gum || echo "")
|
GUM=$(have gum && echo gum || echo "")
|
||||||
|
|
||||||
say() {
|
say() {
|
||||||
# Print a status line. Coloured if gum present, else plain.
|
|
||||||
if [[ -n $GUM ]]; then
|
if [[ -n $GUM ]]; then
|
||||||
gum style --foreground 212 --bold "$1"
|
gum style --foreground 212 --bold "$1"
|
||||||
else
|
else
|
||||||
|
|
@ -27,46 +24,50 @@ say() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
run_with_spinner() {
|
confirm() {
|
||||||
local title=$1; shift
|
local prompt=$1
|
||||||
if [[ -n $GUM ]]; then
|
if [[ -n $GUM ]]; then
|
||||||
gum spin --spinner dot --title "$title" -- "$@"
|
gum confirm "$prompt"
|
||||||
else
|
else
|
||||||
echo "[+] $title"
|
read -r -p "$prompt [y/N] " yn
|
||||||
"$@"
|
[[ ${yn,,} == y* ]]
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Pre-flight: network check ───────────────────────────────────────
|
# ── Pre-flight: network ─────────────────────────────────────────────
|
||||||
say "veilor-update: checking network"
|
say "veilor-update: checking network"
|
||||||
if ! ping -c 1 -W 2 mirrors.fedoraproject.org >/dev/null 2>&1; then
|
if ! ping -c 1 -W 2 1.1.1.1 >/dev/null 2>&1; then
|
||||||
echo
|
echo " No network. Connect and re-run \`veilor-update\`."
|
||||||
echo " No route to mirrors.fedoraproject.org."
|
|
||||||
echo " Connect to a network and re-run \`veilor-update\`."
|
|
||||||
exit 3
|
exit 3
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Snapshot kernel before upgrade so we can warn about reboot need ─
|
# ── Pre-flight: rollback target available ───────────────────────────
|
||||||
KERNEL_BEFORE=$(uname -r)
|
# bootc has two deployments by design (booted + rollback). If
|
||||||
|
# something's wrong we want the user to see it before staging more.
|
||||||
# ── DNF upgrade ─────────────────────────────────────────────────────
|
if have bootc; then
|
||||||
say "veilor-update: refreshing DNF metadata + applying updates"
|
say "veilor-update: bootc status"
|
||||||
# Capture upgrade output so we can count packages afterwards. Tee to
|
bootc status || true
|
||||||
# stdout for live progress; swallow into a tempfile for the count.
|
else
|
||||||
LOG=$(mktemp -t veilor-update.XXXXXX)
|
echo " bootc not present — this CLI targets v0.7+ atomic systems."
|
||||||
trap 'rm -f "$LOG"' EXIT
|
|
||||||
|
|
||||||
if ! sudo dnf upgrade --refresh -y 2>&1 | tee "$LOG"; then
|
|
||||||
echo
|
|
||||||
echo " dnf upgrade failed. See output above."
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Count packages updated ──────────────────────────────────────────
|
# ── Pause auditd while staging ──────────────────────────────────────
|
||||||
# DNF prints "Upgraded: N", "Installed: N", "Removed: N" at end.
|
# Reduces audit log noise during the heavy fs writes; resume after.
|
||||||
# Sum the upgrade/install lines for the user-visible total.
|
AUDIT_PAUSED=0
|
||||||
UPDATED=$(grep -E '^(Upgraded|Installed)\b' "$LOG" 2>/dev/null \
|
if systemctl is-active auditd >/dev/null 2>&1; then
|
||||||
| awk -F: '{ gsub(/[^0-9]/,"",$2); s+=$2 } END { print s+0 }')
|
if sudo systemctl stop auditd 2>/dev/null; then
|
||||||
|
AUDIT_PAUSED=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
trap '[[ $AUDIT_PAUSED == 1 ]] && sudo systemctl start auditd 2>/dev/null || true' EXIT
|
||||||
|
|
||||||
|
# ── bootc upgrade ───────────────────────────────────────────────────
|
||||||
|
say "veilor-update: bootc upgrade"
|
||||||
|
if ! sudo bootc upgrade; then
|
||||||
|
echo " bootc upgrade failed. See output above."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# ── Flatpak (best-effort) ───────────────────────────────────────────
|
# ── Flatpak (best-effort) ───────────────────────────────────────────
|
||||||
FLATPAK_RC=0
|
FLATPAK_RC=0
|
||||||
|
|
@ -74,21 +75,20 @@ if have flatpak; then
|
||||||
say "veilor-update: updating flatpaks"
|
say "veilor-update: updating flatpaks"
|
||||||
if ! flatpak update -y; then
|
if ! flatpak update -y; then
|
||||||
FLATPAK_RC=2
|
FLATPAK_RC=2
|
||||||
echo " flatpak update failed; continuing anyway."
|
echo " flatpak update failed; continuing."
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
echo " (flatpak not installed — skipping)"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Post-update: reboot hint if kernel changed ──────────────────────
|
# ── Post-update summary ─────────────────────────────────────────────
|
||||||
KERNEL_AFTER_LATEST=$(rpm -q kernel --last 2>/dev/null \
|
|
||||||
| awk 'NR==1 { sub(/^kernel-/,"",$1); print $1 }')
|
|
||||||
|
|
||||||
say "veilor-update: complete"
|
say "veilor-update: complete"
|
||||||
printf ' Packages updated : %s\n' "${UPDATED:-0}"
|
bootc status 2>/dev/null | head -20 || true
|
||||||
printf ' Running kernel : %s\n' "$KERNEL_BEFORE"
|
|
||||||
if [[ -n ${KERNEL_AFTER_LATEST:-} && $KERNEL_AFTER_LATEST != "$KERNEL_BEFORE" ]]; then
|
# ── Reboot prompt ───────────────────────────────────────────────────
|
||||||
printf ' Newest kernel : %s (reboot suggested)\n' "$KERNEL_AFTER_LATEST"
|
# bootc always writes the new image into the staged deployment; reboot
|
||||||
|
# is required for it to become the running root.
|
||||||
|
if confirm " Reboot now to activate the new image?"; then
|
||||||
|
say "veilor-update: rebooting"
|
||||||
|
sudo systemctl reboot
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exit $FLATPAK_RC
|
exit $FLATPAK_RC
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue