diff --git a/README.md b/README.md index 49e92d9..a25697e 100644 --- a/README.md +++ b/README.md @@ -202,8 +202,12 @@ Eintragen ausgegeben: - **Voller Zugriff für einen bestimmten Nutzer (`owner_user`)**: Bei CIFS/WebDAV (keine nativen Unix-Rechte) setzt SmartMount automatisch `uid=`/`gid=`/`file_mode=0700`/ `dir_mode=0700`, sobald ein Paar ein `owner_user` hat - optional, ohne `owner_user` gehört - der Mount root. Bei NFS gibt es keine clientseitige `uid=`/`gid=`-Option, Zugriff bestimmt - dort ausschließlich der Server über die tatsächlichen Datei-Eigentümer/-Rechte des Exports. + der Mount root. `smart-mount drive add` setzt `owner_user` standardmäßig auf den Nutzer, der + `sudo` aufgerufen hat (`$SUDO_USER`) - wer ein Paar einrichtet, bekommt also automatisch + vollen Zugriff darauf, sofern nicht per `--owner-user` (nicht-interaktiv) oder im + interaktiven Prompt bewusst ein anderer Nutzer angegeben bzw. abgelehnt wird. Bei NFS gibt es + keine clientseitige `uid=`/`gid=`-Option, Zugriff bestimmt dort ausschließlich der Server über + die tatsächlichen Datei-Eigentümer/-Rechte des Exports. - **davfs2-Konfiguration**: SmartMount setzt in `davfs2.conf` automatisch `gui_optimize 1` (bündelt PROPFIND-Anfragen, wichtig für grafische Dateimanager) sowie `buf_size 16384` (deutlich über dem Standard von 16 KiB) - Letzteres behebt ein bekanntes Praxisproblem, bei diff --git a/src/cli/drive.rs b/src/cli/drive.rs index c07f902..0e5e54c 100644 --- a/src/cli/drive.rs +++ b/src/cli/drive.rs @@ -151,7 +151,10 @@ async fn add(args: DriveArgs) -> anyhow::Result<()> { let ni = args.non_interactive; let name = resolve_field(args.name, None, "Drive pair name", ni, true)?.expect("required"); - let owner_user = resolve_owner_user(args.owner_user, None, ni)?; + // Der Nutzer, der das Paar einrichtet, bekommt standardmäßig vollen Zugriff darauf (siehe + // `invoking_user`) - überschreibbar per '--owner-user' oder (interaktiv) durch Ablehnen/ + // einen anderen Namen im Prompt. + let owner_user = resolve_owner_user(args.owner_user, invoking_user().as_deref(), ni)?; let local_kind = resolve_kind(args.local_kind, None, "Local mount type", ni)?; let local_address = resolve_local_address(args.local_ip, args.local_mac, None, ni)?; @@ -391,29 +394,47 @@ fn resolve_field( Ok(Some(input.interact_text()?)) } +/// Der Nutzer, in dessen Namen `sudo` aufgerufen wurde (falls so aufgerufen) - Standardwert für +/// `owner_user` beim Anlegen eines neuen Paares (siehe `add`), damit der einrichtende Nutzer +/// ohne extra Angabe vollen Zugriff auf sein eigenes Laufwerkspaar bekommt. `None`, wenn direkt +/// als root angemeldet (kein "einrichtender Nutzer" außer root selbst) oder `SUDO_USER` leer/ +/// nicht gesetzt ist. +fn invoking_user() -> Option { + std::env::var("SUDO_USER").ok().filter(|u| !u.is_empty()) +} + /// Optional: falls gesetzt, bekommt dieser Nutzer bei CIFS/WebDAV vollen Zugriff /// (uid=/gid=/file_mode=0700/dir_mode=0700) statt der sonst üblichen root-Ownership - der -/// Mount selbst läuft immer als root (siehe [`smart_mount::systemd`]). +/// Mount selbst läuft immer als root (siehe [`smart_mount::systemd`]). `default_owner` ist der +/// vorbelegte/vorgeschlagene Wert (bei `add`: der einrichtende Nutzer, siehe `invoking_user`; +/// bei `edit`: der bisherige `owner_user`) - immer überschreibbar per Flag, im interaktiven +/// Prompt auch durch Ablehnen oder einen anderen Namen. fn resolve_owner_user( flag: Option, - current: Option<&str>, + default_owner: Option<&str>, non_interactive: bool, ) -> anyhow::Result> { if let Some(v) = flag { return Ok(Some(v)); } if non_interactive { - return Ok(current.map(str::to_string)); + return Ok(default_owner.map(str::to_string)); } + let prompt = match default_owner { + Some(user) => format!( + "Should '{user}' get full access to this drive (uid/gid, including script execution)?" + ), + None => "Should a specific user get full access to this drive (uid/gid, including script execution)?".to_string(), + }; let want_owner = Confirm::new() - .with_prompt("Should a specific user get full access to this drive (uid/gid, including script execution)?") - .default(current.is_some()) + .with_prompt(prompt) + .default(default_owner.is_some()) .interact()?; if !want_owner { return Ok(None); } let mut input = Input::::new().with_prompt("Linux username"); - if let Some(c) = current { + if let Some(c) = default_owner { input = input.default(c.to_string()); } Ok(Some(input.interact_text()?))