1use std::mem::MaybeUninit;
2
3use libc;
4use libc::c_int;
5use local_shell::current_shell;
6use result::check_errno;
7use result::ShellError;
8use result::ShellResult;
9use result::ShellResultExt;
10use std::io::Read;
11use std::process::Child;
12use std::process::Command;
13use std::sync::Arc;
14use std::sync::RwLock;
15
16#[derive(Debug)]
17pub struct ShellChildCore {
18 command_line: String,
19 pub child: Child,
20}
21
22impl ShellChildCore {
23 fn new(command_line: String, child: Child) -> ShellChildCore {
24 ShellChildCore {
25 command_line: command_line,
26 child: child,
27 }
28 }
29
30 pub fn signal(&self, sig: c_int) -> Result<(), ShellError> {
31 let kill_pid = self.child.id() as i32;
32
33 info!("Sending signal {} to {}", sig, self.child.id());
34 unsafe {
35 check_errno("kill", libc::kill(kill_pid, sig))?;
36 }
37 Ok(())
38 }
39 #[allow(warnings)]
40 pub fn wait_null(&self) -> Result<(), ShellError> {
41 unsafe {
42 let mut info = MaybeUninit::<libc::siginfo_t>::uninit();
43 check_errno(
44 "waitid",
45 libc::waitid(
46 libc::P_PID,
47 self.child.id() as u32,
48 &mut info.assume_init(),
49 libc::WEXITED | libc::WNOWAIT,
50 ),
51 )?;
52 }
53 Ok(())
54 }
55
56 pub fn wait(mut self) -> ShellResult {
57 ShellResult::from_status(self.command_line, self.child.wait()?)
58 }
59}
60
61pub type ShellChildArc = Arc<RwLock<Option<ShellChildCore>>>;
74
75pub struct ShellChild(pub ShellChildArc);
77
78impl ShellChild {
79 pub fn new(line: String, mut command: Command) -> Result<ShellChild, ShellError> {
80 let shell = current_shell();
81 let mut lock = shell.lock().unwrap();
82 if lock.signaled() {
83 return Err(ShellError::from_signal(line, 101));
84 }
85 let child = command.spawn()?;
86 let process = Arc::new(RwLock::new(Some(ShellChildCore::new(line, child))));
87 lock.add_process(&process);
88 Ok(ShellChild(process))
89 }
90
91 pub fn signal(&self, signal: c_int) -> Result<(), ShellError> {
93 let process = &self.0;
94 let process = process.read().unwrap();
95 process
96 .as_ref()
97 .ok_or(ShellError::NoSuchProcess)?
98 .signal(signal)
99 }
100
101 pub fn wait(self) -> ShellResult {
103 {
104 let data = self.0.read().unwrap();
105 data.as_ref()
106 .ok_or(ShellError::NoSuchProcess)?
107 .wait_null()?;
108 }
109 let result = {
110 let mut data = self.0.write().unwrap();
111 data.take()
112 .ok_or(ShellError::NoSuchProcess)
113 .and_then(|c| c.wait())
114 };
115 {
116 let shell = current_shell();
117 let mut lock = shell.lock().unwrap();
118 lock.remove_process(&self.0);
119 }
120 result
121 }
122
123 pub fn stdout_utf8(self) -> Result<String, ShellError> {
126 let mut string = String::new();
127 {
128 let mut lock = self.0.write().unwrap();
129 let lock = lock.as_mut().ok_or(ShellError::NoSuchProcess)?;
130 lock.child
131 .stdout
132 .as_mut()
133 .unwrap()
134 .read_to_string(&mut string)?;
135 }
136 self.wait()?;
137 Ok(string)
138 }
139}