feat(builtins): add nofork on builtins
Signed-off-by: Charlotte Meyer <dev@buffet.sh>
This commit is contained in:
parent
a5d971de35
commit
c3bcdf5cd8
3 changed files with 45 additions and 22 deletions
|
@ -9,6 +9,8 @@ use syn::{parse_macro_input, AttributeArgs, Ident, ItemFn, Signature};
|
|||
struct AttrArgs {
|
||||
#[darling(default)]
|
||||
description: String,
|
||||
#[darling(default)]
|
||||
nofork: bool,
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
|
@ -25,7 +27,10 @@ pub fn builtin(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||
} = sig;
|
||||
|
||||
let name = ident.to_string();
|
||||
let AttrArgs { description } = match AttrArgs::from_list(&attrs) {
|
||||
let AttrArgs {
|
||||
description,
|
||||
nofork,
|
||||
} = match AttrArgs::from_list(&attrs) {
|
||||
Ok(args) => args,
|
||||
Err(err) => return err.write_errors().into(),
|
||||
};
|
||||
|
@ -46,6 +51,7 @@ pub fn builtin(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||
#builtin {
|
||||
name: #name,
|
||||
description: #description,
|
||||
nofork: #nofork,
|
||||
fun: #ident,
|
||||
}
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@ use crate::Shell;
|
|||
pub struct Builtin {
|
||||
pub name: &'static str,
|
||||
pub description: &'static str,
|
||||
pub nofork: bool,
|
||||
pub fun: fn(shell: &mut Shell, args: &[Cow<OsStr>]),
|
||||
}
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ impl<'a> PreparedCommand<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
let child = match self.kind {
|
||||
match self.kind {
|
||||
CommandKind::External => {
|
||||
let mut cmd = Command::new(&self.cmd);
|
||||
cmd.args(self.args);
|
||||
|
@ -131,21 +131,30 @@ impl<'a> PreparedCommand<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
Pid::from_raw(child.id() as i32)
|
||||
}
|
||||
CommandKind::Builtin(builtin) => {
|
||||
match unsafe { unistd::fork() }.map_err(RuntimeError::ForkFailed)? {
|
||||
ForkResult::Parent { child } => child,
|
||||
ForkResult::Child => {
|
||||
fn redirect(old: Option<File>, new: RawFd) {
|
||||
if let Some(old) = old {
|
||||
let _ = unistd::dup2(old.as_raw_fd(), new);
|
||||
}
|
||||
let child = Pid::from_raw(child.id() as i32);
|
||||
if *pgid == Pid::from_raw(0) {
|
||||
*pgid = child;
|
||||
}
|
||||
|
||||
redirect(self.stdin, libc::STDIN_FILENO);
|
||||
redirect(self.stdout, libc::STDOUT_FILENO);
|
||||
redirect(self.stderr, libc::STDERR_FILENO);
|
||||
// prevent race conditions
|
||||
let _ = unistd::setpgid(child, *pgid);
|
||||
}
|
||||
CommandKind::Builtin(builtin) => {
|
||||
if builtin.nofork {
|
||||
self.do_redirects();
|
||||
(builtin.fun)(shell, &self.args);
|
||||
} else {
|
||||
match unsafe { unistd::fork() }.map_err(RuntimeError::ForkFailed)? {
|
||||
ForkResult::Parent { child } => {
|
||||
if *pgid == Pid::from_raw(0) {
|
||||
*pgid = child;
|
||||
}
|
||||
|
||||
// prevent race conditions
|
||||
let _ = unistd::setpgid(child, *pgid);
|
||||
}
|
||||
ForkResult::Child => {
|
||||
self.do_redirects();
|
||||
|
||||
let _ = pre_exec();
|
||||
(builtin.fun)(shell, &self.args);
|
||||
|
@ -153,16 +162,23 @@ impl<'a> PreparedCommand<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if *pgid == Pid::from_raw(0) {
|
||||
*pgid = child;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// prevent race conditions
|
||||
let _ = unistd::setpgid(child, *pgid);
|
||||
/// Redirect stdio.
|
||||
fn do_redirects(&self) {
|
||||
fn redirect(old: &Option<File>, new: RawFd) {
|
||||
if let Some(old) = old {
|
||||
let _ = unistd::dup2(old.as_raw_fd(), new);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
redirect(&self.stdin, libc::STDIN_FILENO);
|
||||
redirect(&self.stdout, libc::STDOUT_FILENO);
|
||||
redirect(&self.stderr, libc::STDERR_FILENO);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue