ic_host_process/status/
mod.rs1use std::process::ExitStatus;
4
5#[must_use]
11pub fn shell_status_code(status: ExitStatus) -> Option<i32> {
12 if let Some(code) = status.code() {
13 return Some(code);
14 }
15 #[cfg(unix)]
16 {
17 use std::os::unix::process::ExitStatusExt as _;
18 status.signal().map(|signal| 128 + signal)
19 }
20 #[cfg(not(unix))]
21 {
22 None
23 }
24}
25
26#[cfg(all(test, unix))]
27mod tests {
28 use super::*;
29 use std::{os::unix::process::ExitStatusExt as _, process::Command};
30
31 #[test]
32 fn observed_exits_and_signals_keep_their_numeric_identity() {
33 for code in [0, 37, 255] {
34 let status = Command::new("/bin/sh")
35 .args(["-c", &format!("exit {code}")])
36 .status()
37 .unwrap();
38 assert_eq!(shell_status_code(status), Some(code));
39 }
40 let status = Command::new("/bin/sh")
41 .args(["-c", "kill -TERM $$"])
42 .status()
43 .unwrap();
44 assert_eq!(shell_status_code(status), Some(143));
45 }
46
47 #[test]
48 fn unclassified_status_leaves_the_fallback_to_each_caller() {
49 let stopped = ExitStatus::from_raw((19 << 8) | 0x7f);
50 assert_eq!(shell_status_code(stopped), None);
51 assert_eq!(shell_status_code(stopped).unwrap_or(1), 1);
52 assert_eq!(shell_status_code(stopped).unwrap_or(129), 129);
53 }
54}