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}