process_wrap/std/
process_session.rs

1use std::{
2	io::{Error, Result},
3	os::unix::process::CommandExt,
4	process::Command,
5};
6
7use nix::unistd::{setsid, Pid};
8#[cfg(feature = "tracing")]
9use tracing::instrument;
10
11use super::{CommandWrap, CommandWrapper};
12
13/// Wrapper which creates a new session and group for the `Command`.
14///
15/// This wrapper is only available on Unix.
16///
17/// It creates a new session and new process group and sets the [`Command`] as its leader.
18/// See [setsid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html).
19///
20/// You may find that some programs behave differently or better when running in a session rather
21/// than a process group, or vice versa.
22///
23/// This wrapper uses [the same child wrapper as `ProcessGroup`](super::ProcessGroupChild) and does
24/// the same setup (plus the session setup); using both together is unnecessary and may misbehave.
25#[derive(Clone, Copy, Debug)]
26pub struct ProcessSession;
27
28impl CommandWrapper for ProcessSession {
29	#[cfg_attr(feature = "tracing", instrument(level = "debug", skip(self)))]
30	fn pre_spawn(&mut self, command: &mut Command, _core: &CommandWrap) -> Result<()> {
31		unsafe {
32			command.pre_exec(move || setsid().map_err(Error::from).map(|_| ()));
33		}
34
35		Ok(())
36	}
37
38	#[cfg_attr(feature = "tracing", instrument(level = "debug", skip(self)))]
39	fn wrap_child(
40		&mut self,
41		inner: Box<dyn super::core::ChildWrapper>,
42		_core: &CommandWrap,
43	) -> Result<Box<dyn super::core::ChildWrapper>> {
44		let pgid = Pid::from_raw(i32::try_from(inner.id()).expect("Command PID > i32::MAX"));
45
46		Ok(Box::new(super::ProcessGroupChild::new(inner, pgid)))
47	}
48}