diff --git a/src/lib/builtins/man_pages.rs b/src/lib/builtins/man_pages.rs index 135d598f22007fd7c2b81c27c6b3814171e6050f..82e1da209fe79cd2c011502cc44791f454c759e5 100644 --- a/src/lib/builtins/man_pages.rs +++ b/src/lib/builtins/man_pages.rs @@ -78,6 +78,16 @@ OPTIONS returns 0 if the two arguments are not equal. "#; +pub(crate) const MAN_ISATTY: &'static str = r#" + isatty - Checks if argument is a file descriptor + +SYNOPSIS + isatty [FD] + +DESCRIPTION + Returns 0 exit status if the supplied file descriptor is a tty. +"#; + pub(crate) const MAN_DIRS: &'static str = r#"NAME dirs - prints the directory stack diff --git a/src/lib/builtins/mod.rs b/src/lib/builtins/mod.rs index 3d1415009f189b71981dd4bdf132fb6629552480..5a2338b8a582192a5c53c0498d872b90585e1451 100644 --- a/src/lib/builtins/mod.rs +++ b/src/lib/builtins/mod.rs @@ -64,7 +64,7 @@ macro_rules! map { /// If you are implementing a builtin add it to the table below, create a well named manpage in /// man_pages and check for help flags by adding to the start of your builtin the following -/// if check_help(args, MAN_CD) { +/// if check_help(args, MAN_BUILTIN_NAME) { /// return SUCCESS /// } @@ -93,6 +93,7 @@ pub const BUILTINS: &'static BuiltinMap = &map!( "history" => builtin_history : "Display a log of all commands previously executed", "ion-docs" => ion_docs : "Opens the Ion manual", "is" => builtin_is : "Simple alternative to == and !=", + "isatty" => builtin_isatty : "Returns 0 exit status if the supplied FD is a tty", "jobs" => builtin_jobs : "Displays all jobs that are attached to the background", "matches" => builtin_matches : "Checks if a string matches a given regex", "not" => builtin_not : "Reverses the exit status value of the given command.", @@ -637,3 +638,50 @@ fn builtin_which(args: &[&str], shell: &mut Shell) -> i32 { } result } + +/// There are two different `builtin_isatty()` functions because +/// `sys::isatty()` when built for redox expects a usize while otherwise expecting a i32. +/// This could probably be done more elegantly. +#[cfg(target_os = "redox")] +fn builtin_isatty(args: &[&str], _: &mut Shell) -> i32 { + if check_help(args, MAN_ISATTY) { + return SUCCESS + } + + let stderr = io::stderr(); + let mut stderr = stderr.lock(); + if args.len() > 1 { + match args[1].parse::<usize>() { + Ok(r) => if sys::isatty(r) { + return SUCCESS + }, + Err(_) => { let _ = stderr.write_all("ion: isatty given bad number".as_bytes()); } + } + } else { + return SUCCESS + } + + FAILURE +} + +#[cfg(not(target_os = "redox"))] +fn builtin_isatty(args: &[&str], _: &mut Shell) -> i32 { + if check_help(args, MAN_ISATTY) { + return SUCCESS + } + + let stderr = io::stderr(); + let mut stderr = stderr.lock(); + if args.len() > 1 { + match args[1].parse::<i32>() { + Ok(r) => if sys::isatty(r) { + return SUCCESS + }, + Err(_) => { let _ = stderr.write_all("ion: isatty given bad number".as_bytes()); } + } + } else { + return SUCCESS + } + + FAILURE +} \ No newline at end of file diff --git a/src/lib/sys/redox.rs b/src/lib/sys/redox.rs index 58e1cd478f39a244a0d73b5797fa865a972a2b02..62bb6409c72303d2a0d30fad61cabd6a0f7ebe04 100644 --- a/src/lib/sys/redox.rs +++ b/src/lib/sys/redox.rs @@ -93,91 +93,46 @@ pub(crate) fn fork_and_exec<F: Fn()>( clear_env: bool, before_exec: F ) -> io::Result<u32> { - // Construct a valid set of arguments to pass to execve. Ensure - // that the program is the first argument. - let mut cvt_args: Vec<[usize; 2]> = Vec::new(); - cvt_args.push([prog.as_ptr() as usize, prog.len()]); - for arg in args { - cvt_args.push([arg.as_ptr() as usize, arg.len()]); - } - - // Get the PathBuf of the program if it exists. - let prog = if prog.contains(':') || prog.contains('/') { - // This is a fully specified scheme or path to an - // executable. - Some(PathBuf::from(prog)) - } else if let Ok(paths) = env::var("PATH") { - // This is not a fully specified scheme or path. - // Iterate through the possible paths in the - // env var PATH that this executable may be found - // in and return the first one found. - env::split_paths(&paths) - .filter_map(|mut path| { - path.push(prog); - if path.exists() { - Some(path) - } else { - None + unsafe { + match fork()? { + 0 => { + if let Some(stdin) = stdin { + let _ = dup2(stdin, STDIN_FILENO); + let _ = close(stdin); } - }) - .next() - } else { - None - }; - - // If clear_env set, clear the env. - if clear_env { - for (key, _) in env::vars() { - env::remove_var(key); - } - } - - if let Some(prog) = prog { - unsafe { - match fork()? { - 0 => { - if let Some(stdin) = stdin { - let _ = dup2(stdin, STDIN_FILENO); - let _ = close(stdin); - } - if let Some(stdout) = stdout { - let _ = dup2(stdout, STDOUT_FILENO); - let _ = close(stdout); - } + if let Some(stdout) = stdout { + let _ = dup2(stdout, STDOUT_FILENO); + let _ = close(stdout); + } - if let Some(stderr) = stderr { - let _ = dup2(stderr, STDERR_FILENO); - let _ = close(stderr); - } + if let Some(stderr) = stderr { + let _ = dup2(stderr, STDERR_FILENO); + let _ = close(stderr); + } - before_exec(); + before_exec(); - let error = syscall::execve(prog.as_os_str().as_bytes(), &cvt_args); - let error = io::Error::from_raw_os_error(error.err().unwrap().errno); - eprintln!("ion: command exec: {}", error); - fork_exit(1); + let error = execve(prog, args, clear_env); + eprintln!("ion: command exec: {}", error); + fork_exit(1); + } + pid => { + if let Some(stdin) = stdin { + let _ = close(stdin); } - pid => { - if let Some(stdin) = stdin { - let _ = close(stdin); - } - if let Some(stdout) = stdout { - let _ = close(stdout); - } - - if let Some(stderr) = stderr { - let _ = close(stderr); - } + if let Some(stdout) = stdout { + let _ = close(stdout); + } - Ok(pid) + if let Some(stderr) = stderr { + let _ = close(stderr); } + + Ok(pid) } } - } else { - // The binary was not found. - Err(io::Error::from_raw_os_error(syscall::ENOENT)) } }