LibrePortal/scripts/webui/data/lock/webui_check_update_lock.sh
librelad 2d24a764a8 refactor(storage): route elevation tests and the WebUI tree through paths.sh
Two mechanical sweeps, no behaviour change on a single-root install.

The 14 `[[ "$p" == "$containers_dir"* ]]` prefix tests that decide
manager-vs-container-user elevation become pathIsContainerData, so a file
on a second storage root is no longer misclassified as manager-owned —
which would have written it with the wrong owner and failed later, far
from the cause. The 65 references to the WebUI's own tree become
webuiDir(), which is pinned to the primary root by design.

Two traps found while doing it:

run_privileged.sh is sourced directly by init.sh without paths.sh, so it
needs a fallback. Defining one named pathIsContainerData was wrong:
generate_function_manifest.sh indexes top-level definitions, and the
resulting autoload stub would have shadowed the real multi-root
implementation with the primary-only fallback — silently classifying
every file on a second disk as manager-owned, which is exactly the bug
this sweep exists to prevent. Renamed to _runCfgIsContainerPath, which
delegates when the real one is loaded.

setup_lock.sh built its path in a top-level assignment, so it was
evaluated at source time and needed the file flagged eager. Made it a
function instead: the path resolves on call, and the file drops off
LP_EAGER_FILES entirely.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 04:04:19 +01:00

43 lines
1.7 KiB
Bash
Executable File

#!/bin/bash
# LibrePortal WebUI Update Lock Check
# Guards against concurrent WebUI data refreshes.
#
# Echoes its verdict ("true" = a live lock is held, skip; "false" = clear to
# proceed) on stdout, and auto-clears a STALE lock. Callers must capture the
# echo — `result=$(webuiCheckUpdateLock)` runs the function in a subshell, so a
# global it set would never reach the caller (that was a real bug: the guard
# read an always-empty global and so never actually blocked anything).
#
# Staleness matters because the lock's remover (webuiRemoveUpdateLock) is itself
# a lazy-loaded function whose backing file can be transiently missing while the
# scripts tree is wiped+repopulated mid-deploy. If that removal is skipped once,
# the leftover lock would otherwise wedge EVERY future refresh. No single refresh
# runs anywhere near this long, so a lock older than the threshold is a leftover.
webuiCheckUpdateLock() {
local lock_file="$(webuiDir)/frontend/data/updater.lock"
local stale_after=900 # seconds (15 min); far longer than any real refresh
if [ ! -f "$lock_file" ]; then
isNotice "No update lock file found" >&2
echo "false"
return 0
fi
local now lock_mtime age
now=$(date +%s 2>/dev/null || echo 0)
lock_mtime=$(stat -c '%Y' "$lock_file" 2>/dev/null || echo 0)
age=$(( now - lock_mtime ))
if (( now > 0 && lock_mtime > 0 && age >= stale_after )); then
isNotice "Stale update lock (${age}s old ≥ ${stale_after}s) — clearing and continuing." >&2
runFileOp rm -f "$lock_file" >/dev/null 2>&1
echo "false"
return 0
fi
isNotice "Update lock file exists: $lock_file" >&2
echo "true"
return 0
}