command_group/
unix_ext.rs

1use std::{
2	convert::TryInto,
3	io::{Error, Result},
4	process::Child,
5};
6
7use nix::{
8	sys::signal::{kill, Signal},
9	unistd::Pid,
10};
11
12/// Unix-specific extensions to process [`Child`]ren.
13pub trait UnixChildExt {
14	/// Sends a signal to the child process. If the process has already exited, an [`InvalidInput`]
15	/// error is returned.
16	///
17	/// # Examples
18	///
19	/// Basic usage:
20	///
21	/// ```no_run
22	/// use std::process::Command;
23	/// use command_group::{UnixChildExt, Signal};
24	///
25	/// let mut command = Command::new("yes");
26	/// if let Ok(mut child) = command.spawn() {
27	///     child.signal(Signal::SIGTERM).expect("command wasn't running");
28	/// } else {
29	///     println!("yes command didn't start");
30	/// }
31	/// ```
32	///
33	/// With a process group:
34	///
35	/// ```no_run
36	/// use std::process::Command;
37	/// use command_group::{CommandGroup, UnixChildExt, Signal};
38	///
39	/// let mut command = Command::new("yes");
40	/// if let Ok(mut child) = command.group_spawn() {
41	///     child.signal(Signal::SIGTERM).expect("command wasn't running");
42	/// } else {
43	///     println!("yes command didn't start");
44	/// }
45	/// ```
46	///
47	/// [`InvalidInput`]: std::io::ErrorKind::InvalidInput
48	fn signal(&self, sig: Signal) -> Result<()>;
49}
50
51impl UnixChildExt for Child {
52	fn signal(&self, sig: Signal) -> Result<()> {
53		let pid = Pid::from_raw(self.id().try_into().expect("Command PID > i32::MAX"));
54		kill(pid, sig).map_err(Error::from)
55	}
56}
57
58#[cfg(feature = "with-tokio")]
59impl UnixChildExt for ::tokio::process::Child {
60	fn signal(&self, sig: Signal) -> Result<()> {
61		if let Some(id) = self.id() {
62			let pid = Pid::from_raw(id.try_into().expect("Command PID > i32::MAX"));
63			kill(pid, sig).map_err(Error::from)
64		} else {
65			Ok(())
66		}
67	}
68}