1use std::{ffi::CStr, mem, os::fd::RawFd};
4
5#[cfg(any(feature = "fs", feature = "term"))]
6use crate::fcntl::OFlag;
7#[cfg(feature = "signal")]
8use crate::sys::signal::SigSet;
9#[cfg(feature = "fs")]
10use crate::sys::stat::Mode;
11use crate::{errno::Errno, unistd::Pid, NixPath, Result};
12
13#[repr(transparent)]
15#[derive(Debug)]
16pub struct PosixSpawnAttr {
17 attr: libc::posix_spawnattr_t,
18}
19
20impl PosixSpawnAttr {
21 #[doc(alias("posix_spawnattr_init"))]
24 pub fn init() -> Result<PosixSpawnAttr> {
25 let mut attr = mem::MaybeUninit::uninit();
26 let res = unsafe { libc::posix_spawnattr_init(attr.as_mut_ptr()) };
27
28 Errno::result(res)?;
29
30 let attr = unsafe { attr.assume_init() };
31 Ok(PosixSpawnAttr { attr })
32 }
33
34 #[doc(alias("posix_spawnattr_destroy"))]
40 pub fn reinit(mut self) -> Result<PosixSpawnAttr> {
41 let res = unsafe {
42 libc::posix_spawnattr_destroy(
43 &mut self.attr as *mut libc::posix_spawnattr_t,
44 )
45 };
46 Errno::result(res)?;
47
48 let res = unsafe {
49 libc::posix_spawnattr_init(
50 &mut self.attr as *mut libc::posix_spawnattr_t,
51 )
52 };
53 Errno::result(res)?;
54
55 Ok(self)
56 }
57
58 #[doc(alias("posix_spawnattr_setflags"))]
61 pub fn set_flags(&mut self, flags: PosixSpawnFlags) -> Result<()> {
62 let res = unsafe {
63 libc::posix_spawnattr_setflags(
64 &mut self.attr as *mut libc::posix_spawnattr_t,
65 flags.bits() as libc::c_short,
66 )
67 };
68 Errno::result(res)?;
69
70 Ok(())
71 }
72
73 #[doc(alias("posix_spawnattr_getflags"))]
76 pub fn flags(&self) -> Result<PosixSpawnFlags> {
77 let mut flags: libc::c_short = 0;
78 let res = unsafe {
79 libc::posix_spawnattr_getflags(
80 &self.attr as *const libc::posix_spawnattr_t,
81 &mut flags,
82 )
83 };
84 Errno::result(res)?;
85
86 Ok(PosixSpawnFlags::from_bits_truncate(flags.into()))
87 }
88
89 #[doc(alias("posix_spawnattr_setpgroup"))]
92 pub fn set_pgroup(&mut self, pgroup: Pid) -> Result<()> {
93 let res = unsafe {
94 libc::posix_spawnattr_setpgroup(
95 &mut self.attr as *mut libc::posix_spawnattr_t,
96 pgroup.as_raw(),
97 )
98 };
99 Errno::result(res)?;
100
101 Ok(())
102 }
103
104 #[doc(alias("posix_spawnattr_getpgroup"))]
107 pub fn pgroup(&self) -> Result<Pid> {
108 let mut pid: libc::pid_t = 0;
109
110 let res = unsafe {
111 libc::posix_spawnattr_getpgroup(
112 &self.attr as *const libc::posix_spawnattr_t,
113 &mut pid,
114 )
115 };
116 Errno::result(res)?;
117
118 Ok(Pid::from_raw(pid))
119 }
120
121 feature! {
122 #![feature = "signal"]
123 #[doc(alias("posix_spawnattr_setsigdefault"))]
126 pub fn set_sigdefault(&mut self, sigdefault: &SigSet) -> Result<()> {
127 let res = unsafe {
128 libc::posix_spawnattr_setsigdefault(
129 &mut self.attr as *mut libc::posix_spawnattr_t,
130 sigdefault.as_ref(),
131 )
132 };
133 Errno::result(res)?;
134
135 Ok(())
136 }
137
138 #[doc(alias("posix_spawnattr_getsigdefault"))]
141 pub fn sigdefault(&self) -> Result<SigSet> {
142 let mut sigset = mem::MaybeUninit::uninit();
143
144 let res = unsafe {
145 libc::posix_spawnattr_getsigdefault(
146 &self.attr as *const libc::posix_spawnattr_t,
147 sigset.as_mut_ptr(),
148 )
149 };
150 Errno::result(res)?;
151
152 let sigdefault =
153 unsafe { SigSet::from_sigset_t_unchecked(sigset.assume_init()) };
154 Ok(sigdefault)
155 }
156
157 #[doc(alias("posix_spawnattr_setsigmask"))]
160 pub fn set_sigmask(&mut self, sigdefault: &SigSet) -> Result<()> {
161 let res = unsafe {
162 libc::posix_spawnattr_setsigmask(
163 &mut self.attr as *mut libc::posix_spawnattr_t,
164 sigdefault.as_ref(),
165 )
166 };
167 Errno::result(res)?;
168
169 Ok(())
170 }
171
172 #[doc(alias("posix_spawnattr_getsigmask"))]
175 pub fn sigmask(&self) -> Result<SigSet> {
176 let mut sigset = mem::MaybeUninit::uninit();
177
178 let res = unsafe {
179 libc::posix_spawnattr_getsigmask(
180 &self.attr as *const libc::posix_spawnattr_t,
181 sigset.as_mut_ptr(),
182 )
183 };
184 Errno::result(res)?;
185
186 let sigdefault =
187 unsafe { SigSet::from_sigset_t_unchecked(sigset.assume_init()) };
188 Ok(sigdefault)
189 }
190 }
191}
192
193impl Drop for PosixSpawnAttr {
194 fn drop(&mut self) {
195 unsafe {
196 libc::posix_spawnattr_destroy(
197 &mut self.attr as *mut libc::posix_spawnattr_t,
198 );
199 }
200 }
201}
202
203libc_bitflags!(
204 pub struct PosixSpawnFlags: libc::c_int {
208 POSIX_SPAWN_RESETIDS;
210 POSIX_SPAWN_SETPGROUP;
213 #[cfg(feature = "signal")]
216 POSIX_SPAWN_SETSIGDEF;
217 #[cfg(feature = "signal")]
220 POSIX_SPAWN_SETSIGMASK;
221 }
227);
228
229#[repr(transparent)]
231#[derive(Debug)]
232pub struct PosixSpawnFileActions {
233 fa: libc::posix_spawn_file_actions_t,
234}
235
236impl PosixSpawnFileActions {
237 #[doc(alias("posix_spawn_file_actions_init"))]
240 pub fn init() -> Result<PosixSpawnFileActions> {
241 let mut actions = mem::MaybeUninit::uninit();
242 let res = unsafe {
243 libc::posix_spawn_file_actions_init(actions.as_mut_ptr())
244 };
245 Errno::result(res)?;
246 Ok(unsafe {
247 PosixSpawnFileActions {
248 fa: actions.assume_init(),
249 }
250 })
251 }
252
253 #[doc(alias("posix_spawn_file_actions_destroy"))]
259 pub fn reinit(mut self) -> Result<PosixSpawnFileActions> {
260 let res = unsafe {
261 libc::posix_spawn_file_actions_destroy(
262 &mut self.fa as *mut libc::posix_spawn_file_actions_t,
263 )
264 };
265 Errno::result(res)?;
266
267 let res = unsafe {
268 libc::posix_spawn_file_actions_init(
269 &mut self.fa as *mut libc::posix_spawn_file_actions_t,
270 )
271 };
272 Errno::result(res)?;
273
274 Ok(self)
275 }
276
277 #[doc(alias("posix_spawn_file_actions_adddup2"))]
280 pub fn add_dup2(&mut self, fd: RawFd, newfd: RawFd) -> Result<()> {
281 let res = unsafe {
282 libc::posix_spawn_file_actions_adddup2(
283 &mut self.fa as *mut libc::posix_spawn_file_actions_t,
284 fd,
285 newfd,
286 )
287 };
288 Errno::result(res)?;
289
290 Ok(())
291 }
292
293 feature! {
294 #![all(feature = "fs", feature = "term")]
295 #[doc(alias("posix_spawn_file_actions_addopen"))]
298 pub fn add_open<P: ?Sized + NixPath>(
299 &mut self,
300 fd: RawFd,
301 path: &P,
302 oflag: OFlag,
303 mode: Mode,
304 ) -> Result<()> {
305 let res = path.with_nix_path(|cstr| unsafe {
306 libc::posix_spawn_file_actions_addopen(
307 &mut self.fa as *mut libc::posix_spawn_file_actions_t,
308 fd,
309 cstr.as_ptr(),
310 oflag.bits(),
311 mode.bits(),
312 )
313 })?;
314 Errno::result(res)?;
315
316 Ok(())
317 }
318 }
319
320 #[doc(alias("posix_spawn_file_actions_addclose"))]
323 pub fn add_close(&mut self, fd: RawFd) -> Result<()> {
324 let res = unsafe {
325 libc::posix_spawn_file_actions_addclose(
326 &mut self.fa as *mut libc::posix_spawn_file_actions_t,
327 fd,
328 )
329 };
330 Errno::result(res)?;
331
332 Ok(())
333 }
334}
335
336impl Drop for PosixSpawnFileActions {
337 fn drop(&mut self) {
338 unsafe {
339 libc::posix_spawn_file_actions_destroy(
340 &mut self.fa as *mut libc::posix_spawn_file_actions_t,
341 );
342 }
343 }
344}
345
346unsafe fn to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*mut libc::c_char> {
354 let mut v: Vec<*mut libc::c_char> = args
355 .iter()
356 .map(|s| s.as_ref().as_ptr().cast_mut())
357 .collect();
358 v.push(std::ptr::null_mut());
359 v
360}
361
362pub fn posix_spawn<P, SA, SE>(
365 path: &P,
366 file_actions: &PosixSpawnFileActions,
367 attr: &PosixSpawnAttr,
368 args: &[SA],
369 envp: &[SE],
370) -> Result<Pid>
371where
372 P: NixPath + ?Sized,
373 SA: AsRef<CStr>,
374 SE: AsRef<CStr>,
375{
376 let mut pid = 0;
377
378 let ret = unsafe {
379 let args_p = to_exec_array(args);
380 let env_p = to_exec_array(envp);
381
382 path.with_nix_path(|c_str| {
383 libc::posix_spawn(
384 &mut pid as *mut libc::pid_t,
385 c_str.as_ptr(),
386 &file_actions.fa as *const libc::posix_spawn_file_actions_t,
387 &attr.attr as *const libc::posix_spawnattr_t,
388 args_p.as_ptr(),
389 env_p.as_ptr(),
390 )
391 })?
392 };
393
394 if ret != 0 {
395 return Err(Errno::from_raw(ret));
396 }
397
398 Ok(Pid::from_raw(pid))
399}
400
401pub fn posix_spawnp<SA: AsRef<CStr>, SE: AsRef<CStr>>(
404 path: &CStr,
405 file_actions: &PosixSpawnFileActions,
406 attr: &PosixSpawnAttr,
407 args: &[SA],
408 envp: &[SE],
409) -> Result<Pid> {
410 let mut pid = 0;
411
412 let ret = unsafe {
413 let args_p = to_exec_array(args);
414 let env_p = to_exec_array(envp);
415
416 libc::posix_spawnp(
417 &mut pid as *mut libc::pid_t,
418 path.as_ptr(),
419 &file_actions.fa as *const libc::posix_spawn_file_actions_t,
420 &attr.attr as *const libc::posix_spawnattr_t,
421 args_p.as_ptr(),
422 env_p.as_ptr(),
423 )
424 };
425
426 if ret != 0 {
427 return Err(Errno::from_raw(ret));
428 }
429
430 Ok(Pid::from_raw(pid))
431}