Files
ThothII/scripts/prepare-server-pi-state.sh

73 lines
2.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# Prepare the nested targets required beneath the server profile's writable Pi-state parent bind.
set -euo pipefail
fail() {
printf 'prepare-server-pi-state: %s\n' "$*" >&2
exit 2
}
[[ $# -ge 1 && $# -le 3 ]] \
|| fail "usage: $0 ABSOLUTE_PI_STATE_ROOT [NUMERIC_UID [NUMERIC_GID]]"
pi_state_root="$1"
owner="${2:-$(id -u)}"
group="${3:-$(id -g)}"
[[ "$pi_state_root" == /* && "$pi_state_root" != / && "$pi_state_root" != */ \
&& "$pi_state_root" != *//* && "$pi_state_root/" != */../* \
&& "$pi_state_root/" != */./* ]] \
|| fail "Pi-state root must be an absolute canonical non-root path"
[[ "$owner" =~ ^[0-9]+$ && "$group" =~ ^[0-9]+$ ]] \
|| fail "owner and group must be numeric"
[[ ! -L "$pi_state_root" ]] || fail "Pi-state root must not be a symlink"
if [[ "$(id -u)" -ne 0 && ( "$owner" != "$(id -u)" || "$group" != "$(id -g)" ) ]]; then
fail "non-root execution may prepare only its own UID/GID"
fi
ensure_directory() {
local path="$1" mode="$2"
if [[ -e "$path" && ( ! -d "$path" || -L "$path" ) ]]; then
fail "expected a real directory: $path"
fi
mkdir -p "$path"
chmod "$mode" "$path"
if [[ "$(id -u)" -eq 0 ]]; then
chown "$owner:$group" "$path"
fi
}
ensure_target() {
local target="$1" temporary=""
if [[ -e "$target" || -L "$target" ]]; then
[[ -f "$target" && ! -L "$target" ]] || fail "expected a regular target file: $target"
else
temporary="$(mktemp "${target%/*}/.${target##*/}.XXXXXX")"
trap '[[ -z "${temporary:-}" ]] || rm -f "$temporary"' RETURN
chmod 0600 "$temporary"
if [[ "$(id -u)" -eq 0 ]]; then
chown "$owner:$group" "$temporary"
fi
if ! ln "$temporary" "$target" 2>/dev/null; then
[[ -f "$target" && ! -L "$target" ]] \
|| fail "could not atomically create target: $target"
fi
rm -f "$temporary"
temporary=""
trap - RETURN
fi
chmod 0600 "$target"
if [[ "$(id -u)" -eq 0 ]]; then
chown "$owner:$group" "$target"
fi
}
ensure_directory "$pi_state_root" 0750
ensure_directory "$pi_state_root/agent" 0700
for name in auth.json models.json settings.json; do
ensure_target "$pi_state_root/agent/$name"
done
printf 'Prepared server Pi-state targets under %s for %s:%s.\n' \
"$pi_state_root" "$owner" "$group"