From 9e720f4fc7f009451f142e52ba4618fb40510efc Mon Sep 17 00:00:00 2001 From: None <190783071+CodeBormen@users.noreply.github.com> Date: Tue, 17 Mar 2026 18:27:19 -0500 Subject: [PATCH] fix: handle chown failures gracefully on external mounts DATA_DIRS chown failures (NFS, SMB/CIFS, FUSE) crashed the container under set -e. The old image never chowned these directories, so users with external mounts had a working setup that broke on upgrade with zero config changes. - Collect mkdir and chown failures per-directory instead of crashing - Emit a single consolidated warning listing all affected directories with current ownership and remediation steps - Container continues to start; Django reports at runtime if it cannot write to a specific directory - Local volumes are unaffected: chown still runs and succeeds silently --- docker/init/03-init-dispatcharr.sh | 74 +++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 12 deletions(-) diff --git a/docker/init/03-init-dispatcharr.sh b/docker/init/03-init-dispatcharr.sh index b580fe1e..2e66e3ee 100644 --- a/docker/init/03-init-dispatcharr.sh +++ b/docker/init/03-init-dispatcharr.sh @@ -1,6 +1,9 @@ #!/bin/bash -# Define directories that need to exist and be owned by PUID:PGID +# Define directories that need to exist and be owned by PUID:PGID. +# DATA_DIRS may reside on external mounts (NFS, SMB/CIFS, FUSE) where +# mkdir and chown can fail. Failures are collected and reported as a +# single consolidated warning so the container still starts. DATA_DIRS=( "/data/backups" "/data/logos" @@ -14,17 +17,24 @@ DATA_DIRS=( "/data/scripts" ) +# APP_DIRS live on the image layer and are always locally writable. APP_DIRS=( "/app/logo_cache" "/app/media" "/app/static" ) -# Create all directories -for dir in "${DATA_DIRS[@]}" "${APP_DIRS[@]}"; do +# Create app directories (image layer — always writable) +for dir in "${APP_DIRS[@]}"; do mkdir -p "$dir" done +# Create data directories, tolerating failures on external mounts +_failed_mkdir=() +for dir in "${DATA_DIRS[@]}"; do + _mkdir_err=$(mkdir -p "$dir" 2>&1) || _failed_mkdir+=("$dir ($_mkdir_err)") +done + # Ensure /app itself is owned by PUID:PGID (needed for uwsgi socket creation) if [ "$(id -u)" = "0" ] && [ -d "/app" ]; then if [ "$(stat -c '%u:%g' /app)" != "$PUID:$PGID" ]; then @@ -50,11 +60,16 @@ fi # NOTE: mac doesn't run as root, so only manage permissions # if this script is running as root if [ "$(id -u)" = "0" ]; then - # Fix data directories (non-recursive to avoid touching user files) + # Fix data directories (non-recursive to avoid touching user files). + # Failures are collected rather than fatal — directories may be on + # external mounts (NFS, SMB/CIFS, FUSE) that reject chown. + _failed_chown=() for dir in "${DATA_DIRS[@]}"; do - if [ -d "$dir" ] && [ "$(stat -c '%u:%g' "$dir")" != "$PUID:$PGID" ]; then - echo "Fixing ownership for $dir" - chown "$PUID:$PGID" "$dir" + if [ -d "$dir" ] && [ "$(stat -c '%u:%g' "$dir" 2>/dev/null)" != "$PUID:$PGID" ]; then + _chown_err=$(chown "$PUID:$PGID" "$dir" 2>&1) || { + _current_owner=$(stat -c '%u:%g' "$dir" 2>/dev/null || echo "unknown") + _failed_chown+=("$dir (current: $_current_owner, error: $_chown_err)") + } fi done @@ -70,11 +85,46 @@ if [ "$(id -u)" = "0" ]; then # No secondary check needed here — duplicating it could chown without updating # the sentinel, creating inconsistent state. - # Fix /data directory ownership (non-recursive) - if [ -d "/data" ] && [ "$(stat -c '%u:%g' /data)" != "$PUID:$PGID" ]; then - echo "Fixing ownership for /data (non-recursive)" - chown "$PUID:$PGID" /data + # Fix /data directory ownership (non-recursive). + # Tolerates failure for the same external-mount reasons as DATA_DIRS. + if [ -d "/data" ] && [ "$(stat -c '%u:%g' /data 2>/dev/null)" != "$PUID:$PGID" ]; then + _chown_err=$(chown "$PUID:$PGID" /data 2>&1) || { + _current_owner=$(stat -c '%u:%g' /data 2>/dev/null || echo "unknown") + _failed_chown+=("/data (current: $_current_owner, error: $_chown_err)") + } fi - chmod +x /data + chmod +x /data 2>/dev/null || true +fi + +# Consolidated warning for all mkdir/chown failures. +# Emitted outside the root guard so non-root mkdir failures are also reported. +if [ ${#_failed_mkdir[@]} -gt 0 ] || [ ${#_failed_chown[@]} -gt 0 ]; then + echo "" + echo "================================================================" + echo "WARNING: Some data directories could not be created or updated." + echo " This typically occurs with NFS, SMB/CIFS, or other external" + echo " mounts that restrict ownership changes." + echo "" + if [ ${#_failed_mkdir[@]} -gt 0 ]; then + echo " Could not create:" + for entry in "${_failed_mkdir[@]}"; do + echo " - $entry" + done + echo "" + fi + if [ ${#_failed_chown[@]} -gt 0 ]; then + echo " Could not set ownership to $PUID:$PGID:" + for entry in "${_failed_chown[@]}"; do + echo " - $entry" + done + echo "" + fi + echo " To fix, either:" + echo " 1. Set PUID/PGID to match your mount's owner" + echo " 2. Fix ownership on the host/NAS:" + echo " sudo chown $PUID:$PGID " + echo " 3. For SMB/CIFS: set uid=$PUID,gid=$PGID in mount options" + echo "================================================================" + echo "" fi