73 lines
2.2 KiB
Bash
Executable File
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"
|