Created
January 7, 2024 09:32
-
-
Save krobelus/72da136712c3016561ed521198e79c33 to your computer and use it in GitHub Desktop.
prr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> diff --git a/Cargo.toml b/Cargo.toml | |
> index 1ca5a435ad0c..18b289c4a2cb 100644 | |
> --- a/Cargo.toml | |
> +++ b/Cargo.toml | |
> @@ -45,7 +45,7 @@ printf-compat = { git = "https://github.com/fish-shell/printf-compat.git", branc | |
> autocxx = "0.23.1" | |
> bitflags = "2.4.0" | |
> cxx = "1.0" | |
> -errno = "0.2.8" | |
> +_errno = { package="errno", version = "0.2.8" } | |
> inventory = { version = "0.3.3", optional = true} | |
> lazy_static = "1.4.0" | |
> libc = "0.2.137" | |
> diff --git a/fish-rust/src/builtins/cd.rs b/fish-rust/src/builtins/cd.rs | |
> index 982adb348377..0d754776db2e 100644 | |
> --- a/fish-rust/src/builtins/cd.rs | |
> +++ b/fish-rust/src/builtins/cd.rs | |
> @@ -5,10 +5,11 @@ use crate::{ | |
> env::{EnvMode, Environment}, | |
> fds::{wopen_cloexec, AutoCloseFd}, | |
> path::path_apply_cdpath, | |
> + set_errno, | |
> wutil::{normalize_path, wperror, wreadlink}, | |
> }; | |
> -use errno::{self, Errno}; | |
> -use libc::{fchdir, EACCES, ELOOP, ENOENT, ENOTDIR, EPERM, O_RDONLY}; | |
> +use libc::{fchdir, O_RDONLY}; | |
> +use nix::errno::Errno; | |
> use std::sync::Arc; | |
> | |
> // The cd builtin. Changes the current directory to the one specified or to $HOME if none is | |
> @@ -77,14 +78,14 @@ pub fn cd(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> Optio | |
> return STATUS_CMD_ERROR; | |
> } | |
> | |
> - let mut best_errno = 0; | |
> + let mut best_errno = Errno::from_i32(0); | |
> let mut broken_symlink = WString::new(); | |
> let mut broken_symlink_target = WString::new(); | |
> | |
> for dir in dirs { | |
> let norm_dir = normalize_path(&dir, true); | |
> | |
> - errno::set_errno(Errno(0)); | |
> + Errno::clear(); | |
> | |
> // We need to keep around the fd for this directory, in the parser. | |
> let dir_fd = Arc::new(AutoCloseFd::new(wopen_cloexec(&norm_dir, O_RDONLY, 0))); | |
> @@ -94,22 +95,27 @@ pub fn cd(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> Optio | |
> // ENOENT in particular is very low priority | |
> // - if in another directory there was a *file* by the correct name | |
> // we prefer *that* error because it's more specific | |
> - if errno::errno().0 == ENOENT { | |
> - let tmp = wreadlink(&norm_dir); | |
> - // clippy doesn't like this is_some/unwrap pair, but using if let is harder to read IMO | |
> - #[allow(clippy::unnecessary_unwrap)] | |
> - if broken_symlink.is_empty() && tmp.is_some() { | |
> - broken_symlink = norm_dir; | |
> - broken_symlink_target = tmp.unwrap(); | |
> - } else if best_errno == 0 { | |
> - best_errno = errno::errno().0; | |
> + match Errno::last() { | |
> + Errno::ENOENT => { | |
> + let tmp = wreadlink(&norm_dir); | |
> + // clippy doesn't like this is_some/unwrap pair, but using if let is harder to read IMO | |
> + #[allow(clippy::unnecessary_unwrap)] | |
> + if broken_symlink.is_empty() && tmp.is_some() { | |
> + broken_symlink = norm_dir; | |
> + broken_symlink_target = tmp.unwrap(); | |
> + } else if best_errno == Errno::from_i32(0) { | |
> + best_errno = Errno::last(); | |
> + } | |
> + continue; | |
> } | |
> - continue; | |
> - } else if errno::errno().0 == ENOTDIR { | |
> - best_errno = errno::errno().0; | |
> - continue; | |
> + Errno::ENOTDIR => { | |
> + best_errno = Errno::ENOTDIR; | |
> + continue; | |
> + } | |
> + _ => {} | |
> } | |
> - best_errno = errno::errno().0; | |
> + | |
> + best_errno = Errno::last(); | |
> break; | |
> } | |
> | |
> @@ -120,45 +126,52 @@ pub fn cd(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> Optio | |
> return STATUS_CMD_OK; | |
> } | |
> | |
> - if best_errno == ENOTDIR { | |
> - streams.err.append(wgettext_fmt!( | |
> - "%ls: '%ls' is not a directory\n", | |
> - cmd, | |
> - dir_in | |
> - )); | |
> - } else if !broken_symlink.is_empty() { | |
> - streams.err.append(wgettext_fmt!( | |
> - "%ls: '%ls' is a broken symbolic link to '%ls'\n", | |
> - cmd, | |
> - broken_symlink, | |
> - broken_symlink_target | |
> - )); | |
> - } else if best_errno == ELOOP { | |
> - streams.err.append(wgettext_fmt!( | |
> - "%ls: Too many levels of symbolic links: '%ls'\n", | |
> - cmd, | |
> - dir_in | |
> - )); | |
> - } else if best_errno == ENOENT { | |
> - streams.err.append(wgettext_fmt!( | |
> - "%ls: The directory '%ls' does not exist\n", | |
> - cmd, | |
> - dir_in | |
> - )); | |
> - } else if best_errno == EACCES || best_errno == EPERM { | |
> - streams.err.append(wgettext_fmt!( | |
> - "%ls: Permission denied: '%ls'\n", | |
> - cmd, | |
> - dir_in | |
> - )); | |
> - } else { | |
> - errno::set_errno(Errno(best_errno)); | |
> - wperror(L!("cd")); | |
> - streams.err.append(wgettext_fmt!( | |
> - "%ls: Unknown error trying to locate directory '%ls'\n", | |
> - cmd, | |
> - dir_in | |
> - )); | |
> + match best_errno { | |
> + Errno::ENOTDIR => { | |
> + streams.err.append(wgettext_fmt!( | |
> + "%ls: '%ls' is not a directory\n", | |
> + cmd, | |
> + dir_in | |
> + )); | |
> + } | |
> + _ if !broken_symlink.is_empty() => { | |
> + streams.err.append(wgettext_fmt!( | |
> + "%ls: '%ls' is a broken symbolic link to '%ls'\n", | |
> + cmd, | |
> + broken_symlink, | |
> + broken_symlink_target | |
> + )); | |
> + } | |
> + Errno::ELOOP => { | |
> + streams.err.append(wgettext_fmt!( | |
> + "%ls: Too many levels of symbolic links: '%ls'\n", | |
> + cmd, | |
> + dir_in | |
> + )); | |
> + } | |
> + Errno::ENOENT => { | |
> + streams.err.append(wgettext_fmt!( | |
> + "%ls: The directory '%ls' does not exist\n", | |
> + cmd, | |
> + dir_in | |
> + )); | |
> + } | |
> + Errno::EACCES | Errno::EPERM => { | |
> + streams.err.append(wgettext_fmt!( | |
> + "%ls: Permission denied: '%ls'\n", | |
> + cmd, | |
> + dir_in | |
> + )); | |
> + } | |
> + _ => { | |
> + set_errno(best_errno); | |
> + wperror(L!("cd")); | |
> + streams.err.append(wgettext_fmt!( | |
> + "%ls: Unknown error trying to locate directory '%ls'\n", | |
> + cmd, | |
> + dir_in | |
> + )); | |
> + } | |
> } | |
> | |
> if !parser.is_interactive() { | |
> diff --git a/fish-rust/src/builtins/pwd.rs b/fish-rust/src/builtins/pwd.rs | |
> index 70243fbb8cb2..e6f212a406c7 100644 | |
> --- a/fish-rust/src/builtins/pwd.rs | |
> +++ b/fish-rust/src/builtins/pwd.rs | |
> @@ -1,5 +1,5 @@ | |
> //! Implementation of the pwd builtin. | |
> -use errno::errno; | |
> +use nix::errno::Errno; | |
> | |
> use super::prelude::*; | |
> use crate::{env::Environment, wutil::wrealpath}; | |
> @@ -51,7 +51,7 @@ pub fn pwd(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opti | |
> streams.err.append(wgettext_fmt!( | |
> "%ls: realpath failed: %s\n", | |
> cmd, | |
> - errno().to_string() | |
> + Errno::last().desc() | |
> )); | |
> return STATUS_CMD_ERROR; | |
> } | |
> diff --git a/fish-rust/src/builtins/realpath.rs b/fish-rust/src/builtins/realpath.rs | |
> index 5605ae9fca54..b7402ba968be 100644 | |
> --- a/fish-rust/src/builtins/realpath.rs | |
> +++ b/fish-rust/src/builtins/realpath.rs | |
> @@ -1,6 +1,6 @@ | |
> //! Implementation of the realpath builtin. | |
> | |
> -use errno::errno; | |
> +use nix::errno::Errno; | |
> | |
> use super::prelude::*; | |
> use crate::env::Environment; | |
> @@ -86,15 +86,15 @@ pub fn realpath(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> | |
> if let Some(real_path) = wrealpath(arg) { | |
> streams.out.append(real_path); | |
> } else { | |
> - let errno = errno(); | |
> - if errno.0 != 0 { | |
> + let errno = Errno::last(); | |
> + if errno != Errno::from_i32(0) { | |
> // realpath() just couldn't do it. Report the error and make it clear | |
> // this is an error from our builtin, not the system's realpath. | |
> streams.err.append(wgettext_fmt!( | |
> "builtin %ls: %ls: %s\n", | |
> cmd, | |
> arg, | |
> - errno.to_string() | |
> + errno.desc() | |
> )); | |
> } else { | |
> // Who knows. Probably a bug in our wrealpath() implementation. | |
> @@ -120,7 +120,7 @@ pub fn realpath(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> | |
> streams.err.append(wgettext_fmt!( | |
> "builtin %ls: realpath failed: %s\n", | |
> cmd, | |
> - errno().to_string() | |
> + Errno::last().desc() | |
> )); | |
> return STATUS_CMD_ERROR; | |
> } | |
> diff --git a/fish-rust/src/builtins/shared.rs b/fish-rust/src/builtins/shared.rs | |
> index 8f2119028eaa..ab2c4aef0503 100644 | |
> --- a/fish-rust/src/builtins/shared.rs | |
> +++ b/fish-rust/src/builtins/shared.rs | |
> @@ -11,8 +11,8 @@ use crate::reader::reader_read; | |
> use crate::wchar::{wstr, WString, L}; | |
> use crate::wgetopt::{wgetopter_t, wopt, woption, woption_argument_t}; | |
> use cxx::CxxWString; | |
> -use errno::errno; | |
> use libc::{c_int, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; | |
> +use nix::errno::Errno; | |
> | |
> use std::borrow::Cow; | |
> use std::fs::File; | |
> @@ -641,11 +641,11 @@ pub fn builtin_print_error_trailer(parser: &Parser, b: &mut OutputStream, cmd: & | |
> /// This function works like perror, but it prints its result into the streams.err string instead | |
> /// to stderr. Used by the builtin commands. | |
> pub fn builtin_wperror(program_name: &wstr, streams: &mut IoStreams) { | |
> - let err = errno(); | |
> + let err = Errno::last(); | |
> streams.err.append(program_name); | |
> streams.err.append(L!(": ")); | |
> - if err.0 != 0 { | |
> - let werr = WString::from_str(&err.to_string()); | |
> + if err != Errno::from_i32(0) { | |
> + let werr = WString::from_str(&err.desc()); | |
> streams.err.append(werr); | |
> streams.err.push('\n'); | |
> } | |
> diff --git a/fish-rust/src/common.rs b/fish-rust/src/common.rs | |
> index ea771f35be0b..8b6acd6174d0 100644 | |
> --- a/fish-rust/src/common.rs | |
> +++ b/fish-rust/src/common.rs | |
> @@ -20,7 +20,8 @@ use crate::wutil::fish_iswalnum; | |
> use bitflags::bitflags; | |
> use core::slice; | |
> use cxx::{CxxWString, UniquePtr}; | |
> -use libc::{EINTR, EIO, O_WRONLY, SIGTTOU, SIG_IGN, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; | |
> +use libc::{O_WRONLY, SIGTTOU, SIG_IGN, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; | |
> +use nix::errno::Errno; | |
> use num_traits::ToPrimitive; | |
> use once_cell::sync::{Lazy, OnceCell}; | |
> use std::env; | |
> @@ -1485,7 +1486,7 @@ fn can_be_encoded(wc: char) -> bool { | |
> pub fn read_blocked(fd: RawFd, buf: &mut [u8]) -> isize { | |
> loop { | |
> let res = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), buf.len()) }; | |
> - if res < 0 && errno::errno().0 == EINTR { | |
> + if res < 0 && Errno::last() == Errno::EINTR { | |
> continue; | |
> } | |
> return res; | |
> @@ -1512,11 +1513,11 @@ pub fn write_loop<Fd: AsRawFd>(fd: &Fd, buf: &[u8]) -> std::io::Result<usize> { | |
> let written = | |
> unsafe { libc::write(fd, buf[total..].as_ptr() as *const _, buf.len() - total) }; | |
> if written < 0 { | |
> - let errno = errno::errno().0; | |
> - if matches!(errno, libc::EAGAIN | libc::EINTR) { | |
> + let errno = Errno::last(); | |
> + if matches!(errno, Errno::EAGAIN | Errno::EINTR) { | |
> continue; | |
> } | |
> - return Err(std::io::Error::from_raw_os_error(errno)); | |
> + return Err(std::io::Error::from(errno)); | |
> } | |
> total += written as usize; | |
> } | |
> @@ -1532,11 +1533,11 @@ pub fn read_loop<Fd: AsRawFd>(fd: &Fd, buf: &mut [u8]) -> std::io::Result<usize> | |
> loop { | |
> let read = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut _, buf.len()) }; | |
> if read < 0 { | |
> - let errno = errno::errno().0; | |
> - if matches!(errno, libc::EAGAIN | libc::EINTR) { | |
> + let errno = Errno::last(); | |
> + if matches!(errno, Errno::EAGAIN | Errno::EINTR) { | |
> continue; | |
> } | |
> - return Err(std::io::Error::from_raw_os_error(errno)); | |
> + return Err(std::io::Error::from(errno)); | |
> } | |
> return Ok(read as usize); | |
> } | |
> @@ -1751,7 +1752,7 @@ pub fn redirect_tty_output() { | |
> let fd = libc::open(s.as_ptr(), O_WRONLY); | |
> assert!(fd != -1, "Could not open /dev/null!"); | |
> for stdfd in [STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO] { | |
> - if libc::tcgetattr(stdfd, &mut t) == -1 && errno::errno().0 == EIO { | |
> + if libc::tcgetattr(stdfd, &mut t) == -1 && Errno::last() == Errno::EIO { | |
> libc::dup2(fd, stdfd); | |
> } | |
> } | |
> diff --git a/fish-rust/src/env_universal_common.rs b/fish-rust/src/env_universal_common.rs | |
> index 6a797cc66582..46001e962ae0 100644 | |
> --- a/fish-rust/src/env_universal_common.rs | |
> +++ b/fish-rust/src/env_universal_common.rs | |
> @@ -17,10 +17,8 @@ use crate::wutil::{ | |
> file_id_for_fd, file_id_for_path, file_id_for_path_narrow, wdirname, wrealpath, wrename, wstat, | |
> wunlink, FileId, INVALID_FILE_ID, | |
> }; | |
> -use errno::{errno, Errno}; | |
> -use libc::{ | |
> - CLOCK_REALTIME, EINTR, ENOTSUP, EOPNOTSUPP, LOCK_EX, O_CREAT, O_RDONLY, O_RDWR, UTIME_OMIT, | |
> -}; | |
> +use libc::{CLOCK_REALTIME, LOCK_EX, O_CREAT, O_RDONLY, O_RDWR, UTIME_OMIT}; | |
> +use nix::errno::Errno; | |
> use std::collections::hash_map::Entry; | |
> use std::collections::HashSet; | |
> use std::ffi::CString; | |
> @@ -442,13 +440,14 @@ impl EnvUniversal { | |
> fd = AutoCloseFd::new(wopen_cloexec(&self.vars_path, flags, 0o644)); | |
> | |
> if !fd.is_valid() { | |
> - let err = errno(); | |
> - if err.0 == EINTR { | |
> + let err = Errno::last(); | |
> + if err == Errno::EINTR { | |
> continue; // signaled; try again | |
> } | |
> | |
> if O_EXLOCK != 0 { | |
> - if (flags & O_EXLOCK) != 0 && [ENOTSUP, EOPNOTSUPP].contains(&err.0) { | |
> + if (flags & O_EXLOCK) != 0 && [Errno::ENOTSUP, Errno::EOPNOTSUPP].contains(&err) | |
> + { | |
> // Filesystem probably does not support locking. Give up on locking. | |
> // Note that on Linux the two errno symbols have the same value but on BSD they're | |
> // different. | |
> @@ -496,7 +495,7 @@ impl EnvUniversal { | |
> // This should almost always succeed on the first try. | |
> assert!(!string_suffixes_string(L!("/"), directory)); | |
> | |
> - let mut saved_errno = Errno(0); | |
> + let mut saved_errno = Errno::from_i32(0); | |
> let tmp_name_template = directory.to_owned() + L!("/fishd.tmp.XXXXXX"); | |
> let mut result = AutoCloseFd::empty(); | |
> let mut narrow_str = CString::default(); | |
> @@ -507,7 +506,7 @@ impl EnvUniversal { | |
> let (fd, tmp_name) = fish_mkstemp_cloexec(wcs2zstring(&tmp_name_template)); | |
> result.reset(fd); | |
> narrow_str = tmp_name; | |
> - saved_errno = errno(); | |
> + saved_errno = Errno::last(); | |
> } | |
> *out_path = str2wcstring(narrow_str.as_bytes()); | |
> | |
> @@ -529,7 +528,7 @@ impl EnvUniversal { | |
> let mut success = true; | |
> let contents = Self::serialize_with_vars(&self.vars); | |
> if let Err(err) = write_loop(&fd, &contents) { | |
> - let error = Errno(err.raw_os_error().unwrap()); | |
> + let error = Errno::try_from(err).unwrap(); | |
> FLOG!( | |
> error, | |
> wgettext_fmt!( | |
> @@ -551,7 +550,7 @@ impl EnvUniversal { | |
> fn move_new_vars_file_into_place(&mut self, src: &wstr, dst: &wstr) -> bool { | |
> let ret = wrename(src, dst); | |
> if ret != 0 { | |
> - let error = errno(); | |
> + let error = Errno::last(); | |
> FLOG!( | |
> error, | |
> wgettext_fmt!( | |
> @@ -1017,7 +1016,7 @@ fn encode_serialized(vals: &[WString]) -> WString { | |
> fn flock_uvar_file(fd: RawFd) -> bool { | |
> let start_time = timef(); | |
> while unsafe { libc::flock(fd, LOCK_EX) } == -1 { | |
> - if errno().0 != EINTR { | |
> + if Errno::last() != Errno::EINTR { | |
> return false; // do nothing per issue #2149 | |
> } | |
> } | |
> diff --git a/fish-rust/src/exec.rs b/fish-rust/src/exec.rs | |
> index 475359ce68f0..e0803c84609e 100644 | |
> --- a/fish-rust/src/exec.rs | |
> +++ b/fish-rust/src/exec.rs | |
> @@ -42,6 +42,7 @@ use crate::proc::{ | |
> }; | |
> use crate::reader::{reader_run_count, restore_term_mode}; | |
> use crate::redirection::{dup2_list_resolve_chain, Dup2List}; | |
> +use crate::set_errno; | |
> use crate::threads::{iothread_perform_cant_wait, is_forked_child}; | |
> use crate::timer::push_timer; | |
> use crate::trace::trace_if_enabled_with_args; | |
> @@ -52,12 +53,12 @@ use crate::wchar_ffi::WCharToFFI; | |
> use crate::wutil::{fish_wcstol, perror}; | |
> use crate::wutil::{wgettext, wgettext_fmt}; | |
> use cxx::{CxxWString, UniquePtr}; | |
> -use errno::{errno, set_errno}; | |
> use libc::c_int; | |
> use libc::{ | |
> - c_char, EACCES, ENOENT, ENOEXEC, ENOTDIR, EPIPE, EXIT_FAILURE, EXIT_SUCCESS, O_NOCTTY, | |
> - O_RDONLY, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO, | |
> + c_char, EPIPE, EXIT_FAILURE, EXIT_SUCCESS, O_NOCTTY, O_RDONLY, STDERR_FILENO, STDIN_FILENO, | |
> + STDOUT_FILENO, | |
> }; | |
> +use nix::errno::Errno; | |
> use std::ffi::CStr; | |
> use std::io::{Read, Write}; | |
> use std::os::fd::{FromRawFd, RawFd}; | |
> @@ -311,20 +312,20 @@ static FORK_COUNT: AtomicUsize = AtomicUsize::new(0); | |
> type LaunchResult = Result<(), ()>; | |
> | |
> /// Given an error \p err returned from either posix_spawn or exec, \return a process exit code. | |
> -fn exit_code_from_exec_error(err: libc::c_int) -> libc::c_int { | |
> - assert!(err != 0, "Zero is success, not an error"); | |
> +fn exit_code_from_exec_error(err: Errno) -> libc::c_int { | |
> + assert!(err != Errno::from_i32(0), "Zero is success, not an error"); | |
> match err { | |
> - ENOENT | ENOTDIR => { | |
> + Errno::ENOENT | Errno::ENOTDIR => { | |
> // This indicates either the command was not found, or a file redirection was not found. | |
> // We do not use posix_spawn file redirections so this is always command-not-found. | |
> STATUS_CMD_UNKNOWN.unwrap() | |
> } | |
> - EACCES | ENOEXEC => { | |
> + Errno::EACCES | Errno::ENOEXEC => { | |
> // The file is not executable for various reasons. | |
> STATUS_NOT_EXECUTABLE.unwrap() | |
> } | |
> #[cfg(target_os = "macos")] | |
> - libc::EBADARCH => { | |
> + Errno::EBADARCH => { | |
> // This is for e.g. running ARM app on Intel Mac. | |
> STATUS_NOT_EXECUTABLE.unwrap() | |
> } | |
> @@ -370,7 +371,7 @@ pub fn is_thompson_shell_script(path: &CStr) -> bool { | |
> if path.to_bytes().ends_with(".fish".as_bytes()) { | |
> return false; | |
> } | |
> - let e = errno(); | |
> + let e = Errno::last(); | |
> let mut res = false; | |
> let fd = open_cloexec(path, O_RDONLY | O_NOCTTY, 0); | |
> if fd != -1 { | |
> @@ -398,14 +399,14 @@ fn safe_launch_process( | |
> // This function never returns, so we take certain liberties with constness. | |
> | |
> unsafe { libc::execve(actual_cmd.as_ptr(), argv.get(), envv.get()) }; | |
> - let err = errno(); | |
> + let err = Errno::last(); | |
> | |
> // The shebang wasn't introduced until UNIX Seventh Edition, so if | |
> // the kernel won't run the binary we hand it off to the interpreter | |
> // after performing a binary safety check, recommended by POSIX: a | |
> // line needs to exist before the first \0 with a lowercase letter | |
> | |
> - if err.0 == ENOEXEC && is_thompson_shell_script(actual_cmd) { | |
> + if err == Errno::ENOEXEC && is_thompson_shell_script(actual_cmd) { | |
> // Construct new argv. | |
> // We must not allocate memory, so only 128 args are supported. | |
> const maxargs: usize = 128; | |
> @@ -426,8 +427,8 @@ fn safe_launch_process( | |
> } | |
> | |
> set_errno(err); | |
> - safe_report_exec_error(errno().0, actual_cmd.as_ptr(), argv.get(), envv.get()); | |
> - exit_without_destructors(exit_code_from_exec_error(err.0)); | |
> + safe_report_exec_error(err, actual_cmd.as_ptr(), argv.get(), envv.get()); | |
> + exit_without_destructors(exit_code_from_exec_error(err)); | |
> } | |
> | |
> /// This function is similar to launch_process, except it is not called after a fork (i.e. it only | |
> @@ -720,7 +721,7 @@ fn fork_child_for_process( | |
> { | |
> if let Some(pgid) = job.group().get_pgid() { | |
> let err = execute_setpgid(p.pid(), pgid, is_parent); | |
> - if err != 0 { | |
> + if let Some(err) = err { | |
> report_setpgid_error( | |
> err, | |
> is_parent, | |
> @@ -864,11 +865,9 @@ fn exec_external_command( | |
> let pid = match pid { | |
> Ok(pid) => pid, | |
> Err(err) => { | |
> - safe_report_exec_error(err.0, actual_cmd.as_ptr(), argv.get(), envv.get()); | |
> + safe_report_exec_error(err, actual_cmd.as_ptr(), argv.get(), envv.get()); | |
> p.status | |
> - .update(&ProcStatus::from_exit_code(exit_code_from_exec_error( | |
> - err.0, | |
> - ))); | |
> + .update(&ProcStatus::from_exit_code(exit_code_from_exec_error(err))); | |
> return Err(()); | |
> } | |
> }; | |
> diff --git a/fish-rust/src/fd_monitor.rs b/fish-rust/src/fd_monitor.rs | |
> index 3bbb1c7e4c57..1c62b1559b0b 100644 | |
> --- a/fish-rust/src/fd_monitor.rs | |
> +++ b/fish-rust/src/fd_monitor.rs | |
> @@ -11,8 +11,8 @@ use crate::ffi::void_ptr; | |
> use crate::flog::FLOG; | |
> use crate::threads::assert_is_background_thread; | |
> use crate::wutil::perror; | |
> -use errno::errno; | |
> -use libc::{self, c_void, EAGAIN, EINTR, EWOULDBLOCK}; | |
> +use libc::{self, c_void}; | |
> +use nix::errno::Errno; | |
> | |
> #[cfg(not(HAVE_EVENTFD))] | |
> use crate::fds::{make_autoclose_pipes, make_fd_nonblocking}; | |
> @@ -148,11 +148,11 @@ impl FdEventSignaller { | |
> std::mem::size_of_val(&buff), | |
> ) | |
> }; | |
> - if ret >= 0 || errno().0 != EINTR { | |
> + if ret >= 0 || Errno::last() != Errno::EINTR { | |
> break; | |
> } | |
> } | |
> - if ret < 0 && ![EAGAIN, EWOULDBLOCK].contains(&errno().0) { | |
> + if ret < 0 && ![Errno::EAGAIN, Errno::EWOULDBLOCK].contains(&Errno::last()) { | |
> perror("read"); | |
> } | |
> ret > 0 | |
> @@ -175,12 +175,12 @@ impl FdEventSignaller { | |
> std::mem::size_of_val(&c), | |
> ) | |
> }; | |
> - if ret >= 0 || errno().0 != EINTR { | |
> + if ret >= 0 || Errno::last() != Errno::EINTR { | |
> break; | |
> } | |
> } | |
> // EAGAIN occurs if either the pipe buffer is full or the eventfd overflows (very unlikely). | |
> - if ret < 0 && ![EAGAIN, EWOULDBLOCK].contains(&errno().0) { | |
> + if ret < 0 && ![Errno::EAGAIN, Errno::EWOULDBLOCK].contains(&Errno::last()) { | |
> perror("write"); | |
> } | |
> } | |
> @@ -640,7 +640,7 @@ impl BackgroundFdMonitor { | |
> .map(|duration| duration.as_micros() as u64) | |
> .unwrap_or(FdReadableSet::kNoTimeout), | |
> ); | |
> - if ret < 0 && errno::errno().0 != libc::EINTR { | |
> + if ret < 0 && Errno::last() != Errno::EINTR { | |
> // Surprising error | |
> perror("select"); | |
> } | |
> diff --git a/fish-rust/src/fds.rs b/fish-rust/src/fds.rs | |
> index 9f9981e5e631..d793ee45cbd3 100644 | |
> --- a/fish-rust/src/fds.rs | |
> +++ b/fish-rust/src/fds.rs | |
> @@ -3,9 +3,9 @@ use crate::flog::FLOG; | |
> use crate::wchar::prelude::*; | |
> use crate::wutil::perror; | |
> use libc::{ | |
> - c_int, EINTR, FD_CLOEXEC, F_DUPFD_CLOEXEC, F_GETFD, F_GETFL, F_SETFD, F_SETFL, O_CLOEXEC, | |
> - O_NONBLOCK, | |
> + c_int, FD_CLOEXEC, F_DUPFD_CLOEXEC, F_GETFD, F_GETFL, F_SETFD, F_SETFL, O_CLOEXEC, O_NONBLOCK, | |
> }; | |
> +use nix::errno::Errno; | |
> use nix::unistd; | |
> use std::ffi::CStr; | |
> use std::io::{self, Read, Write}; | |
> @@ -31,23 +31,13 @@ pub struct AutoCloseFd { | |
> | |
> impl Read for AutoCloseFd { | |
> fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { | |
> - unsafe { | |
> - match libc::read(self.as_raw_fd(), buf.as_mut_ptr() as *mut _, buf.len()) { | |
> - -1 => Err(std::io::Error::from_raw_os_error(errno::errno().0)), | |
> - bytes => Ok(bytes as usize), | |
> - } | |
> - } | |
> + unistd::read(self.as_raw_fd(), buf).map_err(std::io::Error::from) | |
> } | |
> } | |
> | |
> impl Write for AutoCloseFd { | |
> fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { | |
> - unsafe { | |
> - match libc::write(self.as_raw_fd(), buf.as_ptr() as *const _, buf.len()) { | |
> - -1 => Err(std::io::Error::from_raw_os_error(errno::errno().0)), | |
> - bytes => Ok(bytes as usize), | |
> - } | |
> - } | |
> + unistd::write(self.as_raw_fd(), buf).map_err(std::io::Error::from) | |
> } | |
> | |
> fn flush(&mut self) -> std::io::Result<()> { | |
> @@ -258,8 +248,9 @@ pub fn open_cloexec(path: &CStr, flags: i32, mode: libc::c_int) -> RawFd { | |
> /// Close a file descriptor \p fd, retrying on EINTR. | |
> pub fn exec_close(fd: RawFd) { | |
> assert!(fd >= 0, "Invalid fd"); | |
> - while unsafe { libc::close(fd) } == -1 { | |
> - if errno::errno().0 != EINTR { | |
> + | |
> + while let Err(err) = unistd::close(fd) { | |
> + if err != Errno::EINTR { | |
> perror("close"); | |
> break; | |
> } | |
> @@ -271,10 +262,7 @@ pub fn make_fd_nonblocking(fd: RawFd) -> Result<(), io::Error> { | |
> let flags = unsafe { libc::fcntl(fd, F_GETFL, 0) }; | |
> let nonblocking = (flags & O_NONBLOCK) == O_NONBLOCK; | |
> if !nonblocking { | |
> - match unsafe { libc::fcntl(fd, F_SETFL, flags | O_NONBLOCK) } { | |
> - -1 => return Err(io::Error::last_os_error()), | |
> - _ => return Ok(()), | |
> - }; | |
> + Errno::result(unsafe { libc::fcntl(fd, F_SETFL, flags | O_NONBLOCK) })?; | |
> } | |
> Ok(()) | |
> } | |
> @@ -284,10 +272,7 @@ pub fn make_fd_blocking(fd: RawFd) -> Result<(), io::Error> { | |
> let flags = unsafe { libc::fcntl(fd, F_GETFL, 0) }; | |
> let nonblocking = (flags & O_NONBLOCK) == O_NONBLOCK; | |
> if nonblocking { | |
> - match unsafe { libc::fcntl(fd, F_SETFL, flags & !O_NONBLOCK) } { | |
> - -1 => return Err(io::Error::last_os_error()), | |
> - _ => return Ok(()), | |
> - }; | |
> + Errno::result(unsafe { libc::fcntl(fd, F_SETFL, flags & !O_NONBLOCK) })?; | |
> } | |
> Ok(()) | |
> } | |
> diff --git a/fish-rust/src/fork_exec/postfork.rs b/fish-rust/src/fork_exec/postfork.rs | |
> index 54a4190c03ca..dd88c62102a3 100644 | |
> --- a/fish-rust/src/fork_exec/postfork.rs | |
> +++ b/fish-rust/src/fork_exec/postfork.rs | |
> @@ -7,6 +7,7 @@ use crate::nix::getpid; | |
> use crate::redirection::Dup2List; | |
> use crate::signal::signal_reset_handlers; | |
> use libc::{c_char, c_int, pid_t}; | |
> +use nix::errno::Errno; | |
> use std::ffi::CStr; | |
> | |
> /// The number of times to try to call fork() before giving up. | |
> @@ -47,7 +48,7 @@ fn strlen_safe(s: *const libc::c_char) -> usize { | |
> | |
> /// Report the error code for a failed setpgid call. | |
> pub fn report_setpgid_error( | |
> - err: i32, | |
> + err: Errno, | |
> is_parent: bool, | |
> pid: pid_t, | |
> desired_pgid: pid_t, | |
> @@ -82,9 +83,9 @@ pub fn report_setpgid_error( | |
> ); | |
> | |
> match err { | |
> - libc::EACCES => FLOG_SAFE!(error, "setpgid: Process ", pid, " has already exec'd"), | |
> - libc::EINVAL => FLOG_SAFE!(error, "setpgid: pgid ", cur_group, " unsupported"), | |
> - libc::EPERM => { | |
> + Errno::EACCES => FLOG_SAFE!(error, "setpgid: Process ", pid, " has already exec'd"), | |
> + Errno::EINVAL => FLOG_SAFE!(error, "setpgid: pgid ", cur_group, " unsupported"), | |
> + Errno::EPERM => { | |
> FLOG_SAFE!( | |
> error, | |
> "setpgid: Process ", | |
> @@ -94,30 +95,30 @@ pub fn report_setpgid_error( | |
> " does not match" | |
> ); | |
> } | |
> - libc::ESRCH => FLOG_SAFE!(error, "setpgid: Process ID ", pid, " does not match"), | |
> - _ => FLOG_SAFE!(error, "setpgid: Unknown error number ", err), | |
> + Errno::ESRCH => FLOG_SAFE!(error, "setpgid: Process ID ", pid, " does not match"), | |
> + _ => FLOG_SAFE!(error, "setpgid: Unknown error number ", err as i32), | |
> } | |
> } | |
> | |
> /// Execute setpgid, moving pid into the given pgroup. | |
> /// Return the result of setpgid. | |
> -pub fn execute_setpgid(pid: pid_t, pgroup: pid_t, is_parent: bool) -> i32 { | |
> +pub fn execute_setpgid(pid: pid_t, pgroup: pid_t, is_parent: bool) -> Option<Errno> { | |
> // There is a comment "Historically we have looped here to support WSL." | |
> // TODO: stop looping. | |
> let mut eperm_count = 0; | |
> loop { | |
> if unsafe { libc::setpgid(pid, pgroup) } == 0 { | |
> - return 0; | |
> + return None; | |
> } | |
> - let err = errno::errno().0; | |
> - if err == libc::EACCES && is_parent { | |
> + let err = Errno::last(); | |
> + if err == Errno::EACCES && is_parent { | |
> // We are the parent process and our child has called exec(). | |
> // This is an unavoidable benign race. | |
> - return 0; | |
> - } else if err == libc::EINTR { | |
> + return None; | |
> + } else if err == Errno::EINTR { | |
> // Paranoia. | |
> continue; | |
> - } else if err == libc::EPERM && eperm_count < 100 { | |
> + } else if err == Errno::EPERM && eperm_count < 100 { | |
> eperm_count += 1; | |
> // The setpgid(2) man page says that EPERM is returned only if attempts are made | |
> // to move processes into groups across session boundaries (which can never be | |
> @@ -134,14 +135,14 @@ pub fn execute_setpgid(pid: pid_t, pgroup: pid_t, is_parent: bool) -> i32 { | |
> // and returns ESRCH (process not found) instead of EACCES (child has called exec). | |
> // See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=251227 | |
> #[cfg(any(feature = "bsd", target_os = "macos"))] | |
> - if err == libc::ESRCH && is_parent { | |
> + if err == Errno::ESRCH && is_parent { | |
> // Handle this just like we would EACCES above, as we're virtually certain that | |
> // setpgid(2) was called against a process that was at least at one point in time a | |
> // valid child. | |
> - return 0; | |
> + return None; | |
> } | |
> | |
> - return err; | |
> + return Some(err); | |
> } | |
> } | |
> | |
> @@ -206,14 +207,14 @@ pub fn child_setup_process( | |
> /// FORK_LAPS times, with a very slight delay between each lap. If fork fails even then, the process | |
> /// will exit with an error message. | |
> pub fn execute_fork() -> pid_t { | |
> - let mut err = 0; | |
> + let mut err = Errno::UnknownErrno; | |
> for i in 0..FORK_LAPS { | |
> let pid = unsafe { libc::fork() }; | |
> if pid >= 0 { | |
> return pid; | |
> } | |
> - err = errno::errno().0; | |
> - if err != libc::EAGAIN { | |
> + err = Errno::last(); | |
> + if err != Errno::EAGAIN { | |
> break; | |
> } | |
> let pollint = libc::timespec { | |
> @@ -227,24 +228,24 @@ pub fn execute_fork() -> pid_t { | |
> } | |
> | |
> match err { | |
> - libc::EAGAIN => { | |
> + Errno::EAGAIN => { | |
> FLOG_SAFE!( | |
> error, | |
> "fork: Out of resources. Check RLIMIT_NPROC and pid_max." | |
> ); | |
> } | |
> - libc::ENOMEM => { | |
> + Errno::ENOMEM => { | |
> FLOG_SAFE!(error, "fork: Out of memory."); | |
> } | |
> _ => { | |
> - FLOG_SAFE!(error, "fork: Unknown error number", err); | |
> + FLOG_SAFE!(error, "fork: Unknown error number", err as i32); | |
> } | |
> } | |
> exit_without_destructors(1) | |
> } | |
> | |
> pub fn safe_report_exec_error( | |
> - err: i32, | |
> + err: Errno, | |
> actual_cmd: *const c_char, | |
> argvv: *const *const c_char, | |
> envv: *const *const c_char, | |
> @@ -252,7 +253,7 @@ pub fn safe_report_exec_error( | |
> // TODO: actual_cmd may be passed as a CStr. | |
> let actual_cmd: &CStr = unsafe { CStr::from_ptr(actual_cmd) }; | |
> match err { | |
> - libc::E2BIG => { | |
> + Errno::E2BIG => { | |
> let mut sz = 0; | |
> let mut szenv = 0; | |
> unsafe { | |
> @@ -317,7 +318,7 @@ pub fn safe_report_exec_error( | |
> } | |
> } | |
> | |
> - libc::ENOEXEC => { | |
> + Errno::ENOEXEC => { | |
> FLOG_SAFE!( | |
> exec, | |
> "Failed to execute process: '", | |
> @@ -340,7 +341,7 @@ pub fn safe_report_exec_error( | |
> } | |
> } | |
> } | |
> - libc::EACCES | libc::ENOENT => { | |
> + Errno::EACCES | Errno::ENOENT => { | |
> // ENOENT is returned by exec() when the path fails, but also returned by posix_spawn if | |
> // an open file action fails. These cases appear to be impossible to distinguish. We | |
> // address this by not using posix_spawn for file redirections, so all the ENOENTs we | |
> @@ -386,7 +387,7 @@ pub fn safe_report_exec_error( | |
> actual_cmd, | |
> "': The file exists and is executable. Check the interpreter or linker?" | |
> ); | |
> - } else if err == libc::ENOENT { | |
> + } else if err == Errno::ENOENT { | |
> FLOG_SAFE!( | |
> exec, | |
> "Failed to execute process '", | |
> @@ -403,11 +404,11 @@ pub fn safe_report_exec_error( | |
> } | |
> } | |
> | |
> - libc::ENOMEM => { | |
> + Errno::ENOMEM => { | |
> FLOG_SAFE!(exec, "Out of memory"); | |
> } | |
> | |
> - libc::ETXTBSY => { | |
> + Errno::ETXTBSY => { | |
> FLOG_SAFE!( | |
> exec, | |
> "Failed to execute process '", | |
> @@ -416,7 +417,7 @@ pub fn safe_report_exec_error( | |
> ); | |
> } | |
> | |
> - libc::ELOOP => { | |
> + Errno::ELOOP => { | |
> FLOG_SAFE!( | |
> exec, | |
> "Failed to execute process '", | |
> @@ -425,7 +426,7 @@ pub fn safe_report_exec_error( | |
> ); | |
> } | |
> | |
> - libc::EINVAL => { | |
> + Errno::EINVAL => { | |
> FLOG_SAFE!( | |
> exec, | |
> "Failed to execute process '", | |
> @@ -433,7 +434,7 @@ pub fn safe_report_exec_error( | |
> "': Unsupported format." | |
> ); | |
> } | |
> - libc::EISDIR => { | |
> + Errno::EISDIR => { | |
> FLOG_SAFE!( | |
> exec, | |
> "Failed to execute process '", | |
> @@ -441,7 +442,7 @@ pub fn safe_report_exec_error( | |
> "': File is a directory." | |
> ); | |
> } | |
> - libc::ENOTDIR => { | |
> + Errno::ENOTDIR => { | |
> FLOG_SAFE!( | |
> exec, | |
> "Failed to execute process '", | |
> @@ -450,7 +451,7 @@ pub fn safe_report_exec_error( | |
> ); | |
> } | |
> | |
> - libc::EMFILE => { | |
> + Errno::EMFILE => { | |
> FLOG_SAFE!( | |
> exec, | |
> "Failed to execute process '", | |
> @@ -458,7 +459,7 @@ pub fn safe_report_exec_error( | |
> "': Too many open files in this process." | |
> ); | |
> } | |
> - libc::ENFILE => { | |
> + Errno::ENFILE => { | |
> FLOG_SAFE!( | |
> exec, | |
> "Failed to execute process '", | |
> @@ -466,7 +467,7 @@ pub fn safe_report_exec_error( | |
> "': Too many open files on the system." | |
> ); | |
> } | |
> - libc::ENAMETOOLONG => { | |
> + Errno::ENAMETOOLONG => { | |
> FLOG_SAFE!( | |
> exec, | |
> "Failed to execute process '", | |
> @@ -474,7 +475,7 @@ pub fn safe_report_exec_error( | |
> "': Name is too long." | |
> ); | |
> } | |
> - libc::EPERM => { | |
> + Errno::EPERM => { | |
> FLOG_SAFE!( | |
> exec, | |
> "Failed to execute process '", | |
> @@ -485,7 +486,7 @@ pub fn safe_report_exec_error( | |
> } | |
> | |
> #[cfg(target_os = "macos")] | |
> - libc::EBADARCH => { | |
> + Errno::EBADARCH => { | |
> FLOG_SAFE!( | |
> exec, | |
> "Failed to execute process '", | |
> @@ -500,7 +501,7 @@ pub fn safe_report_exec_error( | |
> "Failed to execute process '", | |
> actual_cmd, | |
> "', unknown error number ", | |
> - err, | |
> + err as i32, | |
> ); | |
> } | |
> } | |
> @@ -569,7 +570,7 @@ mod ffi { | |
> argvv: *const *const c_char, | |
> envv: *const *const c_char, | |
> ) { | |
> - super::safe_report_exec_error(err, actual_cmd, argvv, envv) | |
> + super::safe_report_exec_error(Errno::from_i32(err), actual_cmd, argvv, envv) | |
> } | |
> | |
> #[no_mangle] | |
> @@ -580,6 +581,8 @@ mod ffi { | |
> #[no_mangle] | |
> pub extern "C" fn execute_setpgid(pid: pid_t, pgroup: pid_t, is_parent: bool) -> i32 { | |
> super::execute_setpgid(pid, pgroup, is_parent) | |
> + .map(|e| e as i32) | |
> + .unwrap_or(0) | |
> } | |
> | |
> #[no_mangle] | |
> @@ -593,7 +596,7 @@ mod ffi { | |
> argv0_str: *const c_char, | |
> ) { | |
> super::report_setpgid_error( | |
> - err, | |
> + Errno::from_i32(err), | |
> is_parent, | |
> pid, | |
> desired_pgid, | |
> diff --git a/fish-rust/src/fork_exec/spawn.rs b/fish-rust/src/fork_exec/spawn.rs | |
> index 59d9fdaca0e9..d277a1480e81 100644 | |
> --- a/fish-rust/src/fork_exec/spawn.rs | |
> +++ b/fish-rust/src/fork_exec/spawn.rs | |
> @@ -4,9 +4,10 @@ use super::blocked_signals_for_job; | |
> use crate::exec::is_thompson_shell_script; | |
> use crate::proc::Job; | |
> use crate::redirection::Dup2List; | |
> +use crate::set_errno; | |
> use crate::signal::get_signals_with_handlers; | |
> -use errno::{self, set_errno, Errno}; | |
> use libc::{self, c_char, posix_spawn_file_actions_t, posix_spawnattr_t}; | |
> +use nix::errno::Errno; | |
> use std::ffi::{CStr, CString}; | |
> | |
> // The posix_spawn family of functions is unusual in that it returns errno codes directly in the return value, not via errno. | |
> @@ -14,7 +15,7 @@ use std::ffi::{CStr, CString}; | |
> fn check_fail(res: i32) -> Result<(), Errno> { | |
> match res { | |
> 0 => Ok(()), | |
> - err => Err(Errno(err)), | |
> + err => Err(Errno::from_i32(err)), | |
> } | |
> } | |
> | |
> @@ -181,7 +182,7 @@ impl PosixSpawner { | |
> // after performing a binary safety check, recommended by POSIX: a | |
> // line needs to exist before the first \0 with a lowercase letter. | |
> let cmdcstr = unsafe { CStr::from_ptr(cmd) }; | |
> - if spawn_err.0 == libc::ENOEXEC && is_thompson_shell_script(cmdcstr) { | |
> + if spawn_err == Errno::ENOEXEC && is_thompson_shell_script(cmdcstr) { | |
> // Create a new argv with /bin/sh prepended. | |
> let interp = get_path_bshell(); | |
> let mut argv2 = vec![interp.as_ptr() as *mut c_char]; | |
> diff --git a/fish-rust/src/history.rs b/fish-rust/src/history.rs | |
> index 3f351e60caa7..b1695fd66589 100644 | |
> --- a/fish-rust/src/history.rs | |
> +++ b/fish-rust/src/history.rs | |
> @@ -37,6 +37,7 @@ use libc::{ | |
> O_RDONLY, O_WRONLY, SEEK_SET, | |
> }; | |
> use lru::LruCache; | |
> +use nix::errno::Errno; | |
> use rand::Rng; | |
> use widestring_suffix::widestrs; | |
> | |
> @@ -862,7 +863,7 @@ impl HistoryImpl { | |
> FLOGF!( | |
> history_file, | |
> "Error %d when truncating temporary history file", | |
> - errno::errno().0 | |
> + Errno::last() as i32, | |
> ); | |
> } | |
> } else { | |
> @@ -882,14 +883,14 @@ impl HistoryImpl { | |
> FLOGF!( | |
> history_file, | |
> "Error %d when changing ownership of history file", | |
> - errno::errno().0 | |
> + Errno::last() as i32, | |
> ); | |
> } | |
> if unsafe { fchmod(tmp_fd, sbuf.st_mode) } == -1 { | |
> FLOGF!( | |
> history_file, | |
> "Error %d when changing mode of history file", | |
> - errno::errno().0, | |
> + Errno::last() as i32, | |
> ); | |
> } | |
> } | |
> @@ -898,10 +899,7 @@ impl HistoryImpl { | |
> if wrename(&tmp_name, &target_name) == -1 { | |
> FLOG!( | |
> error, | |
> - wgettext_fmt!( | |
> - "Error when renaming history file: %s", | |
> - errno::errno().to_string() | |
> - ) | |
> + wgettext_fmt!("Error when renaming history file: %s", Errno::last().desc()) | |
> ); | |
> } | |
> | |
> diff --git a/fish-rust/src/history/file.rs b/fish-rust/src/history/file.rs | |
> index 6ff6785a591e..9d9da4b7bd75 100644 | |
> --- a/fish-rust/src/history/file.rs | |
> +++ b/fish-rust/src/history/file.rs | |
> @@ -7,11 +7,11 @@ use std::{ | |
> time::{Duration, SystemTime, UNIX_EPOCH}, | |
> }; | |
> | |
> -use errno::errno; | |
> use libc::{ | |
> - c_void, lseek, mmap, munmap, EINTR, MAP_ANONYMOUS, MAP_FAILED, MAP_PRIVATE, PROT_READ, | |
> - PROT_WRITE, SEEK_END, SEEK_SET, | |
> + c_void, lseek, mmap, munmap, MAP_ANONYMOUS, MAP_FAILED, MAP_PRIVATE, PROT_READ, PROT_WRITE, | |
> + SEEK_END, SEEK_SET, | |
> }; | |
> +use nix::errno::Errno; | |
> | |
> use crate::{ | |
> common::{str2wcstring, subslice_position, wcs2string}, | |
> @@ -238,7 +238,7 @@ fn read_from_fd(fd: RawFd, dest: &mut [u8]) -> bool { | |
> let amt = | |
> unsafe { libc::read(fd, (&mut dest[nread]) as *mut u8 as *mut c_void, remaining) }; | |
> if amt < 0 { | |
> - if errno().0 != EINTR { | |
> + if Errno::last() != Errno::EINTR { | |
> return false; | |
> } | |
> } else if amt == 0 { | |
> diff --git a/fish-rust/src/input.rs b/fish-rust/src/input.rs | |
> index bdcaebff9892..c5ea8b5a3a85 100644 | |
> --- a/fish-rust/src/input.rs | |
> +++ b/fish-rust/src/input.rs | |
> @@ -12,10 +12,11 @@ use crate::proc::job_reap; | |
> use crate::reader::{ | |
> reader_reading_interrupted, reader_reset_interrupted, reader_schedule_prompt_repaint, | |
> }; | |
> +use crate::set_errno; | |
> use crate::signal::signal_clear_cancel; | |
> use crate::threads::assert_is_main_thread; | |
> use crate::wchar::prelude::*; | |
> -use errno::{set_errno, Errno}; | |
> +use nix::errno::Errno; | |
> use once_cell::sync::{Lazy, OnceCell}; | |
> use std::cell::RefCell; | |
> use std::collections::VecDeque; | |
> @@ -1135,7 +1136,7 @@ pub fn input_terminfo_get_sequence(name: &wstr, out_seq: &mut WString) -> bool { | |
> if name == m.name { | |
> // Found the mapping. | |
> if m.seq.is_none() { | |
> - set_errno(Errno(libc::EILSEQ)); | |
> + set_errno(Errno::EILSEQ); | |
> return false; | |
> } else { | |
> *out_seq = str2wcstring(m.seq.as_ref().unwrap()); | |
> @@ -1143,7 +1144,7 @@ pub fn input_terminfo_get_sequence(name: &wstr, out_seq: &mut WString) -> bool { | |
> } | |
> } | |
> } | |
> - set_errno(Errno(libc::ENOENT)); | |
> + set_errno(Errno::ENOENT); | |
> false | |
> } | |
> | |
> diff --git a/fish-rust/src/input_common.rs b/fish-rust/src/input_common.rs | |
> index 14a46fd65555..ef55920f722f 100644 | |
> --- a/fish-rust/src/input_common.rs | |
> +++ b/fish-rust/src/input_common.rs | |
> @@ -8,6 +8,7 @@ use crate::universal_notifier::default_notifier; | |
> use crate::wchar::prelude::*; | |
> use crate::wutil::encoding::{mbrtowc, zero_mbstate}; | |
> use crate::wutil::fish_wcstol; | |
> +use nix::errno::Errno; | |
> use std::collections::VecDeque; | |
> use std::os::fd::RawFd; | |
> use std::ptr; | |
> @@ -176,8 +177,8 @@ fn readb(in_fd: RawFd) -> ReadbResult { | |
> // Here's where we call select(). | |
> let select_res = fdset.check_readable(FdReadableSet::kNoTimeout); | |
> if select_res < 0 { | |
> - let err = errno::errno().0; | |
> - if err == libc::EINTR || err == libc::EAGAIN { | |
> + let err = Errno::last(); | |
> + if err == Errno::EINTR || err == Errno::EAGAIN { | |
> // A signal. | |
> return ReadbResult::Interrupted; | |
> } else { | |
> diff --git a/fish-rust/src/io.rs b/fish-rust/src/io.rs | |
> index ac1b469e2346..e660c0c8ed66 100644 | |
> --- a/fish-rust/src/io.rs | |
> +++ b/fish-rust/src/io.rs | |
> @@ -18,8 +18,8 @@ use crate::wchar::prelude::*; | |
> use crate::wchar_ffi::WCharFromFFI; | |
> use crate::wutil::{perror, perror_io, wdirname, wstat, wwrite_to_fd}; | |
> use cxx::CxxWString; | |
> -use errno::Errno; | |
> -use libc::{EAGAIN, EEXIST, EINTR, ENOENT, ENOTDIR, EPIPE, EWOULDBLOCK, O_EXCL, STDOUT_FILENO}; | |
> +use libc::{O_EXCL, STDOUT_FILENO}; | |
> +use nix::errno::Errno; | |
> use std::cell::{RefCell, UnsafeCell}; | |
> use std::os::fd::RawFd; | |
> use std::sync::atomic::{AtomicU64, Ordering}; | |
> @@ -478,7 +478,7 @@ impl IoBuffer { | |
> /// set). | |
> pub fn read_once(fd: RawFd, buffer: &mut MutexGuard<'_, SeparatedBuffer>) -> isize { | |
> assert!(fd >= 0, "Invalid fd"); | |
> - errno::set_errno(Errno(0)); | |
> + Errno::clear(); | |
> let mut bytes = [b'\0'; 4096 * 4]; | |
> | |
> // We want to swallow EINTR only; in particular EAGAIN needs to be returned back to the caller. | |
> @@ -490,12 +490,12 @@ impl IoBuffer { | |
> std::mem::size_of_val(&bytes), | |
> ) | |
> }; | |
> - if amt < 0 && errno::errno().0 == EINTR { | |
> + if amt < 0 && Errno::last() == Errno::EINTR { | |
> continue; | |
> } | |
> break amt; | |
> }; | |
> - if amt < 0 && ![EAGAIN, EWOULDBLOCK].contains(&errno::errno().0) { | |
> + if amt < 0 && ![Errno::EAGAIN, Errno::EWOULDBLOCK].contains(&Errno::last()) { | |
> perror("read"); | |
> } else if amt > 0 { | |
> buffer.append( | |
> @@ -582,8 +582,9 @@ fn begin_filling(iobuffer: &Arc<IoBuffer>, fd: AutoCloseFd) { | |
> // select() reported us as readable; read a bit. | |
> let mut buf = iobuffer.buffer.lock().unwrap(); | |
> let ret = IoBuffer::read_once(fd.fd(), &mut buf); | |
> - done = | |
> - ret == 0 || (ret < 0 && ![EAGAIN, EWOULDBLOCK].contains(&errno::errno().0)); | |
> + done = ret == 0 | |
> + || (ret < 0 | |
> + && ![Errno::EAGAIN, Errno::EWOULDBLOCK].contains(&Errno::last())); | |
> } else if iobuffer.shutdown_fillthread.load() { | |
> // Here our caller asked us to shut down; read while we keep getting data. | |
> // This will stop when the fd is closed or if we get EAGAIN. | |
> @@ -676,16 +677,16 @@ impl IoChain { | |
> let oflags = spec.oflags(); | |
> let file = AutoCloseFd::new(wopen_cloexec(&path, oflags, OPEN_MASK)); | |
> if !file.is_valid() { | |
> - if (oflags & O_EXCL) != 0 && errno::errno().0 == EEXIST { | |
> + if (oflags & O_EXCL) != 0 && Errno::last() == Errno::EEXIST { | |
> FLOGF!(warning, NOCLOB_ERROR, spec.target); | |
> } else { | |
> if should_flog!(warning) { | |
> FLOGF!(warning, FILE_ERROR, spec.target); | |
> - let err = errno::errno().0; | |
> + let err = Errno::last(); | |
> // If the error is that the file doesn't exist | |
> // or there's a non-directory component, | |
> // find the first problematic component for a better message. | |
> - if [ENOENT, ENOTDIR].contains(&err) { | |
> + if [Errno::ENOENT, Errno::ENOTDIR].contains(&err) { | |
> let mut dname: &wstr = &spec.target; | |
> while !dname.is_empty() { | |
> let next: &wstr = wdirname(dname); | |
> @@ -875,14 +876,14 @@ impl FdOutputStream { | |
> // Some of our builtins emit multiple screens worth of data sent to a pager (the primary | |
> // example being the `history` builtin) and receiving SIGINT should be considered normal and | |
> // non-exceptional (user request to abort via Ctrl-C), meaning we shouldn't print an error. | |
> - if errno::errno().0 == EINTR && self.sigcheck.check() { | |
> + if Errno::last() == Errno::EINTR && self.sigcheck.check() { | |
> // We have two options here: we can either return false without setting errored_ to | |
> // true (*this* write will be silently aborted but the onus is on the caller to check | |
> // the return value and skip future calls to `append()`) or we can flag the entire | |
> // output stream as errored, causing us to both return false and skip any future writes. | |
> // We're currently going with the latter, especially seeing as no callers currently | |
> // check the result of `append()` (since it was always a void function before). | |
> - } else if errno::errno().0 != EPIPE { | |
> + } else if Errno::last() != Errno::EPIPE { | |
> perror("write"); | |
> } | |
> self.errored = true; | |
> diff --git a/fish-rust/src/lib.rs b/fish-rust/src/lib.rs | |
> index 409f1f029aea..947a8d2723c8 100644 | |
> --- a/fish-rust/src/lib.rs | |
> +++ b/fish-rust/src/lib.rs | |
> @@ -121,3 +121,9 @@ mod wutil; | |
> #[cfg(any(test, feature = "fish-ffi-tests"))] | |
> #[allow(unused_imports)] // Easy way to suppress warnings while we have two testing modes. | |
> mod tests; | |
> + | |
> +// TODO: Remove once nix is updated to include set_errno | |
> +// https://github.com/nix-rust/nix/pull/2283 | |
> +fn set_errno(errno: ::nix::errno::Errno) { | |
> + ::_errno::set_errno(::_errno::Errno(errno as i32)) | |
> +} | |
> diff --git a/fish-rust/src/parse_execution.rs b/fish-rust/src/parse_execution.rs | |
> index c2a5372a8601..e79c273707c3 100644 | |
> --- a/fish-rust/src/parse_execution.rs | |
> +++ b/fish-rust/src/parse_execution.rs | |
> @@ -799,7 +799,7 @@ impl<'a> ParseExecutionContext { | |
> &external_cmd.path | |
> }, | |
> statement, | |
> - std::io::Error::from_raw_os_error(external_cmd.err.unwrap().into()), | |
> + std::io::Error::from(external_cmd.err.unwrap()), | |
> ); | |
> } | |
> }; | |
> diff --git a/fish-rust/src/path.rs b/fish-rust/src/path.rs | |
> index 4877a975ca74..72c9f994890c 100644 | |
> --- a/fish-rust/src/path.rs | |
> +++ b/fish-rust/src/path.rs | |
> @@ -8,10 +8,11 @@ use crate::compat::{MNT_LOCAL, ST_LOCAL}; | |
> use crate::env::{EnvMode, EnvStack, Environment}; | |
> use crate::expand::{expand_tilde, HOME_DIRECTORY}; | |
> use crate::flog::{FLOG, FLOGF}; | |
> +use crate::set_errno; | |
> use crate::wchar::prelude::*; | |
> use crate::wutil::{normalize_path, path_normalize_for_cd, waccess, wdirname, wmkdir, wstat}; | |
> -use errno::{errno, set_errno, Errno}; | |
> -use libc::{EACCES, ENOENT, ENOTDIR, F_OK, X_OK}; | |
> +use libc::{F_OK, X_OK}; | |
> +use nix::errno::Errno; | |
> use once_cell::sync::Lazy; | |
> use std::ffi::OsStr; | |
> use std::io::ErrorKind; | |
> @@ -117,7 +118,7 @@ fn maybe_issue_path_warning( | |
> using_xdg: bool, | |
> xdg_var: &wstr, | |
> path: &wstr, | |
> - saved_errno: libc::c_int, | |
> + saved_errno: Errno, | |
> vars: &EnvStack, | |
> ) { | |
> let warning_var_name = "_FISH_WARNED_"L.to_owned() + which_dir; | |
> @@ -159,7 +160,7 @@ fn maybe_issue_path_warning( | |
> ); | |
> FLOG!( | |
> warning_path, | |
> - wgettext_fmt!("The error was '%s'.", Errno(saved_errno).to_string()) | |
> + wgettext_fmt!("The error was '%s'.", saved_errno.desc()) | |
> ); | |
> FLOG!( | |
> warning_path, | |
> @@ -262,22 +263,22 @@ pub fn path_get_paths(cmd: &wstr, vars: &dyn Environment) -> Vec<WString> { | |
> } | |
> | |
> fn path_get_path_core<S: AsRef<wstr>>(cmd: &wstr, pathsv: &[S]) -> GetPathResult { | |
> - let noent_res = GetPathResult::new(Some(Errno(ENOENT)), WString::new()); | |
> + let noent_res = GetPathResult::new(Some(Errno::ENOENT), WString::new()); | |
> // Test if the given path can be executed. | |
> // \return 0 on success, an errno value on failure. | |
> let test_path = |path: &wstr| -> Result<(), Errno> { | |
> let narrow = wcs2zstring(path); | |
> if unsafe { libc::access(narrow.as_ptr(), X_OK) } != 0 { | |
> - return Err(errno()); | |
> + return Err(Errno::last()); | |
> } | |
> let narrow: Vec<u8> = narrow.into(); | |
> let Ok(md) = std::fs::metadata(OsStr::from_bytes(&narrow)) else { | |
> - return Err(errno()); | |
> + return Err(Errno::last()); | |
> }; | |
> if md.is_file() { | |
> Ok(()) | |
> } else { | |
> - Err(Errno(EACCES)) | |
> + Err(Errno::EACCES) | |
> } | |
> }; | |
> | |
> @@ -310,7 +311,7 @@ fn path_get_path_core<S: AsRef<wstr>>(cmd: &wstr, pathsv: &[S]) -> GetPathResult | |
> return GetPathResult::new(None, proposed_path); | |
> } | |
> Err(err) => { | |
> - if err.0 != ENOENT && best.err == Some(Errno(ENOENT)) { | |
> + if err != Errno::ENOENT && best.err == Some(Errno::ENOENT) { | |
> // Keep the first *interesting* error and path around. | |
> // ENOENT isn't interesting because not having a file is the normal case. | |
> // Ignore if the parent directory is already inaccessible. | |
> @@ -336,7 +337,7 @@ fn path_get_path_core<S: AsRef<wstr>>(cmd: &wstr, pathsv: &[S]) -> GetPathResult | |
> /// \param vars The environment variables to use (for the CDPATH variable) | |
> /// \return the command, or none() if it could not be found. | |
> pub fn path_get_cdpath(dir: &wstr, wd: &wstr, vars: &dyn Environment) -> Option<WString> { | |
> - let mut err = ENOENT; | |
> + let mut err = Errno::ENOENT; | |
> if dir.is_empty() { | |
> return None; | |
> } | |
> @@ -348,11 +349,11 @@ pub fn path_get_cdpath(dir: &wstr, wd: &wstr, vars: &dyn Environment) -> Option< | |
> if md.is_dir() { | |
> return Some(a_dir); | |
> } | |
> - err = ENOTDIR; | |
> + err = Errno::ENOTDIR; | |
> } | |
> } | |
> | |
> - set_errno(Errno(err)); | |
> + set_errno(err); | |
> None | |
> } | |
> | |
> @@ -568,14 +569,14 @@ struct BaseDirectory { | |
> /// whether the dir is remote | |
> remoteness: DirRemoteness, | |
> /// the error code if creating the directory failed, or 0 on success. | |
> - err: libc::c_int, | |
> + err: Errno, | |
> /// whether an XDG variable was used in resolving the directory. | |
> used_xdg: bool, | |
> } | |
> | |
> impl BaseDirectory { | |
> fn success(&self) -> bool { | |
> - self.err == 0 | |
> + self.err == Errno::from_i32(0) | |
> } | |
> } | |
> | |
> @@ -601,15 +602,15 @@ fn make_base_directory(xdg_var: &wstr, non_xdg_homepath: &wstr) -> BaseDirectory | |
> used_xdg = false; | |
> } | |
> | |
> - set_errno(Errno(0)); | |
> + Errno::clear(); | |
> let err; | |
> let mut remoteness = DirRemoteness::unknown; | |
> if path.is_empty() { | |
> - err = ENOENT; | |
> + err = Errno::ENOENT; | |
> } else if !create_directory(&path) { | |
> - err = errno().0; | |
> + err = Errno::last(); | |
> } else { | |
> - err = 0; | |
> + err = Errno::from_i32(0); | |
> // Need to append a trailing slash to check the contents of the directory, not its parent. | |
> let mut tmp = path.clone(); | |
> tmp.push('/'); | |
> diff --git a/fish-rust/src/proc.rs b/fish-rust/src/proc.rs | |
> index f623b7e0e692..987f3a9bfb98 100644 | |
> --- a/fish-rust/src/proc.rs | |
> +++ b/fish-rust/src/proc.rs | |
> @@ -24,11 +24,11 @@ use crate::wchar::{wstr, WString, L}; | |
> use crate::wchar_ext::ToWString; | |
> use crate::wutil::{perror, wbasename, wgettext, wperror}; | |
> use libc::{ | |
> - EBADF, EINVAL, ENOTTY, EPERM, EXIT_SUCCESS, SIGABRT, SIGBUS, SIGCONT, SIGFPE, SIGHUP, SIGILL, | |
> - SIGINT, SIGPIPE, SIGQUIT, SIGSEGV, SIGSYS, SIGTTOU, SIG_DFL, SIG_IGN, STDIN_FILENO, WCONTINUED, | |
> - WEXITSTATUS, WIFCONTINUED, WIFEXITED, WIFSIGNALED, WIFSTOPPED, WNOHANG, WTERMSIG, WUNTRACED, | |
> - _SC_CLK_TCK, | |
> + EXIT_SUCCESS, SIGABRT, SIGBUS, SIGCONT, SIGFPE, SIGHUP, SIGILL, SIGINT, SIGPIPE, SIGQUIT, | |
> + SIGSEGV, SIGSYS, SIGTTOU, SIG_DFL, SIG_IGN, STDIN_FILENO, WCONTINUED, WEXITSTATUS, | |
> + WIFCONTINUED, WIFEXITED, WIFSIGNALED, WIFSTOPPED, WNOHANG, WTERMSIG, WUNTRACED, _SC_CLK_TCK, | |
> }; | |
> +use nix::errno::Errno; | |
> use once_cell::sync::Lazy; | |
> use printf_compat::sprintf; | |
> use std::cell::{Cell, Ref, RefCell, RefMut}; | |
> @@ -353,7 +353,7 @@ impl TtyTransfer { | |
> let mut tmodes: libc::termios = unsafe { std::mem::zeroed() }; | |
> if unsafe { libc::tcgetattr(STDIN_FILENO, &mut tmodes) } == 0 { | |
> owner.tmodes.replace(Some(tmodes)); | |
> - } else if errno::errno().0 != ENOTTY { | |
> + } else if Errno::last() != Errno::ENOTTY { | |
> perror("tcgetattr"); | |
> } | |
> } | |
> @@ -410,7 +410,7 @@ impl TtyTransfer { | |
> // guarantee the process isn't going to exit while we wait (which would cause us to possibly | |
> // block indefinitely). | |
> while unsafe { libc::tcsetpgrp(STDIN_FILENO, pgid) } != 0 { | |
> - FLOGF!(proc_termowner, "tcsetpgrp failed: %d", errno::errno().0); | |
> + FLOGF!(proc_termowner, "tcsetpgrp failed: %d", Errno::last() as i32); | |
> | |
> // Before anything else, make sure that it's even necessary to call tcsetpgrp. | |
> // Since it usually _is_ necessary, we only check in case it fails so as to avoid the | |
> @@ -418,13 +418,13 @@ impl TtyTransfer { | |
> // a significant cost when running process groups in quick succession. | |
> let getpgrp_res = unsafe { libc::tcgetpgrp(STDIN_FILENO) }; | |
> if getpgrp_res < 0 { | |
> - match errno::errno().0 { | |
> - ENOTTY => { | |
> + match Errno::last() { | |
> + Errno::ENOTTY => { | |
> // stdin is not a tty. This may come about if job control is enabled but we are | |
> // not a tty - see #6573. | |
> return false; | |
> } | |
> - EBADF => { | |
> + Errno::EBADF => { | |
> // stdin has been closed. Workaround a glibc bug - see #3644. | |
> redirect_tty_output(); | |
> return false; | |
> @@ -445,46 +445,52 @@ impl TtyTransfer { | |
> } | |
> | |
> let pgroup_terminated; | |
> - if errno::errno().0 == EINVAL { | |
> - // OS X returns EINVAL if the process group no longer lives. Probably other OSes, | |
> - // too. Unlike EPERM below, EINVAL can only happen if the process group has | |
> - // terminated. | |
> - pgroup_terminated = true; | |
> - } else if errno::errno().0 == EPERM { | |
> - // Retry so long as this isn't because the process group is dead. | |
> - let mut result: libc::c_int = 0; | |
> - let wait_result = unsafe { libc::waitpid(-pgid, &mut result, WNOHANG) }; | |
> - if wait_result == -1 { | |
> - // Note that -1 is technically an "error" for waitpid in the sense that an | |
> - // invalid argument was specified because no such process group exists any | |
> - // longer. This is the observed behavior on Linux 4.4.0. a "success" result | |
> - // would mean processes from the group still exist but is still running in some | |
> - // state or the other. | |
> + | |
> + match Errno::last() { | |
> + Errno::EINVAL => { | |
> + // OS X returns EINVAL if the process group no longer lives. Probably other OSes, | |
> + // too. Unlike EPERM below, EINVAL can only happen if the process group has | |
> + // terminated. | |
> pgroup_terminated = true; | |
> - } else { | |
> - // Debug the original tcsetpgrp error (not the waitpid errno) to the log, and | |
> - // then retry until not EPERM or the process group has exited. | |
> + } | |
> + Errno::EPERM => { | |
> + // Retry so long as this isn't because the process group is dead. | |
> + let mut result: libc::c_int = 0; | |
> + let wait_result = unsafe { libc::waitpid(-pgid, &mut result, WNOHANG) }; | |
> + if wait_result == -1 { | |
> + // Note that -1 is technically an "error" for waitpid in the sense that an | |
> + // invalid argument was specified because no such process group exists any | |
> + // longer. This is the observed behavior on Linux 4.4.0. a "success" result | |
> + // would mean processes from the group still exist but is still running in some | |
> + // state or the other. | |
> + pgroup_terminated = true; | |
> + } else { | |
> + // Debug the original tcsetpgrp error (not the waitpid errno) to the log, and | |
> + // then retry until not EPERM or the process group has exited. | |
> + FLOGF!( | |
> + proc_termowner, | |
> + "terminal_give_to_job(): EPERM with pgid %d.", | |
> + pgid | |
> + ); | |
> + continue; | |
> + } | |
> + } | |
> + Errno::ENOTTY => { | |
> + // stdin is not a TTY. In general we expect this to be caught via the tcgetpgrp | |
> + // call's EBADF handler above. | |
> + return false; | |
> + } | |
> + _ => { | |
> FLOGF!( | |
> - proc_termowner, | |
> - "terminal_give_to_job(): EPERM with pgid %d.", | |
> + warning, | |
> + "Could not send job %d ('%ls') with pgid %d to foreground", | |
> + jg.job_id.to_wstring(), | |
> + jg.command, | |
> pgid | |
> ); | |
> - continue; | |
> + perror("tcsetpgrp"); | |
> + return false; | |
> } | |
> - } else if errno::errno().0 == ENOTTY { | |
> - // stdin is not a TTY. In general we expect this to be caught via the tcgetpgrp | |
> - // call's EBADF handler above. | |
> - return false; | |
> - } else { | |
> - FLOGF!( | |
> - warning, | |
> - "Could not send job %d ('%ls') with pgid %d to foreground", | |
> - jg.job_id.to_wstring(), | |
> - jg.command, | |
> - pgid | |
> - ); | |
> - perror("tcsetpgrp"); | |
> - return false; | |
> } | |
> | |
> if pgroup_terminated { | |
> diff --git a/fish-rust/src/reader.rs b/fish-rust/src/reader.rs | |
> index cf2a6c6dc392..032aabeb252d 100644 | |
> --- a/fish-rust/src/reader.rs | |
> +++ b/fish-rust/src/reader.rs | |
> @@ -13,9 +13,9 @@ | |
> //! end of the list is reached, at which point regular searching will commence. | |
> | |
> use libc::{ | |
> - c_char, c_int, c_void, EAGAIN, ECHO, EINTR, EIO, EISDIR, ENOTTY, EPERM, ESRCH, EWOULDBLOCK, | |
> - ICANON, ICRNL, IEXTEN, INLCR, IXOFF, IXON, ONLCR, OPOST, O_NONBLOCK, O_RDONLY, SIGINT, SIGTTIN, | |
> - STDIN_FILENO, STDOUT_FILENO, S_IFDIR, TCSANOW, VMIN, VQUIT, VSUSP, VTIME, _POSIX_VDISABLE, | |
> + c_char, c_int, c_void, ECHO, ICANON, ICRNL, IEXTEN, INLCR, IXOFF, IXON, ONLCR, OPOST, | |
> + O_NONBLOCK, O_RDONLY, SIGINT, SIGTTIN, STDIN_FILENO, STDOUT_FILENO, S_IFDIR, TCSANOW, VMIN, | |
> + VQUIT, VSUSP, VTIME, _POSIX_VDISABLE, | |
> }; | |
> use once_cell::sync::Lazy; | |
> use std::cell::UnsafeCell; | |
> @@ -30,7 +30,7 @@ use std::sync::atomic::{AtomicI32, AtomicU32, AtomicU64, AtomicU8}; | |
> use std::sync::{Arc, Mutex, MutexGuard}; | |
> use std::time::{Duration, Instant}; | |
> | |
> -use errno::{errno, Errno}; | |
> +use nix::errno::Errno; | |
> | |
> use crate::abbrs::abbrs_match; | |
> use crate::ast::{self, Ast, Category, Traversal}; | |
> @@ -546,7 +546,9 @@ pub fn reader_read(parser: &Parser, fd: RawFd, io: &IoChain) -> c_int { | |
> let a_tty = unsafe { libc::isatty(STDIN_FILENO) } != 0; | |
> if a_tty { | |
> interactive = true; | |
> - } else if unsafe { libc::tcgetattr(STDIN_FILENO, &mut t) } == -1 && errno().0 == EIO { | |
> + } else if unsafe { libc::tcgetattr(STDIN_FILENO, &mut t) } == -1 | |
> + && Errno::last() == Errno::EIO | |
> + { | |
> redirect_tty_output(); | |
> interactive = true; | |
> } | |
> @@ -662,10 +664,10 @@ fn read_i(parser: &Parser) -> i32 { | |
> fn read_ni(parser: &Parser, fd: RawFd, io: &IoChain) -> i32 { | |
> let mut buf: libc::stat = unsafe { std::mem::zeroed() }; | |
> if unsafe { libc::fstat(fd, &mut buf) } == -1 { | |
> - let err = errno(); | |
> + let err = Errno::last(); | |
> FLOG!( | |
> error, | |
> - wgettext_fmt!("Unable to read input file: %s", err.to_string()) | |
> + wgettext_fmt!("Unable to read input file: %s", err.desc()) | |
> ); | |
> return 1; | |
> } | |
> @@ -676,7 +678,7 @@ fn read_ni(parser: &Parser, fd: RawFd, io: &IoChain) -> i32 { | |
> if fd != STDIN_FILENO && (buf.st_mode & S_IFDIR) != 0 { | |
> FLOG!( | |
> error, | |
> - wgettext_fmt!("Unable to read input file: %s", Errno(EISDIR).to_string()) | |
> + wgettext_fmt!("Unable to read input file: %s", Errno::EISDIR.desc()) | |
> ); | |
> return 1; | |
> } | |
> @@ -693,17 +695,19 @@ fn read_ni(parser: &Parser, fd: RawFd, io: &IoChain) -> i32 { | |
> break; | |
> } else { | |
> assert!(amt == -1); | |
> - let err = errno(); | |
> - if err.0 == EINTR { | |
> + let err = Errno::last(); | |
> + if err == Errno::EINTR { | |
> continue; | |
> - } else if err.0 == EAGAIN || err.0 == EWOULDBLOCK && make_fd_blocking(fd).is_ok() { | |
> + } else if err == Errno::EAGAIN | |
> + || err == Errno::EWOULDBLOCK && make_fd_blocking(fd).is_ok() | |
> + { | |
> // We succeeded in making the fd blocking, keep going. | |
> continue; | |
> } else { | |
> // Fatal error. | |
> FLOG!( | |
> error, | |
> - wgettext_fmt!("Unable to read input file: %s", err.to_string()) | |
> + wgettext_fmt!("Unable to read input file: %s", err.desc()) | |
> ); | |
> return 1; | |
> } | |
> @@ -784,7 +788,7 @@ pub fn restore_term_mode() { | |
> TCSANOW, | |
> &*TERMINAL_MODE_ON_STARTUP.lock().unwrap(), | |
> ) == -1 | |
> - } && errno().0 == EIO | |
> + } && Errno::last() == Errno::EIO | |
> { | |
> redirect_tty_output(); | |
> } | |
> @@ -1690,21 +1694,23 @@ impl ReaderData { | |
> | |
> // Get the current terminal modes. These will be restored when the function returns. | |
> let mut old_modes: libc::termios = unsafe { std::mem::zeroed() }; | |
> - if unsafe { libc::tcgetattr(zelf.conf.inputfd, &mut old_modes) } == -1 && errno().0 == EIO { | |
> + if unsafe { libc::tcgetattr(zelf.conf.inputfd, &mut old_modes) } == -1 | |
> + && Errno::last() == Errno::EIO | |
> + { | |
> redirect_tty_output(); | |
> } | |
> | |
> // Set the new modes. | |
> if unsafe { libc::tcsetattr(zelf.conf.inputfd, TCSANOW, shell_modes()) } == -1 { | |
> - let err = errno().0; | |
> - if err == EIO { | |
> + let err = Errno::last(); | |
> + if err == Errno::EIO { | |
> redirect_tty_output(); | |
> } | |
> | |
> // This check is required to work around certain issues with fish's approach to | |
> // terminal control when launching interactive processes while in non-interactive | |
> // mode. See #4178 for one such example. | |
> - if err != ENOTTY || is_interactive_session() { | |
> + if err != Errno::ENOTTY || is_interactive_session() { | |
> perror("tcsetattr"); | |
> } | |
> } | |
> @@ -1897,7 +1903,7 @@ impl ReaderData { | |
> if unsafe { libc::tcsetattr(zelf.conf.inputfd, TCSANOW, &old_modes) } == -1 | |
> && is_interactive_session() | |
> { | |
> - if errno().0 == EIO { | |
> + if Errno::last() == Errno::EIO { | |
> redirect_tty_output(); | |
> } | |
> perror("tcsetattr"); // return to previous mode | |
> @@ -1927,7 +1933,7 @@ impl ReaderData { | |
> let mut res; | |
> loop { | |
> res = unsafe { libc::tcsetattr(STDIN_FILENO, TCSANOW, shell_modes_mut()) }; | |
> - if res >= 0 || errno().0 != EINTR { | |
> + if res >= 0 || Errno::last() != Errno::EINTR { | |
> break; | |
> } | |
> } | |
> @@ -3298,10 +3304,10 @@ fn term_donate(quiet: bool /* = false */) { | |
> ) | |
> } == -1 | |
> { | |
> - if errno().0 == EIO { | |
> + if Errno::last() == Errno::EIO { | |
> redirect_tty_output(); | |
> } | |
> - if errno().0 != EINTR { | |
> + if Errno::last() != Errno::EINTR { | |
> if !quiet { | |
> FLOG!( | |
> warning, | |
> @@ -3338,10 +3344,10 @@ pub fn term_copy_modes() { | |
> fn term_steal() { | |
> term_copy_modes(); | |
> while unsafe { libc::tcsetattr(STDIN_FILENO, TCSANOW, shell_modes()) } == -1 { | |
> - if errno().0 == EIO { | |
> + if Errno::last() == Errno::EIO { | |
> redirect_tty_output(); | |
> } | |
> - if errno().0 != EINTR { | |
> + if Errno::last() != Errno::EINTR { | |
> FLOG!(warning, wgettext!("Could not set terminal mode for shell")); | |
> perror("tcsetattr"); | |
> break; | |
> @@ -3403,7 +3409,7 @@ fn acquire_tty_or_exit(shell_pgid: libc::pid_t) { | |
> // avoid a second pass through this loop. | |
> owner = unsafe { libc::tcgetpgrp(STDIN_FILENO) }; | |
> } | |
> - if owner == -1 && errno().0 == ENOTTY { | |
> + if owner == -1 && Errno::last() == Errno::ENOTTY { | |
> if !is_interactive_session() { | |
> // It's OK if we're not able to take control of the terminal. We handle | |
> // the fallout from this in a few other places. | |
> @@ -3463,7 +3469,7 @@ fn reader_interactive_init(parser: &Parser) { | |
> // don't apply as we passed our own pid. | |
> // | |
> // This should be harmless, so we ignore it. | |
> - if errno().0 != EPERM { | |
> + if Errno::last() != Errno::EPERM { | |
> FLOG!( | |
> error, | |
> wgettext!("Failed to assign shell to its own process group") | |
> @@ -3475,7 +3481,7 @@ fn reader_interactive_init(parser: &Parser) { | |
> | |
> // Take control of the terminal | |
> if unsafe { libc::tcsetpgrp(STDIN_FILENO, shell_pgid) } == -1 { | |
> - if errno().0 == ENOTTY { | |
> + if Errno::last() == Errno::ENOTTY { | |
> redirect_tty_output(); | |
> } | |
> FLOG!(error, wgettext!("Failed to take control of the terminal")); | |
> @@ -3485,7 +3491,7 @@ fn reader_interactive_init(parser: &Parser) { | |
> | |
> // Configure terminal attributes | |
> if unsafe { libc::tcsetattr(STDIN_FILENO, TCSANOW, shell_modes_mut()) } == -1 { | |
> - if errno().0 == EIO { | |
> + if Errno::last() == Errno::EIO { | |
> redirect_tty_output(); | |
> } | |
> FLOG!(warning, wgettext!("Failed to set startup terminal mode!")); | |
> @@ -4541,7 +4547,10 @@ fn check_for_orphaned_process(loop_count: usize, shell_pgid: libc::pid_t) -> boo | |
> // Try kill-0'ing the process whose pid corresponds to our process group ID. It's possible this | |
> // will fail because we don't have permission to signal it. But more likely it will fail because | |
> // it no longer exists, and we are orphaned. | |
> - if loop_count % 64 == 0 && unsafe { libc::kill(shell_pgid, 0) } < 0 && errno().0 == ESRCH { | |
> + if loop_count % 64 == 0 | |
> + && unsafe { libc::kill(shell_pgid, 0) } < 0 | |
> + && Errno::last() == Errno::ESRCH | |
> + { | |
> we_think_we_are_orphaned = true; | |
> } | |
> | |
> @@ -4572,7 +4581,7 @@ fn check_for_orphaned_process(loop_count: usize, shell_pgid: libc::pid_t) -> boo | |
> 1, | |
> ) | |
> } < 0 | |
> - && errno().0 == EIO | |
> + && Errno::last() == Errno::EIO | |
> { | |
> we_think_we_are_orphaned = true; | |
> } | |
> diff --git a/fish-rust/src/signal.rs b/fish-rust/src/signal.rs | |
> index 60a0ef45c35f..f827cba9d710 100644 | |
> --- a/fish-rust/src/signal.rs | |
> +++ b/fish-rust/src/signal.rs | |
> @@ -4,13 +4,14 @@ use crate::common::{exit_without_destructors, restore_term_foreground_process_gr | |
> use crate::event::{enqueue_signal, is_signal_observed}; | |
> use crate::nix::getpid; | |
> use crate::reader::{reader_handle_sigint, reader_sighup}; | |
> +use crate::set_errno; | |
> use crate::termsize::TermsizeContainer; | |
> use crate::topic_monitor::{generation_t, topic_monitor_principal, topic_t, GenerationsList}; | |
> use crate::wchar::prelude::*; | |
> use crate::wchar_ffi::{AsWstr, WCharToFFI}; | |
> use crate::wutil::{fish_wcstoi, perror}; | |
> use cxx::{CxxWString, UniquePtr}; | |
> -use errno::{errno, set_errno}; | |
> +use nix::errno::Errno; | |
> use std::sync::atomic::{AtomicI32, Ordering}; | |
> | |
> #[cxx::bridge] | |
> @@ -115,7 +116,7 @@ extern "C" fn fish_signal_handler( | |
> _context: *mut libc::c_void, | |
> ) { | |
> // Ensure we preserve errno. | |
> - let saved_errno = errno(); | |
> + let saved_errno = Errno::last(); | |
> | |
> // Check if we are a forked child. | |
> if reraise_if_forked_child(sig) { | |
> diff --git a/fish-rust/src/threads.rs b/fish-rust/src/threads.rs | |
> index fd99ca5cdb0d..619c0f29025a 100644 | |
> --- a/fish-rust/src/threads.rs | |
> +++ b/fish-rust/src/threads.rs | |
> @@ -3,6 +3,7 @@ | |
> | |
> use crate::flog::{FloggableDebug, FLOG}; | |
> use crate::reader::ReaderData; | |
> +use nix::errno::Errno; | |
> use once_cell::race::OnceBox; | |
> use std::num::NonZeroU64; | |
> use std::sync::atomic::{AtomicBool, Ordering}; | |
> @@ -140,7 +141,7 @@ pub fn init() { | |
> } | |
> unsafe { | |
> let result = libc::pthread_atfork(None, None, Some(child_post_fork)); | |
> - assert_eq!(result, 0, "pthread_atfork() failure: {}", errno::errno()); | |
> + assert_eq!(result, 0, "pthread_atfork() failure: {}", Errno::last()); | |
> } | |
> | |
> IO_THREAD_POOL | |
> diff --git a/fish-rust/src/wutil/dir_iter.rs b/fish-rust/src/wutil/dir_iter.rs | |
> index 8fdbc940b755..b0284d359f1b 100644 | |
> --- a/fish-rust/src/wutil/dir_iter.rs | |
> +++ b/fish-rust/src/wutil/dir_iter.rs | |
> @@ -2,10 +2,10 @@ use super::wopendir; | |
> use crate::common::{cstr2wcstring, wcs2zstring}; | |
> use crate::wchar::{wstr, WString}; | |
> use libc::{ | |
> - DT_BLK, DT_CHR, DT_DIR, DT_FIFO, DT_LNK, DT_REG, DT_SOCK, EACCES, EIO, ELOOP, ENAMETOOLONG, | |
> - ENODEV, ENOENT, ENOTDIR, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFREG, | |
> - S_IFSOCK, | |
> + DT_BLK, DT_CHR, DT_DIR, DT_FIFO, DT_LNK, DT_REG, DT_SOCK, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, | |
> + S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK, | |
> }; | |
> +use nix::errno::Errno; | |
> use std::cell::Cell; | |
> use std::io::{self}; | |
> use std::os::fd::RawFd; | |
> @@ -107,7 +107,8 @@ impl DirEntry { | |
> self.stat.set(Some(s)); | |
> self.typ.set(stat_mode_to_entry_type(s.st_mode)); | |
> } else { | |
> - match errno::errno().0 { | |
> + use Errno::*; | |
> + match Errno::last() { | |
> ELOOP => { | |
> self.typ.set(Some(DirEntryType::lnk)); | |
> } | |
> @@ -245,15 +246,15 @@ impl DirIter { | |
> /// This returns an error if readir errors, or Ok(None) if there are no more entries; else an Ok entry. | |
> /// This is slightly more efficient than the Iterator version, as it avoids allocating. | |
> pub fn next(&mut self) -> Option<io::Result<&DirEntry>> { | |
> - errno::set_errno(errno::Errno(0)); | |
> + Errno::clear(); | |
> let dent = unsafe { libc::readdir(self.dir.dir()).as_ref() }; | |
> let Some(dent) = dent else { | |
> // readdir distinguishes between EOF and error via errno. | |
> - let err = errno::errno().0; | |
> - if err == 0 { | |
> + let err = Errno::last(); | |
> + if err == Errno::from_i32(0) { | |
> return None; | |
> } else { | |
> - return Some(Err(io::Error::from_raw_os_error(err))); | |
> + return Some(Err(io::Error::from(err))); | |
> } | |
> }; | |
> | |
> @@ -373,8 +374,8 @@ fn test_dir_iter() { | |
> let Err(err) = baditer else { | |
> panic!("Expected error"); | |
> }; | |
> - let err = err.raw_os_error().expect("Should have an errno value"); | |
> - assert!(err == ENOENT || err == EACCES); | |
> + let err = Errno::try_from(err).expect("Should have an errno value"); | |
> + assert!(err == Errno::ENOENT || err == Errno::EACCES); | |
> | |
> let mut t1: [u8; 31] = *b"/tmp/fish_test_dir_iter.XXXXXX\0"; | |
> let basepath_narrow = unsafe { libc::mkdtemp(t1.as_mut_ptr().cast()) }; | |
> diff --git a/fish-rust/src/wutil/mod.rs b/fish-rust/src/wutil/mod.rs | |
> index dfc03b62ffa8..425c93d88c29 100644 | |
> --- a/fish-rust/src/wutil/mod.rs | |
> +++ b/fish-rust/src/wutil/mod.rs | |
> @@ -19,8 +19,8 @@ use crate::flog::FLOGF; | |
> use crate::wchar::{wstr, WString, L}; | |
> use crate::wchar_ext::WExt; | |
> use crate::wcstringutil::{join_strings, split_string, wcs2string_callback}; | |
> -use errno::errno; | |
> pub(crate) use gettext::{wgettext, wgettext_fmt, wgettext_maybe_fmt, wgettext_str}; | |
> +use nix::errno::Errno; | |
> pub(crate) use printf::sprintf; | |
> use std::ffi::{CStr, OsStr}; | |
> use std::fs::{self, canonicalize}; | |
> @@ -68,13 +68,13 @@ pub fn wperror(s: &wstr) { | |
> | |
> /// Port of the wide-string wperror from `src/wutil.cpp` but for rust `&str`. | |
> pub fn perror(s: &str) { | |
> - let e = errno().0; | |
> + let e = Errno::last(); | |
The weird thing about `nix::errno::Errno` is that they treat "unknown error" the same as "no error". | |
This could cause subtle issues if the OS ever returns an error that hasn't been added to `nix` yet. | |
Unless they have a way of guaranteeing consistency with the host libc? | |
--- | |
I'm not sure `enum` is the right type for `Errno`. | |
It's already marked `#[non_exhaustive]` so client code can't do exhaustive matching. | |
I guess they could make it: | |
``` | |
enum Errno { | |
NoError = 0 | |
EPERM = libc::EPERM, | |
... | |
UnknownErrno(i32), | |
} | |
``` | |
but at that point it's probably better to use a struct that wraps `libc::c_int` (or `i32`?), similar to `std::io::Error`. | |
--- | |
I guess we could use the `nix::errno::Errno::last_raw()` (which is `nix::errno::errno()` today) and `nix::errno::Errno::set_raw()` precisely in the cases where we don't want to ignore unknown errors. | |
But the problem of being easy to misuse remains. | |
> let mut stderr = std::io::stderr().lock(); | |
> if !s.is_empty() { | |
> let _ = write!(stderr, "{s}: "); | |
> } | |
> let slice = unsafe { | |
> - let msg = libc::strerror(e) as *const u8; | |
> + let msg = libc::strerror(e as i32) as *const u8; | |
> let len = libc::strlen(msg as *const _); | |
> std::slice::from_raw_parts(msg, len) | |
> }; | |
> @@ -102,8 +102,8 @@ pub fn wgetcwd() -> WString { | |
> FLOGF!( | |
> error, | |
> "getcwd() failed with errno %d/%s", | |
> - errno::errno().0, | |
> - errno::errno().to_string() | |
> + Errno::last() as i32, | |
> + Errno::last().desc() | |
> ); | |
> WString::new() | |
> } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment