Skill Tracer
Skills › gstack › freeze › freeze-state.sh

freeze-state.sh

68 lines · freeze/bin/freeze-state.sh at 3f79d81

1#!/usr/bin/env bash
2set -euo pipefail
3
4_here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5. "$_here/../../careful/bin/hook-extract.sh"
6if ! command -v gstack_hook_state_root >/dev/null 2>&1; then
7 echo "FREEZE_ERROR: cannot resolve the gstack state root: $_here/../../bin/gstack-state-root.sh is missing. No boundary changed. Fix: reinstall with ./setup or /gstack-upgrade (docs/state-root.md)." >&2
8 exit 1
9fi
10STATE_DIR="$(gstack_hook_state_root; printf x)"; STATE_DIR="${STATE_DIR%x}"
11mkdir -p "$STATE_DIR"
12STATE_DIR="$(cd "$STATE_DIR" && pwd -P && printf x)"; STATE_DIR="${STATE_DIR%$'\nx'}"
13state="$STATE_DIR/freeze-dir.txt"
14mutex="$STATE_DIR/.freeze-mutation.lock"
15action="${1:-}"
16case "$action" in acquire|set|release|clear) ;; *) echo 'Usage: freeze-state.sh acquire|set DIRECTORY | release OWNER | clear' >&2; exit 2 ;; esac
18if ! mkdir "$mutex" 2>/dev/null; then
19 echo 'FREEZE_BUSY: another writer or an interrupted mutation owns the state lock. Retry after it finishes; if abandoned, inspect it with the user before recovery. No boundary changed.' >&2
20 exit 1
21fi
22temp=""
23finish() {
24 local rc=$?
25 [ -z "$temp" ] || rm -f -- "$temp"
26 rmdir "$mutex"
27 exit "$rc"
29trap finish EXIT
30trap 'exit 130' INT
31trap 'exit 143' TERM
33if [ "$action" = acquire ] && { [ -e "$state" ] || [ -L "$state" ]; }; then
34 echo 'FREEZE_PRESERVED: an existing boundary belongs to the user or another run. Do not release it; use /freeze to re-establish an ambiguous legacy boundary with the user.'
35 exit 0
36fi
37if [ -L "$state" ] || { [ -e "$state" ] && [ ! -f "$state" ]; }; then
38 echo 'FREEZE_PRESERVED: unexpected state type; inspect it with the user before recovery.' >&2
39 exit 1
40fi
41case "$action" in
42 acquire|set)
43 boundary="$(cd -- "${2:?Directory required}" && pwd -P && printf x)"; boundary="${boundary%$'\nx'}"
44 case "$boundary" in *$'\n'*|*$'\r'*) echo 'FREEZE_ERROR: boundary must fit on one line.' >&2; exit 2 ;; esac
45 owner="$(od -An -N16 -tx1 /dev/urandom | tr -d '[:space:]')"
46 [ "${#owner}" -eq 32 ] || exit 1
47 temp="$(mktemp "$STATE_DIR/.freeze-write.XXXXXX")"
48 printf '%s\ngstack-freeze-v1:%s\n' "$boundary" "$owner" > "$temp"
49 mv -f -- "$temp" "$state"
50 temp=""
51 printf 'FREEZE_OWNER=%s\nFREEZE_DIR=%s\n' "$owner" "$boundary"
52 ;;
53 release)
54 owner="${2:?Owner required}"
55 case "$owner" in ''|*[!a-f0-9]*) echo 'FREEZE_ERROR: invalid owner token.' >&2; exit 2 ;; esac
56 [ "${#owner}" -eq 32 ] || exit 2
57 if [ -f "$state" ] && [ "$(sed -n '2p' "$state")" = "gstack-freeze-v1:$owner" ]; then
58 rm -- "$state"
59 echo 'FREEZE_RELEASED: investigation-owned boundary removed.'
60 else
61 echo 'FREEZE_PRESERVED: no matching owner; existing or replacement state was left untouched.'
62 fi
63 ;;
64 clear)
65 rm -f -- "$state"
66 echo 'FREEZE_CLEARED: user-requested edit boundary removal completed.'
67 ;;
68esac