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 {
|
struct AttrArgs {
|
||||||
#[darling(default)]
|
#[darling(default)]
|
||||||
description: String,
|
description: String,
|
||||||
|
#[darling(default)]
|
||||||
|
nofork: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
|
@ -25,7 +27,10 @@ pub fn builtin(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
} = sig;
|
} = sig;
|
||||||
|
|
||||||
let name = ident.to_string();
|
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,
|
Ok(args) => args,
|
||||||
Err(err) => return err.write_errors().into(),
|
Err(err) => return err.write_errors().into(),
|
||||||
};
|
};
|
||||||
|
@ -46,6 +51,7 @@ pub fn builtin(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
#builtin {
|
#builtin {
|
||||||
name: #name,
|
name: #name,
|
||||||
description: #description,
|
description: #description,
|
||||||
|
nofork: #nofork,
|
||||||
fun: #ident,
|
fun: #ident,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,6 +8,7 @@ use crate::Shell;
|
||||||
pub struct Builtin {
|
pub struct Builtin {
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub description: &'static str,
|
pub description: &'static str,
|
||||||
|
pub nofork: bool,
|
||||||
pub fun: fn(shell: &mut Shell, args: &[Cow<OsStr>]),
|
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 => {
|
CommandKind::External => {
|
||||||
let mut cmd = Command::new(&self.cmd);
|
let mut cmd = Command::new(&self.cmd);
|
||||||
cmd.args(self.args);
|
cmd.args(self.args);
|
||||||
|
@ -131,21 +131,30 @@ impl<'a> PreparedCommand<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Pid::from_raw(child.id() as i32)
|
let child = Pid::from_raw(child.id() as i32);
|
||||||
}
|
if *pgid == Pid::from_raw(0) {
|
||||||
CommandKind::Builtin(builtin) => {
|
*pgid = child;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
redirect(self.stdin, libc::STDIN_FILENO);
|
// prevent race conditions
|
||||||
redirect(self.stdout, libc::STDOUT_FILENO);
|
let _ = unistd::setpgid(child, *pgid);
|
||||||
redirect(self.stderr, libc::STDERR_FILENO);
|
}
|
||||||
|
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();
|
let _ = pre_exec();
|
||||||
(builtin.fun)(shell, &self.args);
|
(builtin.fun)(shell, &self.args);
|
||||||
|
@ -153,16 +162,23 @@ impl<'a> PreparedCommand<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if *pgid == Pid::from_raw(0) {
|
Ok(())
|
||||||
*pgid = child;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent race conditions
|
/// Redirect stdio.
|
||||||
let _ = unistd::setpgid(child, *pgid);
|
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