--- /dev/null
+
+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).
+}
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;
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 _};