nstd_sys/proc.rs
1//! Calling/Child process management.
2use crate::{
3 alloc::CBox,
4 core::{
5 optional::{gen_optional, NSTDOptional},
6 slice::NSTDSlice,
7 str::NSTDStr,
8 },
9 io::NSTDIOError,
10 NSTDInt32, NSTDUInt32,
11};
12use nstdapi::nstdapi;
13use std::process::{Child, Command};
14
15/// A handle to a child process.
16#[nstdapi]
17pub struct NSTDChildProcess {
18 /// A handle to a child process.
19 proc: CBox<Child>,
20}
21gen_optional!(NSTDOptionalChildProcess, NSTDChildProcess);
22
23/// Spawns a new child process with the name `program` and returns a handle to it.
24///
25/// # Parameters:
26///
27/// - `const NSTDStr *program` - A path to the program to run as a child process.
28///
29/// - `const NSTDSlice *args` - A slice of `NSTDStr` arguments to pass to the program.
30///
31/// - `const NSTDSlice *vars` - A slice of `NSTDStr[2]` key/value environment variables to
32/// give to the program.
33///
34/// # Returns
35///
36/// `NSTDOptionalChildProcess child` - A handle to the new child process on success, or an
37/// uninitialized "none" variant if spawning the child process fails.
38///
39/// # Safety
40///
41/// The user must ensure that all of `program`, `args`, and `vars` and their data remain valid for
42/// reads while this function is executing.
43#[nstdapi]
44pub unsafe fn nstd_proc_spawn(
45 program: &NSTDStr,
46 args: &NSTDSlice,
47 vars: &NSTDSlice,
48) -> NSTDOptionalChildProcess {
49 // Create the process command builder.
50 let mut cmd = Command::new(program.as_str());
51 if let Some(args) = args.as_slice::<NSTDStr>() {
52 if let Some(vars) = vars.as_slice::<[NSTDStr; 2]>() {
53 // Add the arguments.
54 cmd.args(args.iter().map(|arg| arg.as_str()));
55 // Add the environment variables.
56 cmd.envs(vars.iter().map(|vars| {
57 (
58 vars.get_unchecked(0).as_str(),
59 vars.get_unchecked(1).as_str(),
60 )
61 }));
62 // Spawn the process.
63 if let Ok(proc) = cmd.spawn() {
64 if let Some(proc) = CBox::new(proc) {
65 return NSTDOptional::Some(NSTDChildProcess { proc });
66 }
67 }
68 }
69 }
70 NSTDOptional::None
71}
72
73/// Returns the OS-assigned ID of a child process.
74///
75/// # Parameters:
76///
77/// - `const NSTDChildProcess *handle` - A handle to the process.
78///
79/// # Returns
80///
81/// `NSTDUInt32 ID` - The child process ID.
82#[inline]
83#[nstdapi]
84pub fn nstd_proc_child_id(handle: &NSTDChildProcess) -> NSTDUInt32 {
85 handle.proc.id()
86}
87
88/// Attempts to kill a child process.
89///
90/// # Parameters:
91///
92/// - `NSTDChildProcess *handle` - A handle to the child process.
93///
94/// # Returns
95///
96/// `NSTDIOError errc` - The operation error code.
97#[inline]
98#[nstdapi]
99pub fn nstd_proc_kill(handle: &mut NSTDChildProcess) -> NSTDIOError {
100 if let Err(err) = handle.proc.kill() {
101 return NSTDIOError::from_err(err.kind());
102 }
103 NSTDIOError::NSTD_IO_ERROR_NONE
104}
105
106/// Waits for a child process to exit.
107///
108/// # Parameters:
109///
110/// - `NSTDChildProcess *handle` - A handle to the process.
111///
112/// # Returns
113///
114/// `NSTDIOError errc` - The operation error code.
115#[nstdapi]
116pub fn nstd_proc_join(handle: &mut NSTDChildProcess) -> NSTDIOError {
117 match handle.proc.wait() {
118 Ok(status) if status.success() => NSTDIOError::NSTD_IO_ERROR_NONE,
119 Err(err) => NSTDIOError::from_err(err.kind()),
120 _ => NSTDIOError::NSTD_IO_ERROR_UNKNOWN,
121 }
122}
123
124/// Frees a handle to a child process, allowing the process to run in the background.
125///
126/// # Parameters:
127///
128/// - `NSTDChildProcess handle` - A handle to the child process.
129#[inline]
130#[nstdapi]
131#[allow(
132 unused_variables,
133 clippy::missing_const_for_fn,
134 clippy::needless_pass_by_value
135)]
136pub fn nstd_proc_free(handle: NSTDChildProcess) {}
137
138/// Terminates the process with the given `exit_code`.
139///
140/// # Parameters:
141///
142/// - `NSTDInt32 exit_code` - The process exit code.
143///
144/// # Example
145///
146/// ```
147/// use nstd_sys::proc::nstd_proc_exit;
148///
149/// unsafe { nstd_proc_exit(0) };
150/// ```
151#[inline]
152#[nstdapi]
153pub fn nstd_proc_exit(exit_code: NSTDInt32) -> ! {
154 std::process::exit(exit_code);
155}
156
157/// Terminates the program in an abnormal fashion.
158#[inline]
159#[nstdapi]
160pub fn nstd_proc_abort() -> ! {
161 std::process::abort();
162}
163
164/// Returns the ID of the current process.
165///
166/// # Returns
167///
168/// `NSTDUInt32 ID` - The process ID.
169#[inline]
170#[nstdapi]
171pub fn nstd_proc_id() -> NSTDUInt32 {
172 std::process::id()
173}