feat: usb-automount feature — udev+systemd auto-mount of USB sticks, flag-gated like autostart
features/usb-automount.sh (installed via ./install.sh --feature, flag usb-automount) mounts every unmounted removable block device at /media/<label> — world-writable via -o umask=000 (fallback plain mount), label-collision bump -2/-3, no-label -> usb-<name>. First root run self-installs the hotplug udev rule (/etc/udev/rules.d/99-usb-automount.rules, SYSTEMD_WANTS=usb-automount.service) + udevadm reload/trigger; an existing rule is never overwritten. systemd/usb-automount.service (Type=oneshot, WantedBy=multi-user.target) covers boot + hotplug + manual start, gated in postinstall.sh's systemd loop exactly like autostart. Purpose: a plugged-in stick is ready for pos system backup's post-verify USB copy without manual mounting. Docs: SYSTEMD/SCRIPTS/README/AGENT_Context (tree, filetable — postinstall.sh count corrected 152->163, it was already stale). Verified: stub suite /tmp/opencode/usb-automount-test 47/47 green; make gen && make check.
This commit is contained in:
@@ -10,19 +10,19 @@
|
||||
|
||||
<!-- GEN:START docmap -->
|
||||
| ## 1. Project Overview | 28–43 |
|
||||
| ## 2. Directory Structure | 44–189 |
|
||||
| ## 3. Installation Flow | 190–242 |
|
||||
| ## 4. The `pos` CLI System | 243–312 |
|
||||
| ## 5. Shared Library — `lib/common.sh` | 313–344 |
|
||||
| ## 6. Docker Compose / ScaleTail | 345–387 |
|
||||
| ## 7. Optional Apps (`apps/`) | 388–417 |
|
||||
| ## 8. Entertainment Module | 418–431 |
|
||||
| ## 9. Systemd Services | 432–444 |
|
||||
| ## 10. Configuration Files | 445–471 |
|
||||
| ## 11. Coding Conventions | 472–504 |
|
||||
| ## 12. Development Workflow | 505–557 |
|
||||
| ## 13. Key File Quick Reference | 558–614 |
|
||||
| ## 14. Common Tasks for Agents | 615–644 |
|
||||
| ## 2. Directory Structure | 44–190 |
|
||||
| ## 3. Installation Flow | 191–243 |
|
||||
| ## 4. The `pos` CLI System | 244–313 |
|
||||
| ## 5. Shared Library — `lib/common.sh` | 314–345 |
|
||||
| ## 6. Docker Compose / ScaleTail | 346–388 |
|
||||
| ## 7. Optional Apps (`apps/`) | 389–418 |
|
||||
| ## 8. Entertainment Module | 419–432 |
|
||||
| ## 9. Systemd Services | 433–445 |
|
||||
| ## 10. Configuration Files | 446–472 |
|
||||
| ## 11. Coding Conventions | 473–505 |
|
||||
| ## 12. Development Workflow | 506–558 |
|
||||
| ## 13. Key File Quick Reference | 559–616 |
|
||||
| ## 14. Common Tasks for Agents | 617–646 |
|
||||
<!-- GEN:END docmap -->
|
||||
|
||||
## 1. Project Overview
|
||||
@@ -100,7 +100,8 @@ Linux_post_install/
|
||||
│ └── ssh-load-all # Legacy wrapper → pos ssh load-keys
|
||||
│
|
||||
├── features/ # User-customizable scripts (installed via --feature)
|
||||
│ └── autostart.sh # Boot-time script (via systemd, flag-gated)
|
||||
│ ├── autostart.sh # Boot-time script (via systemd, flag-gated)
|
||||
│ └── usb-automount.sh # USB automount (udev rule + flag-gated service)
|
||||
│
|
||||
├── entertainment/ # Public-API plugins for pos entertainment send (→ /usr/local/bin)
|
||||
│ ├── weather.sh # Current weather via Open-Meteo (no API key)
|
||||
@@ -561,7 +562,7 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
|
||||
|------|-------|---------|
|
||||
| `install.sh` | 206 | Main orchestrator — 4 phases with CLI flags, `--feature`, prebuilt arch bins |
|
||||
| `preinstall.sh` | 73 | System packages + hotspot deps + yt-dlp + fail2ban |
|
||||
| `postinstall.sh` | 152 | fail2ban config, PATH, bash completion, systemd (flag-gated) |
|
||||
| `postinstall.sh` | 163 | fail2ban config, PATH, bash completion, systemd (flag-gated) |
|
||||
| `lib/common.sh` | 144 | Shared library (log/warn/err/run/spawn, dry-run aware, `load_system_env`) |
|
||||
| `lib/flags.sh` | 60 | Feature flag store (set/clear/is_set/value/list/status) |
|
||||
| `lib/notify.sh` | 76 | Multi-platform alerting (`notify_send`) — opt-in source, silent-fails |
|
||||
@@ -571,6 +572,7 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
|
||||
| `bin/flag-set` | 21 | Set a flag (optionally with a value) |
|
||||
| `bin/flag-clear` | 21 | Unset a flag |
|
||||
| `features/autostart.sh` | 14 | Boot-time feature (moved from `bin/`, flag-gated service) |
|
||||
| `features/usb-automount.sh` | 134 | USB automount feature (udev rule + flag-gated service) |
|
||||
<!-- GEN:START filetable -->
|
||||
| `bin/pos` | 292 | CLI dispatcher with smart arg matching + logging + category help |
|
||||
| `bin/pos-ai-gemini` | 311 | Chat with Google Gemini (ask, chat, models, sessions) |
|
||||
|
||||
+2
-2
@@ -5,10 +5,10 @@ Everything in this folder is reference material for the `Linux_post_install` pro
|
||||
| Document | What it covers |
|
||||
|----------|----------------|
|
||||
| [HOWTO.md](HOWTO.md) | Hands-on guides per category (ai, network, docker, media, system, ssh, share, communication, entertainment): flags, recipes, config, troubleshooting |
|
||||
| [SCRIPTS.md](SCRIPTS.md) | Core installer scripts: `install.sh`, `preinstall.sh`, `postinstall.sh`, `lib/common.sh`, `lib/flags.sh`, `lib/entertainment-lib.sh`, `features/autostart.sh` — purpose, how each works, configuration |
|
||||
| [SCRIPTS.md](SCRIPTS.md) | Core installer scripts: `install.sh`, `preinstall.sh`, `postinstall.sh`, `lib/common.sh`, `lib/flags.sh`, `lib/entertainment-lib.sh`, `features/autostart.sh`, `features/usb-automount.sh` — purpose, how each works, configuration |
|
||||
| [POS.md](POS.md) | The `pos` CLI: dispatcher, every `pos-*` command, Docker Compose / ScaleTail config, legacy wrappers, flag CLIs |
|
||||
| [APPS.md](APPS.md) | Optional apps: `apps/install.sh` picker, installer conventions, full app catalog |
|
||||
| [SYSTEMD.md](SYSTEMD.md) | Systemd units (`autostart.service`, `ssh-agent.service`), feature-flag gating, bash completion |
|
||||
| [SYSTEMD.md](SYSTEMD.md) | Systemd units (`autostart.service`, `usb-automount.service`, `ssh-agent.service`), feature-flag gating, bash completion |
|
||||
| [DEV.md](DEV.md) | Developer guide: architecture, conventions, how to add tools/apps/features, commit guidelines |
|
||||
| [AGENT_Context_Project.md](AGENT_Context_Project.md) | Single-source context doc for AI agents working on the repo |
|
||||
| [algorithm.md](algorithm.md) | ASCII diagrams: install flow, `pos` dispatch, compose `up`, config cascade, logging, vbox lifecycle |
|
||||
|
||||
+22
-1
@@ -13,6 +13,7 @@ Everything that runs during the bootstrap install: `install.sh`, `preinstall.sh`
|
||||
- [lib/flags.sh — feature flags](#libflagssh--feature-flags)
|
||||
- [lib/notify.sh — multi-platform alerting](#libnotifysh--multi-platform-alerting)
|
||||
- [features/autostart.sh — boot-time feature](#featuresautostartsh--boot-time-feature)
|
||||
- [features/usb-automount.sh — USB automount feature](#featuresusb-automountsh--usb-automount-feature)
|
||||
- [x64_bin/ — precompiled binaries](#x64_bin--precompiled-binaries)
|
||||
|
||||
---
|
||||
@@ -108,7 +109,7 @@ Add or remove package names here. `nmap` and `fail2ban` are used later by `pos n
|
||||
2. **PATH** — appends a `PATH` line to `~/.bashrc` if not already present.
|
||||
3. **pos bash completion** — installs `completions/pos.bash` to `/usr/local/share/bash-completion/completions/` and sources it from `~/.bashrc`.
|
||||
4. **SSH authorized keys** — if `config/authorized_keys` exists, appends missing keys to `~/.ssh/authorized_keys` (skips comments and duplicates, chmod 600).
|
||||
5. **systemd services** — copies `systemd/*.service` to `/etc/systemd/system/`, daemon-reloads, then enables each service. **`autostart.service` is only enabled when the `autostart` feature flag is set** (see [lib/flags.sh](#libflagssh--feature-flags)); otherwise it's skipped with a hint to run `./install.sh --feature`.
|
||||
5. **systemd services** — copies `systemd/*.service` to `/etc/systemd/system/`, daemon-reloads, then enables each service. **`autostart.service` is only enabled when the `autostart` feature flag is set**, and **`usb-automount.service` only when the `usb-automount` flag is set** (see [lib/flags.sh](#libflagssh--feature-flags)); otherwise they're skipped with a hint to run `./install.sh --feature`.
|
||||
|
||||
### Configuration
|
||||
|
||||
@@ -221,6 +222,26 @@ Appends timestamped lines to `~/.autostart.log`:
|
||||
|
||||
---
|
||||
|
||||
## features/usb-automount.sh — USB automount feature
|
||||
|
||||
**File:** `features/usb-automount.sh` (installed to `/usr/local/bin/usb-automount.sh` by `./install.sh --feature`)
|
||||
**Purpose:** mounts USB storage automatically — at boot and on hotplug — so a plugged-in stick is immediately ready for `pos system backup`'s post-verify USB copy without manual mounting.
|
||||
|
||||
### How it works
|
||||
|
||||
1. Every run (boot via `usb-automount.service`, hotplug via its self-installed udev rule, or manual `sudo usb-automount.sh`) scans `lsblk -J` for unmounted removable block devices — partitions and raw whole-disk filesystems — and mounts each at `/media/<label>`.
|
||||
2. vfat/exfat/ntfs mounts are world-writable (`-o umask=000`) so a non-root user can write; filesystems that reject `umask` fall back to a plain mount.
|
||||
3. Idempotent: already-mounted devices are skipped, and repeated runs are no-ops.
|
||||
4. First root run installs the hotplug rule `/etc/udev/rules.d/99-usb-automount.rules` (`SYSTEMD_WANTS="usb-automount.service"`) and reloads udev — an edited rule is never overwritten.
|
||||
|
||||
### Configuration
|
||||
|
||||
- Log file: `$HOME/.usb-automount.log` (edit the `LOG` variable at the top).
|
||||
- Mount point: `/media/<label>` (bumps to `-2`, `-3` when the label is already in use as a mountpoint); mount options are tuned in `mount_one`.
|
||||
- The script is user-customizable like any feature — a plain reinstall never overwrites your edits.
|
||||
|
||||
---
|
||||
|
||||
## x64_bin/ — precompiled binaries
|
||||
|
||||
**Folder:** `x64_bin/` (future: `arm64_bin/`)
|
||||
|
||||
+26
-1
@@ -4,6 +4,7 @@ The units installed and enabled by `postinstall.sh`, plus the `pos` bash complet
|
||||
|
||||
- [Services](#services)
|
||||
- [`autostart.service`](#autostartservice)
|
||||
- [`usb-automount.service`](#usb-automountservice)
|
||||
- [`ssh-agent.service`](#ssh-agentservice)
|
||||
- [`pos-health.service`](#pos-healthservice)
|
||||
- [Per-user units (`pos network download`)](#per-user-units-pos-network-download)
|
||||
@@ -38,6 +39,25 @@ WantedBy=multi-user.target
|
||||
|
||||
**Configuration:** point `ExecStart` at your boot script. Because the target script is a *feature*, this unit is only **enabled** when the `autostart` flag is set — the file is still copied, but a skipped feature leaves the unit present-but-disabled.
|
||||
|
||||
### usb-automount.service
|
||||
|
||||
**Purpose:** mount USB storage automatically — at boot (via `WantedBy=multi-user.target`) and on hotplug (a udev rule installed by the feature script triggers this unit). Each run mounts every unmounted removable block device at `/media/<label>`, world-writable (`-o umask=000`), so `pos system backup`'s post-verify USB copy finds the stick and the unprivileged user can write to it.
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Auto-mount USB storage (usb-automount feature)
|
||||
After=local-fs.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/bin/usb-automount.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
**Configuration:** `Type=oneshot` — each start (boot, hotplug, manual `systemctl start usb-automount`) does one idempotent scan. `features/usb-automount.sh` self-installs its udev rule (`/etc/udev/rules.d/99-usb-automount.rules`, `SYSTEMD_WANTS="usb-automount.service"`) on first root run and reloads udev, so plugging in a stick fires the mount with no extra setup; an edited rule is never overwritten. Because the target script is a *feature*, this unit is only **enabled** when the `usb-automount` flag is set — the file is still copied, but a skipped feature leaves the unit present-but-disabled. Hotplug is restricted to USB (`ENV{ID_BUS}=="usb"`); the boot scan covers all removable media.
|
||||
|
||||
### ssh-agent.service
|
||||
|
||||
**Purpose:** a system-wide SSH agent, one shared socket for all sessions (so `pos ssh load-keys` and everyday ssh work without per-login agents).
|
||||
@@ -116,19 +136,24 @@ enable-linger` warning so the user units survive logout.
|
||||
|
||||
## Feature-flag gating
|
||||
|
||||
The systemd loop in `postinstall.sh` special-cases two units:
|
||||
The systemd loop in `postinstall.sh` special-cases three units:
|
||||
|
||||
```bash
|
||||
if [ "$svc_name" = "autostart.service" ] && ! flag_is_set autostart; then
|
||||
warn "autostart feature not installed — skipping autostart.service (run ./install.sh --feature)"
|
||||
continue
|
||||
fi
|
||||
if [ "$svc_name" = "usb-automount.service" ] && ! flag_is_set usb-automount; then
|
||||
warn "usb-automount feature not installed — skipping usb-automount.service (run ./install.sh --feature)"
|
||||
continue
|
||||
fi
|
||||
if [ "$svc_name" = "pos-health.service" ]; then
|
||||
# substitute User= and enable pos-health.timer only if Telegram is configured
|
||||
fi
|
||||
```
|
||||
|
||||
- `autostart.service` is **enabled** only when the `autostart` feature flag is set (`./install.sh --feature` or `flag-set autostart`). See [SCRIPTS.md → lib/flags.sh](SCRIPTS.md#libflagssh--feature-flags).
|
||||
- `usb-automount.service` is **enabled** only when the `usb-automount` feature flag is set — same mechanism.
|
||||
- `pos-health.service` is **not** enabled at all — `postinstall.sh` enables `pos-health.timer` instead, and only when a Telegram config already exists.
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user