pal/
unix.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4#![cfg(unix)]
5// UNSAFETY: Calls to libc functions to interact with low level primitives.
6#![expect(unsafe_code)]
7
8pub mod affinity;
9pub mod pipe;
10pub mod process;
11pub mod pthread;
12
13use std::fs::File;
14use std::io;
15use std::io::Error;
16use std::os::unix::prelude::*;
17
18/// A Linux error value.
19#[derive(Copy, Clone, PartialEq, Eq)]
20pub struct Errno(pub i32);
21
22impl std::fmt::Debug for Errno {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        std::fmt::Debug::fmt(&Error::from(*self), f)
25    }
26}
27
28impl From<Errno> for Error {
29    fn from(code: Errno) -> Self {
30        Self::from_raw_os_error(code.0)
31    }
32}
33
34/// Trait for extracting a Unix error value from an error type.
35pub trait TryAsErrno {
36    /// Gets the Unix error value if there is one.
37    fn try_as_errno(&self) -> Option<Errno>;
38}
39
40impl TryAsErrno for Errno {
41    fn try_as_errno(&self) -> Option<Errno> {
42        Some(*self)
43    }
44}
45
46impl TryAsErrno for Error {
47    fn try_as_errno(&self) -> Option<Errno> {
48        self.raw_os_error().map(Errno)
49    }
50}
51
52/// Returns the value of errno.
53pub(crate) fn errno() -> Errno {
54    Errno(Error::last_os_error().raw_os_error().unwrap())
55}
56
57/// A helper trait to convert from a libc return value to a `Result<_, Errno>`.
58pub trait SyscallResult: Sized {
59    /// Returns `Ok(self)` if `self >= 0`, otherwise `Err(errno())`.
60    fn syscall_result(self) -> Result<Self, Errno>;
61}
62
63impl SyscallResult for i32 {
64    fn syscall_result(self) -> Result<Self, Errno> {
65        if self >= 0 { Ok(self) } else { Err(errno()) }
66    }
67}
68
69impl SyscallResult for isize {
70    fn syscall_result(self) -> Result<Self, Errno> {
71        if self >= 0 { Ok(self) } else { Err(errno()) }
72    }
73}
74
75/// Runs f() until it stop failing with EINTR (as indicated by errno).
76pub fn while_eintr<F, R, E>(mut f: F) -> Result<R, E>
77where
78    F: FnMut() -> Result<R, E>,
79    E: TryAsErrno,
80{
81    loop {
82        match f() {
83            Err(err) if err.try_as_errno() == Some(Errno(libc::EINTR)) => {}
84            r => break r,
85        }
86    }
87}
88
89/// Closes stdout, replacing it the null device.
90pub fn close_stdout() -> io::Result<()> {
91    let new_stdout = File::open("/dev/null")?;
92    // SAFETY: replacing stdout with an owned fd
93    unsafe { libc::dup2(new_stdout.as_raw_fd(), 1) }.syscall_result()?;
94    Ok(())
95}