muster/adapter/
process_identity.rs1use crate::domain::agent_session::{AgentProcessId, AgentProcessStartToken};
2
3#[cfg(all(unix, not(target_os = "linux")))]
5const START_TOKEN_HASH_OFFSET: u64 = 14_695_981_039_346_656_037;
6#[cfg(all(unix, not(target_os = "linux")))]
8const START_TOKEN_HASH_PRIME: u64 = 1_099_511_628_211;
9
10pub struct LocalProcessIdentity;
12
13impl LocalProcessIdentity {
14 pub fn start_token(process_id: AgentProcessId) -> Option<AgentProcessStartToken> {
16 Self::platform_start_token(process_id)
17 }
18
19 #[cfg(target_os = "linux")]
20 fn platform_start_token(process_id: AgentProcessId) -> Option<AgentProcessStartToken> {
21 let stat =
22 std::fs::read_to_string(format!("/proc/{}/stat", process_id.into_inner())).ok()?;
23 let fields = stat
24 .rsplit_once(") ")?
25 .1
26 .split_whitespace()
27 .collect::<Vec<_>>();
28 fields
29 .get(19)?
30 .parse::<u64>()
31 .ok()
32 .and_then(|token| AgentProcessStartToken::try_new(token).ok())
33 }
34
35 #[cfg(windows)]
36 fn platform_start_token(process_id: AgentProcessId) -> Option<AgentProcessStartToken> {
37 use windows_sys::Win32::{
38 Foundation::{CloseHandle, FILETIME},
39 System::Threading::{GetProcessTimes, OpenProcess, PROCESS_QUERY_LIMITED_INFORMATION},
40 };
41
42 unsafe {
45 let handle = OpenProcess(
46 PROCESS_QUERY_LIMITED_INFORMATION,
47 0,
48 process_id.into_inner(),
49 );
50 if handle.is_null() {
51 return None;
52 }
53 let mut created = std::mem::zeroed::<FILETIME>();
54 let mut exited = std::mem::zeroed::<FILETIME>();
55 let mut kernel = std::mem::zeroed::<FILETIME>();
56 let mut user = std::mem::zeroed::<FILETIME>();
57 let result = GetProcessTimes(handle, &mut created, &mut exited, &mut kernel, &mut user);
58 let _ = CloseHandle(handle);
59 (result != 0)
60 .then(|| {
61 u64::from(created.dwLowDateTime) | (u64::from(created.dwHighDateTime) << 32)
62 })
63 .and_then(|token| AgentProcessStartToken::try_new(token).ok())
64 }
65 }
66
67 #[cfg(all(unix, not(target_os = "linux")))]
68 fn platform_start_token(process_id: AgentProcessId) -> Option<AgentProcessStartToken> {
69 use std::process::Command;
70
71 let output = Command::new("ps")
72 .args(["-o", "lstart=", "-p", &process_id.into_inner().to_string()])
73 .output()
74 .ok()?;
75 let started = String::from_utf8(output.stdout).ok()?;
76 let token = started
77 .trim()
78 .bytes()
79 .fold(START_TOKEN_HASH_OFFSET, |hash, byte| {
80 (hash ^ u64::from(byte)).wrapping_mul(START_TOKEN_HASH_PRIME)
81 });
82 AgentProcessStartToken::try_new(token).ok()
83 }
84
85 #[cfg(not(any(unix, windows)))]
86 fn platform_start_token(_process_id: AgentProcessId) -> Option<AgentProcessStartToken> {
87 None
88 }
89}