From 00a618447c850061664690199acaabd45f434b73 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Wed, 15 May 2024 19:53:17 -0700 Subject: [PATCH 1/5] use rustix instead of libc --- Cargo.toml | 9 ++- src/terminal/sys/file_descriptor.rs | 65 ++++++++++++++++++++- src/terminal/sys/unix.rs | 91 ++++++++++++++++++++++++++--- src/tty.rs | 10 +++- 4 files changed, 161 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2c53c14be..a6d44966c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ all-features = true # Features # [features] -default = ["bracketed-paste", "windows", "events"] +default = ["bracketed-paste", "windows", "events", "libc"] windows = [ "dep:winapi", "dep:crossterm_winapi", @@ -71,7 +71,12 @@ crossterm_winapi = { version = "0.9.1", optional = true } # UNIX dependencies # [target.'cfg(unix)'.dependencies] -libc = "0.2" +libc = { version = "0.2", default-features = false, optional = true } +rustix = { version = "0.38.34", default-features = false, features = [ + "std", + "stdio", + "termios", +], optional = true } signal-hook = { version = "0.3.17", optional = true } filedescriptor = { version = "0.8", optional = true } mio = { version = "0.8", features = ["os-poll"], optional = true } diff --git a/src/terminal/sys/file_descriptor.rs b/src/terminal/sys/file_descriptor.rs index 81c3fb2e3..3f41c682f 100644 --- a/src/terminal/sys/file_descriptor.rs +++ b/src/terminal/sys/file_descriptor.rs @@ -1,23 +1,36 @@ +use std::io; + +#[cfg(feature = "libc")] +use libc::size_t; +#[cfg(feature = "rustix")] +use rustix::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd}; +#[cfg(feature = "libc")] use std::{ - fs, io, + fs, os::unix::{ io::{IntoRawFd, RawFd}, prelude::AsRawFd, }, }; -use libc::size_t; - /// A file descriptor wrapper. /// /// It allows to retrieve raw file descriptor, write to the file descriptor and /// mainly it closes the file descriptor once dropped. #[derive(Debug)] +#[cfg(feature = "libc")] pub struct FileDesc { fd: RawFd, close_on_drop: bool, } +#[cfg(feature = "rustix")] +pub enum FileDesc { + Owned(OwnedFd), + Static(BorrowedFd<'static>), +} + +#[cfg(feature = "libc")] impl FileDesc { /// Constructs a new `FileDesc` with the given `RawFd`. /// @@ -51,6 +64,26 @@ impl FileDesc { } } +#[cfg(feature = "rustix")] +impl FileDesc { + pub fn read(&self, buffer: &mut [u8]) -> io::Result { + let fd = match self { + FileDesc::Owned(fd) => fd.as_fd(), + FileDesc::Static(fd) => fd.as_fd(), + }; + let result = rustix::io::read(fd, buffer)?; + Ok(result) + } + + pub fn raw_fd(&self) -> RawFd { + match self { + FileDesc::Owned(fd) => fd.as_raw_fd(), + FileDesc::Static(fd) => fd.as_raw_fd(), + } + } +} + +#[cfg(feature = "libc")] impl Drop for FileDesc { fn drop(&mut self) { if self.close_on_drop { @@ -70,6 +103,17 @@ impl AsRawFd for FileDesc { } } +#[cfg(feature = "rustix")] +impl AsFd for FileDesc { + fn as_fd(&self) -> BorrowedFd<'_> { + match self { + FileDesc::Owned(fd) => fd.as_fd(), + FileDesc::Static(fd) => fd.as_fd(), + } + } +} + +#[cfg(feature = "libc")] /// Creates a file descriptor pointing to the standard input or `/dev/tty`. pub fn tty_fd() -> io::Result { let (fd, close_on_drop) = if unsafe { libc::isatty(libc::STDIN_FILENO) == 1 } { @@ -87,3 +131,18 @@ pub fn tty_fd() -> io::Result { Ok(FileDesc::new(fd, close_on_drop)) } + +#[cfg(feature = "rustix")] +/// Creates a file descriptor pointing to the standard input or `/dev/tty`. +pub fn tty_fd() -> io::Result { + use std::fs::File; + + let stdin = rustix::stdio::stdin(); + let fd = if rustix::termios::isatty(stdin) { + FileDesc::Static(stdin) + } else { + let dev_tty = File::options().read(true).write(true).open("/dev/tty")?; + FileDesc::Owned(dev_tty.into()) + }; + Ok(fd) +} diff --git a/src/terminal/sys/unix.rs b/src/terminal/sys/unix.rs index ed545c5b2..ea0cb0d06 100644 --- a/src/terminal/sys/unix.rs +++ b/src/terminal/sys/unix.rs @@ -4,16 +4,24 @@ use crate::terminal::{ sys::file_descriptor::{tty_fd, FileDesc}, WindowSize, }; +#[cfg(feature = "libc")] use libc::{ cfmakeraw, ioctl, tcgetattr, tcsetattr, termios as Termios, winsize, STDOUT_FILENO, TCSANOW, TIOCGWINSZ, }; use parking_lot::Mutex; -use std::fs::File; - -use std::os::unix::io::{IntoRawFd, RawFd}; +#[cfg(feature = "rustix")] +use rustix::{ + fd::AsFd, + termios::{Termios, Winsize}, +}; -use std::{io, mem, process}; +use std::{fs::File, io, process}; +#[cfg(feature = "libc")] +use std::{ + mem, + os::unix::io::{IntoRawFd, RawFd}, +}; // Some(Termios) -> we're in the raw mode and this is the previous mode // None -> we're not in the raw mode @@ -23,6 +31,7 @@ pub(crate) fn is_raw_mode_enabled() -> bool { TERMINAL_MODE_PRIOR_RAW_MODE.lock().is_some() } +#[cfg(feature = "libc")] impl From for WindowSize { fn from(size: winsize) -> WindowSize { WindowSize { @@ -33,8 +42,20 @@ impl From for WindowSize { } } } +#[cfg(feature = "rustix")] +impl From for WindowSize { + fn from(size: Winsize) -> WindowSize { + WindowSize { + columns: size.ws_col, + rows: size.ws_row, + width: size.ws_xpixel, + height: size.ws_ypixel, + } + } +} #[allow(clippy::useless_conversion)] +#[cfg(feature = "libc")] pub(crate) fn window_size() -> io::Result { // http://rosettacode.org/wiki/Terminal_control/Dimensions#Library:_BSD_libc let mut size = winsize { @@ -59,6 +80,19 @@ pub(crate) fn window_size() -> io::Result { Err(std::io::Error::last_os_error().into()) } +#[cfg(feature = "rustix")] +pub(crate) fn window_size() -> io::Result { + let file = File::open("/dev/tty").map(|file| (FileDesc::Owned(file.into()))); + let fd = if let Ok(file) = &file { + file.as_fd() + } else { + // Fallback to libc::STDOUT_FILENO if /dev/tty is missing + rustix::stdio::stdout() + }; + let size = rustix::termios::tcgetwinsize(fd)?; + Ok(size.into()) +} + #[allow(clippy::useless_conversion)] pub(crate) fn size() -> io::Result<(u16, u16)> { if let Ok(window_size) = window_size() { @@ -68,9 +102,9 @@ pub(crate) fn size() -> io::Result<(u16, u16)> { tput_size().ok_or_else(|| std::io::Error::last_os_error().into()) } +#[cfg(feature = "libc")] pub(crate) fn enable_raw_mode() -> io::Result<()> { let mut original_mode = TERMINAL_MODE_PRIOR_RAW_MODE.lock(); - if original_mode.is_some() { return Ok(()); } @@ -79,13 +113,27 @@ pub(crate) fn enable_raw_mode() -> io::Result<()> { let fd = tty.raw_fd(); let mut ios = get_terminal_attr(fd)?; let original_mode_ios = ios; - raw_terminal_attr(&mut ios); set_terminal_attr(fd, &ios)?; - // Keep it last - set the original mode only if we were able to switch to the raw mode *original_mode = Some(original_mode_ios); + Ok(()) +} +#[cfg(feature = "rustix")] +pub(crate) fn enable_raw_mode() -> io::Result<()> { + let mut original_mode = TERMINAL_MODE_PRIOR_RAW_MODE.lock(); + if original_mode.is_some() { + return Ok(()); + } + + let tty = tty_fd()?; + let mut ios = get_terminal_attr(&tty)?; + let original_mode_ios = ios.clone(); + ios.make_raw(); + set_terminal_attr(&tty, &ios)?; + // Keep it last - set the original mode only if we were able to switch to the raw mode + *original_mode = Some(original_mode_ios); Ok(()) } @@ -94,16 +142,39 @@ pub(crate) fn enable_raw_mode() -> io::Result<()> { /// More precisely, reset the whole termios mode to what it was before the first call /// to [enable_raw_mode]. If you don't mess with termios outside of crossterm, it's /// effectively disabling the raw mode and doing nothing else. +#[cfg(feature = "libc")] pub(crate) fn disable_raw_mode() -> io::Result<()> { let mut original_mode = TERMINAL_MODE_PRIOR_RAW_MODE.lock(); - if let Some(original_mode_ios) = original_mode.as_ref() { let tty = tty_fd()?; set_terminal_attr(tty.raw_fd(), original_mode_ios)?; // Keep it last - remove the original mode only if we were able to switch back *original_mode = None; } + Ok(()) +} + +#[cfg(feature = "rustix")] +pub(crate) fn disable_raw_mode() -> io::Result<()> { + let mut original_mode = TERMINAL_MODE_PRIOR_RAW_MODE.lock(); + if let Some(original_mode_ios) = original_mode.as_ref() { + let tty = tty_fd()?; + set_terminal_attr(&tty, original_mode_ios)?; + // Keep it last - remove the original mode only if we were able to switch back + *original_mode = None; + } + Ok(()) +} + +#[cfg(feature = "rustix")] +fn get_terminal_attr(fd: impl AsFd) -> io::Result { + let result = rustix::termios::tcgetattr(fd)?; + Ok(result) +} +#[cfg(feature = "rustix")] +fn set_terminal_attr(fd: impl AsFd, termios: &Termios) -> io::Result<()> { + rustix::termios::tcsetattr(fd, rustix::termios::OptionalActions::Now, termios)?; Ok(()) } @@ -214,11 +285,13 @@ fn tput_size() -> Option<(u16, u16)> { } } +#[cfg(feature = "libc")] // Transform the given mode into an raw mode (non-canonical) mode. fn raw_terminal_attr(termios: &mut Termios) { unsafe { cfmakeraw(termios) } } +#[cfg(feature = "libc")] fn get_terminal_attr(fd: RawFd) -> io::Result { unsafe { let mut termios = mem::zeroed(); @@ -227,10 +300,12 @@ fn get_terminal_attr(fd: RawFd) -> io::Result { } } +#[cfg(feature = "libc")] fn set_terminal_attr(fd: RawFd, termios: &Termios) -> io::Result<()> { wrap_with_result(unsafe { tcsetattr(fd, TCSANOW, termios) }) } +#[cfg(feature = "libc")] fn wrap_with_result(result: i32) -> io::Result<()> { if result == -1 { Err(io::Error::last_os_error()) diff --git a/src/tty.rs b/src/tty.rs index 78e32aae7..12c86d61b 100644 --- a/src/tty.rs +++ b/src/tty.rs @@ -26,7 +26,7 @@ pub trait IsTty { /// On UNIX, the `isatty()` function returns true if a file /// descriptor is a terminal. -#[cfg(unix)] +#[cfg(all(unix, feature = "libc"))] impl IsTty for S { fn is_tty(&self) -> bool { let fd = self.as_raw_fd(); @@ -34,6 +34,14 @@ impl IsTty for S { } } +#[cfg(all(unix, feature = "rustix"))] +impl IsTty for S { + fn is_tty(&self) -> bool { + let fd = self.as_raw_fd(); + rustix::termios::isatty(unsafe { std::os::unix::io::BorrowedFd::borrow_raw(fd) }) + } +} + /// On windows, `GetConsoleMode` will return true if we are in a terminal. /// Otherwise false. #[cfg(windows)] From 4b6a4ef9e53ab3caea9d3b197ba0c643fe4afd26 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Wed, 15 May 2024 19:59:15 -0700 Subject: [PATCH 2/5] make rustix the default feature --- Cargo.toml | 6 ++++-- src/terminal/sys/file_descriptor.rs | 10 +++++----- src/terminal/sys/unix.rs | 14 +++++++------- src/tty.rs | 2 +- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a6d44966c..fe4b35e89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ all-features = true # Features # [features] -default = ["bracketed-paste", "windows", "events", "libc"] +default = ["bracketed-paste", "windows", "events"] windows = [ "dep:winapi", "dep:crossterm_winapi", @@ -71,12 +71,14 @@ crossterm_winapi = { version = "0.9.1", optional = true } # UNIX dependencies # [target.'cfg(unix)'.dependencies] +# Default to using rustix for UNIX systems, but provide an option to use libc for backwards +# compatibility. libc = { version = "0.2", default-features = false, optional = true } rustix = { version = "0.38.34", default-features = false, features = [ "std", "stdio", "termios", -], optional = true } +] } signal-hook = { version = "0.3.17", optional = true } filedescriptor = { version = "0.8", optional = true } mio = { version = "0.8", features = ["os-poll"], optional = true } diff --git a/src/terminal/sys/file_descriptor.rs b/src/terminal/sys/file_descriptor.rs index 3f41c682f..3212c4849 100644 --- a/src/terminal/sys/file_descriptor.rs +++ b/src/terminal/sys/file_descriptor.rs @@ -2,7 +2,7 @@ use std::io; #[cfg(feature = "libc")] use libc::size_t; -#[cfg(feature = "rustix")] +#[cfg(not(feature = "libc"))] use rustix::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd}; #[cfg(feature = "libc")] use std::{ @@ -24,7 +24,7 @@ pub struct FileDesc { close_on_drop: bool, } -#[cfg(feature = "rustix")] +#[cfg(not(feature = "libc"))] pub enum FileDesc { Owned(OwnedFd), Static(BorrowedFd<'static>), @@ -64,7 +64,7 @@ impl FileDesc { } } -#[cfg(feature = "rustix")] +#[cfg(not(feature = "libc"))] impl FileDesc { pub fn read(&self, buffer: &mut [u8]) -> io::Result { let fd = match self { @@ -103,7 +103,7 @@ impl AsRawFd for FileDesc { } } -#[cfg(feature = "rustix")] +#[cfg(not(feature = "libc"))] impl AsFd for FileDesc { fn as_fd(&self) -> BorrowedFd<'_> { match self { @@ -132,7 +132,7 @@ pub fn tty_fd() -> io::Result { Ok(FileDesc::new(fd, close_on_drop)) } -#[cfg(feature = "rustix")] +#[cfg(not(feature = "libc"))] /// Creates a file descriptor pointing to the standard input or `/dev/tty`. pub fn tty_fd() -> io::Result { use std::fs::File; diff --git a/src/terminal/sys/unix.rs b/src/terminal/sys/unix.rs index ea0cb0d06..7129730a6 100644 --- a/src/terminal/sys/unix.rs +++ b/src/terminal/sys/unix.rs @@ -10,7 +10,7 @@ use libc::{ TIOCGWINSZ, }; use parking_lot::Mutex; -#[cfg(feature = "rustix")] +#[cfg(not(feature = "libc"))] use rustix::{ fd::AsFd, termios::{Termios, Winsize}, @@ -42,7 +42,7 @@ impl From for WindowSize { } } } -#[cfg(feature = "rustix")] +#[cfg(not(feature = "libc"))] impl From for WindowSize { fn from(size: Winsize) -> WindowSize { WindowSize { @@ -80,7 +80,7 @@ pub(crate) fn window_size() -> io::Result { Err(std::io::Error::last_os_error().into()) } -#[cfg(feature = "rustix")] +#[cfg(not(feature = "libc"))] pub(crate) fn window_size() -> io::Result { let file = File::open("/dev/tty").map(|file| (FileDesc::Owned(file.into()))); let fd = if let Ok(file) = &file { @@ -120,7 +120,7 @@ pub(crate) fn enable_raw_mode() -> io::Result<()> { Ok(()) } -#[cfg(feature = "rustix")] +#[cfg(not(feature = "libc"))] pub(crate) fn enable_raw_mode() -> io::Result<()> { let mut original_mode = TERMINAL_MODE_PRIOR_RAW_MODE.lock(); if original_mode.is_some() { @@ -154,7 +154,7 @@ pub(crate) fn disable_raw_mode() -> io::Result<()> { Ok(()) } -#[cfg(feature = "rustix")] +#[cfg(not(feature = "libc"))] pub(crate) fn disable_raw_mode() -> io::Result<()> { let mut original_mode = TERMINAL_MODE_PRIOR_RAW_MODE.lock(); if let Some(original_mode_ios) = original_mode.as_ref() { @@ -166,13 +166,13 @@ pub(crate) fn disable_raw_mode() -> io::Result<()> { Ok(()) } -#[cfg(feature = "rustix")] +#[cfg(not(feature = "libc"))] fn get_terminal_attr(fd: impl AsFd) -> io::Result { let result = rustix::termios::tcgetattr(fd)?; Ok(result) } -#[cfg(feature = "rustix")] +#[cfg(not(feature = "libc"))] fn set_terminal_attr(fd: impl AsFd, termios: &Termios) -> io::Result<()> { rustix::termios::tcsetattr(fd, rustix::termios::OptionalActions::Now, termios)?; Ok(()) diff --git a/src/tty.rs b/src/tty.rs index 12c86d61b..5a710b4ab 100644 --- a/src/tty.rs +++ b/src/tty.rs @@ -34,7 +34,7 @@ impl IsTty for S { } } -#[cfg(all(unix, feature = "rustix"))] +#[cfg(all(unix, not(feature = "libc")))] impl IsTty for S { fn is_tty(&self) -> bool { let fd = self.as_raw_fd(); From 8da9a7cfc04781181075f2e6ba4ba1d86333a220 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Wed, 15 May 2024 20:27:15 -0700 Subject: [PATCH 3/5] bump msrv to 1.63.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fe4b35e89..cee169750 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ keywords = ["event", "color", "cli", "input", "terminal"] exclude = ["target", "Cargo.lock"] readme = "README.md" edition = "2021" -rust-version = "1.58.0" +rust-version = "1.63.0" categories = ["command-line-interface", "command-line-utilities"] [lib] From 62a01637ef475a5b858469d8ef2d7d477523447a Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Thu, 16 May 2024 20:04:58 -0700 Subject: [PATCH 4/5] fix remaining libc issues - use rustix version of sigwinch signal - add a lifetime to FileDesc and replace FileDesc::Static to FileDesc::Borrowed. This made it necessary to either add a lifetime to the libc version of FileDesc or replace all the callers with multiple paths (libc, rustix). Changing FileDesc was more straightforward. There are no usages of FileDesc found in any repo on github, so this change should be reasonably safe. --- src/event/source/unix/mio.rs | 4 +-- src/event/source/unix/tty.rs | 14 +++++++++-- src/terminal/sys/file_descriptor.rs | 38 +++++++++++++++++------------ 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/event/source/unix/mio.rs b/src/event/source/unix/mio.rs index 8372a1ddb..0368e61b6 100644 --- a/src/event/source/unix/mio.rs +++ b/src/event/source/unix/mio.rs @@ -26,7 +26,7 @@ pub(crate) struct UnixInternalEventSource { events: Events, parser: Parser, tty_buffer: [u8; TTY_BUFFER_SIZE], - tty_fd: FileDesc, + tty_fd: FileDesc<'static>, signals: Signals, #[cfg(feature = "event-stream")] waker: Waker, @@ -37,7 +37,7 @@ impl UnixInternalEventSource { UnixInternalEventSource::from_file_descriptor(tty_fd()?) } - pub(crate) fn from_file_descriptor(input_fd: FileDesc) -> io::Result { + pub(crate) fn from_file_descriptor(input_fd: FileDesc<'static>) -> io::Result { let poll = Poll::new()?; let registry = poll.registry(); diff --git a/src/event/source/unix/tty.rs b/src/event/source/unix/tty.rs index b8cbfeffd..03d76b401 100644 --- a/src/event/source/unix/tty.rs +++ b/src/event/source/unix/tty.rs @@ -1,6 +1,10 @@ +#[cfg(feature = "libc")] use std::os::unix::prelude::AsRawFd; use std::{collections::VecDeque, io, os::unix::net::UnixStream, time::Duration}; +#[cfg(not(feature = "libc"))] +use rustix::fd::{AsFd, AsRawFd}; + use signal_hook::low_level::pipe; use crate::event::timeout::PollTimeout; @@ -38,7 +42,7 @@ const TTY_BUFFER_SIZE: usize = 1_024; pub(crate) struct UnixInternalEventSource { parser: Parser, tty_buffer: [u8; TTY_BUFFER_SIZE], - tty: FileDesc, + tty: FileDesc<'static>, winch_signal_receiver: UnixStream, #[cfg(feature = "event-stream")] wake_pipe: WakePipe, @@ -56,7 +60,7 @@ impl UnixInternalEventSource { UnixInternalEventSource::from_file_descriptor(tty_fd()?) } - pub(crate) fn from_file_descriptor(input_fd: FileDesc) -> io::Result { + pub(crate) fn from_file_descriptor(input_fd: FileDesc<'static>) -> io::Result { Ok(UnixInternalEventSource { parser: Parser::default(), tty_buffer: [0u8; TTY_BUFFER_SIZE], @@ -64,7 +68,10 @@ impl UnixInternalEventSource { winch_signal_receiver: { let (receiver, sender) = nonblocking_unix_pair()?; // Unregistering is unnecessary because EventSource is a singleton + #[cfg(feature = "libc")] pipe::register(libc::SIGWINCH, sender)?; + #[cfg(not(feature = "libc"))] + pipe::register(rustix::process::Signal::Winch as i32, sender)?; receiver }, #[cfg(feature = "event-stream")] @@ -157,7 +164,10 @@ impl EventSource for UnixInternalEventSource { } } if fds[1].revents & POLLIN != 0 { + #[cfg(feature = "libc")] let fd = FileDesc::new(self.winch_signal_receiver.as_raw_fd(), false); + #[cfg(not(feature = "libc"))] + let fd = FileDesc::Borrowed(self.winch_signal_receiver.as_fd()); // drain the pipe while read_complete(&fd, &mut [0; 1024])? != 0 {} // TODO Should we remove tput? diff --git a/src/terminal/sys/file_descriptor.rs b/src/terminal/sys/file_descriptor.rs index 3212c4849..baff266c6 100644 --- a/src/terminal/sys/file_descriptor.rs +++ b/src/terminal/sys/file_descriptor.rs @@ -7,6 +7,7 @@ use rustix::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd}; #[cfg(feature = "libc")] use std::{ fs, + marker::PhantomData, os::unix::{ io::{IntoRawFd, RawFd}, prelude::AsRawFd, @@ -19,27 +20,32 @@ use std::{ /// mainly it closes the file descriptor once dropped. #[derive(Debug)] #[cfg(feature = "libc")] -pub struct FileDesc { +pub struct FileDesc<'a> { fd: RawFd, close_on_drop: bool, + phantom: PhantomData<&'a ()>, } #[cfg(not(feature = "libc"))] -pub enum FileDesc { +pub enum FileDesc<'a> { Owned(OwnedFd), - Static(BorrowedFd<'static>), + Borrowed(BorrowedFd<'a>), } #[cfg(feature = "libc")] -impl FileDesc { +impl FileDesc<'_> { /// Constructs a new `FileDesc` with the given `RawFd`. /// /// # Arguments /// /// * `fd` - raw file descriptor /// * `close_on_drop` - specify if the raw file descriptor should be closed once the `FileDesc` is dropped - pub fn new(fd: RawFd, close_on_drop: bool) -> FileDesc { - FileDesc { fd, close_on_drop } + pub fn new(fd: RawFd, close_on_drop: bool) -> FileDesc<'static> { + FileDesc { + fd, + close_on_drop, + phantom: PhantomData, + } } pub fn read(&self, buffer: &mut [u8]) -> io::Result { @@ -65,11 +71,11 @@ impl FileDesc { } #[cfg(not(feature = "libc"))] -impl FileDesc { +impl FileDesc<'_> { pub fn read(&self, buffer: &mut [u8]) -> io::Result { let fd = match self { FileDesc::Owned(fd) => fd.as_fd(), - FileDesc::Static(fd) => fd.as_fd(), + FileDesc::Borrowed(fd) => fd.as_fd(), }; let result = rustix::io::read(fd, buffer)?; Ok(result) @@ -78,13 +84,13 @@ impl FileDesc { pub fn raw_fd(&self) -> RawFd { match self { FileDesc::Owned(fd) => fd.as_raw_fd(), - FileDesc::Static(fd) => fd.as_raw_fd(), + FileDesc::Borrowed(fd) => fd.as_raw_fd(), } } } #[cfg(feature = "libc")] -impl Drop for FileDesc { +impl Drop for FileDesc<'_> { fn drop(&mut self) { if self.close_on_drop { // Note that errors are ignored when closing a file descriptor. The @@ -97,25 +103,25 @@ impl Drop for FileDesc { } } -impl AsRawFd for FileDesc { +impl AsRawFd for FileDesc<'_> { fn as_raw_fd(&self) -> RawFd { self.raw_fd() } } #[cfg(not(feature = "libc"))] -impl AsFd for FileDesc { +impl AsFd for FileDesc<'_> { fn as_fd(&self) -> BorrowedFd<'_> { match self { FileDesc::Owned(fd) => fd.as_fd(), - FileDesc::Static(fd) => fd.as_fd(), + FileDesc::Borrowed(fd) => fd.as_fd(), } } } #[cfg(feature = "libc")] /// Creates a file descriptor pointing to the standard input or `/dev/tty`. -pub fn tty_fd() -> io::Result { +pub fn tty_fd() -> io::Result> { let (fd, close_on_drop) = if unsafe { libc::isatty(libc::STDIN_FILENO) == 1 } { (libc::STDIN_FILENO, false) } else { @@ -134,12 +140,12 @@ pub fn tty_fd() -> io::Result { #[cfg(not(feature = "libc"))] /// Creates a file descriptor pointing to the standard input or `/dev/tty`. -pub fn tty_fd() -> io::Result { +pub fn tty_fd() -> io::Result> { use std::fs::File; let stdin = rustix::stdio::stdin(); let fd = if rustix::termios::isatty(stdin) { - FileDesc::Static(stdin) + FileDesc::Borrowed(stdin) } else { let dev_tty = File::options().read(true).write(true).open("/dev/tty")?; FileDesc::Owned(dev_tty.into()) From 63b0d03240afff851d632bcbe33fab3e2d4c37c0 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Sat, 18 May 2024 17:37:54 -0700 Subject: [PATCH 5/5] add changelog entry for rustix / filedesc change --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c7f661c9..41e438b90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# Unreleased + +- Use Rustix by default instead of libc. Libc can be re-enabled if necessary with the libc feature flag. +- `FileDesc` now requires a lifetime annotation. + # Version 0.27.1 ## Added ⭐