Always heightenize file descriptors

Fixes #12618

Closes #12681
This commit is contained in:
Nahor
2026-04-25 18:12:25 -07:00
committed by Johannes Altmanninger
parent 6701b7f6c8
commit 27fb4d6731
7 changed files with 76 additions and 26 deletions

View File

@@ -32,6 +32,7 @@
},
eprintf, err_fmt,
event::{self, Event},
fds::heightenize_fd,
flog::{self, activate_flog_categories_by_pattern, flog, flogf, set_flog_file_fd},
fprintf, function,
history::{self, start_private_mode},
@@ -564,11 +565,11 @@ fn throwing_main() -> i32 {
}
res = reader_read(parser, libc::STDIN_FILENO, &IoChain::new());
} else {
let n = wcs2bytes(&args[my_optind]);
let filename = &args[my_optind];
let n = wcs2bytes(filename);
let path = OsStr::from_bytes(&n);
my_optind += 1;
// Rust sets cloexec by default, see above
// We don't need autoclose_fd_t when we use File, it will be closed on drop.
match File::open(path) {
Err(e) => {
flogf!(
@@ -579,24 +580,25 @@ fn throwing_main() -> i32 {
eprintf!("%s\n", e);
}
Ok(f) => {
let list = &args[my_optind..];
parser.set_var(
L!("argv"),
ParserEnvSetMode::default(),
list.iter().map(|s| s.to_owned()).collect(),
);
let rel_filename = &args[my_optind - 1];
let _filename_push = parser
.library_data
.scoped_set(Some(Arc::new(rel_filename.to_owned())), |s| {
&mut s.current_filename
});
res = reader_read(parser, f.as_raw_fd(), &IoChain::new());
if res.is_err() {
flog!(
warning,
wgettext_fmt!("Error while reading file %s", path.to_string_lossy())
if let Ok(f) = heightenize_fd(f.into(), true).map(File::from) {
let list = &args[my_optind..];
parser.set_var(
L!("argv"),
ParserEnvSetMode::default(),
list.iter().map(|s| s.to_owned()).collect(),
);
let _filename_push = parser
.library_data
.scoped_set(Some(Arc::new(filename.to_owned())), |s| {
&mut s.current_filename
});
res = reader_read(parser, f.as_raw_fd(), &IoChain::new());
if res.is_err() {
flog!(
warning,
wgettext_fmt!("Error while reading file %s", path.to_string_lossy())
);
}
}
}
}

View File

@@ -1,4 +1,5 @@
use crate::fd_readable_set::{FdReadableSet, Timeout};
use crate::fds::heightenize_fd;
use crate::flog::flog;
use crate::portable_atomic::AtomicU64;
use crate::threads::assert_is_background_thread;
@@ -49,8 +50,12 @@ pub fn new() -> Self {
perror("eventfd");
exit_without_destructors(1);
}
let Ok(fd) = heightenize_fd(unsafe { OwnedFd::from_raw_fd(fd) }, true) else {
perror("eventfd");
exit_without_destructors(1);
};
Self {
fd: unsafe { OwnedFd::from_raw_fd(fd) },
fd
}
} else {
// Implementation using pipes.

View File

@@ -86,7 +86,7 @@ pub fn make_autoclose_pipes() -> nix::Result<AutoClosePipes> {
/// setting it again.
/// Return the fd, which always has CLOEXEC set; or an invalid fd on failure, in
/// which case an error will have been printed, and the input fd closed.
fn heightenize_fd(fd: OwnedFd, input_has_cloexec: bool) -> nix::Result<OwnedFd> {
pub fn heightenize_fd(fd: OwnedFd, input_has_cloexec: bool) -> nix::Result<OwnedFd> {
let raw_fd = fd.as_raw_fd();
if raw_fd >= FIRST_HIGH_FD {
@@ -145,7 +145,7 @@ pub fn open_cloexec(path: &CStr, flags: OFlag, mode: nix::sys::stat::Mode) -> ni
// If it is that's our cancel signal, so we abort.
loop {
let ret = nix::fcntl::open(path, flags | OFlag::O_CLOEXEC, mode);
let ret = ret.map(File::from);
let ret = ret.and_then(|fd| heightenize_fd(fd, true)).map(File::from);
match ret {
Ok(file) => {
return Ok(file);

View File

@@ -1,11 +1,12 @@
use crate::env_universal_common::default_vars_path;
use crate::fds::heightenize_fd;
use crate::prelude::*;
use crate::universal_notifier::UniversalNotifier;
use crate::wutil::{wbasename, wdirname};
use fish_widestring::wcs2osstring;
use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify};
use std::ffi::OsString;
use std::os::fd::{AsFd as _, AsRawFd as _, RawFd};
use std::os::fd::{AsFd as _, AsRawFd as _, OwnedFd, RawFd};
/// A notifier based on inotify.
pub struct InotifyNotifier {
@@ -30,6 +31,9 @@ pub fn new_at(path: &wstr) -> Option<Self> {
let dirname = wdirname(path);
let basename = wbasename(path);
let inotify = Inotify::init(InitFlags::IN_CLOEXEC | InitFlags::IN_NONBLOCK).ok()?;
let inotify = heightenize_fd(OwnedFd::from(inotify), true).ok()?;
// SAFETY: We pass a valid inotify fd.
let inotify = unsafe { Inotify::from_owned_fd(inotify) };
inotify
.add_watch(
wcs2osstring(dirname).as_os_str(),

View File

@@ -1,4 +1,5 @@
use crate::env_universal_common::default_vars_path;
use crate::fds::heightenize_fd;
use crate::flogf;
use crate::prelude::*;
use crate::universal_notifier::UniversalNotifier;
@@ -6,7 +7,7 @@
use fish_widestring::wcs2osstring;
use nix::sys::event::{EvFlags, EventFilter, FilterFlag, KEvent, Kqueue};
use std::fs::File;
use std::os::fd::AsFd;
use std::os::fd::{AsFd, OwnedFd};
use std::os::unix::fs::MetadataExt;
use std::os::unix::io::{AsRawFd, RawFd};
use std::path::PathBuf;
@@ -48,6 +49,7 @@ pub fn new_at(path: &wstr) -> Option<Self> {
// Open the directory to get a valid file descriptor or bail if it doesn't exist
let dir_fd = File::open(dir.as_os_str()).ok()?;
let dir_fd = File::from(heightenize_fd(OwnedFd::from(dir_fd), true).ok()?);
// Add a watch for EVFILT_VNODE events
let change_event = KEvent::new(