rust_shell/
shell_child.rs1use libc::c_int;
16use libc;
17use local_shell::current_shell;
18use result::ShellError;
19use result::ShellResult;
20use result::ShellResultExt;
21use result::check_errno;
22use std::io::Read;
23use std::mem;
24use std::process::Child;
25use std::process::Command;
26use std::sync::Arc;
27use std::sync::RwLock;
28
29#[derive(Debug)]
30pub struct ShellChildCore {
31 command_line: String,
32 pub child: Child,
33}
34
35impl ShellChildCore {
36 fn new(command_line: String, child: Child) -> ShellChildCore {
37 ShellChildCore {
38 command_line: command_line,
39 child: child,
40 }
41 }
42
43 pub fn signal(&self, sig: c_int) -> Result<(), ShellError> {
44 let kill_pid = self.child.id() as i32;
45
46 info!("Sending signal {} to {}", sig, self.child.id());
47 unsafe {
48 check_errno("kill", libc::kill(kill_pid, sig))?;
49 }
50 Ok(())
51 }
52
53 pub fn wait_null(&self) -> Result<(), ShellError> {
54 unsafe {
55 let mut info = mem::uninitialized::<libc::siginfo_t>();
56 check_errno("waitid",
57 libc::waitid(
58 libc::P_PID,
59 self.child.id() as u32,
60 &mut info as *mut libc::siginfo_t,
61 libc::WEXITED | libc::WNOWAIT))?;
62 }
63 Ok(())
64 }
65
66 pub fn wait(mut self) -> ShellResult {
67 ShellResult::from_status(self.command_line, self.child.wait()?)
68 }
69}
70
71pub type ShellChildArc = Arc<RwLock<Option<ShellChildCore>>>;
84
85pub struct ShellChild(pub ShellChildArc);
87
88impl ShellChild {
89 pub fn new(line: String, mut command: Command)
90 -> Result<ShellChild, ShellError> {
91 let shell = current_shell();
92 let mut lock = shell.lock().unwrap();
93 if lock.signaled() {
94 return Err(ShellError::from_signal(line, 101))
95 }
96 let child = command.spawn()?;
97 let process = Arc::new(RwLock::new(
98 Some(ShellChildCore::new(line, child))));
99 lock.add_process(&process);
100 Ok(ShellChild(process))
101 }
102
103 pub fn signal(&self, signal: c_int) -> Result<(), ShellError> {
105 let process = &self.0;
106 let process = process.read().unwrap();
107 process.as_ref().ok_or(ShellError::NoSuchProcess)?.signal(signal)
108 }
109
110 pub fn wait(self) -> ShellResult {
112 {
113 let data = self.0.read().unwrap();
114 data.as_ref().ok_or(ShellError::NoSuchProcess)?.wait_null()?;
115 }
116 let result = {
117 let mut data = self.0.write().unwrap();
118 data.take().ok_or(ShellError::NoSuchProcess)
119 .and_then(|c| c.wait())
120 };
121 {
122 let shell = current_shell();
123 let mut lock = shell.lock().unwrap();
124 lock.remove_process(&self.0);
125 }
126 result
127 }
128
129 pub fn stdout_utf8(self) -> Result<String, ShellError> {
132 let mut string = String::new();
133 {
134 let mut lock = self.0.write().unwrap();
135 let lock = lock.as_mut().ok_or(ShellError::NoSuchProcess)?;
136 lock.child.stdout.as_mut().unwrap().read_to_string(&mut string)?;
137 }
138 self.wait()?;
139 Ok(string)
140 }
141}