From 1327c2a7ba3b81fe69e4126270b2cfe24c8aa4ee Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Mon, 17 Jan 2022 00:54:50 -0500 Subject: make nbsh -c work --- src/main.rs | 32 ++++++++++++++++++++++++++++---- src/runner/mod.rs | 36 ++++++++++++++---------------------- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/src/main.rs b/src/main.rs index b65fb1e..48d2b2b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,17 +24,41 @@ mod prelude; mod runner; mod shell; -async fn async_main() -> anyhow::Result { +use prelude::*; + +async fn async_main( + shell_write: Option<&async_std::fs::File>, +) -> anyhow::Result { if std::env::args().nth(1).as_deref() == Some("-c") { - return runner::run(std::env::args().nth(2).as_deref().unwrap()) - .await; + return runner::run( + std::env::args().nth(2).as_deref().unwrap(), + shell_write, + ) + .await; } shell::main().await } fn main() { - match async_std::task::block_on(async_main()) { + // need to do this here because the async-std executor allocates some fds, + // and so in the case where we aren't being called from the main shell and + // fd 3 wasn't preallocated in advance, we need to be able to tell that + // before async-std opens something on fd 3 + let shell_write = if nix::sys::stat::fstat(3).is_ok() { + nix::fcntl::fcntl( + 3, + nix::fcntl::FcntlArg::F_SETFD(nix::fcntl::FdFlag::FD_CLOEXEC), + ) + .unwrap(); + // Safety: we don't create File instances for or read/write data on fd + // 3 anywhere else + Some(unsafe { async_std::fs::File::from_raw_fd(3) }) + } else { + None + }; + + match async_std::task::block_on(async_main(shell_write.as_ref())) { Ok(code) => { std::process::exit(code); } diff --git a/src/runner/mod.rs b/src/runner/mod.rs index 0f02ef0..98894b3 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -69,16 +69,14 @@ enum Frame { For(bool, usize, Vec), } -pub async fn run(commands: &str) -> anyhow::Result { - // Safety: we don't create File instances for or read/write data on fd - // 3 anywhere else - let shell_write = unsafe { async_std::fs::File::from_raw_fd(3) }; - cloexec(3)?; - +pub async fn run( + commands: &str, + shell_write: Option<&async_std::fs::File>, +) -> anyhow::Result { let mut env = Env::new_from_env()?; - run_commands(commands, &mut env, &shell_write).await?; + run_commands(commands, &mut env, shell_write).await?; let status = env.latest_status(); - write_event(&shell_write, Event::Exit(env)).await?; + write_event(shell_write, Event::Exit(env)).await?; if let Some(signal) = status.signal() { nix::sys::signal::raise(signal.try_into().unwrap())?; @@ -89,7 +87,7 @@ pub async fn run(commands: &str) -> anyhow::Result { async fn run_commands( commands: &str, env: &mut Env, - shell_write: &async_std::fs::File, + shell_write: Option<&async_std::fs::File>, ) -> anyhow::Result<()> { let commands = crate::parse::ast::Commands::parse(commands)?; let commands = commands.commands(); @@ -194,7 +192,7 @@ async fn run_commands( async fn run_pipeline( pipeline: crate::parse::ast::Pipeline, env: &mut Env, - shell_write: &async_std::fs::File, + shell_write: Option<&async_std::fs::File>, ) -> anyhow::Result<()> { write_event(shell_write, Event::RunPipeline(env.idx(), pipeline.span())) .await?; @@ -224,11 +222,13 @@ async fn run_pipeline( } async fn write_event( - mut fh: &async_std::fs::File, + fh: Option<&async_std::fs::File>, event: Event, ) -> anyhow::Result<()> { - fh.write_all(&bincode::serialize(&event)?).await?; - fh.flush().await?; + if let Some(mut fh) = fh { + fh.write_all(&bincode::serialize(&event)?).await?; + fh.flush().await?; + } Ok(()) } @@ -277,7 +277,7 @@ async fn wait_children( pg: Option, env: &Env, io: &builtins::Io, - shell_write: &async_std::fs::File, + shell_write: Option<&async_std::fs::File>, ) -> std::process::ExitStatus { enum Res { Child(nix::Result), @@ -514,14 +514,6 @@ fn setpgid_parent( Ok(()) } -fn cloexec(fd: std::os::unix::io::RawFd) -> anyhow::Result<()> { - nix::fcntl::fcntl( - fd, - nix::fcntl::FcntlArg::F_SETFD(nix::fcntl::FdFlag::FD_CLOEXEC), - )?; - Ok(()) -} - fn id_to_pid(id: u32) -> nix::unistd::Pid { nix::unistd::Pid::from_raw(id.try_into().unwrap()) } -- cgit v1.2.3-54-g00ecf