diff --git a/Cargo.lock b/Cargo.lock index 7bb8d1f..758dc4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -685,12 +685,13 @@ checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" [[package]] name = "launch-pad" version = "0.1.0" -source = "git+https://github.com/pop-os/launch-pad#1596d1b83ae5d5c804a69146f89718776022b46b" +source = "git+https://github.com/pop-os/launch-pad#a267ea1fe5f80b30f82b8ec557a88b23fa4ebdc3" dependencies = [ "log", "nix 0.26.2", "rand", "slotmap", + "sync_wrapper", "thiserror", "tokio", "tokio-util", @@ -1255,6 +1256,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + [[package]] name = "tempfile" version = "3.6.0" diff --git a/Cargo.toml b/Cargo.toml index df32846..b7015dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ color-eyre = "0.6" futures-util = "0.3" launch-pad = { git = "https://github.com/pop-os/launch-pad" } itertools = "0.12" -#launch-pad = { path = "../../../launch-pad" } +#launch-pad = { git = "https://github.com/pop-os/launch-pad", branch = "remove-sync-bounds" } libc = "0.2" log-panics = { version = "2", features = ["with-backtrace"] } rustix = "0.38" diff --git a/src/main.rs b/src/main.rs index 817495d..6f64eb1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ mod service; mod systemd; use std::{ + borrow::Cow, os::fd::{AsRawFd, OwnedFd}, sync::Arc, }; @@ -331,7 +332,7 @@ async fn start( } async fn start_component( - cmd: &str, + cmd: impl Into>, span: tracing::Span, process_manager: &ProcessManager, env_vars: &[(String, String)], @@ -344,7 +345,9 @@ async fn start_component( let socket_tx_clone = socket_tx.clone(); let stdout_span = span.clone(); let stderr_span = span.clone(); - let cmd_clone = cmd.to_string(); + let cmd = cmd.into(); + let cmd_clone = cmd.clone(); + let (mut fds, extra_fd_env, mut streams): (Vec<_>, Vec<_>, Vec<_>) = itertools::multiunzip(extra_fds); for kv in &extra_fd_env { @@ -357,10 +360,10 @@ async fn start_component( } let (extra_fd_env, _): (Vec<_>, Vec<_>) = extra_fd_env.into_iter().unzip(); fds.push(fd); - let key = process_manager + process_manager .start( Process::new() - .with_executable(cmd) + .with_executable(cmd.clone()) .with_env(env_vars.iter().cloned()) .with_on_stdout(move |_, _, line| { let stdout_span = stdout_span.clone(); @@ -376,6 +379,25 @@ async fn start_component( } .instrument(stderr_span) }) + .with_on_start(move |pman, pkey, _will_restart| { + #[cfg(feature = "systemd")] + { + async move { + if *is_systemd_used() { + if let Ok((innr_cmd, Some(pid))) = pman.get_exe_and_pid(pkey).await + { + if let Err(err) = spawn_scope(innr_cmd.clone(), vec![pid]).await + { + warn!( + "Failed to spawn scope for {}. Creating transient unit failed with {}", + innr_cmd, err + ); + }; + } + } + } + } + }) .with_on_exit(move |mut pman, key, err_code, will_restart| { if let Some(err) = err_code { error!("{cmd_clone} exited with error {}", err.to_string()); @@ -415,20 +437,4 @@ async fn start_component( ) .await .unwrap_or_else(|_| panic!("failed to start {}", cmd)); - #[cfg(feature = "systemd")] - { - if *is_systemd_used() { - //currently pid is optional hence the double unwrap - let pids = process_manager.get_pid(key).await.unwrap().unwrap(); - //spawn_scope takes a vec of pids in case we want to spawn a scope for multiple processes - spawn_scope(cmd.to_string(), vec![pids]) - .await - .unwrap_or_else(|err| { - warn!( - "Failed to spawn scope for {}. Creating transient unit failed with {}", - cmd, err - ); - }); - } - } } diff --git a/src/systemd.rs b/src/systemd.rs index be101c6..9d617d5 100644 --- a/src/systemd.rs +++ b/src/systemd.rs @@ -33,18 +33,21 @@ pub fn stop_systemd_target() { ///Determine if systemd is used as the init system. This should work on all linux distributions. pub fn is_systemd_used() -> &'static bool { static IS_SYSTEMD_USED: OnceLock = OnceLock::new(); - IS_SYSTEMD_USED.get_or_init( - || match Command::new("readlink").args(&["/sbin/init"]).output() { + IS_SYSTEMD_USED.get_or_init(|| { + match Command::new("ls").args(["/run/systemd/system"]).output() { Ok(output) => { - let init = String::from_utf8_lossy(&output.stdout); - init.trim().ends_with("/lib/systemd/systemd") + if output.status.success() { + true + } else { + false + } } Err(error) => { warn!("unable to check if systemd is used: {}", error); false } - }, - ) + } + }) } #[cfg(feature = "systemd")] @@ -53,8 +56,8 @@ pub async fn spawn_scope(mut command: String, pids: Vec) -> Result<(), zbus let connection = Connection::session().await?; let systemd_manager = SystemdManagerProxy::new(&connection).await?; let pids = OwnedValue::try_from(Array::from(pids)).unwrap(); - let properties = vec![(String::from("PIDs"), pids)]; - if command.starts_with("/") { + let properties: Vec<(String, OwnedValue)> = vec![(String::from("PIDs"), pids)]; + if command.starts_with('/') { // use the last component of the path as the unit name command = command.rsplit('/').next().unwrap().to_string(); } @@ -62,7 +65,7 @@ pub async fn spawn_scope(mut command: String, pids: Vec) -> Result<(), zbus systemd_manager .start_transient_unit( scope_name.to_string(), - String::from("fail"), + String::from("replace"), properties, Vec::new(), )