use std::io::Read;
use std::os::fd::FromRawFd;
use nix::sys::wait::{WaitStatus, waitpid};
use nix::unistd::{ForkResult, fork};
use crate::env::ShellEnv;
use crate::exec::Executor;
use crate::parser::ast::Program;
pub fn execute(env: &mut ShellEnv, program: &Program) -> String {
let mut pipe_fds: [libc::c_int; 2] = [0; 2];
let ret = unsafe { libc::pipe(pipe_fds.as_mut_ptr()) };
if ret != 0 {
eprintln!("yosh: pipe: failed to create pipe");
return String::new();
}
let pipe_read = pipe_fds[0];
let pipe_write = pipe_fds[1];
match unsafe { fork() } {
Err(e) => {
eprintln!("yosh: fork: {}", e);
unsafe {
libc::close(pipe_read);
libc::close(pipe_write);
}
String::new()
}
Ok(ForkResult::Child) => {
unsafe { libc::close(pipe_read) };
unsafe {
libc::dup2(pipe_write, 1);
libc::close(pipe_write);
}
let mut child_env = ShellEnv {
vars: env.vars.clone(),
exec: crate::env::ExecState {
last_exit_status: env.exec.last_exit_status,
flow_control: None,
},
process: crate::env::ProcessState {
shell_pid: env.process.shell_pid,
shell_pgid: env.process.shell_pgid,
jobs: env.process.jobs.clone(),
},
mode: crate::env::ShellMode {
options: env.mode.options.clone(),
is_interactive: false,
in_dot_script: false,
},
shell_name: env.shell_name.clone(),
functions: env.functions.clone(),
traps: env.traps.clone(),
aliases: env.aliases.clone(),
history: env.history.clone(),
};
child_env.traps.reset_for_command_sub();
let mut executor = Executor::from_env(child_env);
let status = executor.exec_program(program);
std::process::exit(status);
}
Ok(ForkResult::Parent { child }) => {
unsafe { libc::close(pipe_write) };
let mut output = String::new();
let mut file = unsafe { std::fs::File::from_raw_fd(pipe_read) };
if let Err(e) = file.read_to_string(&mut output) {
eprintln!("yosh: command substitution: read error: {}", e);
}
match waitpid(child, None) {
Ok(WaitStatus::Exited(_, code)) => {
env.exec.last_exit_status = code;
}
Ok(WaitStatus::Signaled(_, signal, _)) => {
env.exec.last_exit_status = 128 + signal as i32;
}
Ok(_) => {}
Err(e) => {
eprintln!("yosh: waitpid: {}", e);
}
}
while output.ends_with('\n') {
output.pop();
}
output
}
}
}