unix_exec_output_catcher/
exec.rs1use crate::child::ChildProcess;
4use crate::error::UECOError;
5use crate::libc_util::{libc_ret_to_result, LibcSyscall};
6use crate::pipe::CatchPipes;
7use crate::reader::{OutputReader, SimpleOutputReader, SimultaneousOutputReader};
8use crate::OCatchStrategy;
9use crate::ProcessOutput;
10use std::ffi::CString;
11use std::sync::{Arc, Mutex};
12
13pub fn exec(executable: &str, args: Vec<&str>) -> Result<(), UECOError> {
20 let executable = CString::new(executable).expect("Executable must not contain null!");
22 let executable = executable.as_c_str();
23
24 let args = args
26 .iter()
27 .map(|s| CString::new(*s).expect("Arg not contain null!"))
28 .collect::<Vec<CString>>();
29 let mut args_nl = args
31 .iter()
32 .map(|cs| cs.as_ptr())
33 .collect::<Vec<*const libc::c_char>>();
34 args_nl.push(std::ptr::null());
35
36 let ret = unsafe { libc::execvp(executable.as_ptr(), args_nl.as_ptr()) };
37 let res = libc_ret_to_result(ret, LibcSyscall::Execvp);
38
39 res
40}
41
42pub fn fork_exec_and_catch(
63 executable: &str,
64 args: Vec<&str>,
65 strategy: OCatchStrategy,
66) -> Result<ProcessOutput, UECOError> {
67 let cp = CatchPipes::new(strategy)?;
68 let child = match strategy {
69 OCatchStrategy::StdCombined => setup_and_execute_strategy_combined(executable, args, cp),
70 OCatchStrategy::StdSeparately => {
71 setup_and_execute_strategy_separately(executable, args, cp)
72 }
73 };
74 let mut child = child?;
75 child.dispatch()?;
76 let output = match strategy {
77 OCatchStrategy::StdCombined => SimpleOutputReader::new(&mut child).read_all_bl(),
78 OCatchStrategy::StdSeparately => {
79 SimultaneousOutputReader::new(Arc::new(Mutex::new(child))).read_all_bl()
80 }
81 };
82 output
83}
84
85fn setup_and_execute_strategy_combined(
88 executable: &str,
89 args: Vec<&str>,
90 cp: CatchPipes,
91) -> Result<ChildProcess, UECOError> {
92 let pipe = if let CatchPipes::Combined(pipe) = cp {
93 pipe
94 } else {
95 panic!("Wrong CatchPipe-variant")
96 };
97 let pipe = Arc::new(Mutex::new(pipe));
98 let pipe_closure = pipe.clone();
99 let child_setup = move || {
101 let mut pipe_closure = pipe_closure.lock().unwrap();
102 pipe_closure.mark_as_child_process()?;
103 pipe_closure.connect_to_stdout()?;
104 pipe_closure.connect_to_stderr()?;
105 Ok(())
106 };
107 let pipe_closure = pipe.clone();
108 let parent_setup = move || {
109 let mut pipe_closure = pipe_closure.lock().unwrap();
110 pipe_closure.mark_as_parent_process()?;
111 Ok(())
112 };
113 let child = ChildProcess::new(
114 executable,
115 args,
116 Box::new(child_setup),
117 Box::new(parent_setup),
118 pipe.clone(),
119 pipe,
120 );
121 Ok(child)
122}
123
124fn setup_and_execute_strategy_separately(
127 executable: &str,
128 args: Vec<&str>,
129 cp: CatchPipes,
130) -> Result<ChildProcess, UECOError> {
131 let (stdout_pipe, stderr_pipe) = if let CatchPipes::Separately { stdout, stderr } = cp {
132 (stdout, stderr)
133 } else {
134 panic!("Wrong CatchPipe-variant")
135 };
136 let stdout_pipe = Arc::new(Mutex::new(stdout_pipe));
137 let stderr_pipe = Arc::new(Mutex::new(stderr_pipe));
138 let stdout_pipe_closure = stdout_pipe.clone();
139 let stderr_pipe_closure = stderr_pipe.clone();
140 let child_setup = move || {
142 let mut stdout_pipe_closure = stdout_pipe_closure.lock().unwrap();
143 let mut stderr_pipe_closure = stderr_pipe_closure.lock().unwrap();
144 stdout_pipe_closure.mark_as_child_process()?;
145 stderr_pipe_closure.mark_as_child_process()?;
146 stdout_pipe_closure.connect_to_stdout()?;
147 stderr_pipe_closure.connect_to_stderr()?;
148 Ok(())
149 };
150 let stdout_pipe_closure = stdout_pipe.clone();
151 let stderr_pipe_closure = stderr_pipe.clone();
152 let parent_setup = move || {
153 let mut stdout_pipe_closure = stdout_pipe_closure.lock().unwrap();
154 let mut stderr_pipe_closure = stderr_pipe_closure.lock().unwrap();
155 stdout_pipe_closure.mark_as_parent_process()?;
156 stderr_pipe_closure.mark_as_parent_process()?;
157 Ok(())
158 };
159 let child = ChildProcess::new(
160 executable,
161 args,
162 Box::new(child_setup),
163 Box::new(parent_setup),
164 stdout_pipe,
165 stderr_pipe,
166 );
167 Ok(child)
168}