#!/usr/bin/env bash # ============================================================================= # 20-cifs — NAS mounts for the 8 shares Plex actually uses. # # Shares confirmed live from the Windows box 2026-07-27 (exact names/casing): # Audio Books · Education Videos · Health · Home Movies · media # Music Organized · Pictures · Radio Shows (+ "Share" — NOT mounted) # # "Share" is mounted on Windows today but is not a Plex library root, so it is # deliberately left out. Every entry below maps to a real library section. # # 11 Plex library roots resolve onto these 8 mounts: # Audio Books -> /mnt/nas/audiobooks # Music Organized -> /mnt/nas/music-organized # Radio Shows -> /mnt/nas/radio-shows # Pictures -> /mnt/nas/pictures/Plex Pictures # Health -> /mnt/nas/health # Home Movies -> /mnt/nas/home-movies # Education Videos -> /mnt/nas/education-videos # media -> /mnt/nas/media/{movies,tvshows,music,audiobooks} # # WHY EACH OPTION IS THERE — none of these are decoration: # nofail an unreachable NAS must NOT drop a headless # box into an emergency shell. There is no # keyboard attached to type the root password. # _netdev tells systemd this needs the network up. # x-systemd.automount mount on first access rather than at boot, so # a slow NAS never stretches boot time. # x-systemd.mount-timeout=30 bounded failure instead of an indefinite hang. # x-systemd.idle-timeout=600 unmount when idle; keeps stale handles rare. # vers=3.1.1 dialect confirmed from the Windows box. # uid/gid=3000 MUST match Plex's PUID/PGID or every file is # permission-denied. # \040 fstab field separator is whitespace; share # names with spaces MUST escape them. # ============================================================================= set -uo pipefail CRED="/etc/cifs/korval.cred" NAS="10.0.1.254" MEDIA_UID=3000 MEDIA_GID=3000 MARK_BEGIN="# >>> mediabox NAS mounts (managed by 20-cifs.sh) >>>" 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-nas | local mount point SHARES=( "Audio Books|/mnt/nas/audiobooks" "Education Videos|/mnt/nas/education-videos" "Health|/mnt/nas/health" "Home Movies|/mnt/nas/home-movies" "media|/mnt/nas/media" "Music Organized|/mnt/nas/music-organized" "Pictures|/mnt/nas/pictures" "Radio Shows|/mnt/nas/radio-shows" ) # --- --verify mode: check mounts, change nothing ---------------------------- if [ "${1:-}" = "--verify" ]; then echo " verifying NAS mounts" rc=0 if [ ! -s "$CRED" ]; then echo " [FAIL] $CRED is empty — write the NAS credentials first" exit 1 fi for entry in "${SHARES[@]}"; do mp="${entry#*|}" if ls "$mp" >/dev/null 2>&1 && mountpoint -q "$mp"; then printf ' [ok] %-28s %s\n' "$(basename "$mp")" "$(df -h --output=size "$mp" 2>/dev/null | tail -1 | tr -d ' ')" else printf ' [FAIL] %-28s not mounted\n' "$(basename "$mp")" rc=1 fi done exit $rc fi echo " writing fstab entries for ${#SHARES[@]} shares" install -d -m 0700 /etc/cifs [ -f "$CRED" ] || install -m 0600 /dev/null "$CRED" chmod 600 "$CRED" # The credentials file is created EMPTY by autoinstall on purpose. The real # password is written post-boot over the MCP so it never rides on the USB. if [ ! -s "$CRED" ]; then cat <<'CREDNOTE' NOTE: /etc/cifs/korval.cred is empty. That is expected at this stage. The mounts will fail (harmlessly, thanks to nofail) until you write: printf 'username=\npassword=\ndomain=WORKGROUP\n' \ > /etc/cifs/korval.cred chmod 600 /etc/cifs/korval.cred No quotes. No spaces around '='. Trailing newline required. CREDNOTE fi for entry in "${SHARES[@]}"; do mp="${entry#*|}" install -d -m 0755 "$mp" chown ${MEDIA_UID}:${MEDIA_GID} "$mp" done # Rebuild only our managed block; never touch the rest of fstab. tmp="$(mktemp)" awk -v b="$MARK_BEGIN" -v e="$MARK_END" ' $0 == b { skip=1 } !skip { print } $0 == e { skip=0 } ' /etc/fstab > "$tmp" { printf '%s\n' "$MARK_BEGIN" for entry in "${SHARES[@]}"; do share="${entry%%|*}" mp="${entry#*|}" # escape spaces as \040 in BOTH fields (mount points here have none, but # the escaping is applied uniformly so a future renamed mount is safe) esc_share="${share// /\\040}" esc_mp="${mp// /\\040}" printf '//%s/%s %s cifs %s 0 0\n' "$NAS" "$esc_share" "$esc_mp" "$OPTS" done printf '%s\n' "$MARK_END" } >> "$tmp" # Sanity: never install an fstab that lost the root entry. if ! awk '$2=="/" && $1 !~ /^#/' "$tmp" | grep -q .; then echo " [FAIL] refusing to write fstab — root entry missing from generated file" rm -f "$tmp"; exit 1 fi cp -a /etc/fstab "/etc/fstab.bak.$(date +%Y%m%d%H%M%S)" install -m 0644 "$tmp" /etc/fstab rm -f "$tmp" systemctl daemon-reload echo " fstab updated (backup written alongside). Managed block:" sed -n "/${MARK_BEGIN//\//\\/}/,/${MARK_END//\//\\/}/p" /etc/fstab | sed 's/^/ /' if [ -s "$CRED" ]; then echo " credentials present — attempting mounts" for entry in "${SHARES[@]}"; do mp="${entry#*|}" if timeout 40 mount "$mp" 2>/dev/null || mountpoint -q "$mp"; then printf ' [ok] %s\n' "$mp" else printf ' [warn] %s did not mount (check credentials / share name)\n' "$mp" fi done else echo " skipping mount attempts until credentials are written" fi exit 0