add types in preparation for non-blocking stdin
This commit is contained in:
parent
a9068f86f3
commit
a72a48f92b
4 changed files with 111 additions and 1 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -160,6 +160,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"regex",
|
"regex",
|
||||||
"regex-lite",
|
"regex-lite",
|
||||||
|
"rustix",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tap",
|
"tap",
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ itertools = "0.14.0"
|
||||||
libc = { version = "0.2.180", features = ["extra_traits"] }
|
libc = { version = "0.2.180", features = ["extra_traits"] }
|
||||||
regex = { version = "1.12.3", optional = true }
|
regex = { version = "1.12.3", optional = true }
|
||||||
regex-lite = { version = "0.1.9", optional = true }
|
regex-lite = { version = "0.1.9", optional = true }
|
||||||
|
rustix = { version = "1.1.4", features = ["event", "fs"] }
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
serde_json = "1.0.149"
|
serde_json = "1.0.149"
|
||||||
tap = "1.0.1"
|
tap = "1.0.1"
|
||||||
|
|
|
||||||
106
src/daemon_io.rs
Normal file
106
src/daemon_io.rs
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
use std::{
|
||||||
|
mem::ManuallyDrop,
|
||||||
|
os::{
|
||||||
|
fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd},
|
||||||
|
unix::prelude::RawFd,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use rustix::{
|
||||||
|
fs::{OFlags, fcntl_getfl, fcntl_setfl},
|
||||||
|
io::Errno,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// An [`OwnedFd`] that captures file status flags on init and restores them on:
|
||||||
|
///
|
||||||
|
/// - [`IntoRawFd`]
|
||||||
|
/// - [`drop()`]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct OwnedFdWithFlags {
|
||||||
|
fd: OwnedFd,
|
||||||
|
oflags: OFlags,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OwnedFdWithFlags {
|
||||||
|
pub fn new(fd: OwnedFd) -> Result<Self, Errno> {
|
||||||
|
let oflags = fcntl_getfl(&fd)?;
|
||||||
|
Ok(Self { fd, oflags })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If, for some ungodly reason, `fcntl(F_GETFL)` fails, then empty flags are used.
|
||||||
|
/// Empty flags should not be restored on close.
|
||||||
|
///
|
||||||
|
/// I'm pretty sure this should never happen if the program is IO-safe.
|
||||||
|
pub fn new_with_fallback(fd: OwnedFd) -> Self {
|
||||||
|
let oflags = Self::get_flags_or_log(fd.as_fd());
|
||||||
|
Self { fd, oflags }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for OwnedFdWithFlags {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.restore_flags_or_log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Private helpers.
|
||||||
|
impl OwnedFdWithFlags {
|
||||||
|
fn restore_flags_or_log(&self) {
|
||||||
|
// As far as we can tell there's no such thing as a file with entirely empty
|
||||||
|
// flags (at minimum, it needs read/write mode, right?).
|
||||||
|
// So empty `oflags` is our sentinel that `fcntl(F_GETFL)` somehow failed.
|
||||||
|
// Empty oflags is our sentinel that
|
||||||
|
if self.oflags.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = fcntl_setfl(&self.fd, self.oflags) {
|
||||||
|
error!(
|
||||||
|
"fcntl(F_SETFL) to restore flags {:?} on fd {:?} failed: {e}\nIO safety violation?",
|
||||||
|
self.oflags, self.fd,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_flags_or_log(fd: BorrowedFd) -> OFlags {
|
||||||
|
fcntl_getfl(fd)
|
||||||
|
.tap_err(|e| error!("fcntl(F_GETFL) failed on fd {fd:?}: {e}\nIO-safety violation?"))
|
||||||
|
.unwrap_or(OFlags::empty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRawFd for OwnedFdWithFlags {
|
||||||
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
AsRawFd::as_raw_fd(&self.fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoRawFd for OwnedFdWithFlags {
|
||||||
|
fn into_raw_fd(self) -> RawFd {
|
||||||
|
self.restore_flags_or_log();
|
||||||
|
ManuallyDrop::new(self).fd.as_raw_fd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromRawFd for OwnedFdWithFlags {
|
||||||
|
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||||
|
let fd = unsafe { OwnedFd::from_raw_fd(fd) };
|
||||||
|
let oflags = Self::get_flags_or_log(fd.as_fd());
|
||||||
|
Self { fd, oflags }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsFd for OwnedFdWithFlags {
|
||||||
|
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||||
|
AsFd::as_fd(&self.fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<OwnedFd> for OwnedFdWithFlags {
|
||||||
|
fn from(fd: OwnedFd) -> Self {
|
||||||
|
let oflags = Self::get_flags_or_log(fd.as_fd());
|
||||||
|
Self { fd, oflags }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -33,7 +33,7 @@ pub(crate) mod prelude {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub use fs_err::os::unix::fs::{FileExt, OpenOptionsExt};
|
pub use fs_err::os::unix::fs::{FileExt, OpenOptionsExt};
|
||||||
|
|
||||||
pub use tap::{Pipe, Tap};
|
pub use tap::{Pipe, Tap, TapFallible};
|
||||||
|
|
||||||
pub use tracing::{Level, debug, error, info, trace, warn};
|
pub use tracing::{Level, debug, error, info, trace, warn};
|
||||||
}
|
}
|
||||||
|
|
@ -44,6 +44,8 @@ pub mod args;
|
||||||
pub use args::{AppendCmd, Args};
|
pub use args::{AppendCmd, Args};
|
||||||
mod color;
|
mod color;
|
||||||
pub use color::{_CLI_ENABLE_COLOR, SHOULD_COLOR};
|
pub use color::{_CLI_ENABLE_COLOR, SHOULD_COLOR};
|
||||||
|
mod daemon_io;
|
||||||
|
pub use daemon_io::OwnedFdWithFlags;
|
||||||
pub mod line;
|
pub mod line;
|
||||||
mod nixcmd;
|
mod nixcmd;
|
||||||
pub use line::Line;
|
pub use line::Line;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue