summaryrefslogtreecommitdiffstats
path: root/library/std/src/sys/unix
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys/unix')
-rw-r--r--library/std/src/sys/unix/cmath.rs4
-rw-r--r--library/std/src/sys/unix/fs.rs28
-rw-r--r--library/std/src/sys/unix/kernel_copy.rs18
-rw-r--r--library/std/src/sys/unix/mod.rs14
-rw-r--r--library/std/src/sys/unix/os.rs49
-rw-r--r--library/std/src/sys/unix/os_str.rs10
-rw-r--r--library/std/src/sys/unix/process/process_fuchsia.rs2
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs223
-rw-r--r--library/std/src/sys/unix/process/process_unix/tests.rs25
-rw-r--r--library/std/src/sys/unix/process/process_unsupported.rs2
-rw-r--r--library/std/src/sys/unix/process/process_vxworks.rs2
-rw-r--r--library/std/src/sys/unix/rand.rs22
-rw-r--r--library/std/src/sys/unix/stdio.rs2
13 files changed, 265 insertions, 136 deletions
diff --git a/library/std/src/sys/unix/cmath.rs b/library/std/src/sys/unix/cmath.rs
index 2bf80d7a4..5346d2291 100644
--- a/library/std/src/sys/unix/cmath.rs
+++ b/library/std/src/sys/unix/cmath.rs
@@ -30,4 +30,8 @@ extern "C" {
pub fn tanf(n: f32) -> f32;
pub fn tanh(n: f64) -> f64;
pub fn tanhf(n: f32) -> f32;
+ pub fn tgamma(n: f64) -> f64;
+ pub fn tgammaf(n: f32) -> f32;
+ pub fn lgamma_r(n: f64, s: &mut i32) -> f64;
+ pub fn lgammaf_r(n: f32, s: &mut i32) -> f32;
}
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index fbc7f04ce..a5604c92a 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -7,17 +7,6 @@ use crate::ffi::{CStr, OsStr, OsString};
use crate::fmt;
use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
use crate::mem;
-#[cfg(any(
- target_os = "android",
- target_os = "linux",
- target_os = "solaris",
- target_os = "fuchsia",
- target_os = "redox",
- target_os = "illumos",
- target_os = "nto",
- target_os = "vita",
-))]
-use crate::mem::MaybeUninit;
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
use crate::path::{Path, PathBuf};
use crate::ptr;
@@ -712,22 +701,10 @@ impl Iterator for ReadDir {
// requires the full extent of *entry_ptr to be in bounds of the same
// allocation, which is not necessarily the case here.
//
- // Absent any other way to obtain a pointer to `(*entry_ptr).d_name`
- // legally in Rust analogously to how it would be done in C, we instead
- // need to make our own non-libc allocation that conforms to the weird
- // imaginary definition of dirent64, and use that for a field offset
- // computation.
+ // Instead we must access fields individually through their offsets.
macro_rules! offset_ptr {
($entry_ptr:expr, $field:ident) => {{
- const OFFSET: isize = {
- let delusion = MaybeUninit::<dirent64>::uninit();
- let entry_ptr = delusion.as_ptr();
- unsafe {
- ptr::addr_of!((*entry_ptr).$field)
- .cast::<u8>()
- .offset_from(entry_ptr.cast::<u8>())
- }
- };
+ const OFFSET: isize = mem::offset_of!(dirent64, $field) as isize;
if true {
// Cast to the same type determined by the else branch.
$entry_ptr.byte_offset(OFFSET).cast::<_>()
@@ -1227,6 +1204,7 @@ impl File {
self.0.write_vectored_at(bufs, offset)
}
+ #[inline]
pub fn flush(&self) -> io::Result<()> {
Ok(())
}
diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs
index 7d49bbdcb..4d17a1b00 100644
--- a/library/std/src/sys/unix/kernel_copy.rs
+++ b/library/std/src/sys/unix/kernel_copy.rs
@@ -89,6 +89,12 @@ enum FdMeta {
NoneObtained,
}
+#[derive(PartialEq)]
+enum FdHandle {
+ Input,
+ Output,
+}
+
impl FdMeta {
fn maybe_fifo(&self) -> bool {
match self {
@@ -114,12 +120,14 @@ impl FdMeta {
}
}
- fn copy_file_range_candidate(&self) -> bool {
+ fn copy_file_range_candidate(&self, f: FdHandle) -> bool {
match self {
// copy_file_range will fail on empty procfs files. `read` can determine whether EOF has been reached
// without extra cost and skip the write, thus there is no benefit in attempting copy_file_range
- FdMeta::Metadata(meta) if meta.is_file() && meta.len() > 0 => true,
- FdMeta::NoneObtained => true,
+ FdMeta::Metadata(meta) if f == FdHandle::Input && meta.is_file() && meta.len() > 0 => {
+ true
+ }
+ FdMeta::Metadata(meta) if f == FdHandle::Output && meta.is_file() => true,
_ => false,
}
}
@@ -197,7 +205,9 @@ impl<R: CopyRead, W: CopyWrite> SpecCopy for Copier<'_, '_, R, W> {
written += flush()?;
let max_write = reader.min_limit();
- if input_meta.copy_file_range_candidate() && output_meta.copy_file_range_candidate() {
+ if input_meta.copy_file_range_candidate(FdHandle::Input)
+ && output_meta.copy_file_range_candidate(FdHandle::Output)
+ {
let result = copy_regular_files(readfd, writefd, max_write);
result.update_take(reader);
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 326f1481e..77ef086f2 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -110,6 +110,11 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
while libc::poll(pfds.as_mut_ptr(), 3, 0) == -1 {
match errno() {
libc::EINTR => continue,
+ #[cfg(target_vendor = "unikraft")]
+ libc::ENOSYS => {
+ // Not all configurations of Unikraft enable `LIBPOSIX_EVENT`.
+ break 'poll;
+ }
libc::EINVAL | libc::EAGAIN | libc::ENOMEM => {
// RLIMIT_NOFILE or temporary allocation failures
// may be preventing use of poll(), fall back to fcntl
@@ -165,7 +170,14 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
}
unsafe fn reset_sigpipe(#[allow(unused_variables)] sigpipe: u8) {
- #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "horizon")))]
+ #[cfg(not(any(
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "horizon",
+ // Unikraft's `signal` implementation is currently broken:
+ // https://github.com/unikraft/lib-musl/issues/57
+ target_vendor = "unikraft",
+ )))]
{
// We don't want to add this as a public type to std, nor do we
// want to `include!` a file from the compiler (which would break
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index a68c14758..57e1a36da 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -495,6 +495,34 @@ pub struct Env {
iter: vec::IntoIter<(OsString, OsString)>,
}
+// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
+pub struct EnvStrDebug<'a> {
+ slice: &'a [(OsString, OsString)],
+}
+
+impl fmt::Debug for EnvStrDebug<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let Self { slice } = self;
+ f.debug_list()
+ .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap())))
+ .finish()
+ }
+}
+
+impl Env {
+ pub fn str_debug(&self) -> impl fmt::Debug + '_ {
+ let Self { iter } = self;
+ EnvStrDebug { slice: iter.as_slice() }
+ }
+}
+
+impl fmt::Debug for Env {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let Self { iter } = self;
+ f.debug_list().entries(iter.as_slice()).finish()
+ }
+}
+
impl !Send for Env {}
impl !Sync for Env {}
@@ -566,16 +594,21 @@ pub fn env() -> Env {
pub fn getenv(k: &OsStr) -> Option<OsString> {
// environment variables with a nul byte can't be set, so their value is
// always None as well
- let s = run_with_cstr(k.as_bytes(), |k| {
+ run_with_cstr(k.as_bytes(), |k| {
let _guard = env_read_lock();
- Ok(unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char)
+ let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char;
+
+ if v.is_null() {
+ Ok(None)
+ } else {
+ // SAFETY: `v` cannot be mutated while executing this line since we've a read lock
+ let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec();
+
+ Ok(Some(OsStringExt::from_vec(bytes)))
+ }
})
- .ok()?;
- if s.is_null() {
- None
- } else {
- Some(OsStringExt::from_vec(unsafe { CStr::from_ptr(s) }.to_bytes().to_vec()))
- }
+ .ok()
+ .flatten()
}
pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
diff --git a/library/std/src/sys/unix/os_str.rs b/library/std/src/sys/unix/os_str.rs
index f7333fd5a..463b0a275 100644
--- a/library/std/src/sys/unix/os_str.rs
+++ b/library/std/src/sys/unix/os_str.rs
@@ -96,6 +96,16 @@ impl AsInner<[u8]> for Buf {
}
impl Buf {
+ #[inline]
+ pub fn into_os_str_bytes(self) -> Vec<u8> {
+ self.inner
+ }
+
+ #[inline]
+ pub unsafe fn from_os_str_bytes_unchecked(s: Vec<u8>) -> Self {
+ Self { inner: s }
+ }
+
pub fn from_string(s: String) -> Buf {
Buf { inner: s.into_bytes() }
}
diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs
index e45c380a0..9931c2af2 100644
--- a/library/std/src/sys/unix/process/process_fuchsia.rs
+++ b/library/std/src/sys/unix/process/process_fuchsia.rs
@@ -235,7 +235,7 @@ impl Process {
}
}
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
pub struct ExitStatus(i64);
impl ExitStatus {
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 0ce93af66..3963e7f52 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -10,9 +10,6 @@ use core::ffi::NonZero_c_int;
#[cfg(target_os = "linux")]
use crate::os::linux::process::PidFd;
-#[cfg(target_os = "linux")]
-use crate::sys::weak::raw_syscall;
-
#[cfg(any(
target_os = "macos",
target_os = "watchos",
@@ -91,6 +88,11 @@ impl Command {
if let Some(ret) = self.posix_spawn(&theirs, envp.as_ref())? {
return Ok((ret, ours));
}
+
+ #[cfg(target_os = "linux")]
+ let (input, output) = sys::net::Socket::new_pair(libc::AF_UNIX, libc::SOCK_SEQPACKET)?;
+
+ #[cfg(not(target_os = "linux"))]
let (input, output) = sys::pipe::anon_pipe()?;
// Whatever happens after the fork is almost for sure going to touch or
@@ -104,12 +106,16 @@ impl Command {
// The child calls `mem::forget` to leak the lock, which is crucial because
// releasing a lock is not async-signal-safe.
let env_lock = sys::os::env_read_lock();
- let (pid, pidfd) = unsafe { self.do_fork()? };
+ let pid = unsafe { self.do_fork()? };
if pid == 0 {
crate::panic::always_abort();
mem::forget(env_lock); // avoid non-async-signal-safe unlocking
drop(input);
+ #[cfg(target_os = "linux")]
+ if self.get_create_pidfd() {
+ self.send_pidfd(&output);
+ }
let Err(err) = unsafe { self.do_exec(theirs, envp.as_ref()) };
let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32;
let errno = errno.to_be_bytes();
@@ -133,6 +139,12 @@ impl Command {
drop(env_lock);
drop(output);
+ #[cfg(target_os = "linux")]
+ let pidfd = if self.get_create_pidfd() { self.recv_pidfd(&input) } else { -1 };
+
+ #[cfg(not(target_os = "linux"))]
+ let pidfd = -1;
+
// Safety: We obtained the pidfd from calling `clone3` with
// `CLONE_PIDFD` so it's valid an otherwise unowned.
let mut p = unsafe { Process::new(pid, pidfd) };
@@ -160,6 +172,7 @@ impl Command {
}
Ok(..) => {
// pipe I/O up to PIPE_BUF bytes should be atomic
+ // similarly SOCK_SEQPACKET messages should arrive whole
assert!(p.wait().is_ok(), "wait() should either return Ok or panic");
panic!("short read on the CLOEXEC pipe")
}
@@ -185,20 +198,19 @@ impl Command {
);
#[cfg(any(target_os = "tvos", target_os = "watchos"))]
- unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
+ unsafe fn do_fork(&mut self) -> Result<pid_t, io::Error> {
return Err(Self::ERR_APPLE_TV_WATCH_NO_FORK_EXEC);
}
// Attempts to fork the process. If successful, returns Ok((0, -1))
// in the child, and Ok((child_pid, -1)) in the parent.
#[cfg(not(any(
- target_os = "linux",
target_os = "watchos",
target_os = "tvos",
all(target_os = "nto", target_env = "nto71"),
)))]
- unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
- cvt(libc::fork()).map(|res| (res, -1))
+ unsafe fn do_fork(&mut self) -> Result<pid_t, io::Error> {
+ cvt(libc::fork())
}
// On QNX Neutrino, fork can fail with EBADF in case "another thread might have opened
@@ -206,7 +218,7 @@ impl Command {
// Documentation says "... or try calling fork() again". This is what we do here.
// See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html
#[cfg(all(target_os = "nto", target_env = "nto71"))]
- unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
+ unsafe fn do_fork(&mut self) -> Result<pid_t, io::Error> {
use crate::sys::os::errno;
let mut delay = MIN_FORKSPAWN_SLEEP;
@@ -229,91 +241,11 @@ impl Command {
delay *= 2;
continue;
} else {
- return cvt(r).map(|res| (res, -1));
+ return cvt(r);
}
}
}
- // Attempts to fork the process. If successful, returns Ok((0, -1))
- // in the child, and Ok((child_pid, child_pidfd)) in the parent.
- #[cfg(target_os = "linux")]
- unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
- use crate::sync::atomic::{AtomicBool, Ordering};
-
- static HAS_CLONE3: AtomicBool = AtomicBool::new(true);
- const CLONE_PIDFD: u64 = 0x00001000;
-
- #[repr(C)]
- struct clone_args {
- flags: u64,
- pidfd: u64,
- child_tid: u64,
- parent_tid: u64,
- exit_signal: u64,
- stack: u64,
- stack_size: u64,
- tls: u64,
- set_tid: u64,
- set_tid_size: u64,
- cgroup: u64,
- }
-
- raw_syscall! {
- fn clone3(cl_args: *mut clone_args, len: libc::size_t) -> libc::c_long
- }
-
- // Bypassing libc for `clone3` can make further libc calls unsafe,
- // so we use it sparingly for now. See #89522 for details.
- // Some tools (e.g. sandboxing tools) may also expect `fork`
- // rather than `clone3`.
- let want_clone3_pidfd = self.get_create_pidfd();
-
- // If we fail to create a pidfd for any reason, this will
- // stay as -1, which indicates an error.
- let mut pidfd: pid_t = -1;
-
- // Attempt to use the `clone3` syscall, which supports more arguments
- // (in particular, the ability to create a pidfd). If this fails,
- // we will fall through this block to a call to `fork()`
- if want_clone3_pidfd && HAS_CLONE3.load(Ordering::Relaxed) {
- let mut args = clone_args {
- flags: CLONE_PIDFD,
- pidfd: &mut pidfd as *mut pid_t as u64,
- child_tid: 0,
- parent_tid: 0,
- exit_signal: libc::SIGCHLD as u64,
- stack: 0,
- stack_size: 0,
- tls: 0,
- set_tid: 0,
- set_tid_size: 0,
- cgroup: 0,
- };
-
- let args_ptr = &mut args as *mut clone_args;
- let args_size = crate::mem::size_of::<clone_args>();
-
- let res = cvt(clone3(args_ptr, args_size));
- match res {
- Ok(n) => return Ok((n as pid_t, pidfd)),
- Err(e) => match e.raw_os_error() {
- // Multiple threads can race to execute this store,
- // but that's fine - that just means that multiple threads
- // will have tried and failed to execute the same syscall,
- // with no other side effects.
- Some(libc::ENOSYS) => HAS_CLONE3.store(false, Ordering::Relaxed),
- // Fallback to fork if `EPERM` is returned. (e.g. blocked by seccomp)
- Some(libc::EPERM) => {}
- _ => return Err(e),
- },
- }
- }
-
- // Generally, we just call `fork`. If we get here after wanting `clone3`,
- // then the syscall does not exist or we do not have permission to call it.
- cvt(libc::fork()).map(|res| (res, pidfd))
- }
-
pub fn exec(&mut self, default: Stdio) -> io::Error {
let envp = self.capture_env();
@@ -722,6 +654,115 @@ impl Command {
Ok(Some(p))
}
}
+
+ #[cfg(target_os = "linux")]
+ fn send_pidfd(&self, sock: &crate::sys::net::Socket) {
+ use crate::io::IoSlice;
+ use crate::os::fd::RawFd;
+ use crate::sys::cvt_r;
+ use libc::{CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_SPACE, SCM_RIGHTS, SOL_SOCKET};
+
+ unsafe {
+ let child_pid = libc::getpid();
+ // pidfd_open sets CLOEXEC by default
+ let pidfd = libc::syscall(libc::SYS_pidfd_open, child_pid, 0);
+
+ let fds: [c_int; 1] = [pidfd as RawFd];
+
+ const SCM_MSG_LEN: usize = mem::size_of::<[c_int; 1]>();
+
+ #[repr(C)]
+ union Cmsg {
+ buf: [u8; unsafe { CMSG_SPACE(SCM_MSG_LEN as u32) as usize }],
+ _align: libc::cmsghdr,
+ }
+
+ let mut cmsg: Cmsg = mem::zeroed();
+
+ // 0-length message to send through the socket so we can pass along the fd
+ let mut iov = [IoSlice::new(b"")];
+ let mut msg: libc::msghdr = mem::zeroed();
+
+ msg.msg_iov = &mut iov as *mut _ as *mut _;
+ msg.msg_iovlen = 1;
+ msg.msg_controllen = mem::size_of_val(&cmsg.buf) as _;
+ msg.msg_control = &mut cmsg.buf as *mut _ as *mut _;
+
+ // only attach cmsg if we successfully acquired the pidfd
+ if pidfd >= 0 {
+ let hdr = CMSG_FIRSTHDR(&mut msg as *mut _ as *mut _);
+ (*hdr).cmsg_level = SOL_SOCKET;
+ (*hdr).cmsg_type = SCM_RIGHTS;
+ (*hdr).cmsg_len = CMSG_LEN(SCM_MSG_LEN as _) as _;
+ let data = CMSG_DATA(hdr);
+ crate::ptr::copy_nonoverlapping(
+ fds.as_ptr().cast::<u8>(),
+ data as *mut _,
+ SCM_MSG_LEN,
+ );
+ }
+
+ // we send the 0-length message even if we failed to acquire the pidfd
+ // so we get a consistent SEQPACKET order
+ match cvt_r(|| libc::sendmsg(sock.as_raw(), &msg, 0)) {
+ Ok(0) => {}
+ _ => rtabort!("failed to communicate with parent process"),
+ }
+ }
+ }
+
+ #[cfg(target_os = "linux")]
+ fn recv_pidfd(&self, sock: &crate::sys::net::Socket) -> pid_t {
+ use crate::io::IoSliceMut;
+ use crate::sys::cvt_r;
+
+ use libc::{CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_SPACE, SCM_RIGHTS, SOL_SOCKET};
+
+ unsafe {
+ const SCM_MSG_LEN: usize = mem::size_of::<[c_int; 1]>();
+
+ #[repr(C)]
+ union Cmsg {
+ _buf: [u8; unsafe { CMSG_SPACE(SCM_MSG_LEN as u32) as usize }],
+ _align: libc::cmsghdr,
+ }
+ let mut cmsg: Cmsg = mem::zeroed();
+ // 0-length read to get the fd
+ let mut iov = [IoSliceMut::new(&mut [])];
+
+ let mut msg: libc::msghdr = mem::zeroed();
+
+ msg.msg_iov = &mut iov as *mut _ as *mut _;
+ msg.msg_iovlen = 1;
+ msg.msg_controllen = mem::size_of::<Cmsg>() as _;
+ msg.msg_control = &mut cmsg as *mut _ as *mut _;
+
+ match cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, 0)) {
+ Err(_) => return -1,
+ Ok(_) => {}
+ }
+
+ let hdr = CMSG_FIRSTHDR(&mut msg as *mut _ as *mut _);
+ if hdr.is_null()
+ || (*hdr).cmsg_level != SOL_SOCKET
+ || (*hdr).cmsg_type != SCM_RIGHTS
+ || (*hdr).cmsg_len != CMSG_LEN(SCM_MSG_LEN as _) as _
+ {
+ return -1;
+ }
+ let data = CMSG_DATA(hdr);
+
+ let mut fds = [-1 as c_int];
+
+ crate::ptr::copy_nonoverlapping(
+ data as *const _,
+ fds.as_mut_ptr().cast::<u8>(),
+ SCM_MSG_LEN,
+ );
+
+ fds[0]
+ }
+ }
}
////////////////////////////////////////////////////////////////////////////////
@@ -800,7 +841,7 @@ impl Process {
//
// This is not actually an "exit status" in Unix terminology. Rather, it is a "wait status".
// See the discussion in comments and doc comments for `std::process::ExitStatus`.
-#[derive(PartialEq, Eq, Clone, Copy)]
+#[derive(PartialEq, Eq, Clone, Copy, Default)]
pub struct ExitStatus(c_int);
impl fmt::Debug for ExitStatus {
diff --git a/library/std/src/sys/unix/process/process_unix/tests.rs b/library/std/src/sys/unix/process/process_unix/tests.rs
index e5e1f956b..6aa79e7f9 100644
--- a/library/std/src/sys/unix/process/process_unix/tests.rs
+++ b/library/std/src/sys/unix/process/process_unix/tests.rs
@@ -60,3 +60,28 @@ fn test_command_fork_no_unwind() {
|| signal == libc::SIGSEGV
);
}
+
+#[test]
+#[cfg(target_os = "linux")]
+fn test_command_pidfd() {
+ use crate::os::fd::RawFd;
+ use crate::os::linux::process::{ChildExt, CommandExt};
+ use crate::process::Command;
+
+ let our_pid = crate::process::id();
+ let pidfd = unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) };
+ let pidfd_open_available = if pidfd >= 0 {
+ unsafe { libc::close(pidfd as RawFd) };
+ true
+ } else {
+ false
+ };
+
+ // always exercise creation attempts
+ let child = Command::new("echo").create_pidfd(true).spawn().unwrap();
+
+ // but only check if we know that the kernel supports pidfds
+ if pidfd_open_available {
+ assert!(child.pidfd().is_ok())
+ }
+}
diff --git a/library/std/src/sys/unix/process/process_unsupported.rs b/library/std/src/sys/unix/process/process_unsupported.rs
index f28ca58d0..8e0b971af 100644
--- a/library/std/src/sys/unix/process/process_unsupported.rs
+++ b/library/std/src/sys/unix/process/process_unsupported.rs
@@ -55,7 +55,7 @@ impl Process {
}
}
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
pub struct ExitStatus(c_int);
impl ExitStatus {
diff --git a/library/std/src/sys/unix/process/process_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs
index f70d3cb39..1ff2b2fb3 100644
--- a/library/std/src/sys/unix/process/process_vxworks.rs
+++ b/library/std/src/sys/unix/process/process_vxworks.rs
@@ -179,7 +179,7 @@ impl Process {
}
/// Unix exit statuses
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
pub struct ExitStatus(c_int);
impl ExitStatus {
diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs
index d471be33e..fbf158f56 100644
--- a/library/std/src/sys/unix/rand.rs
+++ b/library/std/src/sys/unix/rand.rs
@@ -17,7 +17,6 @@ pub fn hashmap_random_keys() -> (u64, u64) {
not(target_os = "tvos"),
not(target_os = "watchos"),
not(target_os = "openbsd"),
- not(target_os = "freebsd"),
not(target_os = "netbsd"),
not(target_os = "fuchsia"),
not(target_os = "redox"),
@@ -68,11 +67,25 @@ mod imp {
unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) }
}
+ #[cfg(target_os = "freebsd")]
+ fn getrandom(buf: &mut [u8]) -> libc::ssize_t {
+ // FIXME: using the above when libary std's libc is updated
+ extern "C" {
+ fn getrandom(
+ buffer: *mut libc::c_void,
+ length: libc::size_t,
+ flags: libc::c_uint,
+ ) -> libc::ssize_t;
+ }
+ unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) }
+ }
+
#[cfg(not(any(
target_os = "linux",
target_os = "android",
target_os = "espidf",
- target_os = "horizon"
+ target_os = "horizon",
+ target_os = "freebsd"
)))]
fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool {
false
@@ -82,7 +95,8 @@ mod imp {
target_os = "linux",
target_os = "android",
target_os = "espidf",
- target_os = "horizon"
+ target_os = "horizon",
+ target_os = "freebsd"
))]
fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
use crate::sync::atomic::{AtomicBool, Ordering};
@@ -222,7 +236,7 @@ mod imp {
}
}
-#[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
+#[cfg(target_os = "netbsd")]
mod imp {
use crate::ptr;
diff --git a/library/std/src/sys/unix/stdio.rs b/library/std/src/sys/unix/stdio.rs
index a26f20795..97e75f1b5 100644
--- a/library/std/src/sys/unix/stdio.rs
+++ b/library/std/src/sys/unix/stdio.rs
@@ -54,6 +54,7 @@ impl io::Write for Stdout {
true
}
+ #[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
@@ -81,6 +82,7 @@ impl io::Write for Stderr {
true
}
+ #[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}