running_process_platform_internal/platform/
host.rs1use std::io;
9
10pub use crate::{
11 host_boot_id as boot_id, host_current_process_privilege as current_process_privilege,
12 host_environment_keys_are_case_insensitive as environment_keys_are_case_insensitive,
13 host_filesystem_device_id as filesystem_device_id, host_hostname as hostname,
14 host_login_environment as login_environment, host_machine_id as machine_id,
15 host_namespace_id as namespace_id, host_user_machine_identity as user_machine_identity,
16 HostPrivilegedIdentity as PrivilegedIdentity,
17};
18
19pub use crate::host_login_environment_block as login_environment_block;
20
21#[allow(dead_code)]
33pub(crate) fn machine_id_from(machine_id_paths: &[&str], boot_id_path: &str) -> io::Result<String> {
34 for path in machine_id_paths {
35 match std::fs::read_to_string(path) {
36 Ok(s) => {
37 let trimmed = s.trim();
38 if !trimmed.is_empty() {
39 return Ok(trimmed.to_string());
40 }
41 }
42 Err(err) if err.kind() == io::ErrorKind::NotFound => continue,
43 Err(err) => return Err(io::Error::other(format!("read {path}: {err}"))),
49 }
50 }
51 if let Ok(s) = std::fs::read_to_string(boot_id_path) {
58 let trimmed = s.trim();
59 if !trimmed.is_empty() {
60 return Ok(format!("boot:{trimmed}"));
61 }
62 }
63 Err(io::Error::other(
64 "no /etc/machine-id or /var/lib/dbus/machine-id found, and no usable boot_id fallback",
65 ))
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
79 fn an_ordinary_test_process_is_not_privileged() {
80 let privilege = current_process_privilege().expect("privilege lookup must succeed");
81 assert_eq!(
82 privilege, None,
83 "test runs are expected unprivileged; got {privilege:?}"
84 );
85 }
86
87 mod machine_id_sources {
88 use super::super::machine_id_from;
89
90 fn temp_dir(label: &str) -> std::path::PathBuf {
91 let dir = std::env::temp_dir().join(format!(
92 "rp-host-{label}-{}-{:?}",
93 std::process::id(),
94 std::thread::current().id(),
95 ));
96 std::fs::create_dir_all(&dir).expect("create temp dir");
97 dir
98 }
99
100 fn write(dir: &std::path::Path, name: &str, content: &str) -> String {
101 let path = dir.join(name);
102 std::fs::write(&path, content).expect("write fixture file");
103 path.to_string_lossy().into_owned()
104 }
105
106 #[test]
107 fn machine_id_file_wins_over_boot_fallback() {
108 let dir = temp_dir("wins");
109 let machine = write(
110 &dir,
111 "machine-id",
112 " abc123
113",
114 );
115 let boot = write(
116 &dir, "boot-id", "zzz
117",
118 );
119 assert_eq!(
120 machine_id_from(&[&machine], &boot).expect("resolve"),
121 "abc123"
122 );
123 let _ = std::fs::remove_dir_all(&dir);
124 }
125
126 #[test]
127 fn second_path_is_consulted_when_first_is_missing() {
128 let dir = temp_dir("second");
129 let missing = dir.join("absent").to_string_lossy().into_owned();
130 let machine = write(
131 &dir,
132 "machine-id",
133 "def456
134",
135 );
136 let boot = write(
137 &dir, "boot-id", "zzz
138",
139 );
140 assert_eq!(
141 machine_id_from(&[&missing, &machine], &boot).expect("resolve"),
142 "def456"
143 );
144 let _ = std::fs::remove_dir_all(&dir);
145 }
146
147 #[test]
148 fn missing_machine_id_files_fall_back_to_boot_id() {
149 let dir = temp_dir("fallback");
150 let missing = dir.join("absent").to_string_lossy().into_owned();
151 let boot = write(
152 &dir,
153 "boot-id",
154 "boot-value
155",
156 );
157 assert_eq!(
158 machine_id_from(&[&missing], &boot).expect("resolve"),
159 "boot:boot-value"
160 );
161 let _ = std::fs::remove_dir_all(&dir);
162 }
163
164 #[test]
165 fn empty_machine_id_file_falls_through_to_boot_id() {
166 let dir = temp_dir("empty");
167 let machine = write(
168 &dir,
169 "machine-id",
170 "
171",
172 );
173 let boot = write(
174 &dir,
175 "boot-id",
176 "boot-value
177",
178 );
179 assert_eq!(
180 machine_id_from(&[&machine], &boot).expect("resolve"),
181 "boot:boot-value"
182 );
183 let _ = std::fs::remove_dir_all(&dir);
184 }
185
186 #[test]
187 fn unreadable_machine_id_stays_a_hard_error_despite_boot_fallback() {
188 let dir = temp_dir("unreadable");
189 let as_dir = dir.join("machine-id-dir");
192 std::fs::create_dir_all(&as_dir).expect("create dir fixture");
193 let as_dir = as_dir.to_string_lossy().into_owned();
194 let boot = write(&dir, "boot-id", "boot-uuid\n");
195 machine_id_from(&[&as_dir], &boot)
196 .expect_err("unreadable machine-id must not fall through");
197 let _ = std::fs::remove_dir_all(&dir);
198 }
199
200 #[test]
201 fn everything_missing_is_an_error() {
202 let dir = temp_dir("nothing");
203 let missing = dir.join("absent").to_string_lossy().into_owned();
204 let no_boot = dir.join("absent-boot").to_string_lossy().into_owned();
205 assert!(machine_id_from(&[&missing], &no_boot).is_err());
206 let _ = std::fs::remove_dir_all(&dir);
207 }
208 }
209
210 #[test]
212 fn privileged_identities_describe_themselves_concretely() {
213 assert_eq!(
214 PrivilegedIdentity::UnixRoot.to_string(),
215 "root (effective uid 0)"
216 );
217 assert_eq!(
218 PrivilegedIdentity::WindowsLocalSystem.to_string(),
219 "Windows LocalSystem (S-1-5-18)"
220 );
221 }
222}