From 93fb6b6b370c8c3c8e907bc2deed8979d6dea33c Mon Sep 17 00:00:00 2001 From: he Date: Fri, 14 Aug 2026 10:31:45 -0400 Subject: [PATCH] =?UTF-8?q?fix:=20share=20smb=20client=20persist=20?= =?UTF-8?q?=E2=80=94=20write=20a=20real=20.automount=20unit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit x-systemd.automount in a unit file's Options= is only honored when read from /etc/fstab, so persisted mounts never armed an automount; the unit was also static (no [Install]) so enable was a no-op. Result: after a reboot the share sat inactive and the disk never mounted on access. persist now writes both .mount and .automount units (the automount with WantedBy=multi-user.target) and enables/starts the automount; unpersist stops/disables/removes both units. --- DOC/AGENT_Context_Project.md | 2 +- DOC/POS.md | 2 +- DOC/howto/share.md | 5 +++-- bin/pos-share-smb-client | 33 ++++++++++++++++++++++++--------- 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/DOC/AGENT_Context_Project.md b/DOC/AGENT_Context_Project.md index f3b6b2e..41e0ed6 100644 --- a/DOC/AGENT_Context_Project.md +++ b/DOC/AGENT_Context_Project.md @@ -604,7 +604,7 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:` | `bin/pos-network-scan` | 271 | Parallel ping sweep of CIDR | | `bin/pos-share-nfs-client` | 138 | Mount NFS shares (ephemeral or persistent systemd mount units) | | `bin/pos-share-nfs-server` | 134 | Manage the NFS kernel server (status, share/unshare exports, enable/disable) | -| `bin/pos-share-smb-client` | 202 | Mount SMB/CIFS shares (ephemeral or persistent systemd mount units) | +| `bin/pos-share-smb-client` | 217 | Mount SMB/CIFS shares (ephemeral or persistent systemd mount units) | | `bin/pos-share-smb-server` | 253 | Manage the Samba server (status, share/unshare exports, users, enable/disable) | | `bin/pos-share-usb-server` | 218 | USB Redirector server control (--ls, --share; prompts when args omitted) | | `bin/pos-ssh-load-keys` | 31 | Load all SSH keys into the agent | diff --git a/DOC/POS.md b/DOC/POS.md index 157d504..0ed21fe 100644 --- a/DOC/POS.md +++ b/DOC/POS.md @@ -255,7 +255,7 @@ Subcommands that need input prompt interactively when args are omitted. | `pos share nfs server ` | `bin/pos-share-nfs-server` | Manage the NFS kernel server: `status`, `share [client]`, `unshare `, `list`, `reload`, `enable`, `disable` | Requires `nfs-kernel-server` (added to `preinstall.sh` PACKAGES). Exports live in `/etc/exports`; `share` is idempotent (replaces any existing line for the path) and runs `exportfs -ra`. Default client `*(rw,sync,no_subtree_check)` — the tool warns you to restrict it; help prints Tailscale CGNAT (`100.64.0.0/10`), WireGuard (`10.10.0.0/24`) and LAN examples. Mutating commands announce via `lib/notify.sh` | | `pos share nfs client ` | `bin/pos-share-nfs-client` | Mount and manage NFS shares: `mount `, `unmount `, `list`, `persist `, `unpersist ` | Requires `nfs-common` (added to `preinstall.sh` PACKAGES). `persist` writes a systemd `.mount` unit (`systemd-escape --path --suffix=mount`) with `After=network-online.target` / `Wants=network-online.target` — mounts only once all interfaces are up, no fstab edits to break boot — then `daemon-reload` + `enable --now`. `unpersist` stops/disables/removes the unit. `mount`/`persist` announce via `lib/notify.sh` | | `pos share smb server ` | `bin/pos-share-smb-server` | Manage the Samba server: `status`, `share [name] [--read-only|--guest|--users u1,u2]`, `unshare `, `list`, `adduser `, `deluser `, `reload`, `enable`, `disable` | Requires `samba` (added to `preinstall.sh` PACKAGES). Shares are idempotent marker blocks (`# >>> pos-managed share: ` … `# <<< end pos-managed share`) in `/etc/samba/smb.conf` — hand edits outside the markers survive; `share` validates with `testparm` before applying and hot-reloads via `smbcontrol smbd reload-config`. Defaults rw + browsable; warns when unrestricted (guest or no `valid users`). `adduser`/`deluser` manage Samba accounts via `smbpasswd`. Mutating commands announce via `lib/notify.sh` | -| `pos share smb client ` | `bin/pos-share-smb-client` | Mount and manage SMB/CIFS shares: `mount [user]`, `unmount `, `list`, `persist [user]`, `unpersist ` | Requires `cifs-utils` (added to `preinstall.sh` PACKAGES). With a user you are prompted for the Samba password — one-shot mounts use a throwaway chmod-600 credentials file, `persist` keeps one at `/etc/samba/credentials/` (chmod 600). `persist` writes a systemd `.mount` unit (`systemd-escape --path --suffix=mount`) with `x-systemd.automount` + `_netdev` — mounts on first access, never blocks boot — then `daemon-reload` + `enable --now`. `unpersist` stops/disables/removes the unit + credentials. `list` shows active mounts (`findmnt -t cifs`) **and** persistent units (as automount shares aren't mounted until first access, they'd otherwise be invisible). `mount`/`persist` announce via `lib/notify.sh` | +| `pos share smb client ` | `bin/pos-share-smb-client` | Mount and manage SMB/CIFS shares: `mount [user]`, `unmount `, `list`, `persist [user]`, `unpersist ` | Requires `cifs-utils` (added to `preinstall.sh` PACKAGES). With a user you are prompted for the Samba password — one-shot mounts use a throwaway chmod-600 credentials file, `persist` keeps one at `/etc/samba/credentials/` (chmod 600). `persist` writes systemd `.mount` **and** `.automount` units (`systemd-escape --path --suffix=mount`) with `_netdev` — the automount defers the actual mount until first access, never blocks boot — then `daemon-reload` + `enable --now` the automount. `unpersist` stops/disables/removes both units + credentials. `list` shows active mounts (`findmnt -t cifs`) **and** persistent units (as automount shares aren't mounted until first access, they'd otherwise be invisible). `mount`/`persist` announce via `lib/notify.sh` | ### communication diff --git a/DOC/howto/share.md b/DOC/howto/share.md index 7712c78..c0acc8b 100644 --- a/DOC/howto/share.md +++ b/DOC/howto/share.md @@ -231,8 +231,9 @@ mounts use a throwaway chmod-600 credentials file, `persist` keeps one at `/etc/samba/credentials/` (chmod 600) and references it from the unit. **Persistent mounts use systemd, not fstab.** `persist` writes a -`/etc/systemd/system/.mount` unit (`systemd-escape`) with -`x-systemd.automount` + `_netdev`: the share is mounted **on first access** +`/etc/systemd/system/.mount` unit (**and** a matching +`.automount` unit, both `systemd-escape`d) with `_netdev`: the +automount is enabled and armed, and the share is mounted **on first access** instead of at boot, so an unreachable SMB server can never hang boot (with fstab it could). `enable --now` arms the automount immediately. diff --git a/bin/pos-share-smb-client b/bin/pos-share-smb-client index cdb4cca..a15288d 100755 --- a/bin/pos-share-smb-client +++ b/bin/pos-share-smb-client @@ -20,9 +20,9 @@ Commands: mount [user] One-shot mount (creates local-dir if needed) unmount Unmount the share list Show active + persistent SMB mounts - persist [user] Persistent mount via a systemd .mount unit - (automount — never blocks boot) - unpersist Stop, disable and remove the mount unit + persist [user] Persistent mount via systemd .mount + .automount + units (mounts on first access — never blocks boot) + unpersist Stop, disable and remove the mount/automount units With no user, guest access is attempted. With a user, you are prompted for the Samba password — one-shot mounts use a throwaway chmod-600 credentials @@ -143,8 +143,10 @@ case "$cmd" in validate_dir "$where" unit="$(systemd-escape --path --suffix=mount "$where")" + auto_unit="${unit%.mount}.automount" unit_file="${UNIT_DIR}/${unit}" - opts="$(mount_opts "$user"),_netdev,noexec,x-systemd.automount" + auto_file="${UNIT_DIR}/${auto_unit}" + opts="$(mount_opts "$user"),_netdev,noexec" if [ -n "$user" ]; then creds_file="$SMB_CREDS_DIR/$(basename "$where")" sudo mkdir -p "$SMB_CREDS_DIR" @@ -169,10 +171,20 @@ What=${what} Where=${where} Type=cifs Options=${opts} +UNIT + cat </dev/null +[Unit] +Description=Automount of SMB share ${what} at ${where} + +[Automount] +Where=${where} + +[Install] +WantedBy=multi-user.target UNIT sudo systemctl daemon-reload - sudo systemctl enable --now "$unit" - log "Persistent SMB mount: ${what} → ${where} (${unit})" + sudo systemctl enable --now "$auto_unit" + log "Persistent SMB mount (automount): ${what} → ${where} (${auto_unit})" notify_send "SMB mount persisted: ${what} → ${where}" ;; @@ -182,17 +194,20 @@ UNIT validate_dir "$where" unit="$(systemd-escape --path --suffix=mount "$where")" + auto_unit="${unit%.mount}.automount" unit_file="${UNIT_DIR}/${unit}" + auto_file="${UNIT_DIR}/${auto_unit}" - if [ ! -f "$unit_file" ]; then + if [ ! -f "$unit_file" ] && [ ! -f "$auto_file" ]; then warn "No systemd mount unit for $where (${unit})" exit 0 fi + sudo systemctl disable "$auto_unit" 2>/dev/null || true + sudo systemctl stop "$auto_unit" 2>/dev/null || true sudo systemctl disable "$unit" 2>/dev/null || true sudo systemctl stop "$unit" 2>/dev/null || true - sudo systemctl stop "${unit%.mount}.automount" 2>/dev/null || true - sudo rm -f "$unit_file" + sudo rm -f "$unit_file" "$auto_file" sudo rm -f "$SMB_CREDS_DIR/$(basename "$where")" sudo rmdir "$SMB_CREDS_DIR" 2>/dev/null || true sudo systemctl daemon-reload