mod builtins; mod pipeline; 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(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) }; slave.write_all(&[0]).unwrap(); 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()) }