mirror of
https://github.com/theupriser/steamify-cachyos.git
synced 2026-10-03 17:41:58 +02:00
feat: BIOS update in the app, with both warnings
bios_enable split into bios_prepare (download, checksum, fwupd check) and bios_flash; the terminal flow is unchanged. The app: check, warning 1, warning 2 (type UPDATE, or hold A/OK for 5 seconds), flash, restart.
This commit is contained in:
1 parent
232b51e379
commit
23a171c937
4 files changed
+298
-85
No files matched your search
+49
-15
@@ -8,7 +8,9 @@
|
||||
# turns on the listed components and off the others (like ticking them
|
||||
# in the menu), then streams one JSON object per line: plan, start,
|
||||
# log, done, finished. sudo asks through $SUDO_ASKPASS (no terminal).
|
||||
# The BIOS update needs its typed confirmations: it stays in the terminal.
|
||||
# steamify.sh --backend bios-prepare | bios-flash
|
||||
# the BIOS update in two steps, so the app shows both warnings between
|
||||
# them (bios-ready event: current, newest, checksum, compatible).
|
||||
# Sourced by steamify.sh; not meant to be run on its own.
|
||||
|
||||
json_str() {
|
||||
@@ -54,13 +56,17 @@ backend_status() {
|
||||
done
|
||||
local cec="" f
|
||||
for f in /dev/cec*; do [[ -e "$f" ]] && cec+="${cec:+ }$(basename "$f")"; done
|
||||
printf '{"version":%s,"firstRun":%s,"steamMachine":%s,"kernel":%s,"pinnedKernel":%s,"cecDevices":%s,"leds":%s,"items":[%s]}\n' \
|
||||
local bios='null'
|
||||
if bios_available; then
|
||||
bios="{\"current\":$(json_str "$(bios_current)"),\"newest\":$(json_str "${BIOS_NEWEST:-}"),\"selectable\":$(bios_selectable && echo true || echo false),\"dryRun\":$([[ -n "$BIOS_DRY_RUN" ]] && echo true || echo false)}"
|
||||
fi
|
||||
printf '{"version":%s,"firstRun":%s,"steamMachine":%s,"kernel":%s,"pinnedKernel":%s,"cecDevices":%s,"leds":%s,"bios":%s,"items":[%s]}\n' \
|
||||
"$(json_str "$VERSION")" "$first_run" \
|
||||
"$(detect_valve_fremont && echo true || echo false)" \
|
||||
"$(json_str "$(uname -r)")" "$(json_str "${PINNED_KERNEL_VER:-}")" \
|
||||
"$(json_str "$cec")" \
|
||||
"$(compgen -G '/sys/class/leds/valve-leds*' | wc -l)" \
|
||||
"$items"
|
||||
"$bios" "$items"
|
||||
}
|
||||
|
||||
backend_run_component() {
|
||||
@@ -77,6 +83,43 @@ backend_run_component() {
|
||||
return $rc
|
||||
}
|
||||
|
||||
backend_sudo() {
|
||||
# sudo from the app has no terminal: ask through its helper, and keep the
|
||||
# credentials fresh as the menu does.
|
||||
if [[ -z "${SUDO_ASKPASS:-}" ]] && ! sudo -n true 2>/dev/null; then
|
||||
backend_event finished '"failed":[],"restart":false,"error":"no-sudo"'
|
||||
return 1
|
||||
fi
|
||||
sudo() { command sudo ${SUDO_ASKPASS:+-A} "$@"; }
|
||||
if ! sudo -n true 2>/dev/null && ! sudo true 2>/dev/null; then
|
||||
backend_event finished '"failed":[],"restart":false,"error":"wrong-password"'
|
||||
return 1
|
||||
fi
|
||||
while true; do sudo -n true; sleep 50; kill -0 "$$" 2>/dev/null || exit; done 2>/dev/null &
|
||||
}
|
||||
|
||||
backend_bios_prepare() {
|
||||
# Download, checksum and fwupd's device check; the app then shows its
|
||||
# two warnings and calls bios-flash.
|
||||
local rc
|
||||
backend_sudo || return 1
|
||||
backend_event start '"id":"bios","action":"prepare","label":"Update BIOS"'
|
||||
bios_prepare > >(while IFS= read -r line; do backend_event log "\"id\":\"bios\",\"line\":$(json_str "$line")"; done) 2>&1
|
||||
rc=$?; wait $! 2>/dev/null
|
||||
case $rc in
|
||||
0) backend_event bios-ready "\"current\":$(json_str "$(bios_current)"),\"newest\":$(json_str "$BIOS_NEWEST"),\"checksum\":true,\"compatible\":$(json_str "$BIOS_COMPATIBLE")" ;;
|
||||
2) backend_event finished '"failed":[],"restart":false,"nothing":true' ;;
|
||||
*) backend_event finished '"failed":["bios"],"restart":false' ;;
|
||||
esac
|
||||
}
|
||||
|
||||
backend_bios_flash() {
|
||||
backend_sudo || return 1
|
||||
local rc
|
||||
backend_run_component bios flash_only; rc=$?
|
||||
backend_event finished "\"failed\":$([[ $rc -eq 0 ]] && echo '[]' || echo '["bios"]'),\"restart\":$(restart_needed && echo true || echo false),\"bios\":true"
|
||||
}
|
||||
|
||||
backend_apply() {
|
||||
local reapply=false boot="" id c
|
||||
local -a want=()
|
||||
@@ -111,18 +154,7 @@ backend_apply() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
# sudo from the app has no terminal: ask through its helper, and keep the
|
||||
# credentials fresh as the menu does.
|
||||
if [[ -z "${SUDO_ASKPASS:-}" ]] && ! sudo -n true 2>/dev/null; then
|
||||
backend_event finished '"failed":[],"restart":false,"error":"no-sudo"'
|
||||
return 1
|
||||
fi
|
||||
sudo() { command sudo ${SUDO_ASKPASS:+-A} "$@"; }
|
||||
if ! sudo -n true 2>/dev/null && ! sudo true 2>/dev/null; then
|
||||
backend_event finished '"failed":[],"restart":false,"error":"wrong-password"'
|
||||
return 1
|
||||
fi
|
||||
while true; do sudo -n true; sleep 50; kill -0 "$$" 2>/dev/null || exit; done 2>/dev/null &
|
||||
backend_sudo || return 1
|
||||
|
||||
LOGIN_MANAGER=plasmalogin
|
||||
[[ "${WANTED[single]}" == 1 ]] && LOGIN_MANAGER=sddm
|
||||
@@ -137,6 +169,8 @@ backend_main() {
|
||||
case "${1:-}" in
|
||||
status) backend_status ;;
|
||||
apply) shift; backend_apply "$@" ;;
|
||||
bios-prepare) backend_bios_prepare ;;
|
||||
bios-flash) backend_bios_flash ;;
|
||||
*) err "Usage: steamify.sh --backend status | apply [--reapply] [--boot gamescope|desktop] <id>..."; return 2 ;;
|
||||
esac
|
||||
}
|
||||
+74
-44
@@ -121,54 +121,102 @@ bios_fits_device() {
|
||||
grep -q '"Guid"' <<< "$details" && ! grep -q '"UpdateError"' <<< "$details"
|
||||
}
|
||||
|
||||
bios_enable() {
|
||||
# The checked firmware waits here between bios_prepare and bios_flash, so the
|
||||
# app can show its warnings in between (and the terminal flow uses it too).
|
||||
BIOS_STAGE_DIR="${XDG_RUNTIME_DIR:-/tmp}/steamify-bios"
|
||||
|
||||
bios_prepare() {
|
||||
# Downloads Valve's package, checks its SHA-256 and extracts the .cab to
|
||||
# $BIOS_STAGE_DIR, then asks fwupd whether it fits this machine. Sets
|
||||
# BIOS_COMPATIBLE (yes|dry-run). 0 = ready to flash, 2 = nothing to do
|
||||
# (already the newest), 1 = error (nothing was touched).
|
||||
if ! bios_lookup_newest; then
|
||||
err "Couldn't find the newest Steam Machine BIOS on Valve's mirror ($VALVE_MIRROR)."
|
||||
return 1
|
||||
fi
|
||||
local current tmp compatible
|
||||
current="$(bios_current)"
|
||||
[[ -n "$BIOS_DRY_RUN" ]] && warn "DRY RUN (WIZARD_BIOS_DRY_RUN): nothing will be flashed."
|
||||
if [[ "$current" == "$BIOS_NEWEST" ]]; then
|
||||
ok "The BIOS is already the newest version ($current); nothing to do."
|
||||
return 0
|
||||
if [[ "$(bios_current)" == "$BIOS_NEWEST" ]]; then
|
||||
ok "The BIOS is already the newest version ($BIOS_NEWEST); nothing to do."
|
||||
return 2
|
||||
fi
|
||||
|
||||
# Download and check everything before asking: the warnings only come
|
||||
# when the file is Valve's (SHA-256 from Valve's repo database) and fwupd
|
||||
# confirms it's firmware for this very machine.
|
||||
pacman -Q fwupd >/dev/null 2>&1 || sudo pacman -S --needed --noconfirm fwupd ||
|
||||
{ err "Installing fwupd failed."; return 1; }
|
||||
tmp="$(mktemp -d)"
|
||||
rm -rf "$BIOS_STAGE_DIR"; mkdir -p "$BIOS_STAGE_DIR"; chmod 700 "$BIOS_STAGE_DIR"
|
||||
info "Downloading $BIOS_PKG ($BIOS_REPO)..."
|
||||
if ! curl -fsSL "$VALVE_MIRROR/$BIOS_REPO/os/x86_64/$BIOS_PKG" -o "$tmp/pkg.tar.zst" ||
|
||||
! echo "$BIOS_SHA256 $tmp/pkg.tar.zst" | sha256sum -c --quiet - ||
|
||||
! tar -I unzstd -xf "$tmp/pkg.tar.zst" -C "$tmp" "$BIOS_CAB"; then
|
||||
if ! curl -fsSL "$VALVE_MIRROR/$BIOS_REPO/os/x86_64/$BIOS_PKG" -o "$BIOS_STAGE_DIR/pkg.tar.zst" ||
|
||||
! echo "$BIOS_SHA256 $BIOS_STAGE_DIR/pkg.tar.zst" | sha256sum -c --quiet - ||
|
||||
! tar -I unzstd -xf "$BIOS_STAGE_DIR/pkg.tar.zst" -C "$BIOS_STAGE_DIR" "$BIOS_CAB"; then
|
||||
err "Downloading or verifying $BIOS_PKG failed; the BIOS was not touched."
|
||||
rm -rf "$tmp"
|
||||
rm -rf "$BIOS_STAGE_DIR"
|
||||
return 1
|
||||
fi
|
||||
ok "Checksum OK: this is Valve's $BIOS_PKG."
|
||||
local yes="$c_green$c_bold" b="$c_bold" n="$c_reset"
|
||||
if [[ -n "$BIOS_DRY_RUN" ]]; then
|
||||
warn "Dry run: skipping fwupd's check that the firmware fits this machine."
|
||||
compatible="${c_yellow}${b}not checked${n} (dry run)"
|
||||
elif bios_fits_device "$tmp/$BIOS_CAB"; then
|
||||
BIOS_COMPATIBLE=dry-run
|
||||
elif bios_fits_device "$BIOS_STAGE_DIR/$BIOS_CAB"; then
|
||||
ok "fwupd confirms BIOS $BIOS_NEWEST is firmware for this machine."
|
||||
compatible="${yes}yes${n} (checked by fwupd)"
|
||||
BIOS_COMPATIBLE=yes
|
||||
else
|
||||
err "fwupd says BIOS $BIOS_NEWEST is not for this machine's hardware; not installing it."
|
||||
rm -rf "$tmp"
|
||||
rm -rf "$BIOS_STAGE_DIR"
|
||||
return 1
|
||||
fi
|
||||
printf '%s\n' "$BIOS_NEWEST" "$BIOS_CAB" > "$BIOS_STAGE_DIR/ready"
|
||||
}
|
||||
|
||||
bios_flash() {
|
||||
# Hands the firmware bios_prepare checked to fwupd; it is written during
|
||||
# the next restart. Sets BIOS_NEEDS_RESTART.
|
||||
local newest cab
|
||||
{ read -r newest; read -r cab; } < "$BIOS_STAGE_DIR/ready" 2>/dev/null
|
||||
if [[ -z "${cab:-}" || ! -f "$BIOS_STAGE_DIR/$cab" ]]; then
|
||||
err "No checked BIOS file waiting; nothing was flashed."
|
||||
return 1
|
||||
fi
|
||||
if [[ -n "$BIOS_DRY_RUN" ]]; then
|
||||
ok "Dry run: would run: fwupdmgr install -y --no-reboot-check $(basename "$cab")"
|
||||
ok "Dry run finished; nothing was flashed."
|
||||
# Treated as staged, so the restart choices that follow a real
|
||||
# update show up too; restarting only prints (see restart_now).
|
||||
BIOS_NEEDS_RESTART=1
|
||||
rm -rf "$BIOS_STAGE_DIR"
|
||||
return 0
|
||||
fi
|
||||
info "Handing BIOS $newest to fwupd. Do NOT turn off the power from now on."
|
||||
# -y: the user confirmed twice; --no-reboot-check: our own restart
|
||||
# question comes at the end.
|
||||
if ! sudo fwupdmgr install -y --no-reboot-check "$BIOS_STAGE_DIR/$cab"; then
|
||||
err "fwupd could not install the BIOS update (see above); the BIOS was not changed."
|
||||
rm -rf "$BIOS_STAGE_DIR"
|
||||
return 1
|
||||
fi
|
||||
rm -rf "$BIOS_STAGE_DIR"
|
||||
BIOS_NEEDS_RESTART=1
|
||||
ok "BIOS $newest is staged. It is written during the next restart:"
|
||||
warn "keep the power on and don't touch the machine until it has fully started again."
|
||||
}
|
||||
|
||||
bios_enable() {
|
||||
local rc current compatible
|
||||
current="$(bios_current)"
|
||||
bios_prepare; rc=$?
|
||||
[[ $rc -eq 2 ]] && return 0
|
||||
[[ $rc -ne 0 ]] && return 1
|
||||
|
||||
local yes="$c_green$c_bold" b="$c_bold" n="$c_reset"
|
||||
if [[ "$BIOS_COMPATIBLE" == dry-run ]]; then
|
||||
compatible="${c_yellow}${b}not checked${n} (dry run)"
|
||||
else
|
||||
compatible="${yes}yes${n} (checked by fwupd)"
|
||||
fi
|
||||
bios_disclaimer "WARNING: BIOS UPDATE - ENTIRELY AT YOUR OWN RISK" \
|
||||
"Current BIOS: ${b}$current${n}" \
|
||||
"New BIOS: ${b}$BIOS_NEWEST${n}" \
|
||||
"Checksum: ${yes}OK${n} (Valve's package)" \
|
||||
"Compatible: $compatible"
|
||||
if ! ask_yn "Do you understand the risks and want to continue?" n; then
|
||||
info "BIOS update cancelled; nothing was changed."; rm -rf "$tmp"; return 0
|
||||
info "BIOS update cancelled; nothing was changed."; rm -rf "$BIOS_STAGE_DIR"; return 0
|
||||
fi
|
||||
bios_disclaimer "LAST CHANCE: THIS FLASHES BIOS $BIOS_NEWEST" \
|
||||
"After this, keep the power on until the machine has fully" \
|
||||
@@ -176,28 +224,10 @@ bios_enable() {
|
||||
local reply
|
||||
read -rp "$(echo -e "${c_red}${c_bold}Type UPDATE (in capitals) to flash the BIOS, anything else cancels:${c_reset} ")" reply
|
||||
if [[ "$reply" != UPDATE ]]; then
|
||||
info "BIOS update cancelled; nothing was changed."; rm -rf "$tmp"; return 0
|
||||
info "BIOS update cancelled; nothing was changed."; rm -rf "$BIOS_STAGE_DIR"; return 0
|
||||
fi
|
||||
|
||||
if [[ -n "$BIOS_DRY_RUN" ]]; then
|
||||
ok "Dry run: would run: fwupdmgr install -y --no-reboot-check $(basename "$BIOS_CAB")"
|
||||
ok "Dry run finished; nothing was flashed."
|
||||
# Treated as staged, so the restart choices that follow a real
|
||||
# update show up too; restarting only prints (see restart_now).
|
||||
BIOS_NEEDS_RESTART=1
|
||||
rm -rf "$tmp"
|
||||
return 0
|
||||
fi
|
||||
info "Handing BIOS $BIOS_NEWEST to fwupd. Do NOT turn off the power from now on."
|
||||
# -y: we already asked twice; --no-reboot-check: the wizard's own
|
||||
# restart question comes at the end.
|
||||
if ! sudo fwupdmgr install -y --no-reboot-check "$tmp/$BIOS_CAB"; then
|
||||
err "fwupd could not install the BIOS update (see above); the BIOS was not changed."
|
||||
rm -rf "$tmp"
|
||||
return 1
|
||||
fi
|
||||
rm -rf "$tmp"
|
||||
BIOS_NEEDS_RESTART=1
|
||||
ok "BIOS $BIOS_NEWEST is staged. It is written during the next restart:"
|
||||
warn "keep the power on and don't touch the machine until it has fully started again."
|
||||
bios_flash
|
||||
}
|
||||
|
||||
# For the app (lib/backend.sh): the flash step alone, after its warnings.
|
||||
bios_flash_only() { bios_flash; }
|
||||
Reference in new issue
Block a user