diff --git a/Cargo.lock b/Cargo.lock index a1239702e..d5cf5f140 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -401,7 +401,9 @@ dependencies = [ name = "fish-util" version = "0.0.0" dependencies = [ + "errno", "fish-widestring", + "libc", "nix", "rand", ] diff --git a/crates/util/Cargo.toml b/crates/util/Cargo.toml index 781e92040..9aa981a12 100644 --- a/crates/util/Cargo.toml +++ b/crates/util/Cargo.toml @@ -7,7 +7,9 @@ repository.workspace = true license.workspace = true [dependencies] +errno.workspace = true fish-widestring.workspace = true +libc.workspace = true nix.workspace = true rand.workspace = true diff --git a/crates/util/src/lib.rs b/crates/util/src/lib.rs index 60c444c9b..30a63cb68 100644 --- a/crates/util/src/lib.rs +++ b/crates/util/src/lib.rs @@ -1,10 +1,15 @@ //! Generic utilities library. +use errno::errno; use fish_widestring::prelude::*; use rand::{SeedableRng as _, rngs::SmallRng}; -use std::cmp::Ordering; -use std::os::fd::{BorrowedFd, RawFd}; -use std::time; +use std::{ + cmp::Ordering, + ffi::CStr, + io::Write as _, + os::fd::{BorrowedFd, RawFd}, + time, +}; /// Compares two wide character strings with an (arguably) intuitive ordering. This function tries /// to order strings in a way which is intuitive to humans with regards to sorting strings @@ -239,6 +244,22 @@ pub fn write_to_fd(input: &[u8], fd: RawFd) -> nix::Result { nix::unistd::write(unsafe { BorrowedFd::borrow_raw(fd) }, input) } +/// Prints the provided string, followed by a colon, space, and the string representation of the +/// current errno via [`libc::strerror`]. +pub fn perror(s: &str) { + let e = errno().0; + let mut stderr = std::io::stderr().lock(); + if !s.is_empty() { + let _ = write!(stderr, "{s}: "); + } + let slice = unsafe { + let msg = libc::strerror(e); + CStr::from_ptr(msg).to_bytes() + }; + let _ = stderr.write_all(slice); + let _ = stderr.write_all(b"\n"); +} + #[cfg(test)] mod tests { use super::wcsfilecmp; diff --git a/src/builtins/cd.rs b/src/builtins/cd.rs index 6915c66e1..97ba123d4 100644 --- a/src/builtins/cd.rs +++ b/src/builtins/cd.rs @@ -6,9 +6,10 @@ fds::{BEST_O_SEARCH, wopen_dir}, parser::ParserEnvSetMode, path::path_apply_cdpath, - wutil::{normalize_path, perror, wreadlink}, + wutil::{normalize_path, wreadlink}, }; use errno::Errno; +use fish_util::perror; use libc::{EACCES, ELOOP, ENOENT, ENOTDIR, EPERM}; use nix::unistd::fchdir; use std::sync::Arc; diff --git a/src/builtins/fg.rs b/src/builtins/fg.rs index 53922f2ba..6fa05698d 100644 --- a/src/builtins/fg.rs +++ b/src/builtins/fg.rs @@ -4,8 +4,8 @@ use crate::parser::ParserEnvSetMode; use crate::reader::{reader_save_screen_state, reader_write_title}; use crate::tokenizer::tok_command; -use crate::wutil::perror; use crate::{env::EnvMode, tty_handoff::TtyHandoff}; +use fish_util::perror; use libc::STDIN_FILENO; use nix::sys::termios::{self, tcsetattr}; use std::os::fd::BorrowedFd; diff --git a/src/builtins/read.rs b/src/builtins/read.rs index 78956e316..a191abb75 100644 --- a/src/builtins/read.rs +++ b/src/builtins/read.rs @@ -25,7 +25,7 @@ use crate::tokenizer::Tok; use crate::tokenizer::Tokenizer; use crate::wutil; -use crate::wutil::perror; +use fish_util::perror; use fish_wcstringutil::{split_about, split_string_tok}; use libc::SEEK_CUR; use std::num::NonZeroUsize; diff --git a/src/fd_monitor.rs b/src/fd_monitor.rs index cb0a36eea..25bdbd98d 100644 --- a/src/fd_monitor.rs +++ b/src/fd_monitor.rs @@ -1,19 +1,19 @@ +use crate::common::exit_without_destructors; +use crate::fd_readable_set::{FdReadableSet, Timeout}; +use crate::flog::flog; use crate::portable_atomic::AtomicU64; +use crate::threads::assert_is_background_thread; +use crate::wutil::perror_nix; use cfg_if::cfg_if; +use errno::errno; +use fish_util::perror; +use libc::{EAGAIN, EINTR, EWOULDBLOCK}; use std::collections::HashMap; use std::os::unix::prelude::*; use std::sync::atomic::Ordering; use std::sync::{Arc, Mutex}; use std::time::Duration; -use crate::common::exit_without_destructors; -use crate::fd_readable_set::{FdReadableSet, Timeout}; -use crate::flog::flog; -use crate::threads::assert_is_background_thread; -use crate::wutil::{perror, perror_nix}; -use errno::errno; -use libc::{EAGAIN, EINTR, EWOULDBLOCK}; - cfg_if!( if #[cfg(have_eventfd)] { use libc::{EFD_CLOEXEC, EFD_NONBLOCK}; diff --git a/src/fds.rs b/src/fds.rs index e6b025bfb..e7d26ea3d 100644 --- a/src/fds.rs +++ b/src/fds.rs @@ -1,9 +1,9 @@ use crate::flog::flog; use crate::prelude::*; use crate::signal::signal_check_cancel; -use crate::wutil::perror; use crate::wutil::perror_nix; use cfg_if::cfg_if; +use fish_util::perror; use fish_wcstringutil::wcs2zstring; use libc::{EINTR, F_GETFD, F_GETFL, F_SETFD, F_SETFL, FD_CLOEXEC, O_NONBLOCK, c_int}; use nix::fcntl::FcntlArg; diff --git a/src/io.rs b/src/io.rs index abd56fc29..7804c0597 100644 --- a/src/io.rs +++ b/src/io.rs @@ -10,8 +10,9 @@ use crate::prelude::*; use crate::proc::JobGroupRef; use crate::redirection::{RedirectionMode, RedirectionSpecList}; -use crate::wutil::{perror, perror_io, unescape_bytes_and_write_to_fd, wdirname, wstat}; +use crate::wutil::{perror_io, unescape_bytes_and_write_to_fd, wdirname, wstat}; use errno::Errno; +use fish_util::perror; use fish_wcstringutil::wcs2bytes; use libc::{EAGAIN, EINTR, ENOENT, ENOTDIR, EWOULDBLOCK, STDOUT_FILENO}; use nix::fcntl::OFlag; diff --git a/src/nix.rs b/src/nix.rs index 57e2ec58f..2d695e749 100644 --- a/src/nix.rs +++ b/src/nix.rs @@ -1,9 +1,8 @@ //! Safe wrappers around various libc functions that we might want to reuse across modules. -use std::time::Duration; - -use crate::wutil::perror; +use fish_util::perror; use libc::mode_t; +use std::time::Duration; #[allow(clippy::unnecessary_cast)] pub const fn timeval_to_duration(val: &libc::timeval) -> Duration { diff --git a/src/reader/reader.rs b/src/reader/reader.rs index b7392903e..62b075aaf 100644 --- a/src/reader/reader.rs +++ b/src/reader/reader.rs @@ -113,14 +113,14 @@ TtyHandoff, get_tty_protocols_active, initialize_tty_protocols, safe_deactivate_tty_protocols, }; use crate::wildcard::wildcard_has; -use crate::wutil::{fstat, perror, perror_nix, wstat}; +use crate::wutil::{fstat, perror_nix, wstat}; use crate::{abbrs, event, function}; use assert_matches::assert_matches; use errno::{Errno, errno}; use fish_common::{UTF8_BOM_WCHAR, help_section}; use fish_fallback::fish_wcwidth; use fish_fallback::lowercase; -use fish_util::write_to_fd; +use fish_util::{perror, write_to_fd}; use fish_wcstringutil::{ CaseSensitivity, IsPrefix, StringFuzzyMatch, count_preceding_backslashes, is_prefix, join_strings, string_prefixes_string, string_prefixes_string_case_insensitive, diff --git a/src/signal.rs b/src/signal.rs index 6806c6bf8..224f5ccd9 100644 --- a/src/signal.rs +++ b/src/signal.rs @@ -1,6 +1,3 @@ -use std::mem::MaybeUninit; -use std::num::NonZeroI32; - use crate::common::exit_without_destructors; use crate::event::{enqueue_signal, is_signal_observed}; use crate::nix::getpid; @@ -9,12 +6,17 @@ use crate::termsize::safe_termsize_invalidate_tty; use crate::topic_monitor::{Generation, GenerationsList, Topic, topic_monitor_principal}; use crate::tty_handoff::{safe_deactivate_tty_protocols, safe_mark_tty_invalid}; -use crate::wutil::{fish_wcstoi, perror}; +use crate::wutil::fish_wcstoi; use errno::{errno, set_errno}; +use fish_util::perror; use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, SigmaskHow, sigprocmask}; -use std::sync::{ - LazyLock, - atomic::{AtomicI32, Ordering}, +use std::{ + mem::MaybeUninit, + num::NonZeroI32, + sync::{ + LazyLock, + atomic::{AtomicI32, Ordering}, + }, }; /// Store the "main" pid. This allows us to reliably determine if we are in a forked child. diff --git a/src/topic_monitor.rs b/src/topic_monitor.rs index 459a15ba4..9e5efd2b1 100644 --- a/src/topic_monitor.rs +++ b/src/topic_monitor.rs @@ -23,7 +23,7 @@ use crate::fd_readable_set::{FdReadableSet, Timeout}; use crate::fds::{self, AutoClosePipes, make_fd_nonblocking}; use crate::flog::{FloggableDebug, flog}; -use crate::wutil::perror; +use fish_util::perror; use fish_widestring::WString; use nix::errno::Errno; use nix::unistd; diff --git a/src/tty_handoff.rs b/src/tty_handoff.rs index 121e09989..f52430383 100644 --- a/src/tty_handoff.rs +++ b/src/tty_handoff.rs @@ -17,7 +17,8 @@ KittyKeyboardProgressiveEnhancementsEnable, ModifyOtherKeysDisable, ModifyOtherKeysEnable, }; use crate::threads::assert_is_main_thread; -use crate::wutil::{perror, perror_nix, wcstoi}; +use crate::wutil::{perror_nix, wcstoi}; +use fish_util::perror; use libc::{EINVAL, ENOTTY, EPERM, STDIN_FILENO, WNOHANG}; use nix::sys::termios::tcgetattr; use nix::unistd::getpgrp; diff --git a/src/wutil/mod.rs b/src/wutil/mod.rs index 47fbf691b..498447b25 100644 --- a/src/wutil/mod.rs +++ b/src/wutil/mod.rs @@ -12,14 +12,13 @@ use crate::flog; use crate::signal::SigChecker; use crate::topic_monitor::Topic; -use errno::errno; -use fish_util::write_to_fd; +use fish_util::{perror, write_to_fd}; use fish_wcstringutil::{join_strings, str2bytes_callback, wcs2osstring, wcs2zstring}; use fish_widestring::{IntoCharIter, L, WExt as _, WString, wstr}; use nix::unistd::AccessFlags; -use std::ffi::{CStr, OsStr}; +use std::ffi::OsStr; use std::fs::{self, canonicalize}; -use std::io::{self, Write as _}; +use std::io; use std::os::unix::prelude::*; pub use crate::wutil::printf::{eprintf, fprintf, printf, sprintf}; @@ -66,21 +65,6 @@ pub fn wunlink(file_name: &wstr) -> io::Result<()> { fs::remove_file(tmp) } -/// Port of the wide-string wperror from `src/wutil.cpp` but for rust `&str`. -pub fn perror(s: &str) { - let e = errno().0; - let mut stderr = std::io::stderr().lock(); - if !s.is_empty() { - let _ = write!(stderr, "{s}: "); - } - let slice = unsafe { - let msg = libc::strerror(e); - CStr::from_ptr(msg).to_bytes() - }; - let _ = stderr.write_all(slice); - let _ = stderr.write_all(b"\n"); -} - pub fn perror_nix(s: &str, e: nix::errno::Errno) { eprintf!("%s: %s\n", s, e.desc()); }