mirror of
https://github.com/narrrl/proton-drive-linux.git
synced 2026-11-03 16:41:26 +01:00
default.target is reached before the desktop exports DISPLAY/WAYLAND_DISPLAY to the user manager, so After=graphical-session.target never applied. The daemon's first keyring call D-Bus-activated the Secret Service without a display; on KDE ksecretd aborted, the first start failed, and every login left a coredump. Install into graphical-session.target instead, and use reenable when the front-ends enable the unit so existing default.target.wants links are replaced rather than kept alongside the new one. Fixes #23
122 lines
4.6 KiB
Rust
122 lines
4.6 KiB
Rust
//! Thin wrappers over `systemctl --user` for the auto-mount daemon.
|
|
//!
|
|
//! The mount is owned by a systemd *user* service (`proton-drive.service`, see
|
|
//! `packaging/`). Front-ends never spawn `pdfs mount` directly anymore: logging
|
|
//! in enables+starts the unit, logging out disables+stops it, and the tray's
|
|
//! "Disconnect" just stops it. systemd then handles restart-on-failure and a
|
|
//! clean SIGTERM stop (which the daemon turns into a lazy unmount).
|
|
//!
|
|
//! Every call is best-effort: a failure is logged but not fatal, since the user
|
|
//! can always drive `systemctl --user` by hand.
|
|
|
|
use std::process::{Command, Stdio};
|
|
|
|
/// The systemd user unit that runs `pdfs daemon`.
|
|
pub const SERVICE: &str = "proton-drive.service";
|
|
|
|
/// Run one `systemctl --user <args> proton-drive.service`, returning whether it
|
|
/// succeeded. Output is suppressed; failures are logged.
|
|
fn systemctl(args: &[&str]) -> bool {
|
|
let ok = Command::new("systemctl")
|
|
.arg("--user")
|
|
.args(args)
|
|
.arg(SERVICE)
|
|
.stdout(Stdio::null())
|
|
.stderr(Stdio::null())
|
|
.status()
|
|
.map(|s| s.success())
|
|
.unwrap_or(false);
|
|
if !ok {
|
|
tracing::warn!(args = ?args, "systemctl --user {SERVICE} failed");
|
|
}
|
|
ok
|
|
}
|
|
|
|
/// Like [`systemctl`] but treats a non-zero exit as a plain `false` answer
|
|
/// rather than a failure to log. For query verbs (`is-active`, `is-failed`)
|
|
/// where "no" is the normal, expected result.
|
|
fn systemctl_query(args: &[&str]) -> bool {
|
|
Command::new("systemctl")
|
|
.arg("--user")
|
|
.args(args)
|
|
.arg(SERVICE)
|
|
.stdout(Stdio::null())
|
|
.stderr(Stdio::null())
|
|
.status()
|
|
.map(|s| s.success())
|
|
.unwrap_or(false)
|
|
}
|
|
|
|
/// Enable the service so it survives reboots/logins, and bring it up now.
|
|
/// Called on successful login.
|
|
///
|
|
/// `restart` rather than `enable --now`: the unit may already be active but
|
|
/// parked in the daemon's login-wait backoff (`pdfs daemon` sleeps between
|
|
/// keyring checks). `--now` is a no-op on an active unit, so the daemon would
|
|
/// keep sleeping and the mount would not appear until the next poll fired.
|
|
/// Restarting makes the new session take effect immediately, and starts the
|
|
/// unit when it is not running at all. `reenable` for the reason given on
|
|
/// [`enable`].
|
|
pub fn enable_start() -> bool {
|
|
let enabled = systemctl(&["reenable"]);
|
|
systemctl(&["restart"]) && enabled
|
|
}
|
|
|
|
/// Stop the running mount without disabling it. Called by the tray's
|
|
/// "Disconnect": the next login (or reboot) brings it back.
|
|
pub fn stop() -> bool {
|
|
systemctl(&["stop"])
|
|
}
|
|
|
|
/// Restart the unit now. Used by a front-end "Retry" action when the mount has
|
|
/// failed and the user wants to bring it back without re-logging-in.
|
|
pub fn restart() -> bool {
|
|
systemctl(&["restart"])
|
|
}
|
|
|
|
/// Whether the unit currently reports `active` (running, or starting up).
|
|
/// `systemctl is-active` exits 0 only while the unit is active, so a front-end
|
|
/// can use this to tell "service still coming up" from "service is down".
|
|
pub fn is_active() -> bool {
|
|
systemctl_query(&["is-active"])
|
|
}
|
|
|
|
/// Whether the unit is in the `failed` state. `systemctl is-failed` exits 0
|
|
/// only when the unit has failed, letting a front-end show an actionable error
|
|
/// (with Retry) rather than an indefinite "connecting…" spinner.
|
|
pub fn is_failed() -> bool {
|
|
systemctl_query(&["is-failed"])
|
|
}
|
|
|
|
/// Whether the unit is enabled to start on login/boot. `systemctl is-enabled`
|
|
/// exits 0 only for an enabled unit, so the Settings page can render the
|
|
/// "Start on login" switch in its true state.
|
|
pub fn is_enabled() -> bool {
|
|
systemctl_query(&["is-enabled"])
|
|
}
|
|
|
|
/// Enable the service so it auto-starts on future logins, without necessarily
|
|
/// starting it now beyond what `enable` does. Used by the Settings "Start on
|
|
/// login" switch; pairs with [`disable`](disable).
|
|
///
|
|
/// `reenable` rather than `enable`: older installs were enabled
|
|
/// into `default.target.wants`, and a plain `enable` would add the new
|
|
/// `graphical-session.target.wants` link while leaving the old one to start the
|
|
/// unit too early. `reenable` drops every existing link and recreates them from
|
|
/// the current `[Install]` section.
|
|
pub fn enable() -> bool {
|
|
systemctl(&["reenable"])
|
|
}
|
|
|
|
/// Disable auto-start without stopping the running mount. Used by the Settings
|
|
/// "Start on login" switch turning off; the current session stays mounted.
|
|
pub fn disable() -> bool {
|
|
systemctl(&["disable"])
|
|
}
|
|
|
|
/// Disable the service so it no longer auto-starts, and stop it now. Called on
|
|
/// logout.
|
|
pub fn disable_stop() -> bool {
|
|
systemctl(&["disable", "--now"])
|
|
}
|