diff --git a/scripts/20-cifs.sh b/scripts/20-cifs.sh index 6be22ab..0104b44 100755 --- a/scripts/20-cifs.sh +++ b/scripts/20-cifs.sh @@ -1,16 +1,22 @@ #!/usr/bin/env bash -# ============================================================================= +# ===================================================================================== # 20-cifs — NAS mounts, named to match the Plex database exactly. # -# SIX shares. Confirmed live from the Windows box and cross-checked against -# the Plex database 2026-07-27: +# SEVEN shares. The six Plex library shares are mounted READ-ONLY; media_pc is the +# single share this box may write to. The six were confirmed live from the Windows +# box and cross-checked against the Plex database 2026-07-27; media_pc added +# 2026-07-31 as the box's write location (PMS backup, Calibre, "Nikola iPad"): # -# media 1,360 movies + 23,493 episodes + all audio (~26.5 TB) -# Radio Shows 236 files 1.6 GB -# Education Videos 215 files 50.0 GB -# Health 30 files 14.4 GB -# Home Movies 51 files 28.4 GB -# Pictures 385 files 0.9 GB +# media 1,360 movies + 23,493 episodes + all audio (~26.5 TB) [ro] +# Radio Shows 236 files 1.6 GB [ro] +# Education Videos 215 files 50.0 GB [ro] +# Health 30 files 14.4 GB [ro] +# Home Movies 51 files 28.4 GB [ro] +# Pictures 385 files 0.9 GB [ro] +# media_pc this box's write share [rw] +# +# The NAS account (mediabox) is read-only on the six library shares AT THE SYNOLOGY +# TOO — the ro mount option here is belt-and-braces, not the enforcement. # # NOT mounted, deliberately: # Share not a Plex library root @@ -19,7 +25,7 @@ # All audio actually lives under media/audiobooks and media/music. The two # empty roots are vestigial and are deleted by migration/remap.sql. # -# --------------------------------------------------------------------------- +# ----------------------------------------------------------------------------------- # MOUNT POINTS MIRROR THE SHARE NAMES, VERBATIM. # # /mnt/nas/Home Movies — capital letters, and yes, a space in the path. @@ -33,7 +39,7 @@ # The same paths are bind-mounted into the Plex container at the same # location, so the database, the host and the container all agree with no # further translation anywhere. -# --------------------------------------------------------------------------- +# ----------------------------------------------------------------------------------- # # WHY EACH OPTION IS THERE — none of these are decoration: # nofail an unreachable NAS must NOT drop a headless @@ -48,10 +54,12 @@ # arrsstack talks to this same NAS at 3.0. # uid/gid=3000 MUST equal Plex's PUID/PGID or every file is # permission-denied. +# ro (libraries only) belt-and-braces with the Synology-side +# read-only permission. media_pc omits it. # \040 fstab splits fields on whitespace, so spaces # must be escaped in BOTH the share name and # the mount point. -# ============================================================================= +# ===================================================================================== set -uo pipefail CRED="/etc/cifs/korval.cred" @@ -64,7 +72,8 @@ MARK_END="# <<< mediabox NAS mounts <<<" OPTS="credentials=${CRED},vers=3.1.1,uid=${MEDIA_UID},gid=${MEDIA_GID},file_mode=0664,dir_mode=0775,iocharset=utf8,nofail,_netdev,x-systemd.automount,x-systemd.mount-timeout=30,x-systemd.idle-timeout=600" # Share name on the NAS == directory name under /mnt/nas. Do not "tidy" these. -SHARES=( +# Six Plex library shares — mounted read-only. +SHARES_RO=( "media" "Radio Shows" "Education Videos" @@ -72,10 +81,23 @@ SHARES=( "Home Movies" "Pictures" ) +# The one write share: PMS backup, Calibre and "Nikola iPad" live here. +SHARES_RW=( + "media_pc" +) +SHARES=( "${SHARES_RO[@]}" "${SHARES_RW[@]}" ) mp_for() { printf '/mnt/nas/%s' "$1"; } -# --- --verify mode: check mounts, change nothing ---------------------------- +opts_for() { + local s="$1" rw + for rw in "${SHARES_RW[@]}"; do + if [ "$s" = "$rw" ]; then printf '%s' "$OPTS"; return; fi + done + printf '%s,ro' "$OPTS" +} + +# --- --verify mode: check mounts, change nothing ---------------------------------- if [ "${1:-}" = "--verify" ]; then echo " verifying NAS mounts" rc=0 @@ -92,6 +114,25 @@ if [ "${1:-}" = "--verify" ]; then rc=1 fi done + # Write-permission sanity: libraries must refuse writes, media_pc must accept. + if mountpoint -q "/mnt/nas/media"; then + if touch "/mnt/nas/media/.wtest-mediabox" 2>/dev/null; then + rm -f "/mnt/nas/media/.wtest-mediabox" + printf ' [FAIL] %s\n' "media accepted a write — the account or mount should be read-only" + rc=1 + else + printf ' [ok] %s\n' "media refused a write (read-only confirmed)" + fi + fi + if mountpoint -q "/mnt/nas/media_pc"; then + if touch "/mnt/nas/media_pc/.wtest-mediabox" 2>/dev/null; then + rm -f "/mnt/nas/media_pc/.wtest-mediabox" + printf ' [ok] %s\n' "media_pc write test passed" + else + printf ' [FAIL] %s\n' "media_pc refused a write — check share permissions" + rc=1 + fi + fi exit $rc fi @@ -133,7 +174,7 @@ awk -v b="$MARK_BEGIN" -v e="$MARK_END" ' mp="$(mp_for "$s")" esc_share="${s// /\\040}" esc_mp="${mp// /\\040}" - printf '//%s/%s %s cifs %s 0 0\n' "$NAS" "$esc_share" "$esc_mp" "$OPTS" + printf '//%s/%s %s cifs %s 0 0\n' "$NAS" "$esc_share" "$esc_mp" "$(opts_for "$s")" done printf '%s\n' "$MARK_END" } >> "$tmp"