diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ec45af78..e82a4b7c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ There are several ways to contribute to posixutils-rs: 3. Test coverage: Integration tests, positive and negative, are complete, pass 100% 4. Code coverage: Automated code coverage data indicates 100% 5. Translated: All strings are internationalized, including common OS errors for common error cases. -6. Audited: An external party has reviewed and tested for correctness, +6. Audited: An external party has reviewed and tested for correctness, POSIX compliance, security, races and similar issues. ### Coding considerations @@ -29,12 +29,11 @@ There are several ways to contribute to posixutils-rs: ### CLI utility and Rust style guidelines 1. `cargo fmt` is required. -2. Ideal goal: **Each utility should look like a standard Rust CLI program.** +2. Ideal goal: **Each utility should look like a standard Rust CLI program.** Small, lightweight utility with command line processing, core algorithm, and zero external crate dependencies. 3. "only std" When an external crate is required, avoid mega-crates. Prefer - std-only, or, tiny crates such as `atty` that perform a single, - lightweight function. + std-only, or, tiny crates that perform a single, lightweight function. 4. Correctness, readability, performance, in that order. Code should be readable by unfamiliar developers. Avoid dense, uncommented code. @@ -58,4 +57,3 @@ There are several ways to contribute to posixutils-rs: * Provide any input data can that be used to reproduce the bug. * Provide any error output from the utility. * Describe expected results: What did you expect to happen, and did not? - diff --git a/Cargo.lock b/Cargo.lock index 33330b4a..ed4b1034 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,17 +106,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.4.0" @@ -772,15 +761,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hostname" version = "0.3.1" @@ -1552,7 +1532,6 @@ version = "0.2.2" dependencies = [ "clap", "gettext-rs", - "libc", "plib", ] @@ -1605,7 +1584,6 @@ dependencies = [ name = "posixutils-sh" version = "0.1.7" dependencies = [ - "atty", "gettext-rs", "nix 0.29.0", "plib", diff --git a/misc/Cargo.toml b/misc/Cargo.toml index cdc4ec86..bd5d8625 100644 --- a/misc/Cargo.toml +++ b/misc/Cargo.toml @@ -9,7 +9,6 @@ rust-version.workspace = true [dependencies] clap.workspace = true -libc.workspace = true gettext-rs.workspace = true [dev-dependencies] diff --git a/misc/test.rs b/misc/test.rs index 98654ce3..f1ee8253 100644 --- a/misc/test.rs +++ b/misc/test.rs @@ -11,8 +11,14 @@ // - fix and test unary ops // -use std::os::unix::fs::{FileTypeExt, MetadataExt, PermissionsExt}; -use std::path::Path; +use std::{ + io::IsTerminal, + os::{ + fd::{BorrowedFd, RawFd}, + unix::fs::{FileTypeExt, MetadataExt, PermissionsExt}, + }, + path::Path, +}; use gettextrs::{bind_textdomain_codeset, gettext, setlocale, textdomain, LocaleCategory}; @@ -132,17 +138,14 @@ fn eval_unary_path(op: &UnaryOp, s: &str) -> bool { } fn eval_terminal(s: &str) -> bool { - let fd = match s.parse::() { + let fd = match s.parse::() { Ok(f) => f, Err(_) => { return false; } }; - // Normally, posixutils would use the atty crate. - // Passing an arbitrary fd requires unsafe isatty in this case. - - unsafe { libc::isatty(fd as i32) == 1 } + unsafe { BorrowedFd::borrow_raw(fd).is_terminal() } } fn eval_unary(op_str: &str, s: &str) -> bool { diff --git a/sh/Cargo.toml b/sh/Cargo.toml index d13403eb..8bb55b3e 100644 --- a/sh/Cargo.toml +++ b/sh/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" plib = { path = "../plib" } gettext-rs.workspace = true nix = { version = "0.29", features = ["process", "fs", "resource", "signal", "user", "term"] } -atty = "0.2" [[bin]] name = "sh" diff --git a/sh/src/builtin/read.rs b/sh/src/builtin/read.rs index 6935ab74..965e0bb6 100644 --- a/sh/src/builtin/read.rs +++ b/sh/src/builtin/read.rs @@ -13,10 +13,12 @@ use crate::shell::opened_files::{OpenedFile, OpenedFiles, STDIN_FILENO}; use crate::shell::Shell; use crate::wordexp::expanded_word::ExpandedWord; use crate::wordexp::split_fields; -use atty::Stream; use nix::errno::Errno; -use std::os::fd::{AsRawFd, RawFd}; -use std::time::Duration; +use std::{io::stdin, time::Duration}; +use std::{ + io::IsTerminal, + os::fd::{AsRawFd, RawFd}, +}; fn bytes_to_string(bytes: Vec) -> Result { String::from_utf8(bytes.to_vec()).map_err(|_| "read: invalid UTF-8".into()) @@ -140,13 +142,13 @@ fn read_from_stdin( delimiter: u8, backslash_escape: bool, ) -> Result { - if atty::is(Stream::Stdin) { + if stdin().is_terminal() { let original_terminal_settings = shell.terminal.reset(); shell.terminal.set_nonblocking(); let result = read_until_from_non_blocking_fd( shell, - std::io::stdin().as_raw_fd(), + stdin().as_raw_fd(), delimiter, backslash_escape, ); @@ -155,7 +157,7 @@ fn read_from_stdin( result } else { - read_until_from_file(std::io::stdin().as_raw_fd(), delimiter, backslash_escape) + read_until_from_file(stdin().as_raw_fd(), delimiter, backslash_escape) } } diff --git a/sh/src/cli/terminal.rs b/sh/src/cli/terminal.rs index a2b5e2db..c64d6a12 100644 --- a/sh/src/cli/terminal.rs +++ b/sh/src/cli/terminal.rs @@ -7,11 +7,10 @@ // SPDX-License-Identifier: MIT // -use atty::Stream; use nix::sys::termios; use nix::sys::termios::{LocalFlags, Termios}; -use std::io; use std::io::Read; +use std::io::{self, stdin, stdout, IsTerminal}; use std::os::fd::AsFd; #[derive(Clone)] @@ -81,5 +80,5 @@ pub fn read_nonblocking_char() -> Option { } pub fn is_attached_to_terminal() -> bool { - atty::is(Stream::Stdin) && atty::is(Stream::Stdout) + stdin().is_terminal() && stdout().is_terminal() }