mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-10-07 07:12:50 +03:00
clean up
This commit is contained in:
+11
-22
@@ -97,11 +97,9 @@ jobs:
|
|||||||
echo "response carries frame-ancestors, which breaks cross-origin iframe embedding"
|
echo "response carries frame-ancestors, which breaks cross-origin iframe embedding"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
# -t must NOT run as root: ngx_create_paths would chown the live cache
|
# -t as root would chown the live cache and temp dirs to the `user`
|
||||||
# and temp dirs to the `user root` directive user, breaking the workers.
|
# directive user; stdout discarded because -t reopens the config's
|
||||||
# stdout goes to /dev/null because -t reopens the config's
|
# /dev/stdout logs and the docker exec pipe is root-owned
|
||||||
# error_log/access_log /dev/stdout by path, and the docker exec pipe
|
|
||||||
# is root-owned; -t reports on stderr, so nothing is lost
|
|
||||||
docker exec frigate /command/s6-setuidgid frigate bash -c '/usr/local/nginx/sbin/nginx -e stderr -t -c /tmp/nginx/conf/nginx.conf >/dev/null'
|
docker exec frigate /command/s6-setuidgid frigate bash -c '/usr/local/nginx/sbin/nginx -e stderr -t -c /tmp/nginx/conf/nginx.conf >/dev/null'
|
||||||
docker exec frigate stat -c %a /etc/letsencrypt/live/frigate/privkey.pem | grep -qx 600
|
docker exec frigate stat -c %a /etc/letsencrypt/live/frigate/privkey.pem | grep -qx 600
|
||||||
docker exec frigate stat -c %a /dev/shm/go2rtc.yaml | grep -qx 640
|
docker exec frigate stat -c %a /dev/shm/go2rtc.yaml | grep -qx 640
|
||||||
@@ -125,8 +123,7 @@ jobs:
|
|||||||
code=$(curl -s -o /dev/null -w '%{http_code}' -X POST http://127.0.0.1:5000/api/login \
|
code=$(curl -s -o /dev/null -w '%{http_code}' -X POST http://127.0.0.1:5000/api/login \
|
||||||
-H 'content-type: application/json' -d '{"user":"admin","password":"definitely-wrong"}')
|
-H 'content-type: application/json' -d '{"user":"admin","password":"definitely-wrong"}')
|
||||||
[ "$code" = "401" ] || { echo "login endpoint returned $code"; exit 1; }
|
[ "$code" = "401" ] || { echo "login endpoint returned $code"; exit 1; }
|
||||||
# nginx runtime state must belong to the runtime user (a root nginx -t
|
# a root nginx -t above would have chowned the runtime dirs to root
|
||||||
# in the step above would have chowned it to root)
|
|
||||||
owners=$(docker exec frigate stat -c %U /tmp/nginx /dev/shm/nginx_cache)
|
owners=$(docker exec frigate stat -c %U /tmp/nginx /dev/shm/nginx_cache)
|
||||||
echo "$owners"
|
echo "$owners"
|
||||||
if echo "$owners" | grep -qvx frigate; then
|
if echo "$owners" | grep -qvx frigate; then
|
||||||
@@ -135,12 +132,10 @@ jobs:
|
|||||||
# runtime user can write recordings storage
|
# runtime user can write recordings storage
|
||||||
docker exec frigate /command/s6-setuidgid frigate touch /media/frigate/.write-probe
|
docker exec frigate /command/s6-setuidgid frigate touch /media/frigate/.write-probe
|
||||||
docker exec frigate rm /media/frigate/.write-probe
|
docker exec frigate rm /media/frigate/.write-probe
|
||||||
# /tmp/cache is a tmpfs mount here, as the docs recommend: it arrives
|
# tmpfs mount per the docs: arrives root-owned, holds the ZMQ IPC sockets
|
||||||
# root-owned, and the ZMQ IPC sockets live in it
|
|
||||||
docker exec frigate /command/s6-setuidgid frigate touch /tmp/cache/.write-probe
|
docker exec frigate /command/s6-setuidgid frigate touch /tmp/cache/.write-probe
|
||||||
docker exec frigate rm /tmp/cache/.write-probe
|
docker exec frigate rm /tmp/cache/.write-probe
|
||||||
# bundled models must be readable by the runtime user: they are baked
|
# models are baked in as root and archive members can carry root-only modes
|
||||||
# in as root, and archive members can carry root-only modes
|
|
||||||
docker exec frigate /command/s6-setuidgid frigate sh -c '
|
docker exec frigate /command/s6-setuidgid frigate sh -c '
|
||||||
for f in /cpu_model.tflite /edgetpu_model.tflite /cpu_audio_model.tflite \
|
for f in /cpu_model.tflite /edgetpu_model.tflite /cpu_audio_model.tflite \
|
||||||
/labelmap.txt /audio-labelmap.txt /openvino-model/*; do
|
/labelmap.txt /audio-labelmap.txt /openvino-model/*; do
|
||||||
@@ -151,9 +146,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir -p /tmp/frigate-config-root
|
mkdir -p /tmp/frigate-config-root
|
||||||
printf 'mqtt:\n enabled: false\ncameras: {}\n' > /tmp/frigate-config-root/config.yml
|
printf 'mqtt:\n enabled: false\ncameras: {}\n' > /tmp/frigate-config-root/config.yml
|
||||||
# pre-seed a sentinel: the assertion below is that the escape hatch
|
# pre-seed so the absence check proves the rm -f, not a vacuous pass
|
||||||
# DELETES it. Against a fresh dir the absence check passes vacuously
|
|
||||||
# and proves nothing about the rm -f in the prepare script.
|
|
||||||
echo "2:1000:1000" > /tmp/frigate-config-root/.permissions_version
|
echo "2:1000:1000" > /tmp/frigate-config-root/.permissions_version
|
||||||
docker run -d --name frigate-root --shm-size 256m \
|
docker run -d --name frigate-root --shm-size 256m \
|
||||||
-e FRIGATE_RUN_AS_ROOT=true \
|
-e FRIGATE_RUN_AS_ROOT=true \
|
||||||
@@ -170,8 +163,7 @@ jobs:
|
|||||||
echo "$ps_out" | grep -w python3 | grep -q '^root'
|
echo "$ps_out" | grep -w python3 | grep -q '^root'
|
||||||
echo "$ps_out" | grep -w go2rtc | grep -q '^root'
|
echo "$ps_out" | grep -w go2rtc | grep -q '^root'
|
||||||
echo "$ps_out" | grep -w nginx | grep -q '^root'
|
echo "$ps_out" | grep -w nginx | grep -q '^root'
|
||||||
# escape hatch must have DELETED the pre-seeded sentinel. written as
|
# an if, not ! test: bash exempts negated commands from set -e
|
||||||
# an if because bash exempts a negated command from set -e
|
|
||||||
if docker exec frigate-root test -f /config/.permissions_version; then
|
if docker exec frigate-root test -f /config/.permissions_version; then
|
||||||
echo "escape hatch did not delete the sweep sentinel"; exit 1
|
echo "escape hatch did not delete the sweep sentinel"; exit 1
|
||||||
fi
|
fi
|
||||||
@@ -195,8 +187,7 @@ jobs:
|
|||||||
echo "$ps_out"
|
echo "$ps_out"
|
||||||
# the listed service runs as root
|
# the listed service runs as root
|
||||||
echo "$ps_out" | grep -w python3 | grep -q '^root'
|
echo "$ps_out" | grep -w python3 | grep -q '^root'
|
||||||
# unlisted services still drop. written as ifs because bash exempts
|
# unlisted services still drop; ifs because set -e exempts negated commands
|
||||||
# a negated command from set -e
|
|
||||||
if echo "$ps_out" | grep -w go2rtc | grep -q '^root'; then
|
if echo "$ps_out" | grep -w go2rtc | grep -q '^root'; then
|
||||||
echo "go2rtc is unexpectedly running as root"; exit 1
|
echo "go2rtc is unexpectedly running as root"; exit 1
|
||||||
fi
|
fi
|
||||||
@@ -207,8 +198,7 @@ jobs:
|
|||||||
docker exec frigate-granular cat /config/.permissions_version | grep -qx "2:1000:1000:frigate"
|
docker exec frigate-granular cat /config/.permissions_version | grep -qx "2:1000:1000:frigate"
|
||||||
# the root frigate process chowns the db it creates (first-boot immediacy)
|
# the root frigate process chowns the db it creates (first-boot immediacy)
|
||||||
docker exec frigate-granular stat -c %u /config/frigate.db | grep -qx 1000
|
docker exec frigate-granular stat -c %u /config/frigate.db | grep -qx 1000
|
||||||
# per-boot sweep guard: plant a root-owned straggler, restart, and
|
# plant a root-owned straggler; the per-boot sweep must reclaim it on restart
|
||||||
# it must come back owned by the runtime user
|
|
||||||
docker exec frigate-granular sh -c 'mkdir -p /media/frigate/clips && touch /media/frigate/clips/straggler.webp'
|
docker exec frigate-granular sh -c 'mkdir -p /media/frigate/clips && touch /media/frigate/clips/straggler.webp'
|
||||||
docker restart frigate-granular
|
docker restart frigate-granular
|
||||||
up=0
|
up=0
|
||||||
@@ -235,8 +225,7 @@ jobs:
|
|||||||
if [ "$found" -ne 1 ]; then
|
if [ "$found" -ne 1 ]; then
|
||||||
echo "no fail-fast error for an unknown service name"; docker logs frigate-badsvc; exit 1
|
echo "no fail-fast error for an unknown service name"; docker logs frigate-badsvc; exit 1
|
||||||
fi
|
fi
|
||||||
# the failed oneshot must have blocked startup (prepare and every
|
# the failed oneshot blocks startup through the dependency chain
|
||||||
# service depend on init-usermod transitively)
|
|
||||||
if docker exec frigate-badsvc curl -fs http://127.0.0.1:5000/api/version; then
|
if docker exec frigate-badsvc curl -fs http://127.0.0.1:5000/api/version; then
|
||||||
echo "container came up despite an invalid FRIGATE_ROOT_SERVICES"; exit 1
|
echo "container came up despite an invalid FRIGATE_ROOT_SERVICES"; exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -146,8 +146,6 @@ RUN wget -q https://github.com/openvinotoolkit/open_model_zoo/raw/master/data/da
|
|||||||
RUN wget -qO - https://www.kaggle.com/api/v1/models/google/yamnet/tfLite/classification-tflite/1/download | tar xvz && mv 1.tflite cpu_audio_model.tflite
|
RUN wget -qO - https://www.kaggle.com/api/v1/models/google/yamnet/tfLite/classification-tflite/1/download | tar xvz && mv 1.tflite cpu_audio_model.tflite
|
||||||
COPY audio-labelmap.txt .
|
COPY audio-labelmap.txt .
|
||||||
|
|
||||||
# tar restores the archive's modes and the yamnet member ships 0700, so without
|
|
||||||
# this the unprivileged runtime user cannot read the audio model
|
|
||||||
RUN chmod -R a+rX /rootfs
|
RUN chmod -R a+rX /rootfs
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,8 @@ set -o errexit -o nounset -o pipefail
|
|||||||
|
|
||||||
# Logs should be sent to stdout so that s6 can collect them
|
# Logs should be sent to stdout so that s6 can collect them
|
||||||
|
|
||||||
# Signal the master directly rather than running `nginx -s reload`. That would
|
# Not `nginx -s reload`: that has root parse /tmp/nginx/conf, which the
|
||||||
# have root parse /tmp/nginx/conf, which the unprivileged nginx user can
|
# unprivileged nginx user can rewrite, and nginx chowns path directives on load.
|
||||||
# rewrite, and nginx acts on path directives while loading a config: it creates
|
|
||||||
# them and chowns them to the configured user.
|
|
||||||
function reload_nginx() {
|
function reload_nginx() {
|
||||||
local pid
|
local pid
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,8 @@ if [[ "$(id -u)" -eq 0 ]]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# $HOME is /root from the container env and survives s6-setuidgid, so cache
|
# /root survives s6-setuidgid and breaks cache writes after the drop; set
|
||||||
# and telemetry writes (huggingface, openvino) fail after the drop. Set it
|
# before opt_in_out so the opt-out marker lands where the service will look
|
||||||
# before opt_in_out so the opt-out marker lands where the service will look.
|
|
||||||
# When the service keeps root, /root stays correct.
|
|
||||||
if [[ "$runs_as_root" -eq 0 ]]; then
|
if [[ "$runs_as_root" -eq 0 ]]; then
|
||||||
export HOME=/config
|
export HOME=/config
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -119,10 +119,8 @@ setup_homekit_config "${homekit_config_path}"
|
|||||||
|
|
||||||
if [[ "$(id -u)" -eq 0 && "$runs_as_root" -eq 0 ]]; then
|
if [[ "$(id -u)" -eq 0 && "$runs_as_root" -eq 0 ]]; then
|
||||||
chown go2rtc:go2rtc /dev/shm/go2rtc.yaml 2>/dev/null || true
|
chown go2rtc:go2rtc /dev/shm/go2rtc.yaml 2>/dev/null || true
|
||||||
# go2rtc rewrites this in place (os.WriteFile, no rename), so owning the
|
# go2rtc rewrites this in place, so owning the file is enough. Tolerated so
|
||||||
# file is enough; /config grants frigate-data traverse only. Tolerated so
|
# a chown-refusing mount (NFS root_squash) degrades pairing, not the service
|
||||||
# a chown-refusing mount (NFS root_squash) degrades pairing persistence
|
|
||||||
# instead of crash-looping the service
|
|
||||||
chown go2rtc:frigate-data "${homekit_config_path}" 2>/dev/null && chmod 664 "${homekit_config_path}" 2>/dev/null || \
|
chown go2rtc:frigate-data "${homekit_config_path}" 2>/dev/null && chmod 664 "${homekit_config_path}" 2>/dev/null || \
|
||||||
echo "[WARN] Could not hand ${homekit_config_path} to the go2rtc user; HomeKit pairing changes may not persist"
|
echo "[WARN] Could not hand ${homekit_config_path} to the go2rtc user; HomeKit pairing changes may not persist"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -19,8 +19,7 @@ if [[ "${FRIGATE_RUN_AS_ROOT:-false}" == "true" ]]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Validate before anything consumes the list: a typo silently dropping a
|
# a typo must fail the boot, not silently drop a service to non-root
|
||||||
# service to non-root would defeat the reason the user set it.
|
|
||||||
if [[ -n "${FRIGATE_ROOT_SERVICES:-}" ]]; then
|
if [[ -n "${FRIGATE_ROOT_SERVICES:-}" ]]; then
|
||||||
IFS=',' read -ra root_services <<< "${FRIGATE_ROOT_SERVICES}"
|
IFS=',' read -ra root_services <<< "${FRIGATE_ROOT_SERVICES}"
|
||||||
for entry in "${root_services[@]}"; do
|
for entry in "${root_services[@]}"; do
|
||||||
|
|||||||
@@ -69,11 +69,9 @@ function set_worker_processes() {
|
|||||||
sed -i "s/worker_processes auto;/worker_processes ${cpus};/" /tmp/nginx/conf/nginx.conf
|
sed -i "s/worker_processes auto;/worker_processes ${cpus};/" /tmp/nginx/conf/nginx.conf
|
||||||
}
|
}
|
||||||
|
|
||||||
# Rebuilt root-owned and fresh every start. A previous unprivileged nginx owned
|
# Rebuilt root-owned every start: a symlink planted by the previously
|
||||||
# this tree, and the cp and tempio writes below run as root: without wiping it
|
# unprivileged nginx would redirect the root cp/tempio writes below onto any
|
||||||
# first, a planted symlink here would let those writes land on any root file.
|
# root file. rm does not traverse symlinks; the bare mkdir fails closed if raced.
|
||||||
# rm does not traverse symlinks, and the bare mkdir fails closed if /tmp/nginx
|
|
||||||
# is raced into a symlink before we can create it.
|
|
||||||
rm -rf /tmp/nginx
|
rm -rf /tmp/nginx
|
||||||
mkdir /tmp/nginx
|
mkdir /tmp/nginx
|
||||||
mkdir -p /tmp/nginx/conf /tmp/nginx/client_body /tmp/nginx/proxy \
|
mkdir -p /tmp/nginx/conf /tmp/nginx/client_body /tmp/nginx/proxy \
|
||||||
@@ -113,14 +111,12 @@ echo "$nginx_settings" | \
|
|||||||
|
|
||||||
if [[ "$(id -u)" -eq 0 && "$runs_as_root" -eq 0 ]]; then
|
if [[ "$(id -u)" -eq 0 && "$runs_as_root" -eq 0 ]]; then
|
||||||
chown -R frigate:frigate /tmp/nginx
|
chown -R frigate:frigate /tmp/nginx
|
||||||
# heal the cache if a root `nginx -t` chowned it (ngx_create_paths chowns
|
# heal the cache: a root `nginx -t` chowns every cycle path to the `user` directive user
|
||||||
# every cycle path to the `user` directive user when run as root)
|
|
||||||
if [ -d /dev/shm/nginx_cache ]; then
|
if [ -d /dev/shm/nginx_cache ]; then
|
||||||
chown -R frigate:frigate /dev/shm/nginx_cache
|
chown -R frigate:frigate /dev/shm/nginx_cache
|
||||||
fi
|
fi
|
||||||
# error_log/access_log /dev/stdout make nginx REOPEN the s6 log pipe by
|
# nginx reopens /dev/stdout by path for its logs, and s6 made the pipe
|
||||||
# path, and s6 created it root-owned 0600; without this the non-root
|
# root-owned 0600; without this the non-root master exits EACCES
|
||||||
# master exits with "open() /dev/stdout failed (13: Permission denied)"
|
|
||||||
chown frigate /dev/stdout
|
chown frigate /dev/stdout
|
||||||
# self-signed certs are root-generated; tolerant because mounted certs may be :ro
|
# self-signed certs are root-generated; tolerant because mounted certs may be :ro
|
||||||
if [ -f "$letsencrypt_path/privkey.pem" ]; then
|
if [ -f "$letsencrypt_path/privkey.pem" ]; then
|
||||||
@@ -130,8 +126,7 @@ fi
|
|||||||
|
|
||||||
# Replace the bash process with the NGINX process, redirecting stderr to stdout
|
# Replace the bash process with the NGINX process, redirecting stderr to stdout
|
||||||
exec 2>&1
|
exec 2>&1
|
||||||
# -e stderr: the compile-time default error log under /usr/local/nginx/logs
|
# -e stderr: the compiled-in error log path is not writable by the runtime user
|
||||||
# is not writable by the runtime user and would alert before config load
|
|
||||||
if [[ "$(id -u)" -ne 0 || "$runs_as_root" -eq 1 ]]; then
|
if [[ "$(id -u)" -ne 0 || "$runs_as_root" -eq 1 ]]; then
|
||||||
exec \
|
exec \
|
||||||
s6-notifyoncheck -t 30000 -n 1 \
|
s6-notifyoncheck -t 30000 -n 1 \
|
||||||
|
|||||||
@@ -153,14 +153,12 @@ if [[ "$(id -u)" -eq 0 ]]; then
|
|||||||
if [[ "${FRIGATE_RUN_AS_ROOT:-false}" == "true" ]]; then
|
if [[ "${FRIGATE_RUN_AS_ROOT:-false}" == "true" ]]; then
|
||||||
rm -f /config/.permissions_version
|
rm -f /config/.permissions_version
|
||||||
else
|
else
|
||||||
# Only bless the sentinel when a mount backs /media/frigate itself or
|
# Only when a mount backs /media/frigate itself: under a parent /media
|
||||||
# below it. A parent /media mount doesn't count: a dedicated
|
# mount, a dedicated volume added later would be shadowed and skipped
|
||||||
# /media/frigate volume added later would be shadowed and skipped.
|
|
||||||
sentinel_args=(--sentinel /config/.permissions_version)
|
sentinel_args=(--sentinel /config/.permissions_version)
|
||||||
root_services_mode=""
|
root_services_mode=""
|
||||||
if [[ -n "${FRIGATE_ROOT_SERVICES:-}" ]]; then
|
if [[ -n "${FRIGATE_ROOT_SERVICES:-}" ]]; then
|
||||||
# || true: grep -v exits non-zero on an all-empty list (e.g. ",")
|
# || true: an all-empty list (",") fails grep -v and errexit would kill the boot
|
||||||
# and errexit+pipefail would otherwise abort the boot over it
|
|
||||||
root_services_mode=$(tr ',' '\n' <<< "${FRIGATE_ROOT_SERVICES//[[:space:]]/}" | grep -v '^$' | sort -u | paste -sd, - || true)
|
root_services_mode=$(tr ',' '\n' <<< "${FRIGATE_ROOT_SERVICES//[[:space:]]/}" | grep -v '^$' | sort -u | paste -sd, - || true)
|
||||||
if [[ -n "$root_services_mode" ]]; then
|
if [[ -n "$root_services_mode" ]]; then
|
||||||
sentinel_args+=(--mode "$root_services_mode")
|
sentinel_args+=(--mode "$root_services_mode")
|
||||||
@@ -172,13 +170,10 @@ if [[ "$(id -u)" -eq 0 ]]; then
|
|||||||
/usr/local/bin/fix-ownership "${sentinel_args[@]}" \
|
/usr/local/bin/fix-ownership "${sentinel_args[@]}" \
|
||||||
"${PUID:-1000}" "${PGID:-1000}" /config /media/frigate
|
"${PUID:-1000}" "${PGID:-1000}" /config /media/frigate
|
||||||
|
|
||||||
# Root services write some files as root while running (clips
|
# Root services write clips stragglers and caches mid-run; realign the
|
||||||
# stragglers, caches, stale db journals). These trees are small, so
|
# small trees every boot. Recordings are chowned at create instead.
|
||||||
# realign them on every boot. Recordings are chowned at create and
|
|
||||||
# stay behind the sentinel sweep above.
|
|
||||||
if [[ -n "$root_services_mode" ]]; then
|
if [[ -n "$root_services_mode" ]]; then
|
||||||
# clips and exports don't exist until the frigate service has run
|
# only sweep what exists; clips and exports appear after the first run
|
||||||
# once; a WARN about them on a normal first boot invites reports
|
|
||||||
boot_sweep_paths=(/config)
|
boot_sweep_paths=(/config)
|
||||||
for extra in /media/frigate/clips /media/frigate/exports; do
|
for extra in /media/frigate/clips /media/frigate/exports; do
|
||||||
if [[ -d "$extra" ]]; then
|
if [[ -d "$extra" ]]; then
|
||||||
@@ -191,8 +186,7 @@ if [[ "$(id -u)" -eq 0 ]]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Not in the image, and the runtime user cannot create it under root-owned
|
# Must stay after the sweep, which reads an absent /media/frigate as an
|
||||||
# /media. Must stay after the sweep, which reads an absent /media/frigate as an
|
|
||||||
# unmounted volume rather than a swept one
|
# unmounted volume rather than a swept one
|
||||||
if [[ "$(id -u)" -eq 0 && ! -d /media/frigate ]]; then
|
if [[ "$(id -u)" -eq 0 && ! -d /media/frigate ]]; then
|
||||||
mkdir -p /media/frigate
|
mkdir -p /media/frigate
|
||||||
@@ -201,8 +195,7 @@ if [[ "$(id -u)" -eq 0 && ! -d /media/frigate ]]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Usually a tmpfs mount, so it arrives root-owned and is outside the swept
|
# usually a tmpfs mount: root-owned on arrival and outside the swept volumes
|
||||||
# volumes. The runtime user binds its ZMQ IPC sockets in here.
|
|
||||||
if [[ "$(id -u)" -eq 0 && "${FRIGATE_RUN_AS_ROOT:-false}" != "true" ]]; then
|
if [[ "$(id -u)" -eq 0 && "${FRIGATE_RUN_AS_ROOT:-false}" != "true" ]]; then
|
||||||
mkdir -p /tmp/cache
|
mkdir -p /tmp/cache
|
||||||
chown "${PUID:-1000}:${PGID:-1000}" /tmp/cache
|
chown "${PUID:-1000}:${PGID:-1000}" /tmp/cache
|
||||||
|
|||||||
@@ -11,8 +11,7 @@
|
|||||||
# --mode append STRING to the sentinel, so changing it re-sweeps once
|
# --mode append STRING to the sentinel, so changing it re-sweeps once
|
||||||
#
|
#
|
||||||
# Only files whose uid OR gid differs are touched, so re-runs are cheap.
|
# Only files whose uid OR gid differs are touched, so re-runs are cheap.
|
||||||
# lost+found is skipped: it belongs to the filesystem, not to Frigate, and
|
# lost+found is skipped: fsck fills it with root-only recovered fragments.
|
||||||
# fsck puts recovered fragments of arbitrary files there under root-only 0700.
|
|
||||||
# Top-level /config additionally grants group frigate-data TRAVERSE ONLY
|
# Top-level /config additionally grants group frigate-data TRAVERSE ONLY
|
||||||
# (g+rx) so the separate go2rtc user can reach its pre-created HomeKit file
|
# (g+rx) so the separate go2rtc user can reach its pre-created HomeKit file
|
||||||
# on hosts where /config is mounted 0700. Never g+w: directory write means
|
# on hosts where /config is mounted 0700. Never g+w: directory write means
|
||||||
@@ -64,10 +63,8 @@ if [[ "$(id -u)" -ne 0 ]]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# The mode string folds the FRIGATE_ROOT_SERVICES list into the sentinel, so
|
# The list folds into the sentinel so entering or leaving a granular root mode
|
||||||
# entering or leaving a granular root mode re-sweeps once. That is the
|
# re-sweeps once, catching whatever the other ownership mechanisms missed.
|
||||||
# backstop for anything a root service created that the per-boot sweep and
|
|
||||||
# chown-at-create did not cover.
|
|
||||||
sentinel_content="${schema}:${target_uid}:${target_gid}"
|
sentinel_content="${schema}:${target_uid}:${target_gid}"
|
||||||
if [[ -n "$mode" ]]; then
|
if [[ -n "$mode" ]]; then
|
||||||
sentinel_content="${sentinel_content}:${mode}"
|
sentinel_content="${sentinel_content}:${mode}"
|
||||||
@@ -125,8 +122,7 @@ for path in "$@"; do
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# -print feeds the progress counter while -exec {} + keeps the chown
|
# -print feeds the progress counter; -exec {} + keeps the chown batched
|
||||||
# batched; the scan above is what makes a real percentage possible
|
|
||||||
started=$SECONDS
|
started=$SECONDS
|
||||||
if find "$path" -name lost+found -prune -o \( -not -uid "$target_uid" -o -not -gid "$target_gid" \) \
|
if find "$path" -name lost+found -prune -o \( -not -uid "$target_uid" -o -not -gid "$target_gid" \) \
|
||||||
-print -exec chown -h "${target_uid}:${target_gid}" {} + \
|
-print -exec chown -h "${target_uid}:${target_gid}" {} + \
|
||||||
@@ -137,8 +133,8 @@ for path in "$@"; do
|
|||||||
if (pct > 100) pct = 100
|
if (pct > 100) pct = 100
|
||||||
if (pct >= next_pct) {
|
if (pct >= next_pct) {
|
||||||
printf "[INFO] fix-ownership: %s %d%% (%d/%d entries)\n", path, pct, NR, total
|
printf "[INFO] fix-ownership: %s %d%% (%d/%d entries)\n", path, pct, NR, total
|
||||||
# mawk block-buffers to a pipe; without this the whole
|
# mawk block-buffers to a pipe; without fflush the whole
|
||||||
# progress log arrives at once when the sweep ends
|
# progress log arrives at once
|
||||||
fflush()
|
fflush()
|
||||||
while (next_pct <= pct) next_pct += 5
|
while (next_pct <= pct) next_pct += 5
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Exit 0 when FRIGATE_ROOT_SERVICES names the given service.
|
# Exit 0 when FRIGATE_ROOT_SERVICES names the given service. Membership only:
|
||||||
# Membership only: FRIGATE_RUN_AS_ROOT precedence and the euid check stay in
|
# the euid and FRIGATE_RUN_AS_ROOT checks stay in the callers.
|
||||||
# the callers, which each combine them differently.
|
|
||||||
#
|
#
|
||||||
# Usage: service-runs-as-root SERVICE
|
# Usage: service-runs-as-root SERVICE
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
# Copied to /tmp/nginx/conf at startup and loaded with -c from there. Relative
|
# Loaded with -c from the /tmp/nginx/conf copy: relative includes follow the -c
|
||||||
# includes resolve against the -c file, but every other path directive resolves
|
# file, all other path directives follow --prefix and must stay absolute.
|
||||||
# against the compile-time --prefix, so non-include paths must stay absolute.
|
|
||||||
|
|
||||||
daemon off;
|
daemon off;
|
||||||
# Ignored by a non-root master; required by FRIGATE_RUN_AS_ROOT so workers
|
# ignored by a non-root master; keeps workers root under FRIGATE_RUN_AS_ROOT
|
||||||
# stay root instead of the compiled-in default user
|
|
||||||
user root;
|
user root;
|
||||||
worker_processes auto;
|
worker_processes auto;
|
||||||
|
|
||||||
|
|||||||
+2
-3
@@ -231,9 +231,8 @@ class FrigateApp:
|
|||||||
|
|
||||||
migrate_db.close()
|
migrate_db.close()
|
||||||
|
|
||||||
# A root frigate service (FRIGATE_ROOT_SERVICES) creates these as
|
# a root frigate service creates these as root; wal and shm recreated
|
||||||
# root. The wal and shm journals can be recreated as root later in
|
# later in the run are realigned by the per-boot /config sweep
|
||||||
# the run; the per-boot sweep of /config realigns those on restart.
|
|
||||||
for db_file in (
|
for db_file in (
|
||||||
self.config.database.path,
|
self.config.database.path,
|
||||||
f"{self.config.database.path}-wal",
|
f"{self.config.database.path}-wal",
|
||||||
|
|||||||
@@ -929,8 +929,7 @@ class RecordingMaintainer(threading.Thread):
|
|||||||
)
|
)
|
||||||
|
|
||||||
os.makedirs(directory, exist_ok=True)
|
os.makedirs(directory, exist_ok=True)
|
||||||
# makedirs creates the date and hour levels too; own every level so
|
# own every level makedirs creates so the host user can prune recordings
|
||||||
# the host user can prune old recordings
|
|
||||||
level = directory
|
level = directory
|
||||||
while level != RECORD_DIR:
|
while level != RECORD_DIR:
|
||||||
chown_to_runtime(level)
|
chown_to_runtime(level)
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ class FakePwEntry:
|
|||||||
class TestGetRuntimeIds(unittest.TestCase):
|
class TestGetRuntimeIds(unittest.TestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
ownership.get_runtime_ids.cache_clear()
|
ownership.get_runtime_ids.cache_clear()
|
||||||
# and again on the way out, so a value cached under this test's
|
# a value cached under this test's patches must not leak into later modules
|
||||||
# patches never leaks into later test modules in the same process
|
|
||||||
self.addCleanup(ownership.get_runtime_ids.cache_clear)
|
self.addCleanup(ownership.get_runtime_ids.cache_clear)
|
||||||
|
|
||||||
@patch("frigate.util.ownership.os.geteuid", return_value=1000)
|
@patch("frigate.util.ownership.os.geteuid", return_value=1000)
|
||||||
@@ -53,8 +52,7 @@ class TestGetRuntimeIds(unittest.TestCase):
|
|||||||
class TestChownToRuntime(unittest.TestCase):
|
class TestChownToRuntime(unittest.TestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
ownership.get_runtime_ids.cache_clear()
|
ownership.get_runtime_ids.cache_clear()
|
||||||
# and again on the way out, so a value cached under this test's
|
# a value cached under this test's patches must not leak into later modules
|
||||||
# patches never leaks into later test modules in the same process
|
|
||||||
self.addCleanup(ownership.get_runtime_ids.cache_clear)
|
self.addCleanup(ownership.get_runtime_ids.cache_clear)
|
||||||
|
|
||||||
@patch("frigate.util.ownership.os.chown")
|
@patch("frigate.util.ownership.os.chown")
|
||||||
|
|||||||
Reference in New Issue
Block a user