fix(common): lock registry prevents EXIT trap overwrite orphaning locks

Scripts calling acquire_lock followed by acquire_rsync_lock (rsync.sh)
or a custom EXIT trap (resource_watchdog.sh) would overwrite the lock
release trap, leaving the first lock file behind on exit.

Replace per-acquire trap with a _LOCK_FILES registry. _register_lock()
appends each lock file to the array and sets a single _release_all_locks
trap. All acquired locks release together on exit regardless of how many
traps are subsequently set or overwritten.

resource_watchdog.sh: chain _release_all_locks into both its custom trap
and the state-persisted disarm path so the lock releases in all exit paths.
This commit is contained in:
gmer4lfe
2026-05-24 21:02:59 -04:00
parent 207dead909
commit fc1fd27a3f
2 changed files with 19 additions and 4 deletions
+17 -2
View File
@@ -1253,6 +1253,21 @@ RSYNC_MAX_CONCURRENT=3
LOCK_WARN_AGE=300 # seconds — warn if lock older than this (5min default)
LOCK_WAIT_TIMEOUT=30 # seconds — how long "wait" mode waits before giving up
# Registry of all lock files acquired by this process — released together on exit.
# Prevents the single-trap-per-acquire problem: each new acquire_lock/acquire_rsync_lock
# call used to overwrite the EXIT trap, orphaning the previous lock file.
declare -ga _LOCK_FILES=()
_release_all_locks() {
local lf
for lf in "${_LOCK_FILES[@]}"; do
[[ -f "$lf" ]] && rm -f "$lf"
done
}
_register_lock() {
_LOCK_FILES+=("$1")
trap '_release_all_locks' EXIT
}
# Internal — script name used as lock identifier
_lock_name() {
basename "${BASH_SOURCE[1]:-$0}" .sh
@@ -1344,7 +1359,7 @@ acquire_lock() {
# Acquire lock — store PID:scriptname to prevent PID reuse false positives
echo "$$:$script_name" > "$lockfile"
trap "_release_on_exit '$lockfile'" EXIT
_register_lock "$lockfile"
log "$ICON_LOCK Lock acquired: $script_name (PID $$)"
}
@@ -1402,7 +1417,7 @@ acquire_rsync_lock() {
# Acquire profile lock and increment counter
echo "$$:rsync_${profile}" > "$profile_lock"
echo $(( current_count + 1 )) > "$RSYNC_COUNT_FILE"
trap "_release_rsync_on_exit '$profile_lock'" EXIT
_register_lock "$profile_lock"
log "$ICON_LOCK rsync lock acquired: profile '$profile' (PID $$, active: $(( current_count + 1 ))/$RSYNC_MAX_CONCURRENT)"
}