use std::{
borrow::Cow,
process::exit,
ffi::CString,
};
use nix::{
errno::Errno,
unistd::{self, execvp, getpid, Pid, ForkResult},
sys::wait::{waitpid, WaitStatus, WaitPidFlag},
};
mod io;
pub use self::io::IO;
pub mod jobs;
pub use self::jobs::Jobs;
mod session;
mod signal;
mod thread;
#[derive(Debug)]
pub struct Process {
argv: Vec<CString>,
pid: Pid,
}
impl Process {
pub fn new(argv: Vec<CString>) -> Self {
Process {
argv,
pid: getpid(),
}
}
pub fn body(&self) -> String {
self.argv.iter().map(|a| {
a.to_string_lossy()
}).collect::<Vec<Cow<str>>>().join(" ")
}
pub fn pid(&self) -> Pid {
self.pid
}
pub fn fork(argv: Vec<CString>, io: IO) -> Result<Self, nix::Error> {
match unsafe { unistd::fork() } {
Ok(ForkResult::Parent { child }) => {
Ok(Process {
argv,
pid: child,
})
},
Ok(ForkResult::Child) => {
let process = Process {
argv,
pid: getpid(),
};
io.dup()?;
if let Err(e) = process.exec() {
match e {
Errno::ENOENT => {
let name = process.argv[0].to_string_lossy();
eprintln!("oursh: {}: command not found", name);
exit(127);
},
_ => exit(128),
}
} else {
unreachable!()
}
},
Err(e) => Err(e),
}
}
fn exec(&self) -> Result<(), nix::Error> {
execvp(&self.argv[0], &self.argv.iter()
.map(|a| a.as_c_str())
.collect::<Vec<_>>()[..]).map(|_| ())
}
}
pub trait Wait {
fn wait(&self) -> nix::Result<WaitStatus>;
fn status(&self) -> nix::Result<WaitStatus>;
}
impl Wait for Pid {
fn wait(&self) -> nix::Result<WaitStatus> {
waitpid(Some(*self), None)
}
fn status(&self) -> nix::Result<WaitStatus> {
waitpid(Some(*self), Some(WaitPidFlag::WNOHANG))
}
}
impl Wait for Process {
fn wait(&self) -> nix::Result<WaitStatus> {
self.pid.wait()
}
fn status(&self) -> nix::Result<WaitStatus> {
self.pid.status()
}
}
#[derive(Debug)]
pub struct ProcessGroup(pub Process);
impl ProcessGroup {
pub fn leader(&self) -> &Process {
&self.0
}
pub fn leader_mut(&mut self) -> &mut Process {
&mut self.0
}
}