massive update. Master conf split, now modular with a load sceriprt to drive all configs to scripts. with unraid scpecific safeguard tests , and improved standardized ux. including dynamic host detect, who am i who else it there. EVERY SINGLE SCRIPT UPDATED. DEBATING THAT THIS IS ACUALLY V2

This commit is contained in:
2026-05-03 17:16:49 -04:00
parent 2691a35e80
commit ec7de648dc
72 changed files with 25640 additions and 14629 deletions
+124 -63
View File
@@ -1,64 +1,93 @@
#!/bin/bash
# -----------------------------------------------------------------------------------------------
# --------------------------------- Bulk Permissions Repair ------------------------------------
# -----------------------------------------------------------------------------------------------
# Applies correct permissions to a single share or specific path.
# Faster than running media_shares_permissions.sh which processes all shares.
# Use when a specific share has wrong ownership or permissions after:
# - A failed transfer that left files owned by wrong user
# - A container writing files as root instead of nobody:users
# - Manual file operations that bypassed normal permission handling
# ==============================================================================================
# ============================= Bulk Permissions Repair ========================================
# ==============================================================================================
# Applies correct ownership and permissions to one or more specific paths.
# Faster than running media_shares_permissions.sh which processes all configured shares.
#
# ── WHEN TO USE ───────────────────────────────────────────────────────────────────────────────
# Use for targeted repair after:
# - A failed transfer that left files owned by wrong user (root:root from rsync)
# - A container writing as root instead of nobody:users — before PUID/PGID was fixed
# - Manual file copies that bypassed normal permission handling
# - A new share that needs permissions applied before the next nightly run
# - A large rsync that imported thousands of files before media_shares_permissions.sh ran
#
# Usage:
# ── PERMISSIONS MODEL ─────────────────────────────────────────────────────────────────────────
# Directories: PERMISSIONS_DIR_MODE (default 755)
# Owner (nobody) — rwx enter, list, create files
# Group (users) — r-x enter and list
# Others — r-x Samba guests can browse
#
# Files: PERMISSIONS_FILE_MODE (default 664)
# Owner (nobody) — rw read + write
# Group (users) — rw arrs can import and rename
# Others — r Samba guests can read
# No execute bit — media files are never executable
#
# ── DIAGNOSTIC — HIGH WRONG OWNER COUNT ───────────────────────────────────────────────────────
# This script counts files with wrong ownership before applying the fix.
# A high count on a share that was recently written → a container has wrong PUID/PGID.
# Fix: add PUID=99 PGID=100 to the container's Docker template.
# Common culprits: SABnzbd, qBittorrent, slskd.
#
# ── SAFEGUARDS ────────────────────────────────────────────────────────────────────────────────
# Root check — required for chown
# Path existence check — skips missing paths with error
# Separate passes — directories and files chmod'd separately for correctness
# validate_unraid_cmd — notify validated before use
# Silent on success — only failures produce visible output
#
# ── USAGE ─────────────────────────────────────────────────────────────────────────────────────
# bulk_permissions_repair.sh /mnt/user/Movies
# bulk_permissions_repair.sh /mnt/user/Movies --dry-run
# bulk_permissions_repair.sh /mnt/user/Movies /mnt/user/Tv_Shows
#
# Uses PERMISSIONS_MODE and PERMISSIONS_OWNER from Master.conf.
# Supports --dry-run to show what would be changed without applying.
# -----------------------------------------------------------------------------------------------
# bulk_permissions_repair.sh /mnt/user/Movies --dry-run
# bulk_permissions_repair.sh /mnt/user/Movies --log
# ==============================================================================================
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/../Master.conf"
source "$SCRIPT_DIR/../common.sh"
source "$SCRIPT_DIR/../load_config.sh"
parse_args "$@"
# -----------------------------------------------------------------------------------------------
# ━━━ $ICON_GEAR Setup ━━━
# -----------------------------------------------------------------------------------------------
echo ""
echo "━━━ $ICON_GEAR Setup ━━━"
# ==============================================================================================
# ━━━ Setup ━━━
# ==============================================================================================
if [[ "$EUID" -ne 0 ]]; then
error "Must be run as root"
error "Must be run as root — chown requires root"
exit 1
fi
success "Running as root"
validate_unraid_cmd \
"/usr/local/emhttp/plugins/dynamix/scripts/notify" \
"" "" \
"unRAID notify script" || warn "unRAID notify script not found — native notifications disabled"
# detect_hosts() sets MY_ID — used in summary
detect_hosts
if [[ ${#PARSED_ARGS[@]} -eq 0 ]]; then
error "No paths specified"
error "Usage: bulk_permissions_repair.sh /path/to/share [/another/path]"
error " bulk_permissions_repair.sh /mnt/user/Movies --dry-run"
error "Usage: bulk_permissions_repair.sh /path/to/share [/another/path] [--dry-run]"
exit 1
fi
info "Mode: $PERMISSIONS_MODE"
info "Owner: $PERMISSIONS_OWNER"
log "Dir mode: ${PERMISSIONS_DIR_MODE:-755}"
log "File mode: ${PERMISSIONS_FILE_MODE:-664}"
log "Owner: $PERMISSIONS_OWNER"
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no permissions will be changed"
# -----------------------------------------------------------------------------------------------
# ━━━ $ICON_PERMS Apply Permissions ━━━
# -----------------------------------------------------------------------------------------------
# ==============================================================================================
# ━━━ Apply Permissions ━━━
# ==============================================================================================
echo ""
echo "━━━ $ICON_PERMS Permissions Repair ━━━"
echo "━━━ $ICON_PERMS Permissions Repair$MY_ID ━━━"
START=$(date +%s)
PASS=()
FAIL=()
TOTAL_WRONG_OWNER=0
for share_path in "${PARSED_ARGS[@]}"; do
[[ -z "$share_path" ]] && continue
@@ -72,62 +101,94 @@ for share_path in "${PARSED_ARGS[@]}"; do
continue
fi
# Count files for progress context
# Count files for context — warn level so user knows what they're in for on large shares
FILE_COUNT=$(find "$share_path" -type f 2>/dev/null | wc -l)
DIR_COUNT=$(find "$share_path" -type d 2>/dev/null | wc -l)
DIR_COUNT=$(find "$share_path" -type d 2>/dev/null | wc -l)
SIZE=$(du -sh "$share_path" 2>/dev/null | cut -f1)
warn "$share_path$FILE_COUNT files, $DIR_COUNT dirs ($SIZE)"
info "$share_path$FILE_COUNT files, $DIR_COUNT dirs ($SIZE)"
# Count files with wrong ownership before fixing — diagnostic
WRONG_OWNER=$(find "$share_path" \( ! -user nobody -o ! -group users \) \
2>/dev/null | wc -l)
if [[ "$WRONG_OWNER" -gt 0 ]]; then
warn "$WRONG_OWNER file(s) with wrong ownership — fixing..."
if [[ "$WRONG_OWNER" -gt 500 ]]; then
warn "High wrong-owner count — check container PUID/PGID settings (should be PUID=99 PGID=100)"
warn "Common culprits: SABnzbd, qBittorrent, slskd"
fi
TOTAL_WRONG_OWNER=$(( TOTAL_WRONG_OWNER + WRONG_OWNER ))
else
log "Ownership already correct — applying mode only"
fi
if [[ "$DRY_RUN" == true ]]; then
warn "DRY RUN — would apply: chmod -R $PERMISSIONS_MODE $share_path"
warn "DRY RUN — would apply: chown -R $PERMISSIONS_OWNER $share_path"
warn "DRY RUN — would apply:"
warn " chown -R $PERMISSIONS_OWNER $share_path"
warn " find -type d → chmod ${PERMISSIONS_DIR_MODE:-755}"
warn " find -type f → chmod ${PERMISSIONS_FILE_MODE:-664}"
PASS+=("$(basename "$share_path")")
continue
fi
# Apply ownership first — chmod after so files are owned correctly before mode change
info "Applying ownership: $PERMISSIONS_OWNER..."
chown -R "$PERMISSIONS_OWNER" "$share_path" 2>/dev/null
CHOWN_EXIT=$?
CHOWN_OK=true
CHMOD_DIR_OK=true
CHMOD_FILE_OK=true
info "Applying permissions: $PERMISSIONS_MODE..."
chmod -R "$PERMISSIONS_MODE" "$share_path" 2>/dev/null
CHMOD_EXIT=$?
# Apply ownership first
log "Applying ownership: $PERMISSIONS_OWNER..."
chown -R "$PERMISSIONS_OWNER" "$share_path" 2>/dev/null || CHOWN_OK=false
if [[ "$CHOWN_EXIT" -eq 0 && "$CHMOD_EXIT" -eq 0 ]]; then
success "$ICON_UNLOCKED $(basename "$share_path") — permissions applied"
# Apply directory permissions — separate pass (dirs need execute bit)
log "Applying directory permissions: ${PERMISSIONS_DIR_MODE:-755}..."
find "$share_path" -type d \
-exec chmod "${PERMISSIONS_DIR_MODE:-755}" {} + 2>/dev/null || CHMOD_DIR_OK=false
# Apply file permissions — no execute bit on media files
log "Applying file permissions: ${PERMISSIONS_FILE_MODE:-664}..."
find "$share_path" -type f \
-exec chmod "${PERMISSIONS_FILE_MODE:-664}" {} + 2>/dev/null || CHMOD_FILE_OK=false
if [[ "$CHOWN_OK" == true && "$CHMOD_DIR_OK" == true && "$CHMOD_FILE_OK" == true ]]; then
log "$ICON_UNLOCKED $(basename "$share_path") — permissions applied ✅"
PASS+=("$(basename "$share_path")")
else
error "$(basename "$share_path") permission repair failed"
error "$(basename "$share_path") — repair failed"
error " chown: $CHOWN_OK chmod dirs: $CHMOD_DIR_OK chmod files: $CHMOD_FILE_OK"
FAIL+=("$(basename "$share_path")")
fi
done
END=$(date +%s)
# -----------------------------------------------------------------------------------------------
# ━━━ $ICON_SUMMARY Summary ━━━
# -----------------------------------------------------------------------------------------------
# ==============================================================================================
# ━━━ Summary ━━━
# ==============================================================================================
echo ""
echo "━━━━━ $ICON_SUMMARY PERMISSIONS REPAIR SUMMARY ━━━━━"
echo "$ICON_PERMS Mode: $PERMISSIONS_MODE"
echo "$ICON_PERMS Owner: $PERMISSIONS_OWNER"
echo "$ICON_TIME Duration: $(format_duration $((END - START)))"
echo "$ICON_HOST Identity: $MY_ID ($LOCAL_SERVER_NAME)"
echo "$ICON_PERMS Dir mode: ${PERMISSIONS_DIR_MODE:-755}"
echo "$ICON_PERMS File mode: ${PERMISSIONS_FILE_MODE:-664}"
echo "$ICON_PERMS Owner: $PERMISSIONS_OWNER"
echo "$ICON_TIME Duration: $(format_duration $(( END - START )))"
echo ""
echo " $ICON_SUCCESS Pass: ${#PASS[@]} $ICON_ERROR Fail: ${#FAIL[@]}"
echo ""
[[ ${#PASS[@]} -gt 0 ]] && for p in "${PASS[@]}"; do echo " $ICON_UNLOCKED $p"; done
[[ ${#FAIL[@]} -gt 0 ]] && for f in "${FAIL[@]}"; do echo " $ICON_ERROR $f"; done
[[ ${#PASS[@]} -gt 0 ]] && log "Pass: ${PASS[*]}"
[[ ${#FAIL[@]} -gt 0 ]] && echo "$ICON_ERROR Fail: ${FAIL[*]}"
if [[ "$TOTAL_WRONG_OWNER" -gt 0 ]]; then
warn "Total wrong-owner files fixed: $TOTAL_WRONG_OWNER"
fi
echo ""
if [[ "$DRY_RUN" == true ]]; then
echo "$ICON_WARN Status: DRY RUN — no changes made"
warn "DRY RUN — no changes made"
elif [[ ${#FAIL[@]} -gt 0 ]]; then
echo "$ICON_ERROR Status: SOME REPAIRS FAILED"
notify "Permissions repair failed on $(hostname) failed shares: ${FAIL[*]}" "Permissions Repair" "warning"
notify "Permissions repair failed on $(hostname)${FAIL[*]}" \
"Permissions Repair" "warning"
else
echo "$ICON_DONE Status: $ICON_SUCCESS DONE"
notify "Permissions repair complete on $(hostname)${#PASS[@]} share(s) repaired" "Permissions Repair" "normal"
log "$ICON_DONE Status: done — ${#PASS[@]} path(s) repaired"
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
[[ ${#FAIL[@]} -gt 0 ]] && exit 1
exit 0