Skip to content

Commit

Permalink
Support arbitrary file descriptors in FdReader
Browse files Browse the repository at this point in the history
This commit changes FdReader to take a file descriptor as an argument
instead of always reading from stdin. This will be used to execute shell
script files.
  • Loading branch information
magicant committed Sep 2, 2023
1 parent bec675a commit 95a98f7
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 16 deletions.
59 changes: 48 additions & 11 deletions yash-env/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ use std::slice::from_mut;
#[doc(no_inline)]
pub use yash_syntax::input::*;

// TODO Redefine Stdin as FdReader to support FDs other than stdin

/// Input function that reads from a file descriptor.
///
/// An instance of `FdReader` contains a [`SharedSystem`] to interact with the
Expand All @@ -44,6 +42,8 @@ pub use yash_syntax::input::*;
/// one instance will affect the next read from the other.
#[derive(Clone, Debug)]
pub struct FdReader {
/// File descriptor to read from
fd: Fd,
/// System to interact with the FD
system: SharedSystem,
/// Whether lines read are echoed to stderr
Expand All @@ -52,8 +52,13 @@ pub struct FdReader {

impl FdReader {
/// Creates a new `FdReader` instance.
pub fn new(system: SharedSystem) -> Self {
FdReader { system, echo: None }
///
/// The `fd` argument is the file descriptor to read from. It should be
/// readable, have the close-on-exec flag set, and remain open for the
/// lifetime of the `FdReader` instance.
pub fn new(fd: Fd, system: SharedSystem) -> Self {
let echo = None;
FdReader { fd, system, echo }
}

/// Sets the "echo" flag.
Expand Down Expand Up @@ -81,7 +86,7 @@ impl Input for FdReader {
let mut bytes = Vec::new();
loop {
let mut byte = 0;
match self.system.read_async(Fd::STDIN, from_mut(&mut byte)).await {
match self.system.read_async(self.fd, from_mut(&mut byte)).await {
// End of input
Ok(0) => break,

Expand Down Expand Up @@ -115,16 +120,21 @@ impl Input for FdReader {
mod tests {
use super::*;
use crate::system::r#virtual::FileBody;
use crate::system::r#virtual::INode;
use crate::system::r#virtual::VirtualSystem;
use crate::system::Errno;
use crate::system::Mode;
use crate::system::OFlag;
use crate::System;
use assert_matches::assert_matches;
use futures_util::FutureExt;
use std::ffi::CStr;

#[test]
fn empty_reader() {
let system = VirtualSystem::new();
let system = SharedSystem::new(Box::new(system));
let mut reader = FdReader::new(system);
let mut reader = FdReader::new(Fd::STDIN, system);

let line = reader
.next_line(&Context::default())
Expand All @@ -143,7 +153,7 @@ mod tests {
file.borrow_mut().body = FileBody::new(*b"echo ok\n");
}
let system = SharedSystem::new(Box::new(system));
let mut reader = FdReader::new(system);
let mut reader = FdReader::new(Fd::STDIN, system);

let line = reader
.next_line(&Context::default())
Expand All @@ -168,7 +178,7 @@ mod tests {
file.borrow_mut().body = FileBody::new(*b"#!/bin/sh\necho ok\nexit");
}
let system = SharedSystem::new(Box::new(system));
let mut reader = FdReader::new(system);
let mut reader = FdReader::new(Fd::STDIN, system);

let line = reader
.next_line(&Context::default())
Expand Down Expand Up @@ -196,12 +206,39 @@ mod tests {
assert_eq!(line, "");
}

#[test]
fn reading_from_file() {
let system = VirtualSystem::new();
{
let mut state = system.state.borrow_mut();
let file = Rc::new(INode::new("echo file\n").into());
state.file_system.save("/foo", file).unwrap();
}
let mut system = SharedSystem::new(Box::new(system));
let path = CStr::from_bytes_with_nul(b"/foo\0").unwrap();
let fd = system.open(path, OFlag::O_RDONLY, Mode::empty()).unwrap();
let mut reader = FdReader::new(fd, system);

let line = reader
.next_line(&Context::default())
.now_or_never()
.unwrap()
.unwrap();
assert_eq!(line, "echo file\n");
let line = reader
.next_line(&Context::default())
.now_or_never()
.unwrap()
.unwrap();
assert_eq!(line, "");
}

#[test]
fn reader_error() {
let mut system = VirtualSystem::new();
system.current_process_mut().close_fd(Fd::STDIN);
let system = SharedSystem::new(Box::new(system));
let mut reader = FdReader::new(system);
let mut reader = FdReader::new(Fd::STDIN, system);

let error = reader
.next_line(&Context::default())
Expand All @@ -221,7 +258,7 @@ mod tests {
file.borrow_mut().body = FileBody::new(*b"one\ntwo");
}
let system = SharedSystem::new(Box::new(system));
let mut reader = FdReader::new(system);
let mut reader = FdReader::new(Fd::STDIN, system);
reader.set_echo(Some(Rc::new(Cell::new(State::Off))));

let _ = reader
Expand All @@ -245,7 +282,7 @@ mod tests {
file.borrow_mut().body = FileBody::new(*b"one\ntwo");
}
let system = SharedSystem::new(Box::new(system));
let mut reader = FdReader::new(system);
let mut reader = FdReader::new(Fd::STDIN, system);
reader.set_echo(Some(Rc::new(Cell::new(State::On))));

let _ = reader
Expand Down
9 changes: 5 additions & 4 deletions yash-semantics/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,13 @@ impl<'a, 'b> ReadEvalLoop<'a, 'b> {
/// # use std::rc::Rc;
/// # use yash_env::Env;
/// # use yash_env::input::FdReader;
/// # use yash_env::option::Option::Verbose;
/// # use yash_env::option::State;
/// # use yash_env::io::Fd;
/// # use yash_env::option::{Verbose, State};
/// # use yash_semantics::*;
/// # use yash_syntax::parser::lex::Lexer;
/// # use yash_syntax::source::Source;
/// let mut env = Env::new_virtual();
/// let mut input = Box::new(FdReader::new(Clone::clone(&env.system)));
/// let mut input = Box::new(FdReader::new(Fd::STDIN, Clone::clone(&env.system)));
/// let verbose = Rc::new(Cell::new(State::Off));
/// input.set_echo(Some(Rc::clone(&verbose)));
/// let line = NonZeroU64::new(1).unwrap();
Expand Down Expand Up @@ -171,6 +171,7 @@ mod tests {
use std::ops::ControlFlow::Break;
use std::rc::Rc;
use yash_env::input::FdReader;
use yash_env::io::Fd;
use yash_env::option::Option::Verbose;
use yash_env::option::State::{Off, On};
use yash_env::semantics::Divert;
Expand Down Expand Up @@ -255,7 +256,7 @@ mod tests {
.body = FileBody::new(*b"case _ in esac\n");
let mut env = Env::with_system(Box::new(system));
env.options.set(Verbose, On);
let mut input = Box::new(FdReader::new(Clone::clone(&env.system)));
let mut input = Box::new(FdReader::new(Fd::STDIN, Clone::clone(&env.system)));
let verbose = Rc::new(Cell::new(Off));
input.set_echo(Some(Rc::clone(&verbose)));
let line = NonZeroU64::new(1).unwrap();
Expand Down
2 changes: 1 addition & 1 deletion yash/src/startup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub fn prepare_input<'a>(
) -> Result<SourceInput<'a>, PrepareInputError> {
match source {
Source::Stdin => {
let mut input = Box::new(FdReader::new(system.clone()));
let mut input = Box::new(FdReader::new(Fd::STDIN, system.clone()));
let echo = Rc::new(Cell::new(State::Off));
input.set_echo(Some(Rc::clone(&echo)));
Ok(SourceInput {
Expand Down

0 comments on commit 95a98f7

Please sign in to comment.