From 7f175e1a17df2afa12bb45bc02eafd82e11a6c0d Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Mon, 24 Aug 2026 11:04:06 -0500 Subject: [PATCH] report progress during the ownership sweep --- .../main/rootfs/usr/local/bin/fix-ownership | 34 ++++++++++++++++--- docker/migration/fix-permissions.sh | 10 ++++++ docs/docs/configuration/non_root.md | 12 +++++++ 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/docker/main/rootfs/usr/local/bin/fix-ownership b/docker/main/rootfs/usr/local/bin/fix-ownership index 07f21c3f1a..d899dae2cd 100755 --- a/docker/main/rootfs/usr/local/bin/fix-ownership +++ b/docker/main/rootfs/usr/local/bin/fix-ownership @@ -76,6 +76,8 @@ for path in "$@"; do continue fi + echo "[INFO] fix-ownership: scanning ${path} for ownership mismatches; this may take a while on large filesystems" + # find may fail mid-walk on a live volume (file deleted under it) or on a # stale mount. Tolerate it rather than aborting under errexit, but never # read a failed scan as "nothing to do": that would record the sweep as @@ -98,17 +100,41 @@ for path in "$@"; do echo "[WARN] fix-ownership: ${path} contains symlinked directories; ownership behind them is not managed and must be aligned by hand" fi - echo "[WARN] fix-ownership: adjusting ownership of ${count} entries under ${path}; on large recordings volumes this can take a long time" + echo "[WARN] fix-ownership: adjusting ownership of ${count} entries under ${path}" if [[ "$dry_run" -eq 1 ]]; then echo "[INFO] fix-ownership: dry run, not changing ${path}" continue fi - find "$path" \( -not -uid "$target_uid" -o -not -gid "$target_gid" \) \ - -exec chown -h "${target_uid}:${target_gid}" {} + || { + # -print feeds the progress counter while -exec {} + keeps the chown + # batched; the scan above is what makes a real percentage possible + started=$SECONDS + if find "$path" \( -not -uid "$target_uid" -o -not -gid "$target_gid" \) \ + -print -exec chown -h "${target_uid}:${target_gid}" {} + \ + | awk -v total="$count" -v path="$path" ' + BEGIN { next_pct = 5 } + { + pct = int(NR * 100 / total) + if (pct > 100) pct = 100 + if (pct >= next_pct) { + printf "[INFO] fix-ownership: %s %d%% (%d/%d entries)\n", path, pct, NR, total + # mawk block-buffers to a pipe; without this the whole + # progress log arrives at once when the sweep ends + fflush() + while (next_pct <= pct) next_pct += 5 + } + }'; then + elapsed=$((SECONDS - started)) + if [[ "$elapsed" -ge 60 ]]; then + elapsed="$((elapsed / 60))m $((elapsed % 60))s" + else + elapsed="${elapsed}s" + fi + echo "[INFO] fix-ownership: finished ${path} in ${elapsed}" + else swept_clean=0 echo "[WARN] fix-ownership: some entries under ${path} could not be updated (deleted mid-sweep or chown denied); will retry on next mismatch" - } + fi done # go2rtc (separate user) must be able to REACH its HomeKit state in /config. diff --git a/docker/migration/fix-permissions.sh b/docker/migration/fix-permissions.sh index 0e135a3e7a..94a5f7b66c 100755 --- a/docker/migration/fix-permissions.sh +++ b/docker/migration/fix-permissions.sh @@ -36,6 +36,16 @@ if ! [[ "$puid" =~ ^[0-9]+$ && "$pgid" =~ ^[0-9]+$ ]]; then fi echo "[INFO] Using image ${IMAGE} (override with FRIGATE_IMAGE=...)" +if ! docker image inspect "${IMAGE}" >/dev/null 2>&1; then + echo "[INFO] ${IMAGE} is not present locally and has to be pulled first; this may take a while" +fi + +if [[ -n "$dry_run_flag" ]]; then + echo "[INFO] Dry run: reporting what would change under ${config_dir} and ${media_dir}, changing nothing" +else + echo "[INFO] Aligning ${config_dir} and ${media_dir} to ${puid}:${pgid}; this may take a while on large filesystems" +fi + # shellcheck disable=SC2086 docker run --rm \ -v "${config_dir}:/config" \ diff --git a/docs/docs/configuration/non_root.md b/docs/docs/configuration/non_root.md index 94526286ed..65e789140b 100644 --- a/docs/docs/configuration/non_root.md +++ b/docs/docs/configuration/non_root.md @@ -38,6 +38,18 @@ That reports how many entries would change and touches nothing. When it looks ri ./fix-permissions.sh /path/to/your/config /path/to/your/storage ``` +Both the script and the boot sweep report progress as they go, so you can tell a slow sweep apart from a stuck one: + +``` +[INFO] fix-ownership: scanning /media/frigate for ownership mismatches; this may take a while on large filesystems +[WARN] fix-ownership: adjusting ownership of 4823941 entries under /media/frigate +[INFO] fix-ownership: /media/frigate 5% (241197/4823941 entries) +[INFO] fix-ownership: /media/frigate 10% (482394/4823941 entries) +[INFO] fix-ownership: finished /media/frigate in 12m 4s +``` + +The scan has no percentage behind it because the total isn't known until it finishes. Watch the boot sweep with `docker logs -f frigate`. + Pass `PUID` and `PGID` as the third and fourth arguments if you're not using the default `1000:1000`. The script wraps the same `fix-ownership` helper the container uses, so it's the same logic either way. Override the image it pulls with `FRIGATE_IMAGE=...` if you're not on `stable`. Once the volumes are aligned, start Frigate normally. A sentinel at `/config/.permissions_version` records what was done, so later boots skip the sweep entirely unless you change `PUID`/`PGID`.