start_command/
launch_owner.rs1use crate::{execution_store::ExecutionRecord, local_hostname};
3use serde_json::{json, Value};
4
5pub fn mark_launch(record: &mut ExecutionRecord) {
6 record.options.insert("launchPending".into(), json!(true));
7 record.options.insert(
8 "launchOwner".into(),
9 json!({"pid":std::process::id(), "hostname":hostname()}),
10 );
11}
12
13pub fn has_active_launch(record: &ExecutionRecord) -> bool {
14 if record.options.get("launchPending").and_then(Value::as_bool) != Some(true) {
15 return false;
16 }
17 let Some(owner) = record.options.get("launchOwner") else {
18 return true;
19 };
20 if owner["hostname"].as_str() != Some(&hostname()) {
21 return true;
22 }
23 owner["pid"].as_u64().is_none_or(process_alive)
24}
25
26pub fn hostname() -> String {
27 local_hostname::get()
28 .map(|s| s.to_string_lossy().into())
29 .unwrap_or_default()
30}
31
32pub fn process_alive(pid: u64) -> bool {
33 if pid == 0 || pid > i32::MAX as u64 {
34 return true;
35 }
36 #[cfg(unix)]
37 {
38 (unsafe { libc::kill(pid as i32, 0) }) == 0
39 || std::io::Error::last_os_error().raw_os_error() != Some(libc::ESRCH)
40 }
41 #[cfg(windows)]
42 {
43 let output = std::process::Command::new("tasklist")
44 .args(["/FI", &format!("PID eq {}", pid), "/FO", "CSV", "/NH"])
45 .output();
46 match output {
47 Ok(output) if output.status.success() => {
48 String::from_utf8_lossy(&output.stdout).contains(&format!("\"{}\"", pid))
49 }
50 _ => true,
51 }
52 }
53 #[cfg(not(any(unix, windows)))]
54 {
55 true
56 }
57}