chiark / gitweb /
nix: Gross hack to enable compat with 0.26 *and* 0.27
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Fri, 23 Feb 2024 15:08:54 +0000 (15:08 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Fri, 23 Feb 2024 16:34:20 +0000 (16:34 +0000)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
Cargo.toml
server/daemon.rs
src/compat.rs [new file with mode: 0644]
src/lib.rs
src/prelude.rs

index e396b70ff108d76b35005b4ec8a2258de7d131e0..42d7f595f2f7541e21a03b83b7f1402c7836811e 100644 (file)
@@ -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"
index 1c86d12b05d598657fe49e23eb2f610d7f178cb3..a45fccb9709b81bd0d2ed17b1e451b81bba98121 100644 (file)
@@ -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 (file)
index 0000000..445c758
--- /dev/null
@@ -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<usize> {
+  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::<WhateverOpenPtyResultHas>.
+  // (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<c_int> {
+    type Arg = c_int;
+    unsafe fn arg(&self, fd: c_int) -> c_int { fd.as_raw_fd() }
+  }
+  impl Select for Option<OwnedFd> {
+    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<OwnedFd>, gets dropped here,
+  // but it's always None.  We hope the compiler will notice this
+  // and remove the unreachable call to close(2).
+}
index b6aa60f2ee39fe756b50dd8fc33eafbce1d5d13c..e7f2ca5b8e215a24b81f94f2652719c1904d7fbf 100644 (file)
@@ -21,6 +21,7 @@
 
 pub mod prelude;
 
+pub mod compat;
 pub mod config;
 pub mod ipif;
 pub mod multipart;
index fad8af1d599a91ecfd041ecd81ba8a3856c72879..f39ae74a5863a44ff414f0307b1045b93a519f8c 100644 (file)
@@ -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 _};