2022-11-02 15:33:29 +00:00
|
|
|
mod builtins;
|
2022-09-15 20:16:37 +00:00
|
|
|
mod pipeline;
|
2022-11-02 15:33:29 +00:00
|
|
|
|
|
|
|
use std::{
|
|
|
|
ffi::OsString,
|
|
|
|
fs::File,
|
|
|
|
io::{BufRead, BufReader, Write},
|
|
|
|
os::unix::{ffi::OsStringExt, io::FromRawFd},
|
|
|
|
process,
|
|
|
|
};
|
|
|
|
|
|
|
|
use nix::{
|
|
|
|
ioctl_write_int_bad, libc,
|
|
|
|
pty::{self, OpenptyResult},
|
|
|
|
sys,
|
|
|
|
unistd::{self, ForkResult},
|
|
|
|
};
|
|
|
|
|
|
|
|
ioctl_write_int_bad!(tiocsctty, libc::TIOCSCTTY);
|
|
|
|
|
|
|
|
/// Forks to redirect stdin, stderr, stdout, then run the commands.
|
|
|
|
/// Relies on inserting a NUL byte in the end, so there shouldn't be NUL in the output.
|
|
|
|
fn collect_output<F>(mut f: F) -> OsString
|
|
|
|
where
|
|
|
|
F: FnMut(),
|
|
|
|
{
|
|
|
|
let OpenptyResult { master, slave } = pty::openpty(None, None).unwrap();
|
|
|
|
|
|
|
|
match unsafe { unistd::fork() }.unwrap() {
|
|
|
|
ForkResult::Parent { child } => {
|
|
|
|
sys::wait::waitpid(child, None).unwrap();
|
|
|
|
}
|
|
|
|
ForkResult::Child => {
|
|
|
|
unistd::setsid().unwrap();
|
|
|
|
unsafe { tiocsctty(slave, 0) }.unwrap();
|
|
|
|
|
|
|
|
unistd::dup2(slave, libc::STDIN_FILENO).unwrap();
|
|
|
|
unistd::dup2(slave, libc::STDOUT_FILENO).unwrap();
|
|
|
|
unistd::dup2(slave, libc::STDERR_FILENO).unwrap();
|
|
|
|
|
|
|
|
let _ = unistd::close(master);
|
|
|
|
let _ = unistd::close(slave);
|
|
|
|
|
|
|
|
f();
|
|
|
|
|
|
|
|
process::exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let master = unsafe { File::from_raw_fd(master) };
|
|
|
|
let mut slave = unsafe { File::from_raw_fd(slave) };
|
|
|
|
|
2022-11-05 16:21:34 +00:00
|
|
|
slave.write_all(&[0]).unwrap();
|
2022-11-02 15:33:29 +00:00
|
|
|
let mut r = BufReader::new(master);
|
|
|
|
let mut buf = vec![];
|
|
|
|
r.read_until(0, &mut buf).unwrap();
|
|
|
|
|
|
|
|
OsString::from_vec(buf[..buf.len() - 1].to_vec())
|
|
|
|
}
|