From: Ian Jackson Date: Fri, 23 Feb 2024 15:08:54 +0000 (+0000) Subject: nix: Gross hack to enable compat with 0.26 *and* 0.27 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=7dd19926e96ab98aac041f1c55ee515c25c85ded;p=hippotat.git nix: Gross hack to enable compat with 0.26 *and* 0.27 Signed-off-by: Ian Jackson --- diff --git a/Cargo.toml b/Cargo.toml index e396b70..42d7f59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ libc = "0.2" # just for EISDIR due to IsADirectory log = "0.4.14" memchr = "2" mime = "0.3.4" -nix = { version = ">=0.25, <0.27", features = ["fs", "process", "signal", "uio"] } +nix = { version = ">=0.25, <0.27", features = ["fs", "process", "signal", "term", "uio"] } parking_lot = ">= 0.11, < 0.13" pin-project-lite = "0.2" regex = "1.5" diff --git a/server/daemon.rs b/server/daemon.rs index 1c86d12..a45fccb 100644 --- a/server/daemon.rs +++ b/server/daemon.rs @@ -18,11 +18,10 @@ use nix::fcntl::*; use nix::unistd::*; use nix::sys::stat::*; use nix::sys::signal::*; -use nix::sys::uio::*; use nix::sys::wait::*; use hippotat::prelude as prelude; -use prelude::default; +use prelude::{compat, default}; pub struct Daemoniser { drop_bomb: Option<()>, @@ -33,7 +32,7 @@ pub struct Daemoniser { fn crashv(ms: &[IoSlice<'_>]) -> ! { unsafe { - let _ = writev(2, ms); + let _ = compat::writev(2, ms); libc::_exit(18); } } diff --git a/src/compat.rs b/src/compat.rs new file mode 100644 index 0000000..445c758 --- /dev/null +++ b/src/compat.rs @@ -0,0 +1,67 @@ + +use crate::prelude::*; + +/// Version of [`nix::sys::uio::writev`] with a known type for the fd +// +/// * nix <=0.26 has `fd: c_int` +/// * nix >=0.27 has `fd: impl AsFd` +pub unsafe fn writev(fd: c_int, iov: &[IoSlice]) -> nix::Result { + use std::mem::MaybeUninit; + use std::os::fd::AsRawFd as _; + + // This is not so straightforward. To provide `impl AsFd` we + // need to specify something with a concrete type, so that the + // compiler can select the AsFd impl. But c_int doesn't impl AsFd. + // + // So we must pass something whose type is statically inferrable, + // but differs with the two nix versions. + // + // Selection based on presence/absence of names is no good because + // the ambiguity errors mean we can't rely on shadowing. + // + // We could depend on the type of `writev`, but when it's a generic + // function it doesn't *have* a type. + // + // But! nix changed the type of `OpenptyResult`, as part of the + // same fd-safety update. We can use that. We use the type of its + // fields, which is either OwnedFd (the new io-safe type from std) + // or RawFd aka c_int. We can't *name* the type, since we can't + // get the type name of the field. + // + // But we can trick the compiler into *infeerring* from that type + // to give us a value None::. + // (We mustn't actually create an OwnedFd since those close the fd + // on drop!) + + trait Select { + type Arg; + unsafe fn arg(&self, fd: c_int) -> Self::Arg; + } + impl Select for Option { + type Arg = c_int; + unsafe fn arg(&self, fd: c_int) -> c_int { fd.as_raw_fd() } + } + impl Select for Option { + type Arg = BorrowedFd<'static>; + unsafe fn arg(&self, fd: c_int) -> BorrowedFd<'static> { + BorrowedFd::borrow_raw(fd) + } + } + + let select = if false { + #[allow(invalid_value)] // SAFETY: UB, but inside `if false` + unsafe { + let x: nix::pty::OpenptyResult = MaybeUninit::uninit().assume_init(); + Some(x.master) // decides the type of the if, therefore of the select + } + } else { + // this branch actually runs + None + }; + + nix::sys::uio::writev(select.arg(fd), iov) + + // `select`, which might be Option, gets dropped here, + // but it's always None. We hope the compiler will notice this + // and remove the unreachable call to close(2). +} diff --git a/src/lib.rs b/src/lib.rs index b6aa60f..e7f2ca5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,7 @@ pub mod prelude; +pub mod compat; pub mod config; pub mod ipif; pub mod multipart; diff --git a/src/prelude.rs b/src/prelude.rs index fad8af1..f39ae74 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -12,10 +12,12 @@ pub use std::env; pub use std::fs; pub use std::fmt::{self, Debug, Display, Write as _}; pub use std::future::Future; -pub use std::io::{self, Cursor, ErrorKind, Read as _, Write as _}; +pub use std::io::{self, Cursor, ErrorKind, IoSlice, Read as _, Write as _}; pub use std::iter; pub use std::mem; pub use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +pub use std::os::fd::{BorrowedFd, OwnedFd}; +pub use std::os::raw::c_int; pub use std::path::{Path, PathBuf}; pub use std::panic::{self, AssertUnwindSafe}; pub use std::process; @@ -55,6 +57,7 @@ pub use eyre::eyre as anyhow; pub use eyre::WrapErr; pub use eyre::Error as AE; +pub use crate::compat; pub use crate::config::{self, InstanceConfig, PrintConfigOpt}; pub use crate::config::{InspectableConfig, InspectableConfigValue}; pub use crate::config::{DisplayInspectable, U32Ext as _};