1use std::collections::HashMap;
29use std::env;
30use std::ffi::OsStr;
31use std::process::{Command, ExitStatus, Output, Stdio};
32
33use std::io::Write;
35use std::iter::IntoIterator;
36
37pub struct OutputString {
39 pub status: ExitStatus,
40 pub stdout: String,
41 pub stderr: String,
42}
43
44fn setup_envs<I, K, V>(cmd: &mut Command, vars: I) -> &mut Command
45where
46 I: IntoIterator<Item = (K, V)>,
47 K: AsRef<OsStr>,
48 V: AsRef<OsStr>,
49{
50 let filtered_env: HashMap<String, String> = env::vars()
51 .filter(|(k, _)| k == "TERM" || k == "TZ" || k == "PATH" || k == "LD_LIBRARY_PATH")
52 .collect();
53 cmd.env_clear()
54 .envs(filtered_env)
55 .envs(vars)
56 .env("LANG", "C")
57}
58
59pub fn exec_target<I, S>(target_exe: &str, args: I) -> OutputString
60where
61 I: IntoIterator<Item = S>,
62 S: AsRef<OsStr>,
63{
64 let mut cmd: Command = Command::new(target_exe);
65 setup_envs(&mut cmd, Vec::<(&str, &str)>::new())
66 .args(args)
67 .stdout(Stdio::piped())
68 .stderr(Stdio::piped());
69 let child = cmd.spawn().expect("failed to execute child");
70 let output: Output = child.wait_with_output().expect("failed to wait on child");
71 OutputString {
73 status: output.status,
74 stdout: String::from(String::from_utf8_lossy(&output.stdout)),
75 stderr: String::from(String::from_utf8_lossy(&output.stderr)),
76 }
77}
78
79pub fn exec_target_with_env<I, S, IKV, K, V>(target_exe: &str, args: I, env: IKV) -> OutputString
80where
81 I: IntoIterator<Item = S>,
82 S: AsRef<OsStr>,
83 IKV: IntoIterator<Item = (K, V)>,
84 K: AsRef<OsStr>,
85 V: AsRef<OsStr>,
86{
87 let mut cmd: Command = Command::new(target_exe);
88 setup_envs(&mut cmd, env)
89 .args(args)
90 .stdout(Stdio::piped())
91 .stderr(Stdio::piped());
92 let child = cmd.spawn().expect("failed to execute child");
93 let output: Output = child.wait_with_output().expect("failed to wait on child");
94 OutputString {
96 status: output.status,
97 stdout: String::from(String::from_utf8_lossy(&output.stdout)),
98 stderr: String::from(String::from_utf8_lossy(&output.stderr)),
99 }
100}
101
102pub fn exec_target_with_in<I, S>(target_exe: &str, args: I, in_bytes: &[u8]) -> OutputString
103where
104 I: IntoIterator<Item = S>,
105 S: AsRef<OsStr>,
106{
107 let mut cmd: Command = Command::new(target_exe);
108 setup_envs(&mut cmd, Vec::<(&str, &str)>::new())
109 .args(args)
110 .stdin(Stdio::piped())
111 .stdout(Stdio::piped())
112 .stderr(Stdio::piped());
113 let mut child = cmd.spawn().expect("failed to execute child");
114 {
115 let stdin = child.stdin.as_mut().expect("failed to get stdin");
116 let r = stdin.write_all(in_bytes);
117 match r {
118 Err(ioe) if ioe.kind() == std::io::ErrorKind::BrokenPipe => {
119 }
121 _ => {
122 r.expect("failed to write to stdin");
123 }
124 }
125 }
126 let output: Output = child.wait_with_output().expect("failed to wait on child");
127 OutputString {
129 status: output.status,
130 stdout: String::from(String::from_utf8_lossy(&output.stdout)),
131 stderr: String::from(String::from_utf8_lossy(&output.stderr)),
132 }
133}
134
135pub fn exec_target_with_env_in<I, S, IKV, K, V>(
157 target_exe: &str,
158 args: I,
159 env: IKV,
160 in_bytes: &[u8],
161) -> OutputString
162where
163 I: IntoIterator<Item = S>,
164 S: AsRef<OsStr>,
165 IKV: IntoIterator<Item = (K, V)>,
166 K: AsRef<OsStr>,
167 V: AsRef<OsStr>,
168{
169 let mut cmd: Command = Command::new(target_exe);
170 setup_envs(&mut cmd, env)
171 .args(args)
172 .stdin(Stdio::piped())
173 .stdout(Stdio::piped())
174 .stderr(Stdio::piped());
175 let mut child = cmd.spawn().expect("failed to execute child");
176 {
177 let stdin = child.stdin.as_mut().expect("failed to get stdin");
178 let r = stdin.write_all(in_bytes);
179 match r {
180 Err(ioe) if ioe.kind() == std::io::ErrorKind::BrokenPipe => {
181 }
183 _ => {
184 r.expect("failed to write to stdin");
185 }
186 }
187 }
188 let output: Output = child.wait_with_output().expect("failed to wait on child");
189 OutputString {
191 status: output.status,
192 stdout: String::from(String::from_utf8_lossy(&output.stdout)),
193 stderr: String::from(String::from_utf8_lossy(&output.stderr)),
194 }
195}
196
197pub fn args_from(s: &str) -> Vec<String> {
209 let mut v: Vec<String> = Vec::new();
210 let mut ss = String::new();
211 let mut enter_q: bool = false;
212 let mut enter_qq: bool = false;
213 let mut back_slash: bool = false;
214 for c in s.chars() {
216 if back_slash {
217 ss.push(c);
218 back_slash = false;
219 continue;
220 }
221 if c == '\\' {
222 back_slash = true;
223 continue;
224 }
225 if enter_q {
226 if c == '\'' {
227 v.push(ss.clone());
228 ss.clear();
229 enter_q = false;
230 } else {
231 ss.push(c);
232 }
233 continue;
234 }
235 if enter_qq {
236 if c == '\"' {
237 v.push(ss.clone());
238 ss.clear();
239 enter_qq = false;
240 } else {
241 ss.push(c);
242 }
243 continue;
244 }
245 match c {
246 '\'' => {
247 enter_q = true;
248 continue;
249 }
250 '\"' => {
251 enter_qq = true;
252 continue;
253 }
254 ' ' => {
255 if !ss.is_empty() {
256 v.push(ss.clone());
257 ss.clear();
258 }
259 }
260 _ => {
261 ss.push(c);
262 }
263 }
264 }
265 if !ss.is_empty() {
266 v.push(ss.clone());
267 ss.clear();
268 }
269 v
271}