Index: Cargo.toml ================================================================== --- Cargo.toml +++ Cargo.toml @@ -1,8 +1,8 @@ [package] name = "qsu" -version = "0.6.1" +version = "0.6.2" edition = "2021" license = "0BSD" # https://crates.io/category_slugs categories = [ "os" ] keywords = [ "service", "systemd", "winsvc" ] @@ -36,11 +36,11 @@ wait-for-debugger = ["dep:dbgtools-win"] [dependencies] async-trait = { version = "0.1.83" } chrono = { version = "0.4.38" } -clap = { version = "4.5.19", optional = true, features = [ +clap = { version = "4.5.20", optional = true, features = [ "derive", "env", "string", "wrap_help" ] } env_logger = { version = "0.11.5" } futures = { version = "0.3.31" } itertools = { version = "0.13.0", optional = true } @@ -60,11 +60,11 @@ [target.'cfg(target_os = "linux")'.dependencies] sd-notify = { version = "0.4.3", optional = true } [target.'cfg(unix)'.dependencies] -libc = { version = "0.2.159" } +libc = { version = "0.2.160" } nix = { version = "0.29.0", features = ["pthread", "signal", "time"] } [target.'cfg(windows)'.dependencies] dbgtools-win = { version = "0.2.1", optional = true } eventlog = { version = "0.2.2" } @@ -75,11 +75,11 @@ "Win32_Foundation", "Win32_System_Console" ] } winreg = { version = "0.52.0" } [dev-dependencies] -clap = { version = "4.5.4", features = ["derive", "env", "wrap_help"] } +clap = { version = "4.5.20", features = ["derive", "env", "wrap_help"] } tokio = { version = "1.40.0", features = ["time"] } [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] Index: src/argp.rs ================================================================== --- src/argp.rs +++ src/argp.rs @@ -86,16 +86,18 @@ /// Autostart service at boot. #[arg(short = 's', long)] auto_start: bool, /// Set an optional display name for the service. - #[cfg(windows)] + /// + /// Only used on Windows. #[arg(short = 'D', long, value_name = "DISPNAME")] display_name: Option, /// Set an optional one-line service description. - #[cfg(any(all(target_os = "linux", feature = "systemd"), windows))] + /// + /// Only used on Windows and Linux with systemd. #[arg(short, long, value_name = "DESC")] description: Option, /// Add a command line argument to the service command line. #[arg(short, long)] @@ -250,13 +252,20 @@ /// Used to differentiate between running without a subcommand, or the /// install/uninstall or run service subcommands. pub enum Cmd { + /// The root `Command`. Root, + + /// The service registration/installation `Command`. Inst, + + /// The service deregistration/uninstallation `Command`. Rm, + + /// The service run `Command`. Run } /// Allow application to customise behavior of an [`ArgParser`] instance. pub trait ArgsProc { Index: src/rt.rs ================================================================== --- src/rt.rs +++ src/rt.rs @@ -69,11 +69,11 @@ #[cfg(windows)] pub mod winsvc; use std::sync::{ atomic::{AtomicU32, Ordering}, - Arc + Arc, OnceLock }; #[cfg(any(feature = "tokio", feature = "rocket"))] use async_trait::async_trait; @@ -85,10 +85,26 @@ #[cfg(all(target_os = "linux", feature = "systemd"))] use sd_notify::NotifyState; use crate::{err::CbErr, lumberjack::LumberJack}; + + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum RunAs { + Foreground, + SvcSubsys +} + +/// Keep track of whether the service application is running as foreground +/// process or running under a service subsystem. +static RUNAS: OnceLock = OnceLock::new(); + +pub fn runas() -> Option { + RUNAS.get().copied() +} + /// The run time environment. /// /// Can be used by the application callbacks to determine whether it is running /// as a service. @@ -145,10 +161,16 @@ fn stopped(&self); } /// Context passed to `init()` service application callback. +/// +/// This context can be used to query whether the service application is +/// running as foreground process or running within a service subsystem. +/// +/// It can also be used to report progress status back to the service +/// subsystems, for platforms that support it. pub struct InitCtx { re: RunEnv, sr: Arc, cnt: Arc } @@ -171,10 +193,16 @@ } } /// Context passed to `term()` service application callback. +/// +/// This context can be used to query whether the service application is +/// running as foreground process or running within a service subsystem. +/// +/// It can also be used to report progress status back to the service +/// subsystems, for platforms that support it. pub struct TermCtx { re: RunEnv, sr: Arc, cnt: Arc } @@ -608,18 +636,22 @@ pub fn run(self, st: SrvAppRt) -> Result<(), CbErr> where ApEr: Send + 'static { if self.service { + let _ = RUNAS.set(RunAs::SvcSubsys); + #[cfg(all(target_os = "linux", feature = "systemd"))] self.systemd(st)?; #[cfg(windows)] self.winsvc(st)?; // ToDo: We should check for other platforms here (like macOS/launchd) } else { + let _ = RUNAS.set(RunAs::Foreground); + // Do not run against any specific service subsystem. Despite its name // this isn't necessarily running as a foreground process; some service // subsystems do not make a distinction. Perhaps a better mental model // is that certain service subsystems expects to run regular "foreground" // processes. Index: www/changelog.md ================================================================== --- www/changelog.md +++ www/changelog.md @@ -2,18 +2,36 @@ ⚠️ indicates a breaking change. ## [Unreleased] -[Details](/vdiff?from=qsu-0.6.1&to=trunk) +[Details](/vdiff?from=qsu-0.6.2&to=trunk) ### Added ### Changed ### Removed +--- + +## [0.6.2] - 2024-10-17 + +[Details](/vdiff?from=qsu-0.6.1&to=qsu-0.6.2) + +### Added + +- After the qsu runtime as been launched `rt::runas()` can be used to probe + whether the runtime was run as a foreground application or as a service + subsystem application. + +### Changed + +- Make `display_name` and `description` options for `register-service` + generally available on all platforms, but document which platforms they are + used on." + --- ## [0.6.1] - 2024-10-05 [Details](/vdiff?from=qsu-0.6.0&to=qsu-0.6.1)