13da5c369Sopenharmony_ci//! Safe wrappers around functions found in libc "unistd.h" header
23da5c369Sopenharmony_ci
33da5c369Sopenharmony_ciuse crate::errno::{self, Errno};
43da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))]
53da5c369Sopenharmony_ci#[cfg(feature = "fs")]
63da5c369Sopenharmony_ciuse crate::fcntl::{at_rawfd, AtFlags};
73da5c369Sopenharmony_ci#[cfg(feature = "fs")]
83da5c369Sopenharmony_ciuse crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag};
93da5c369Sopenharmony_ci#[cfg(all(
103da5c369Sopenharmony_ci    feature = "fs",
113da5c369Sopenharmony_ci    any(
123da5c369Sopenharmony_ci        target_os = "openbsd",
133da5c369Sopenharmony_ci        target_os = "netbsd",
143da5c369Sopenharmony_ci        target_os = "freebsd",
153da5c369Sopenharmony_ci        target_os = "dragonfly",
163da5c369Sopenharmony_ci        target_os = "macos",
173da5c369Sopenharmony_ci        target_os = "ios"
183da5c369Sopenharmony_ci    )
193da5c369Sopenharmony_ci))]
203da5c369Sopenharmony_ciuse crate::sys::stat::FileFlag;
213da5c369Sopenharmony_ci#[cfg(feature = "fs")]
223da5c369Sopenharmony_ciuse crate::sys::stat::Mode;
233da5c369Sopenharmony_ciuse crate::{Error, NixPath, Result};
243da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))]
253da5c369Sopenharmony_ciuse cfg_if::cfg_if;
263da5c369Sopenharmony_ciuse libc::{
273da5c369Sopenharmony_ci    self, c_char, c_int, c_long, c_uint, c_void, gid_t, mode_t, off_t, pid_t,
283da5c369Sopenharmony_ci    size_t, uid_t, PATH_MAX,
293da5c369Sopenharmony_ci};
303da5c369Sopenharmony_ciuse std::convert::Infallible;
313da5c369Sopenharmony_ciuse std::ffi::{CStr, OsString};
323da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))]
333da5c369Sopenharmony_ciuse std::ffi::{CString, OsStr};
343da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))]
353da5c369Sopenharmony_ciuse std::os::unix::ffi::OsStrExt;
363da5c369Sopenharmony_ciuse std::os::unix::ffi::OsStringExt;
373da5c369Sopenharmony_ciuse std::os::unix::io::RawFd;
383da5c369Sopenharmony_ciuse std::path::PathBuf;
393da5c369Sopenharmony_ciuse std::{fmt, mem, ptr};
403da5c369Sopenharmony_ci
413da5c369Sopenharmony_cifeature! {
423da5c369Sopenharmony_ci    #![feature = "fs"]
433da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "linux"))]
443da5c369Sopenharmony_ci    pub use self::pivot_root::*;
453da5c369Sopenharmony_ci}
463da5c369Sopenharmony_ci
473da5c369Sopenharmony_ci#[cfg(any(
483da5c369Sopenharmony_ci    target_os = "android",
493da5c369Sopenharmony_ci    target_os = "dragonfly",
503da5c369Sopenharmony_ci    target_os = "freebsd",
513da5c369Sopenharmony_ci    target_os = "linux",
523da5c369Sopenharmony_ci    target_os = "openbsd"
533da5c369Sopenharmony_ci))]
543da5c369Sopenharmony_cipub use self::setres::*;
553da5c369Sopenharmony_ci
563da5c369Sopenharmony_ci#[cfg(any(
573da5c369Sopenharmony_ci    target_os = "android",
583da5c369Sopenharmony_ci    target_os = "dragonfly",
593da5c369Sopenharmony_ci    target_os = "freebsd",
603da5c369Sopenharmony_ci    target_os = "linux",
613da5c369Sopenharmony_ci    target_os = "openbsd"
623da5c369Sopenharmony_ci))]
633da5c369Sopenharmony_cipub use self::getres::*;
643da5c369Sopenharmony_ci
653da5c369Sopenharmony_cifeature! {
663da5c369Sopenharmony_ci#![feature = "user"]
673da5c369Sopenharmony_ci
683da5c369Sopenharmony_ci/// User identifier
693da5c369Sopenharmony_ci///
703da5c369Sopenharmony_ci/// Newtype pattern around `uid_t` (which is just alias). It prevents bugs caused by accidentally
713da5c369Sopenharmony_ci/// passing wrong value.
723da5c369Sopenharmony_ci#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
733da5c369Sopenharmony_cipub struct Uid(uid_t);
743da5c369Sopenharmony_ci
753da5c369Sopenharmony_ciimpl Uid {
763da5c369Sopenharmony_ci    /// Creates `Uid` from raw `uid_t`.
773da5c369Sopenharmony_ci    pub const fn from_raw(uid: uid_t) -> Self {
783da5c369Sopenharmony_ci        Uid(uid)
793da5c369Sopenharmony_ci    }
803da5c369Sopenharmony_ci
813da5c369Sopenharmony_ci    /// Returns Uid of calling process. This is practically a more Rusty alias for `getuid`.
823da5c369Sopenharmony_ci    #[doc(alias("getuid"))]
833da5c369Sopenharmony_ci    pub fn current() -> Self {
843da5c369Sopenharmony_ci        getuid()
853da5c369Sopenharmony_ci    }
863da5c369Sopenharmony_ci
873da5c369Sopenharmony_ci    /// Returns effective Uid of calling process. This is practically a more Rusty alias for `geteuid`.
883da5c369Sopenharmony_ci    #[doc(alias("geteuid"))]
893da5c369Sopenharmony_ci    pub fn effective() -> Self {
903da5c369Sopenharmony_ci        geteuid()
913da5c369Sopenharmony_ci    }
923da5c369Sopenharmony_ci
933da5c369Sopenharmony_ci    /// Returns true if the `Uid` represents privileged user - root. (If it equals zero.)
943da5c369Sopenharmony_ci    pub const fn is_root(self) -> bool {
953da5c369Sopenharmony_ci        self.0 == ROOT.0
963da5c369Sopenharmony_ci    }
973da5c369Sopenharmony_ci
983da5c369Sopenharmony_ci    /// Get the raw `uid_t` wrapped by `self`.
993da5c369Sopenharmony_ci    pub const fn as_raw(self) -> uid_t {
1003da5c369Sopenharmony_ci        self.0
1013da5c369Sopenharmony_ci    }
1023da5c369Sopenharmony_ci}
1033da5c369Sopenharmony_ci
1043da5c369Sopenharmony_ciimpl From<Uid> for uid_t {
1053da5c369Sopenharmony_ci    fn from(uid: Uid) -> Self {
1063da5c369Sopenharmony_ci        uid.0
1073da5c369Sopenharmony_ci    }
1083da5c369Sopenharmony_ci}
1093da5c369Sopenharmony_ci
1103da5c369Sopenharmony_ciimpl From<uid_t> for Uid {
1113da5c369Sopenharmony_ci    fn from(uid: uid_t) -> Self {
1123da5c369Sopenharmony_ci        Uid(uid)
1133da5c369Sopenharmony_ci    }
1143da5c369Sopenharmony_ci}
1153da5c369Sopenharmony_ci
1163da5c369Sopenharmony_ciimpl fmt::Display for Uid {
1173da5c369Sopenharmony_ci    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1183da5c369Sopenharmony_ci        fmt::Display::fmt(&self.0, f)
1193da5c369Sopenharmony_ci    }
1203da5c369Sopenharmony_ci}
1213da5c369Sopenharmony_ci
1223da5c369Sopenharmony_ci/// Constant for UID = 0
1233da5c369Sopenharmony_cipub const ROOT: Uid = Uid(0);
1243da5c369Sopenharmony_ci
1253da5c369Sopenharmony_ci/// Group identifier
1263da5c369Sopenharmony_ci///
1273da5c369Sopenharmony_ci/// Newtype pattern around `gid_t` (which is just alias). It prevents bugs caused by accidentally
1283da5c369Sopenharmony_ci/// passing wrong value.
1293da5c369Sopenharmony_ci#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1303da5c369Sopenharmony_cipub struct Gid(gid_t);
1313da5c369Sopenharmony_ci
1323da5c369Sopenharmony_ciimpl Gid {
1333da5c369Sopenharmony_ci    /// Creates `Gid` from raw `gid_t`.
1343da5c369Sopenharmony_ci    pub const fn from_raw(gid: gid_t) -> Self {
1353da5c369Sopenharmony_ci        Gid(gid)
1363da5c369Sopenharmony_ci    }
1373da5c369Sopenharmony_ci
1383da5c369Sopenharmony_ci    /// Returns Gid of calling process. This is practically a more Rusty alias for `getgid`.
1393da5c369Sopenharmony_ci    #[doc(alias("getgid"))]
1403da5c369Sopenharmony_ci    pub fn current() -> Self {
1413da5c369Sopenharmony_ci        getgid()
1423da5c369Sopenharmony_ci    }
1433da5c369Sopenharmony_ci
1443da5c369Sopenharmony_ci    /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getegid`.
1453da5c369Sopenharmony_ci    #[doc(alias("getegid"))]
1463da5c369Sopenharmony_ci    pub fn effective() -> Self {
1473da5c369Sopenharmony_ci        getegid()
1483da5c369Sopenharmony_ci    }
1493da5c369Sopenharmony_ci
1503da5c369Sopenharmony_ci    /// Get the raw `gid_t` wrapped by `self`.
1513da5c369Sopenharmony_ci    pub const fn as_raw(self) -> gid_t {
1523da5c369Sopenharmony_ci        self.0
1533da5c369Sopenharmony_ci    }
1543da5c369Sopenharmony_ci}
1553da5c369Sopenharmony_ci
1563da5c369Sopenharmony_ciimpl From<Gid> for gid_t {
1573da5c369Sopenharmony_ci    fn from(gid: Gid) -> Self {
1583da5c369Sopenharmony_ci        gid.0
1593da5c369Sopenharmony_ci    }
1603da5c369Sopenharmony_ci}
1613da5c369Sopenharmony_ci
1623da5c369Sopenharmony_ciimpl From<gid_t> for Gid {
1633da5c369Sopenharmony_ci    fn from(gid: gid_t) -> Self {
1643da5c369Sopenharmony_ci        Gid(gid)
1653da5c369Sopenharmony_ci    }
1663da5c369Sopenharmony_ci}
1673da5c369Sopenharmony_ci
1683da5c369Sopenharmony_ciimpl fmt::Display for Gid {
1693da5c369Sopenharmony_ci    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1703da5c369Sopenharmony_ci        fmt::Display::fmt(&self.0, f)
1713da5c369Sopenharmony_ci    }
1723da5c369Sopenharmony_ci}
1733da5c369Sopenharmony_ci}
1743da5c369Sopenharmony_ci
1753da5c369Sopenharmony_cifeature! {
1763da5c369Sopenharmony_ci#![feature = "process"]
1773da5c369Sopenharmony_ci/// Process identifier
1783da5c369Sopenharmony_ci///
1793da5c369Sopenharmony_ci/// Newtype pattern around `pid_t` (which is just alias). It prevents bugs caused by accidentally
1803da5c369Sopenharmony_ci/// passing wrong value.
1813da5c369Sopenharmony_ci#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
1823da5c369Sopenharmony_cipub struct Pid(pid_t);
1833da5c369Sopenharmony_ci
1843da5c369Sopenharmony_ciimpl Pid {
1853da5c369Sopenharmony_ci    /// Creates `Pid` from raw `pid_t`.
1863da5c369Sopenharmony_ci    pub const fn from_raw(pid: pid_t) -> Self {
1873da5c369Sopenharmony_ci        Pid(pid)
1883da5c369Sopenharmony_ci    }
1893da5c369Sopenharmony_ci
1903da5c369Sopenharmony_ci    /// Returns PID of calling process
1913da5c369Sopenharmony_ci    #[doc(alias("getpid"))]
1923da5c369Sopenharmony_ci    pub fn this() -> Self {
1933da5c369Sopenharmony_ci        getpid()
1943da5c369Sopenharmony_ci    }
1953da5c369Sopenharmony_ci
1963da5c369Sopenharmony_ci    /// Returns PID of parent of calling process
1973da5c369Sopenharmony_ci    #[doc(alias("getppid"))]
1983da5c369Sopenharmony_ci    pub fn parent() -> Self {
1993da5c369Sopenharmony_ci        getppid()
2003da5c369Sopenharmony_ci    }
2013da5c369Sopenharmony_ci
2023da5c369Sopenharmony_ci    /// Get the raw `pid_t` wrapped by `self`.
2033da5c369Sopenharmony_ci    pub const fn as_raw(self) -> pid_t {
2043da5c369Sopenharmony_ci        self.0
2053da5c369Sopenharmony_ci    }
2063da5c369Sopenharmony_ci}
2073da5c369Sopenharmony_ci
2083da5c369Sopenharmony_ciimpl From<Pid> for pid_t {
2093da5c369Sopenharmony_ci    fn from(pid: Pid) -> Self {
2103da5c369Sopenharmony_ci        pid.0
2113da5c369Sopenharmony_ci    }
2123da5c369Sopenharmony_ci}
2133da5c369Sopenharmony_ci
2143da5c369Sopenharmony_ciimpl fmt::Display for Pid {
2153da5c369Sopenharmony_ci    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2163da5c369Sopenharmony_ci        fmt::Display::fmt(&self.0, f)
2173da5c369Sopenharmony_ci    }
2183da5c369Sopenharmony_ci}
2193da5c369Sopenharmony_ci
2203da5c369Sopenharmony_ci
2213da5c369Sopenharmony_ci/// Represents the successful result of calling `fork`
2223da5c369Sopenharmony_ci///
2233da5c369Sopenharmony_ci/// When `fork` is called, the process continues execution in the parent process
2243da5c369Sopenharmony_ci/// and in the new child.  This return type can be examined to determine whether
2253da5c369Sopenharmony_ci/// you are now executing in the parent process or in the child.
2263da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug)]
2273da5c369Sopenharmony_cipub enum ForkResult {
2283da5c369Sopenharmony_ci    Parent { child: Pid },
2293da5c369Sopenharmony_ci    Child,
2303da5c369Sopenharmony_ci}
2313da5c369Sopenharmony_ci
2323da5c369Sopenharmony_ciimpl ForkResult {
2333da5c369Sopenharmony_ci
2343da5c369Sopenharmony_ci    /// Return `true` if this is the child process of the `fork()`
2353da5c369Sopenharmony_ci    #[inline]
2363da5c369Sopenharmony_ci    pub fn is_child(self) -> bool {
2373da5c369Sopenharmony_ci        matches!(self, ForkResult::Child)
2383da5c369Sopenharmony_ci    }
2393da5c369Sopenharmony_ci
2403da5c369Sopenharmony_ci    /// Returns `true` if this is the parent process of the `fork()`
2413da5c369Sopenharmony_ci    #[inline]
2423da5c369Sopenharmony_ci    pub fn is_parent(self) -> bool {
2433da5c369Sopenharmony_ci        !self.is_child()
2443da5c369Sopenharmony_ci    }
2453da5c369Sopenharmony_ci}
2463da5c369Sopenharmony_ci
2473da5c369Sopenharmony_ci/// Create a new child process duplicating the parent process ([see
2483da5c369Sopenharmony_ci/// fork(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html)).
2493da5c369Sopenharmony_ci///
2503da5c369Sopenharmony_ci/// After successfully calling the fork system call, a second process will
2513da5c369Sopenharmony_ci/// be created which is identical to the original except for the pid and the
2523da5c369Sopenharmony_ci/// return value of this function.  As an example:
2533da5c369Sopenharmony_ci///
2543da5c369Sopenharmony_ci/// ```
2553da5c369Sopenharmony_ci/// use nix::{sys::wait::waitpid,unistd::{fork, ForkResult, write}};
2563da5c369Sopenharmony_ci///
2573da5c369Sopenharmony_ci/// match unsafe{fork()} {
2583da5c369Sopenharmony_ci///    Ok(ForkResult::Parent { child, .. }) => {
2593da5c369Sopenharmony_ci///        println!("Continuing execution in parent process, new child has pid: {}", child);
2603da5c369Sopenharmony_ci///        waitpid(child, None).unwrap();
2613da5c369Sopenharmony_ci///    }
2623da5c369Sopenharmony_ci///    Ok(ForkResult::Child) => {
2633da5c369Sopenharmony_ci///        // Unsafe to use `println!` (or `unwrap`) here. See Safety.
2643da5c369Sopenharmony_ci///        write(libc::STDOUT_FILENO, "I'm a new child process\n".as_bytes()).ok();
2653da5c369Sopenharmony_ci///        unsafe { libc::_exit(0) };
2663da5c369Sopenharmony_ci///    }
2673da5c369Sopenharmony_ci///    Err(_) => println!("Fork failed"),
2683da5c369Sopenharmony_ci/// }
2693da5c369Sopenharmony_ci/// ```
2703da5c369Sopenharmony_ci///
2713da5c369Sopenharmony_ci/// This will print something like the following (order nondeterministic).  The
2723da5c369Sopenharmony_ci/// thing to note is that you end up with two processes continuing execution
2733da5c369Sopenharmony_ci/// immediately after the fork call but with different match arms.
2743da5c369Sopenharmony_ci///
2753da5c369Sopenharmony_ci/// ```text
2763da5c369Sopenharmony_ci/// Continuing execution in parent process, new child has pid: 1234
2773da5c369Sopenharmony_ci/// I'm a new child process
2783da5c369Sopenharmony_ci/// ```
2793da5c369Sopenharmony_ci///
2803da5c369Sopenharmony_ci/// # Safety
2813da5c369Sopenharmony_ci///
2823da5c369Sopenharmony_ci/// In a multithreaded program, only [async-signal-safe] functions like `pause`
2833da5c369Sopenharmony_ci/// and `_exit` may be called by the child (the parent isn't restricted). Note
2843da5c369Sopenharmony_ci/// that memory allocation may **not** be async-signal-safe and thus must be
2853da5c369Sopenharmony_ci/// prevented.
2863da5c369Sopenharmony_ci///
2873da5c369Sopenharmony_ci/// Those functions are only a small subset of your operating system's API, so
2883da5c369Sopenharmony_ci/// special care must be taken to only invoke code you can control and audit.
2893da5c369Sopenharmony_ci///
2903da5c369Sopenharmony_ci/// [async-signal-safe]: https://man7.org/linux/man-pages/man7/signal-safety.7.html
2913da5c369Sopenharmony_ci#[inline]
2923da5c369Sopenharmony_cipub unsafe fn fork() -> Result<ForkResult> {
2933da5c369Sopenharmony_ci    use self::ForkResult::*;
2943da5c369Sopenharmony_ci    let res = libc::fork();
2953da5c369Sopenharmony_ci
2963da5c369Sopenharmony_ci    Errno::result(res).map(|res| match res {
2973da5c369Sopenharmony_ci        0 => Child,
2983da5c369Sopenharmony_ci        res => Parent { child: Pid(res) },
2993da5c369Sopenharmony_ci    })
3003da5c369Sopenharmony_ci}
3013da5c369Sopenharmony_ci
3023da5c369Sopenharmony_ci/// Get the pid of this process (see
3033da5c369Sopenharmony_ci/// [getpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpid.html)).
3043da5c369Sopenharmony_ci///
3053da5c369Sopenharmony_ci/// Since you are running code, there is always a pid to return, so there
3063da5c369Sopenharmony_ci/// is no error case that needs to be handled.
3073da5c369Sopenharmony_ci#[inline]
3083da5c369Sopenharmony_cipub fn getpid() -> Pid {
3093da5c369Sopenharmony_ci    Pid(unsafe { libc::getpid() })
3103da5c369Sopenharmony_ci}
3113da5c369Sopenharmony_ci
3123da5c369Sopenharmony_ci/// Get the pid of this processes' parent (see
3133da5c369Sopenharmony_ci/// [getpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getppid.html)).
3143da5c369Sopenharmony_ci///
3153da5c369Sopenharmony_ci/// There is always a parent pid to return, so there is no error case that needs
3163da5c369Sopenharmony_ci/// to be handled.
3173da5c369Sopenharmony_ci#[inline]
3183da5c369Sopenharmony_cipub fn getppid() -> Pid {
3193da5c369Sopenharmony_ci    Pid(unsafe { libc::getppid() }) // no error handling, according to man page: "These functions are always successful."
3203da5c369Sopenharmony_ci}
3213da5c369Sopenharmony_ci
3223da5c369Sopenharmony_ci/// Set a process group ID (see
3233da5c369Sopenharmony_ci/// [setpgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html)).
3243da5c369Sopenharmony_ci///
3253da5c369Sopenharmony_ci/// Set the process group id (PGID) of a particular process.  If a pid of zero
3263da5c369Sopenharmony_ci/// is specified, then the pid of the calling process is used.  Process groups
3273da5c369Sopenharmony_ci/// may be used to group together a set of processes in order for the OS to
3283da5c369Sopenharmony_ci/// apply some operations across the group.
3293da5c369Sopenharmony_ci///
3303da5c369Sopenharmony_ci/// `setsid()` may be used to create a new process group.
3313da5c369Sopenharmony_ci#[inline]
3323da5c369Sopenharmony_cipub fn setpgid(pid: Pid, pgid: Pid) -> Result<()> {
3333da5c369Sopenharmony_ci    let res = unsafe { libc::setpgid(pid.into(), pgid.into()) };
3343da5c369Sopenharmony_ci    Errno::result(res).map(drop)
3353da5c369Sopenharmony_ci}
3363da5c369Sopenharmony_ci#[inline]
3373da5c369Sopenharmony_cipub fn getpgid(pid: Option<Pid>) -> Result<Pid> {
3383da5c369Sopenharmony_ci    let res = unsafe { libc::getpgid(pid.unwrap_or(Pid(0)).into()) };
3393da5c369Sopenharmony_ci    Errno::result(res).map(Pid)
3403da5c369Sopenharmony_ci}
3413da5c369Sopenharmony_ci
3423da5c369Sopenharmony_ci/// Create new session and set process group id (see
3433da5c369Sopenharmony_ci/// [setsid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html)).
3443da5c369Sopenharmony_ci#[inline]
3453da5c369Sopenharmony_cipub fn setsid() -> Result<Pid> {
3463da5c369Sopenharmony_ci    Errno::result(unsafe { libc::setsid() }).map(Pid)
3473da5c369Sopenharmony_ci}
3483da5c369Sopenharmony_ci
3493da5c369Sopenharmony_ci/// Get the process group ID of a session leader
3503da5c369Sopenharmony_ci/// [getsid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsid.html).
3513da5c369Sopenharmony_ci///
3523da5c369Sopenharmony_ci/// Obtain the process group ID of the process that is the session leader of the process specified
3533da5c369Sopenharmony_ci/// by pid. If pid is zero, it specifies the calling process.
3543da5c369Sopenharmony_ci#[inline]
3553da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))]
3563da5c369Sopenharmony_cipub fn getsid(pid: Option<Pid>) -> Result<Pid> {
3573da5c369Sopenharmony_ci    let res = unsafe { libc::getsid(pid.unwrap_or(Pid(0)).into()) };
3583da5c369Sopenharmony_ci    Errno::result(res).map(Pid)
3593da5c369Sopenharmony_ci}
3603da5c369Sopenharmony_ci}
3613da5c369Sopenharmony_ci
3623da5c369Sopenharmony_cifeature! {
3633da5c369Sopenharmony_ci#![all(feature = "process", feature = "term")]
3643da5c369Sopenharmony_ci/// Get the terminal foreground process group (see
3653da5c369Sopenharmony_ci/// [tcgetpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetpgrp.html)).
3663da5c369Sopenharmony_ci///
3673da5c369Sopenharmony_ci/// Get the group process id (GPID) of the foreground process group on the
3683da5c369Sopenharmony_ci/// terminal associated to file descriptor (FD).
3693da5c369Sopenharmony_ci#[inline]
3703da5c369Sopenharmony_cipub fn tcgetpgrp(fd: c_int) -> Result<Pid> {
3713da5c369Sopenharmony_ci    let res = unsafe { libc::tcgetpgrp(fd) };
3723da5c369Sopenharmony_ci    Errno::result(res).map(Pid)
3733da5c369Sopenharmony_ci}
3743da5c369Sopenharmony_ci/// Set the terminal foreground process group (see
3753da5c369Sopenharmony_ci/// [tcgetpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetpgrp.html)).
3763da5c369Sopenharmony_ci///
3773da5c369Sopenharmony_ci/// Get the group process id (PGID) to the foreground process group on the
3783da5c369Sopenharmony_ci/// terminal associated to file descriptor (FD).
3793da5c369Sopenharmony_ci#[inline]
3803da5c369Sopenharmony_cipub fn tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()> {
3813da5c369Sopenharmony_ci    let res = unsafe { libc::tcsetpgrp(fd, pgrp.into()) };
3823da5c369Sopenharmony_ci    Errno::result(res).map(drop)
3833da5c369Sopenharmony_ci}
3843da5c369Sopenharmony_ci}
3853da5c369Sopenharmony_ci
3863da5c369Sopenharmony_cifeature! {
3873da5c369Sopenharmony_ci#![feature = "process"]
3883da5c369Sopenharmony_ci/// Get the group id of the calling process (see
3893da5c369Sopenharmony_ci///[getpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html)).
3903da5c369Sopenharmony_ci///
3913da5c369Sopenharmony_ci/// Get the process group id (PGID) of the calling process.
3923da5c369Sopenharmony_ci/// According to the man page it is always successful.
3933da5c369Sopenharmony_ci#[inline]
3943da5c369Sopenharmony_cipub fn getpgrp() -> Pid {
3953da5c369Sopenharmony_ci    Pid(unsafe { libc::getpgrp() })
3963da5c369Sopenharmony_ci}
3973da5c369Sopenharmony_ci
3983da5c369Sopenharmony_ci/// Get the caller's thread ID (see
3993da5c369Sopenharmony_ci/// [gettid(2)](https://man7.org/linux/man-pages/man2/gettid.2.html).
4003da5c369Sopenharmony_ci///
4013da5c369Sopenharmony_ci/// This function is only available on Linux based systems.  In a single
4023da5c369Sopenharmony_ci/// threaded process, the main thread will have the same ID as the process.  In
4033da5c369Sopenharmony_ci/// a multithreaded process, each thread will have a unique thread id but the
4043da5c369Sopenharmony_ci/// same process ID.
4053da5c369Sopenharmony_ci///
4063da5c369Sopenharmony_ci/// No error handling is required as a thread id should always exist for any
4073da5c369Sopenharmony_ci/// process, even if threads are not being used.
4083da5c369Sopenharmony_ci#[cfg(any(target_os = "linux", target_os = "android"))]
4093da5c369Sopenharmony_ci#[inline]
4103da5c369Sopenharmony_cipub fn gettid() -> Pid {
4113da5c369Sopenharmony_ci    Pid(unsafe { libc::syscall(libc::SYS_gettid) as pid_t })
4123da5c369Sopenharmony_ci}
4133da5c369Sopenharmony_ci}
4143da5c369Sopenharmony_ci
4153da5c369Sopenharmony_cifeature! {
4163da5c369Sopenharmony_ci#![feature = "fs"]
4173da5c369Sopenharmony_ci/// Create a copy of the specified file descriptor (see
4183da5c369Sopenharmony_ci/// [dup(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)).
4193da5c369Sopenharmony_ci///
4203da5c369Sopenharmony_ci/// The new file descriptor will have a new index but refer to the same
4213da5c369Sopenharmony_ci/// resource as the old file descriptor and the old and new file descriptors may
4223da5c369Sopenharmony_ci/// be used interchangeably.  The new and old file descriptor share the same
4233da5c369Sopenharmony_ci/// underlying resource, offset, and file status flags.  The actual index used
4243da5c369Sopenharmony_ci/// for the file descriptor will be the lowest fd index that is available.
4253da5c369Sopenharmony_ci///
4263da5c369Sopenharmony_ci/// The two file descriptors do not share file descriptor flags (e.g. `OFlag::FD_CLOEXEC`).
4273da5c369Sopenharmony_ci#[inline]
4283da5c369Sopenharmony_cipub fn dup(oldfd: RawFd) -> Result<RawFd> {
4293da5c369Sopenharmony_ci    let res = unsafe { libc::dup(oldfd) };
4303da5c369Sopenharmony_ci
4313da5c369Sopenharmony_ci    Errno::result(res)
4323da5c369Sopenharmony_ci}
4333da5c369Sopenharmony_ci
4343da5c369Sopenharmony_ci/// Create a copy of the specified file descriptor using the specified fd (see
4353da5c369Sopenharmony_ci/// [dup(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)).
4363da5c369Sopenharmony_ci///
4373da5c369Sopenharmony_ci/// This function behaves similar to `dup()` except that it will try to use the
4383da5c369Sopenharmony_ci/// specified fd instead of allocating a new one.  See the man pages for more
4393da5c369Sopenharmony_ci/// detail on the exact behavior of this function.
4403da5c369Sopenharmony_ci#[inline]
4413da5c369Sopenharmony_cipub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd> {
4423da5c369Sopenharmony_ci    let res = unsafe { libc::dup2(oldfd, newfd) };
4433da5c369Sopenharmony_ci
4443da5c369Sopenharmony_ci    Errno::result(res)
4453da5c369Sopenharmony_ci}
4463da5c369Sopenharmony_ci
4473da5c369Sopenharmony_ci/// Create a new copy of the specified file descriptor using the specified fd
4483da5c369Sopenharmony_ci/// and flags (see [dup(2)](https://man7.org/linux/man-pages/man2/dup.2.html)).
4493da5c369Sopenharmony_ci///
4503da5c369Sopenharmony_ci/// This function behaves similar to `dup2()` but allows for flags to be
4513da5c369Sopenharmony_ci/// specified.
4523da5c369Sopenharmony_cipub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
4533da5c369Sopenharmony_ci    dup3_polyfill(oldfd, newfd, flags)
4543da5c369Sopenharmony_ci}
4553da5c369Sopenharmony_ci
4563da5c369Sopenharmony_ci#[inline]
4573da5c369Sopenharmony_cifn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
4583da5c369Sopenharmony_ci    if oldfd == newfd {
4593da5c369Sopenharmony_ci        return Err(Errno::EINVAL);
4603da5c369Sopenharmony_ci    }
4613da5c369Sopenharmony_ci
4623da5c369Sopenharmony_ci    let fd = dup2(oldfd, newfd)?;
4633da5c369Sopenharmony_ci
4643da5c369Sopenharmony_ci    if flags.contains(OFlag::O_CLOEXEC) {
4653da5c369Sopenharmony_ci        if let Err(e) = fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC)) {
4663da5c369Sopenharmony_ci            let _ = close(fd);
4673da5c369Sopenharmony_ci            return Err(e);
4683da5c369Sopenharmony_ci        }
4693da5c369Sopenharmony_ci    }
4703da5c369Sopenharmony_ci
4713da5c369Sopenharmony_ci    Ok(fd)
4723da5c369Sopenharmony_ci}
4733da5c369Sopenharmony_ci
4743da5c369Sopenharmony_ci/// Change the current working directory of the calling process (see
4753da5c369Sopenharmony_ci/// [chdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html)).
4763da5c369Sopenharmony_ci///
4773da5c369Sopenharmony_ci/// This function may fail in a number of different scenarios.  See the man
4783da5c369Sopenharmony_ci/// pages for additional details on possible failure cases.
4793da5c369Sopenharmony_ci#[inline]
4803da5c369Sopenharmony_cipub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> {
4813da5c369Sopenharmony_ci    let res = path.with_nix_path(|cstr| {
4823da5c369Sopenharmony_ci        unsafe { libc::chdir(cstr.as_ptr()) }
4833da5c369Sopenharmony_ci    })?;
4843da5c369Sopenharmony_ci
4853da5c369Sopenharmony_ci    Errno::result(res).map(drop)
4863da5c369Sopenharmony_ci}
4873da5c369Sopenharmony_ci
4883da5c369Sopenharmony_ci/// Change the current working directory of the process to the one
4893da5c369Sopenharmony_ci/// given as an open file descriptor (see
4903da5c369Sopenharmony_ci/// [fchdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html)).
4913da5c369Sopenharmony_ci///
4923da5c369Sopenharmony_ci/// This function may fail in a number of different scenarios.  See the man
4933da5c369Sopenharmony_ci/// pages for additional details on possible failure cases.
4943da5c369Sopenharmony_ci#[inline]
4953da5c369Sopenharmony_ci#[cfg(not(target_os = "fuchsia"))]
4963da5c369Sopenharmony_cipub fn fchdir(dirfd: RawFd) -> Result<()> {
4973da5c369Sopenharmony_ci    let res = unsafe { libc::fchdir(dirfd) };
4983da5c369Sopenharmony_ci
4993da5c369Sopenharmony_ci    Errno::result(res).map(drop)
5003da5c369Sopenharmony_ci}
5013da5c369Sopenharmony_ci
5023da5c369Sopenharmony_ci/// Creates new directory `path` with access rights `mode`.  (see [mkdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html))
5033da5c369Sopenharmony_ci///
5043da5c369Sopenharmony_ci/// # Errors
5053da5c369Sopenharmony_ci///
5063da5c369Sopenharmony_ci/// There are several situations where mkdir might fail:
5073da5c369Sopenharmony_ci///
5083da5c369Sopenharmony_ci/// - current user has insufficient rights in the parent directory
5093da5c369Sopenharmony_ci/// - the path already exists
5103da5c369Sopenharmony_ci/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X)
5113da5c369Sopenharmony_ci///
5123da5c369Sopenharmony_ci/// # Example
5133da5c369Sopenharmony_ci///
5143da5c369Sopenharmony_ci/// ```rust
5153da5c369Sopenharmony_ci/// use nix::unistd;
5163da5c369Sopenharmony_ci/// use nix::sys::stat;
5173da5c369Sopenharmony_ci/// use tempfile::tempdir;
5183da5c369Sopenharmony_ci///
5193da5c369Sopenharmony_ci/// let tmp_dir1 = tempdir().unwrap();
5203da5c369Sopenharmony_ci/// let tmp_dir2 = tmp_dir1.path().join("new_dir");
5213da5c369Sopenharmony_ci///
5223da5c369Sopenharmony_ci/// // create new directory and give read, write and execute rights to the owner
5233da5c369Sopenharmony_ci/// match unistd::mkdir(&tmp_dir2, stat::Mode::S_IRWXU) {
5243da5c369Sopenharmony_ci///    Ok(_) => println!("created {:?}", tmp_dir2),
5253da5c369Sopenharmony_ci///    Err(err) => println!("Error creating directory: {}", err),
5263da5c369Sopenharmony_ci/// }
5273da5c369Sopenharmony_ci/// ```
5283da5c369Sopenharmony_ci#[inline]
5293da5c369Sopenharmony_cipub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
5303da5c369Sopenharmony_ci    let res = path.with_nix_path(|cstr| {
5313da5c369Sopenharmony_ci        unsafe { libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t) }
5323da5c369Sopenharmony_ci    })?;
5333da5c369Sopenharmony_ci
5343da5c369Sopenharmony_ci    Errno::result(res).map(drop)
5353da5c369Sopenharmony_ci}
5363da5c369Sopenharmony_ci
5373da5c369Sopenharmony_ci/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`.
5383da5c369Sopenharmony_ci///
5393da5c369Sopenharmony_ci/// # Errors
5403da5c369Sopenharmony_ci///
5413da5c369Sopenharmony_ci/// There are several situations where mkfifo might fail:
5423da5c369Sopenharmony_ci///
5433da5c369Sopenharmony_ci/// - current user has insufficient rights in the parent directory
5443da5c369Sopenharmony_ci/// - the path already exists
5453da5c369Sopenharmony_ci/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X)
5463da5c369Sopenharmony_ci///
5473da5c369Sopenharmony_ci/// For a full list consult
5483da5c369Sopenharmony_ci/// [posix specification](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html)
5493da5c369Sopenharmony_ci///
5503da5c369Sopenharmony_ci/// # Example
5513da5c369Sopenharmony_ci///
5523da5c369Sopenharmony_ci/// ```rust
5533da5c369Sopenharmony_ci/// use nix::unistd;
5543da5c369Sopenharmony_ci/// use nix::sys::stat;
5553da5c369Sopenharmony_ci/// use tempfile::tempdir;
5563da5c369Sopenharmony_ci///
5573da5c369Sopenharmony_ci/// let tmp_dir = tempdir().unwrap();
5583da5c369Sopenharmony_ci/// let fifo_path = tmp_dir.path().join("foo.pipe");
5593da5c369Sopenharmony_ci///
5603da5c369Sopenharmony_ci/// // create new fifo and give read, write and execute rights to the owner
5613da5c369Sopenharmony_ci/// match unistd::mkfifo(&fifo_path, stat::Mode::S_IRWXU) {
5623da5c369Sopenharmony_ci///    Ok(_) => println!("created {:?}", fifo_path),
5633da5c369Sopenharmony_ci///    Err(err) => println!("Error creating fifo: {}", err),
5643da5c369Sopenharmony_ci/// }
5653da5c369Sopenharmony_ci/// ```
5663da5c369Sopenharmony_ci#[inline]
5673da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] // RedoxFS does not support fifo yet
5683da5c369Sopenharmony_cipub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
5693da5c369Sopenharmony_ci    let res = path.with_nix_path(|cstr| {
5703da5c369Sopenharmony_ci        unsafe { libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t) }
5713da5c369Sopenharmony_ci    })?;
5723da5c369Sopenharmony_ci
5733da5c369Sopenharmony_ci    Errno::result(res).map(drop)
5743da5c369Sopenharmony_ci}
5753da5c369Sopenharmony_ci
5763da5c369Sopenharmony_ci/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`.
5773da5c369Sopenharmony_ci///
5783da5c369Sopenharmony_ci/// If `dirfd` has a value, then `path` is relative to directory associated with the file descriptor.
5793da5c369Sopenharmony_ci///
5803da5c369Sopenharmony_ci/// If `dirfd` is `None`, then `path` is relative to the current working directory.
5813da5c369Sopenharmony_ci///
5823da5c369Sopenharmony_ci/// # References
5833da5c369Sopenharmony_ci///
5843da5c369Sopenharmony_ci/// [mkfifoat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifoat.html).
5853da5c369Sopenharmony_ci// mkfifoat is not implemented in OSX or android
5863da5c369Sopenharmony_ci#[inline]
5873da5c369Sopenharmony_ci#[cfg(not(any(
5883da5c369Sopenharmony_ci    target_os = "macos", target_os = "ios", target_os = "haiku",
5893da5c369Sopenharmony_ci    target_os = "android", target_os = "redox")))]
5903da5c369Sopenharmony_cipub fn mkfifoat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: Mode) -> Result<()> {
5913da5c369Sopenharmony_ci    let res = path.with_nix_path(|cstr| unsafe {
5923da5c369Sopenharmony_ci        libc::mkfifoat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits() as mode_t)
5933da5c369Sopenharmony_ci    })?;
5943da5c369Sopenharmony_ci
5953da5c369Sopenharmony_ci    Errno::result(res).map(drop)
5963da5c369Sopenharmony_ci}
5973da5c369Sopenharmony_ci
5983da5c369Sopenharmony_ci/// Creates a symbolic link at `path2` which points to `path1`.
5993da5c369Sopenharmony_ci///
6003da5c369Sopenharmony_ci/// If `dirfd` has a value, then `path2` is relative to directory associated
6013da5c369Sopenharmony_ci/// with the file descriptor.
6023da5c369Sopenharmony_ci///
6033da5c369Sopenharmony_ci/// If `dirfd` is `None`, then `path2` is relative to the current working
6043da5c369Sopenharmony_ci/// directory. This is identical to `libc::symlink(path1, path2)`.
6053da5c369Sopenharmony_ci///
6063da5c369Sopenharmony_ci/// See also [symlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html).
6073da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))]
6083da5c369Sopenharmony_cipub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
6093da5c369Sopenharmony_ci    path1: &P1,
6103da5c369Sopenharmony_ci    dirfd: Option<RawFd>,
6113da5c369Sopenharmony_ci    path2: &P2) -> Result<()> {
6123da5c369Sopenharmony_ci    let res =
6133da5c369Sopenharmony_ci        path1.with_nix_path(|path1| {
6143da5c369Sopenharmony_ci            path2.with_nix_path(|path2| {
6153da5c369Sopenharmony_ci                unsafe {
6163da5c369Sopenharmony_ci                    libc::symlinkat(
6173da5c369Sopenharmony_ci                        path1.as_ptr(),
6183da5c369Sopenharmony_ci                        dirfd.unwrap_or(libc::AT_FDCWD),
6193da5c369Sopenharmony_ci                        path2.as_ptr()
6203da5c369Sopenharmony_ci                    )
6213da5c369Sopenharmony_ci                }
6223da5c369Sopenharmony_ci            })
6233da5c369Sopenharmony_ci        })??;
6243da5c369Sopenharmony_ci    Errno::result(res).map(drop)
6253da5c369Sopenharmony_ci}
6263da5c369Sopenharmony_ci}
6273da5c369Sopenharmony_ci
6283da5c369Sopenharmony_ci// Double the buffer capacity up to limit. In case it already has
6293da5c369Sopenharmony_ci// reached the limit, return Errno::ERANGE.
6303da5c369Sopenharmony_ci#[cfg(any(feature = "fs", feature = "user"))]
6313da5c369Sopenharmony_cifn reserve_double_buffer_size<T>(buf: &mut Vec<T>, limit: usize) -> Result<()> {
6323da5c369Sopenharmony_ci    use std::cmp::min;
6333da5c369Sopenharmony_ci
6343da5c369Sopenharmony_ci    if buf.capacity() >= limit {
6353da5c369Sopenharmony_ci        return Err(Errno::ERANGE);
6363da5c369Sopenharmony_ci    }
6373da5c369Sopenharmony_ci
6383da5c369Sopenharmony_ci    let capacity = min(buf.capacity() * 2, limit);
6393da5c369Sopenharmony_ci    buf.reserve(capacity);
6403da5c369Sopenharmony_ci
6413da5c369Sopenharmony_ci    Ok(())
6423da5c369Sopenharmony_ci}
6433da5c369Sopenharmony_ci
6443da5c369Sopenharmony_cifeature! {
6453da5c369Sopenharmony_ci#![feature = "fs"]
6463da5c369Sopenharmony_ci
6473da5c369Sopenharmony_ci/// Returns the current directory as a `PathBuf`
6483da5c369Sopenharmony_ci///
6493da5c369Sopenharmony_ci/// Err is returned if the current user doesn't have the permission to read or search a component
6503da5c369Sopenharmony_ci/// of the current path.
6513da5c369Sopenharmony_ci///
6523da5c369Sopenharmony_ci/// # Example
6533da5c369Sopenharmony_ci///
6543da5c369Sopenharmony_ci/// ```rust
6553da5c369Sopenharmony_ci/// use nix::unistd;
6563da5c369Sopenharmony_ci///
6573da5c369Sopenharmony_ci/// // assume that we are allowed to get current directory
6583da5c369Sopenharmony_ci/// let dir = unistd::getcwd().unwrap();
6593da5c369Sopenharmony_ci/// println!("The current directory is {:?}", dir);
6603da5c369Sopenharmony_ci/// ```
6613da5c369Sopenharmony_ci#[inline]
6623da5c369Sopenharmony_cipub fn getcwd() -> Result<PathBuf> {
6633da5c369Sopenharmony_ci    let mut buf = Vec::with_capacity(512);
6643da5c369Sopenharmony_ci    loop {
6653da5c369Sopenharmony_ci        unsafe {
6663da5c369Sopenharmony_ci            let ptr = buf.as_mut_ptr() as *mut c_char;
6673da5c369Sopenharmony_ci
6683da5c369Sopenharmony_ci            // The buffer must be large enough to store the absolute pathname plus
6693da5c369Sopenharmony_ci            // a terminating null byte, or else null is returned.
6703da5c369Sopenharmony_ci            // To safely handle this we start with a reasonable size (512 bytes)
6713da5c369Sopenharmony_ci            // and double the buffer size upon every error
6723da5c369Sopenharmony_ci            if !libc::getcwd(ptr, buf.capacity()).is_null() {
6733da5c369Sopenharmony_ci                let len = CStr::from_ptr(buf.as_ptr() as *const c_char).to_bytes().len();
6743da5c369Sopenharmony_ci                buf.set_len(len);
6753da5c369Sopenharmony_ci                buf.shrink_to_fit();
6763da5c369Sopenharmony_ci                return Ok(PathBuf::from(OsString::from_vec(buf)));
6773da5c369Sopenharmony_ci            } else {
6783da5c369Sopenharmony_ci                let error = Errno::last();
6793da5c369Sopenharmony_ci                // ERANGE means buffer was too small to store directory name
6803da5c369Sopenharmony_ci                if error != Errno::ERANGE {
6813da5c369Sopenharmony_ci                    return Err(error);
6823da5c369Sopenharmony_ci                }
6833da5c369Sopenharmony_ci           }
6843da5c369Sopenharmony_ci
6853da5c369Sopenharmony_ci            // Trigger the internal buffer resizing logic.
6863da5c369Sopenharmony_ci            reserve_double_buffer_size(&mut buf, PATH_MAX as usize)?;
6873da5c369Sopenharmony_ci        }
6883da5c369Sopenharmony_ci    }
6893da5c369Sopenharmony_ci}
6903da5c369Sopenharmony_ci}
6913da5c369Sopenharmony_ci
6923da5c369Sopenharmony_cifeature! {
6933da5c369Sopenharmony_ci#![all(feature = "user", feature = "fs")]
6943da5c369Sopenharmony_ci
6953da5c369Sopenharmony_ci/// Computes the raw UID and GID values to pass to a `*chown` call.
6963da5c369Sopenharmony_ci// The cast is not unnecessary on all platforms.
6973da5c369Sopenharmony_ci#[allow(clippy::unnecessary_cast)]
6983da5c369Sopenharmony_cifn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc::gid_t) {
6993da5c369Sopenharmony_ci    // According to the POSIX specification, -1 is used to indicate that owner and group
7003da5c369Sopenharmony_ci    // are not to be changed.  Since uid_t and gid_t are unsigned types, we have to wrap
7013da5c369Sopenharmony_ci    // around to get -1.
7023da5c369Sopenharmony_ci    let uid = owner.map(Into::into)
7033da5c369Sopenharmony_ci        .unwrap_or_else(|| (0 as uid_t).wrapping_sub(1));
7043da5c369Sopenharmony_ci    let gid = group.map(Into::into)
7053da5c369Sopenharmony_ci        .unwrap_or_else(|| (0 as gid_t).wrapping_sub(1));
7063da5c369Sopenharmony_ci    (uid, gid)
7073da5c369Sopenharmony_ci}
7083da5c369Sopenharmony_ci
7093da5c369Sopenharmony_ci/// Change the ownership of the file at `path` to be owned by the specified
7103da5c369Sopenharmony_ci/// `owner` (user) and `group` (see
7113da5c369Sopenharmony_ci/// [chown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html)).
7123da5c369Sopenharmony_ci///
7133da5c369Sopenharmony_ci/// The owner/group for the provided path name will not be modified if `None` is
7143da5c369Sopenharmony_ci/// provided for that argument.  Ownership change will be attempted for the path
7153da5c369Sopenharmony_ci/// only if `Some` owner/group is provided.
7163da5c369Sopenharmony_ci#[inline]
7173da5c369Sopenharmony_cipub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
7183da5c369Sopenharmony_ci    let res = path.with_nix_path(|cstr| {
7193da5c369Sopenharmony_ci        let (uid, gid) = chown_raw_ids(owner, group);
7203da5c369Sopenharmony_ci        unsafe { libc::chown(cstr.as_ptr(), uid, gid) }
7213da5c369Sopenharmony_ci    })?;
7223da5c369Sopenharmony_ci
7233da5c369Sopenharmony_ci    Errno::result(res).map(drop)
7243da5c369Sopenharmony_ci}
7253da5c369Sopenharmony_ci
7263da5c369Sopenharmony_ci/// Change the ownership of the file referred to by the open file descriptor `fd` to be owned by
7273da5c369Sopenharmony_ci/// the specified `owner` (user) and `group` (see
7283da5c369Sopenharmony_ci/// [fchown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchown.html)).
7293da5c369Sopenharmony_ci///
7303da5c369Sopenharmony_ci/// The owner/group for the provided file will not be modified if `None` is
7313da5c369Sopenharmony_ci/// provided for that argument.  Ownership change will be attempted for the path
7323da5c369Sopenharmony_ci/// only if `Some` owner/group is provided.
7333da5c369Sopenharmony_ci#[inline]
7343da5c369Sopenharmony_cipub fn fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
7353da5c369Sopenharmony_ci    let (uid, gid) = chown_raw_ids(owner, group);
7363da5c369Sopenharmony_ci    let res = unsafe { libc::fchown(fd, uid, gid) };
7373da5c369Sopenharmony_ci    Errno::result(res).map(drop)
7383da5c369Sopenharmony_ci}
7393da5c369Sopenharmony_ci
7403da5c369Sopenharmony_ci/// Flags for `fchownat` function.
7413da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug)]
7423da5c369Sopenharmony_cipub enum FchownatFlags {
7433da5c369Sopenharmony_ci    FollowSymlink,
7443da5c369Sopenharmony_ci    NoFollowSymlink,
7453da5c369Sopenharmony_ci}
7463da5c369Sopenharmony_ci
7473da5c369Sopenharmony_ci/// Change the ownership of the file at `path` to be owned by the specified
7483da5c369Sopenharmony_ci/// `owner` (user) and `group`.
7493da5c369Sopenharmony_ci///
7503da5c369Sopenharmony_ci/// The owner/group for the provided path name will not be modified if `None` is
7513da5c369Sopenharmony_ci/// provided for that argument.  Ownership change will be attempted for the path
7523da5c369Sopenharmony_ci/// only if `Some` owner/group is provided.
7533da5c369Sopenharmony_ci///
7543da5c369Sopenharmony_ci/// The file to be changed is determined relative to the directory associated
7553da5c369Sopenharmony_ci/// with the file descriptor `dirfd` or the current working directory
7563da5c369Sopenharmony_ci/// if `dirfd` is `None`.
7573da5c369Sopenharmony_ci///
7583da5c369Sopenharmony_ci/// If `flag` is `FchownatFlags::NoFollowSymlink` and `path` names a symbolic link,
7593da5c369Sopenharmony_ci/// then the mode of the symbolic link is changed.
7603da5c369Sopenharmony_ci///
7613da5c369Sopenharmony_ci/// `fchownat(None, path, owner, group, FchownatFlags::NoFollowSymlink)` is identical to
7623da5c369Sopenharmony_ci/// a call `libc::lchown(path, owner, group)`.  That's why `lchown` is unimplemented in
7633da5c369Sopenharmony_ci/// the `nix` crate.
7643da5c369Sopenharmony_ci///
7653da5c369Sopenharmony_ci/// # References
7663da5c369Sopenharmony_ci///
7673da5c369Sopenharmony_ci/// [fchownat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html).
7683da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))]
7693da5c369Sopenharmony_cipub fn fchownat<P: ?Sized + NixPath>(
7703da5c369Sopenharmony_ci    dirfd: Option<RawFd>,
7713da5c369Sopenharmony_ci    path: &P,
7723da5c369Sopenharmony_ci    owner: Option<Uid>,
7733da5c369Sopenharmony_ci    group: Option<Gid>,
7743da5c369Sopenharmony_ci    flag: FchownatFlags,
7753da5c369Sopenharmony_ci) -> Result<()> {
7763da5c369Sopenharmony_ci    let atflag =
7773da5c369Sopenharmony_ci        match flag {
7783da5c369Sopenharmony_ci            FchownatFlags::FollowSymlink => AtFlags::empty(),
7793da5c369Sopenharmony_ci            FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
7803da5c369Sopenharmony_ci        };
7813da5c369Sopenharmony_ci    let res = path.with_nix_path(|cstr| unsafe {
7823da5c369Sopenharmony_ci        let (uid, gid) = chown_raw_ids(owner, group);
7833da5c369Sopenharmony_ci        libc::fchownat(at_rawfd(dirfd), cstr.as_ptr(), uid, gid,
7843da5c369Sopenharmony_ci                       atflag.bits() as libc::c_int)
7853da5c369Sopenharmony_ci    })?;
7863da5c369Sopenharmony_ci
7873da5c369Sopenharmony_ci    Errno::result(res).map(drop)
7883da5c369Sopenharmony_ci}
7893da5c369Sopenharmony_ci}
7903da5c369Sopenharmony_ci
7913da5c369Sopenharmony_cifeature! {
7923da5c369Sopenharmony_ci#![feature = "process"]
7933da5c369Sopenharmony_cifn to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*const c_char> {
7943da5c369Sopenharmony_ci    use std::iter::once;
7953da5c369Sopenharmony_ci    args.iter()
7963da5c369Sopenharmony_ci        .map(|s| s.as_ref().as_ptr())
7973da5c369Sopenharmony_ci        .chain(once(ptr::null()))
7983da5c369Sopenharmony_ci        .collect()
7993da5c369Sopenharmony_ci}
8003da5c369Sopenharmony_ci
8013da5c369Sopenharmony_ci/// Replace the current process image with a new one (see
8023da5c369Sopenharmony_ci/// [exec(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
8033da5c369Sopenharmony_ci///
8043da5c369Sopenharmony_ci/// See the `::nix::unistd::execve` system call for additional details.  `execv`
8053da5c369Sopenharmony_ci/// performs the same action but does not allow for customization of the
8063da5c369Sopenharmony_ci/// environment for the new process.
8073da5c369Sopenharmony_ci#[inline]
8083da5c369Sopenharmony_cipub fn execv<S: AsRef<CStr>>(path: &CStr, argv: &[S]) -> Result<Infallible> {
8093da5c369Sopenharmony_ci    let args_p = to_exec_array(argv);
8103da5c369Sopenharmony_ci
8113da5c369Sopenharmony_ci    unsafe {
8123da5c369Sopenharmony_ci        libc::execv(path.as_ptr(), args_p.as_ptr())
8133da5c369Sopenharmony_ci    };
8143da5c369Sopenharmony_ci
8153da5c369Sopenharmony_ci    Err(Errno::last())
8163da5c369Sopenharmony_ci}
8173da5c369Sopenharmony_ci
8183da5c369Sopenharmony_ci
8193da5c369Sopenharmony_ci/// Replace the current process image with a new one (see
8203da5c369Sopenharmony_ci/// [execve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
8213da5c369Sopenharmony_ci///
8223da5c369Sopenharmony_ci/// The execve system call allows for another process to be "called" which will
8233da5c369Sopenharmony_ci/// replace the current process image.  That is, this process becomes the new
8243da5c369Sopenharmony_ci/// command that is run. On success, this function will not return. Instead,
8253da5c369Sopenharmony_ci/// the new program will run until it exits.
8263da5c369Sopenharmony_ci///
8273da5c369Sopenharmony_ci/// `::nix::unistd::execv` and `::nix::unistd::execve` take as arguments a slice
8283da5c369Sopenharmony_ci/// of `::std::ffi::CString`s for `args` and `env` (for `execve`). Each element
8293da5c369Sopenharmony_ci/// in the `args` list is an argument to the new process. Each element in the
8303da5c369Sopenharmony_ci/// `env` list should be a string in the form "key=value".
8313da5c369Sopenharmony_ci#[inline]
8323da5c369Sopenharmony_cipub fn execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(path: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> {
8333da5c369Sopenharmony_ci    let args_p = to_exec_array(args);
8343da5c369Sopenharmony_ci    let env_p = to_exec_array(env);
8353da5c369Sopenharmony_ci
8363da5c369Sopenharmony_ci    unsafe {
8373da5c369Sopenharmony_ci        libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
8383da5c369Sopenharmony_ci    };
8393da5c369Sopenharmony_ci
8403da5c369Sopenharmony_ci    Err(Errno::last())
8413da5c369Sopenharmony_ci}
8423da5c369Sopenharmony_ci
8433da5c369Sopenharmony_ci/// Replace the current process image with a new one and replicate shell `PATH`
8443da5c369Sopenharmony_ci/// searching behavior (see
8453da5c369Sopenharmony_ci/// [exec(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
8463da5c369Sopenharmony_ci///
8473da5c369Sopenharmony_ci/// See `::nix::unistd::execve` for additional details.  `execvp` behaves the
8483da5c369Sopenharmony_ci/// same as execv except that it will examine the `PATH` environment variables
8493da5c369Sopenharmony_ci/// for file names not specified with a leading slash.  For example, `execv`
8503da5c369Sopenharmony_ci/// would not work if "bash" was specified for the path argument, but `execvp`
8513da5c369Sopenharmony_ci/// would assuming that a bash executable was on the system `PATH`.
8523da5c369Sopenharmony_ci#[inline]
8533da5c369Sopenharmony_cipub fn execvp<S: AsRef<CStr>>(filename: &CStr, args: &[S]) -> Result<Infallible> {
8543da5c369Sopenharmony_ci    let args_p = to_exec_array(args);
8553da5c369Sopenharmony_ci
8563da5c369Sopenharmony_ci    unsafe {
8573da5c369Sopenharmony_ci        libc::execvp(filename.as_ptr(), args_p.as_ptr())
8583da5c369Sopenharmony_ci    };
8593da5c369Sopenharmony_ci
8603da5c369Sopenharmony_ci    Err(Errno::last())
8613da5c369Sopenharmony_ci}
8623da5c369Sopenharmony_ci
8633da5c369Sopenharmony_ci/// Replace the current process image with a new one and replicate shell `PATH`
8643da5c369Sopenharmony_ci/// searching behavior (see
8653da5c369Sopenharmony_ci/// [`execvpe(3)`](https://man7.org/linux/man-pages/man3/exec.3.html)).
8663da5c369Sopenharmony_ci///
8673da5c369Sopenharmony_ci/// This functions like a combination of `execvp(2)` and `execve(2)` to pass an
8683da5c369Sopenharmony_ci/// environment and have a search path. See these two for additional
8693da5c369Sopenharmony_ci/// information.
8703da5c369Sopenharmony_ci#[cfg(any(target_os = "haiku",
8713da5c369Sopenharmony_ci          target_os = "linux",
8723da5c369Sopenharmony_ci          target_os = "openbsd"))]
8733da5c369Sopenharmony_cipub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(filename: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> {
8743da5c369Sopenharmony_ci    let args_p = to_exec_array(args);
8753da5c369Sopenharmony_ci    let env_p = to_exec_array(env);
8763da5c369Sopenharmony_ci
8773da5c369Sopenharmony_ci    unsafe {
8783da5c369Sopenharmony_ci        libc::execvpe(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
8793da5c369Sopenharmony_ci    };
8803da5c369Sopenharmony_ci
8813da5c369Sopenharmony_ci    Err(Errno::last())
8823da5c369Sopenharmony_ci}
8833da5c369Sopenharmony_ci
8843da5c369Sopenharmony_ci/// Replace the current process image with a new one (see
8853da5c369Sopenharmony_ci/// [fexecve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html)).
8863da5c369Sopenharmony_ci///
8873da5c369Sopenharmony_ci/// The `fexecve` function allows for another process to be "called" which will
8883da5c369Sopenharmony_ci/// replace the current process image.  That is, this process becomes the new
8893da5c369Sopenharmony_ci/// command that is run. On success, this function will not return. Instead,
8903da5c369Sopenharmony_ci/// the new program will run until it exits.
8913da5c369Sopenharmony_ci///
8923da5c369Sopenharmony_ci/// This function is similar to `execve`, except that the program to be executed
8933da5c369Sopenharmony_ci/// is referenced as a file descriptor instead of a path.
8943da5c369Sopenharmony_ci#[cfg(any(target_os = "android",
8953da5c369Sopenharmony_ci          target_os = "linux",
8963da5c369Sopenharmony_ci          target_os = "dragonfly",
8973da5c369Sopenharmony_ci          target_os = "freebsd"))]
8983da5c369Sopenharmony_ci#[inline]
8993da5c369Sopenharmony_cipub fn fexecve<SA: AsRef<CStr> ,SE: AsRef<CStr>>(fd: RawFd, args: &[SA], env: &[SE]) -> Result<Infallible> {
9003da5c369Sopenharmony_ci    let args_p = to_exec_array(args);
9013da5c369Sopenharmony_ci    let env_p = to_exec_array(env);
9023da5c369Sopenharmony_ci
9033da5c369Sopenharmony_ci    unsafe {
9043da5c369Sopenharmony_ci        libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr())
9053da5c369Sopenharmony_ci    };
9063da5c369Sopenharmony_ci
9073da5c369Sopenharmony_ci    Err(Errno::last())
9083da5c369Sopenharmony_ci}
9093da5c369Sopenharmony_ci
9103da5c369Sopenharmony_ci/// Execute program relative to a directory file descriptor (see
9113da5c369Sopenharmony_ci/// [execveat(2)](https://man7.org/linux/man-pages/man2/execveat.2.html)).
9123da5c369Sopenharmony_ci///
9133da5c369Sopenharmony_ci/// The `execveat` function allows for another process to be "called" which will
9143da5c369Sopenharmony_ci/// replace the current process image.  That is, this process becomes the new
9153da5c369Sopenharmony_ci/// command that is run. On success, this function will not return. Instead,
9163da5c369Sopenharmony_ci/// the new program will run until it exits.
9173da5c369Sopenharmony_ci///
9183da5c369Sopenharmony_ci/// This function is similar to `execve`, except that the program to be executed
9193da5c369Sopenharmony_ci/// is referenced as a file descriptor to the base directory plus a path.
9203da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
9213da5c369Sopenharmony_ci#[inline]
9223da5c369Sopenharmony_cipub fn execveat<SA: AsRef<CStr>,SE: AsRef<CStr>>(dirfd: RawFd, pathname: &CStr, args: &[SA],
9233da5c369Sopenharmony_ci                env: &[SE], flags: super::fcntl::AtFlags) -> Result<Infallible> {
9243da5c369Sopenharmony_ci    let args_p = to_exec_array(args);
9253da5c369Sopenharmony_ci    let env_p = to_exec_array(env);
9263da5c369Sopenharmony_ci
9273da5c369Sopenharmony_ci    unsafe {
9283da5c369Sopenharmony_ci        libc::syscall(libc::SYS_execveat, dirfd, pathname.as_ptr(),
9293da5c369Sopenharmony_ci                      args_p.as_ptr(), env_p.as_ptr(), flags);
9303da5c369Sopenharmony_ci    };
9313da5c369Sopenharmony_ci
9323da5c369Sopenharmony_ci    Err(Errno::last())
9333da5c369Sopenharmony_ci}
9343da5c369Sopenharmony_ci
9353da5c369Sopenharmony_ci/// Daemonize this process by detaching from the controlling terminal (see
9363da5c369Sopenharmony_ci/// [daemon(3)](https://man7.org/linux/man-pages/man3/daemon.3.html)).
9373da5c369Sopenharmony_ci///
9383da5c369Sopenharmony_ci/// When a process is launched it is typically associated with a parent and it,
9393da5c369Sopenharmony_ci/// in turn, by its controlling terminal/process.  In order for a process to run
9403da5c369Sopenharmony_ci/// in the "background" it must daemonize itself by detaching itself.  Under
9413da5c369Sopenharmony_ci/// posix, this is done by doing the following:
9423da5c369Sopenharmony_ci///
9433da5c369Sopenharmony_ci/// 1. Parent process (this one) forks
9443da5c369Sopenharmony_ci/// 2. Parent process exits
9453da5c369Sopenharmony_ci/// 3. Child process continues to run.
9463da5c369Sopenharmony_ci///
9473da5c369Sopenharmony_ci/// `nochdir`:
9483da5c369Sopenharmony_ci///
9493da5c369Sopenharmony_ci/// * `nochdir = true`: The current working directory after daemonizing will
9503da5c369Sopenharmony_ci///    be the current working directory.
9513da5c369Sopenharmony_ci/// *  `nochdir = false`: The current working directory after daemonizing will
9523da5c369Sopenharmony_ci///    be the root direcory, `/`.
9533da5c369Sopenharmony_ci///
9543da5c369Sopenharmony_ci/// `noclose`:
9553da5c369Sopenharmony_ci///
9563da5c369Sopenharmony_ci/// * `noclose = true`: The process' current stdin, stdout, and stderr file
9573da5c369Sopenharmony_ci///   descriptors will remain identical after daemonizing.
9583da5c369Sopenharmony_ci/// * `noclose = false`: The process' stdin, stdout, and stderr will point to
9593da5c369Sopenharmony_ci///   `/dev/null` after daemonizing.
9603da5c369Sopenharmony_ci#[cfg(any(target_os = "android",
9613da5c369Sopenharmony_ci          target_os = "dragonfly",
9623da5c369Sopenharmony_ci          target_os = "freebsd",
9633da5c369Sopenharmony_ci          target_os = "illumos",
9643da5c369Sopenharmony_ci          target_os = "linux",
9653da5c369Sopenharmony_ci          target_os = "netbsd",
9663da5c369Sopenharmony_ci          target_os = "openbsd",
9673da5c369Sopenharmony_ci          target_os = "solaris"))]
9683da5c369Sopenharmony_cipub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
9693da5c369Sopenharmony_ci    let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) };
9703da5c369Sopenharmony_ci    Errno::result(res).map(drop)
9713da5c369Sopenharmony_ci}
9723da5c369Sopenharmony_ci}
9733da5c369Sopenharmony_ci
9743da5c369Sopenharmony_cifeature! {
9753da5c369Sopenharmony_ci#![feature = "hostname"]
9763da5c369Sopenharmony_ci
9773da5c369Sopenharmony_ci/// Set the system host name (see
9783da5c369Sopenharmony_ci/// [sethostname(2)](https://man7.org/linux/man-pages/man2/gethostname.2.html)).
9793da5c369Sopenharmony_ci///
9803da5c369Sopenharmony_ci/// Given a name, attempt to update the system host name to the given string.
9813da5c369Sopenharmony_ci/// On some systems, the host name is limited to as few as 64 bytes.  An error
9823da5c369Sopenharmony_ci/// will be returned if the name is not valid or the current process does not
9833da5c369Sopenharmony_ci/// have permissions to update the host name.
9843da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))]
9853da5c369Sopenharmony_cipub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> {
9863da5c369Sopenharmony_ci    // Handle some differences in type of the len arg across platforms.
9873da5c369Sopenharmony_ci    cfg_if! {
9883da5c369Sopenharmony_ci        if #[cfg(any(target_os = "dragonfly",
9893da5c369Sopenharmony_ci                     target_os = "freebsd",
9903da5c369Sopenharmony_ci                     target_os = "illumos",
9913da5c369Sopenharmony_ci                     target_os = "ios",
9923da5c369Sopenharmony_ci                     target_os = "macos",
9933da5c369Sopenharmony_ci                     target_os = "solaris", ))] {
9943da5c369Sopenharmony_ci            type sethostname_len_t = c_int;
9953da5c369Sopenharmony_ci        } else {
9963da5c369Sopenharmony_ci            type sethostname_len_t = size_t;
9973da5c369Sopenharmony_ci        }
9983da5c369Sopenharmony_ci    }
9993da5c369Sopenharmony_ci    let ptr = name.as_ref().as_bytes().as_ptr() as *const c_char;
10003da5c369Sopenharmony_ci    let len = name.as_ref().len() as sethostname_len_t;
10013da5c369Sopenharmony_ci
10023da5c369Sopenharmony_ci    let res = unsafe { libc::sethostname(ptr, len) };
10033da5c369Sopenharmony_ci    Errno::result(res).map(drop)
10043da5c369Sopenharmony_ci}
10053da5c369Sopenharmony_ci
10063da5c369Sopenharmony_ci/// Get the host name and store it in an internally allocated buffer, returning an
10073da5c369Sopenharmony_ci/// `OsString` on success (see
10083da5c369Sopenharmony_ci/// [gethostname(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html)).
10093da5c369Sopenharmony_ci///
10103da5c369Sopenharmony_ci/// This function call attempts to get the host name for the running system and
10113da5c369Sopenharmony_ci/// store it in an internal buffer, returning it as an `OsString` if successful.
10123da5c369Sopenharmony_ci///
10133da5c369Sopenharmony_ci/// ```no_run
10143da5c369Sopenharmony_ci/// use nix::unistd;
10153da5c369Sopenharmony_ci///
10163da5c369Sopenharmony_ci/// let hostname = unistd::gethostname().expect("Failed getting hostname");
10173da5c369Sopenharmony_ci/// let hostname = hostname.into_string().expect("Hostname wasn't valid UTF-8");
10183da5c369Sopenharmony_ci/// println!("Hostname: {}", hostname);
10193da5c369Sopenharmony_ci/// ```
10203da5c369Sopenharmony_cipub fn gethostname() -> Result<OsString> {
10213da5c369Sopenharmony_ci    // The capacity is the max length of a hostname plus the NUL terminator.
10223da5c369Sopenharmony_ci    let mut buffer: Vec<u8> = Vec::with_capacity(256);
10233da5c369Sopenharmony_ci    let ptr = buffer.as_mut_ptr() as *mut c_char;
10243da5c369Sopenharmony_ci    let len = buffer.capacity() as size_t;
10253da5c369Sopenharmony_ci
10263da5c369Sopenharmony_ci    let res = unsafe { libc::gethostname(ptr, len) };
10273da5c369Sopenharmony_ci    Errno::result(res).map(|_| {
10283da5c369Sopenharmony_ci        unsafe {
10293da5c369Sopenharmony_ci            buffer.as_mut_ptr().wrapping_add(len - 1).write(0); // ensure always null-terminated
10303da5c369Sopenharmony_ci            let len = CStr::from_ptr(buffer.as_ptr() as *const c_char).len();
10313da5c369Sopenharmony_ci            buffer.set_len(len);
10323da5c369Sopenharmony_ci        }
10333da5c369Sopenharmony_ci        OsString::from_vec(buffer)
10343da5c369Sopenharmony_ci    })
10353da5c369Sopenharmony_ci}
10363da5c369Sopenharmony_ci}
10373da5c369Sopenharmony_ci
10383da5c369Sopenharmony_ci/// Close a raw file descriptor
10393da5c369Sopenharmony_ci///
10403da5c369Sopenharmony_ci/// Be aware that many Rust types implicitly close-on-drop, including
10413da5c369Sopenharmony_ci/// `std::fs::File`.  Explicitly closing them with this method too can result in
10423da5c369Sopenharmony_ci/// a double-close condition, which can cause confusing `EBADF` errors in
10433da5c369Sopenharmony_ci/// seemingly unrelated code.  Caveat programmer.  See also
10443da5c369Sopenharmony_ci/// [close(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html).
10453da5c369Sopenharmony_ci///
10463da5c369Sopenharmony_ci/// # Examples
10473da5c369Sopenharmony_ci///
10483da5c369Sopenharmony_ci/// ```no_run
10493da5c369Sopenharmony_ci/// use std::os::unix::io::AsRawFd;
10503da5c369Sopenharmony_ci/// use nix::unistd::close;
10513da5c369Sopenharmony_ci///
10523da5c369Sopenharmony_ci/// let f = tempfile::tempfile().unwrap();
10533da5c369Sopenharmony_ci/// close(f.as_raw_fd()).unwrap();   // Bad!  f will also close on drop!
10543da5c369Sopenharmony_ci/// ```
10553da5c369Sopenharmony_ci///
10563da5c369Sopenharmony_ci/// ```rust
10573da5c369Sopenharmony_ci/// use std::os::unix::io::IntoRawFd;
10583da5c369Sopenharmony_ci/// use nix::unistd::close;
10593da5c369Sopenharmony_ci///
10603da5c369Sopenharmony_ci/// let f = tempfile::tempfile().unwrap();
10613da5c369Sopenharmony_ci/// close(f.into_raw_fd()).unwrap(); // Good.  into_raw_fd consumes f
10623da5c369Sopenharmony_ci/// ```
10633da5c369Sopenharmony_cipub fn close(fd: RawFd) -> Result<()> {
10643da5c369Sopenharmony_ci    let res = unsafe { libc::close(fd) };
10653da5c369Sopenharmony_ci    Errno::result(res).map(drop)
10663da5c369Sopenharmony_ci}
10673da5c369Sopenharmony_ci
10683da5c369Sopenharmony_ci/// Read from a raw file descriptor.
10693da5c369Sopenharmony_ci///
10703da5c369Sopenharmony_ci/// See also [read(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html)
10713da5c369Sopenharmony_cipub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> {
10723da5c369Sopenharmony_ci    let res = unsafe {
10733da5c369Sopenharmony_ci        libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t)
10743da5c369Sopenharmony_ci    };
10753da5c369Sopenharmony_ci
10763da5c369Sopenharmony_ci    Errno::result(res).map(|r| r as usize)
10773da5c369Sopenharmony_ci}
10783da5c369Sopenharmony_ci
10793da5c369Sopenharmony_ci/// Write to a raw file descriptor.
10803da5c369Sopenharmony_ci///
10813da5c369Sopenharmony_ci/// See also [write(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html)
10823da5c369Sopenharmony_cipub fn write(fd: RawFd, buf: &[u8]) -> Result<usize> {
10833da5c369Sopenharmony_ci    let res = unsafe {
10843da5c369Sopenharmony_ci        libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t)
10853da5c369Sopenharmony_ci    };
10863da5c369Sopenharmony_ci
10873da5c369Sopenharmony_ci    Errno::result(res).map(|r| r as usize)
10883da5c369Sopenharmony_ci}
10893da5c369Sopenharmony_ci
10903da5c369Sopenharmony_cifeature! {
10913da5c369Sopenharmony_ci#![feature = "fs"]
10923da5c369Sopenharmony_ci
10933da5c369Sopenharmony_ci/// Directive that tells [`lseek`] and [`lseek64`] what the offset is relative to.
10943da5c369Sopenharmony_ci///
10953da5c369Sopenharmony_ci/// [`lseek`]: ./fn.lseek.html
10963da5c369Sopenharmony_ci/// [`lseek64`]: ./fn.lseek64.html
10973da5c369Sopenharmony_ci#[repr(i32)]
10983da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug)]
10993da5c369Sopenharmony_cipub enum Whence {
11003da5c369Sopenharmony_ci    /// Specify an offset relative to the start of the file.
11013da5c369Sopenharmony_ci    SeekSet = libc::SEEK_SET,
11023da5c369Sopenharmony_ci    /// Specify an offset relative to the current file location.
11033da5c369Sopenharmony_ci    SeekCur = libc::SEEK_CUR,
11043da5c369Sopenharmony_ci    /// Specify an offset relative to the end of the file.
11053da5c369Sopenharmony_ci    SeekEnd = libc::SEEK_END,
11063da5c369Sopenharmony_ci    /// Specify an offset relative to the next location in the file greater than or
11073da5c369Sopenharmony_ci    /// equal to offset that contains some data. If offset points to
11083da5c369Sopenharmony_ci    /// some data, then the file offset is set to offset.
11093da5c369Sopenharmony_ci    #[cfg(any(target_os = "dragonfly",
11103da5c369Sopenharmony_ci              target_os = "freebsd",
11113da5c369Sopenharmony_ci              target_os = "illumos",
11123da5c369Sopenharmony_ci              target_os = "linux",
11133da5c369Sopenharmony_ci              target_os = "solaris"))]
11143da5c369Sopenharmony_ci    SeekData = libc::SEEK_DATA,
11153da5c369Sopenharmony_ci    /// Specify an offset relative to the next hole in the file greater than
11163da5c369Sopenharmony_ci    /// or equal to offset. If offset points into the middle of a hole, then
11173da5c369Sopenharmony_ci    /// the file offset should be set to offset. If there is no hole past offset,
11183da5c369Sopenharmony_ci    /// then the file offset should be adjusted to the end of the file (i.e., there
11193da5c369Sopenharmony_ci    /// is an implicit hole at the end of any file).
11203da5c369Sopenharmony_ci    #[cfg(any(target_os = "dragonfly",
11213da5c369Sopenharmony_ci              target_os = "freebsd",
11223da5c369Sopenharmony_ci              target_os = "illumos",
11233da5c369Sopenharmony_ci              target_os = "linux",
11243da5c369Sopenharmony_ci              target_os = "solaris"))]
11253da5c369Sopenharmony_ci    SeekHole = libc::SEEK_HOLE
11263da5c369Sopenharmony_ci}
11273da5c369Sopenharmony_ci
11283da5c369Sopenharmony_ci/// Move the read/write file offset.
11293da5c369Sopenharmony_ci///
11303da5c369Sopenharmony_ci/// See also [lseek(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html)
11313da5c369Sopenharmony_cipub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result<off_t> {
11323da5c369Sopenharmony_ci    let res = unsafe { libc::lseek(fd, offset, whence as i32) };
11333da5c369Sopenharmony_ci
11343da5c369Sopenharmony_ci    Errno::result(res).map(|r| r as off_t)
11353da5c369Sopenharmony_ci}
11363da5c369Sopenharmony_ci
11373da5c369Sopenharmony_ci#[cfg(any(target_os = "linux", target_os = "android"))]
11383da5c369Sopenharmony_cipub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result<libc::off64_t> {
11393da5c369Sopenharmony_ci    let res = unsafe { libc::lseek64(fd, offset, whence as i32) };
11403da5c369Sopenharmony_ci
11413da5c369Sopenharmony_ci    Errno::result(res).map(|r| r as libc::off64_t)
11423da5c369Sopenharmony_ci}
11433da5c369Sopenharmony_ci}
11443da5c369Sopenharmony_ci
11453da5c369Sopenharmony_ci/// Create an interprocess channel.
11463da5c369Sopenharmony_ci///
11473da5c369Sopenharmony_ci/// See also [pipe(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html)
11483da5c369Sopenharmony_cipub fn pipe() -> std::result::Result<(RawFd, RawFd), Error> {
11493da5c369Sopenharmony_ci    let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit();
11503da5c369Sopenharmony_ci
11513da5c369Sopenharmony_ci    let res = unsafe { libc::pipe(fds.as_mut_ptr() as *mut c_int) };
11523da5c369Sopenharmony_ci
11533da5c369Sopenharmony_ci    Error::result(res)?;
11543da5c369Sopenharmony_ci
11553da5c369Sopenharmony_ci    unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) }
11563da5c369Sopenharmony_ci}
11573da5c369Sopenharmony_ci
11583da5c369Sopenharmony_cifeature! {
11593da5c369Sopenharmony_ci#![feature = "fs"]
11603da5c369Sopenharmony_ci/// Like `pipe`, but allows setting certain file descriptor flags.
11613da5c369Sopenharmony_ci///
11623da5c369Sopenharmony_ci/// The following flags are supported, and will be set atomically as the pipe is
11633da5c369Sopenharmony_ci/// created:
11643da5c369Sopenharmony_ci///
11653da5c369Sopenharmony_ci/// - `O_CLOEXEC`:    Set the close-on-exec flag for the new file descriptors.
11663da5c369Sopenharmony_ci#[cfg_attr(target_os = "linux", doc = "- `O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode.")]
11673da5c369Sopenharmony_ci#[cfg_attr(target_os = "netbsd", doc = "- `O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`.")]
11683da5c369Sopenharmony_ci/// - `O_NONBLOCK`:   Set the non-blocking flag for the ends of the pipe.
11693da5c369Sopenharmony_ci///
11703da5c369Sopenharmony_ci/// See also [pipe(2)](https://man7.org/linux/man-pages/man2/pipe.2.html)
11713da5c369Sopenharmony_ci#[cfg(any(target_os = "android",
11723da5c369Sopenharmony_ci          target_os = "dragonfly",
11733da5c369Sopenharmony_ci          target_os = "emscripten",
11743da5c369Sopenharmony_ci          target_os = "freebsd",
11753da5c369Sopenharmony_ci          target_os = "illumos",
11763da5c369Sopenharmony_ci          target_os = "linux",
11773da5c369Sopenharmony_ci          target_os = "redox",
11783da5c369Sopenharmony_ci          target_os = "netbsd",
11793da5c369Sopenharmony_ci          target_os = "openbsd",
11803da5c369Sopenharmony_ci          target_os = "solaris"))]
11813da5c369Sopenharmony_cipub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
11823da5c369Sopenharmony_ci    let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit();
11833da5c369Sopenharmony_ci
11843da5c369Sopenharmony_ci    let res = unsafe {
11853da5c369Sopenharmony_ci        libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits())
11863da5c369Sopenharmony_ci    };
11873da5c369Sopenharmony_ci
11883da5c369Sopenharmony_ci    Errno::result(res)?;
11893da5c369Sopenharmony_ci
11903da5c369Sopenharmony_ci    unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) }
11913da5c369Sopenharmony_ci}
11923da5c369Sopenharmony_ci
11933da5c369Sopenharmony_ci/// Truncate a file to a specified length
11943da5c369Sopenharmony_ci///
11953da5c369Sopenharmony_ci/// See also
11963da5c369Sopenharmony_ci/// [truncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html)
11973da5c369Sopenharmony_ci#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
11983da5c369Sopenharmony_cipub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> {
11993da5c369Sopenharmony_ci    let res = path.with_nix_path(|cstr| {
12003da5c369Sopenharmony_ci        unsafe {
12013da5c369Sopenharmony_ci            libc::truncate(cstr.as_ptr(), len)
12023da5c369Sopenharmony_ci        }
12033da5c369Sopenharmony_ci    })?;
12043da5c369Sopenharmony_ci
12053da5c369Sopenharmony_ci    Errno::result(res).map(drop)
12063da5c369Sopenharmony_ci}
12073da5c369Sopenharmony_ci
12083da5c369Sopenharmony_ci/// Truncate a file to a specified length
12093da5c369Sopenharmony_ci///
12103da5c369Sopenharmony_ci/// See also
12113da5c369Sopenharmony_ci/// [ftruncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html)
12123da5c369Sopenharmony_cipub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> {
12133da5c369Sopenharmony_ci    Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop)
12143da5c369Sopenharmony_ci}
12153da5c369Sopenharmony_ci
12163da5c369Sopenharmony_cipub fn isatty(fd: RawFd) -> Result<bool> {
12173da5c369Sopenharmony_ci    unsafe {
12183da5c369Sopenharmony_ci        // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so
12193da5c369Sopenharmony_ci        // we return `Ok(false)`
12203da5c369Sopenharmony_ci        if libc::isatty(fd) == 1 {
12213da5c369Sopenharmony_ci            Ok(true)
12223da5c369Sopenharmony_ci        } else {
12233da5c369Sopenharmony_ci            match Errno::last() {
12243da5c369Sopenharmony_ci                Errno::ENOTTY => Ok(false),
12253da5c369Sopenharmony_ci                err => Err(err),
12263da5c369Sopenharmony_ci            }
12273da5c369Sopenharmony_ci       }
12283da5c369Sopenharmony_ci    }
12293da5c369Sopenharmony_ci}
12303da5c369Sopenharmony_ci
12313da5c369Sopenharmony_ci/// Flags for `linkat` function.
12323da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug)]
12333da5c369Sopenharmony_cipub enum LinkatFlags {
12343da5c369Sopenharmony_ci    SymlinkFollow,
12353da5c369Sopenharmony_ci    NoSymlinkFollow,
12363da5c369Sopenharmony_ci}
12373da5c369Sopenharmony_ci
12383da5c369Sopenharmony_ci/// Link one file to another file
12393da5c369Sopenharmony_ci///
12403da5c369Sopenharmony_ci/// Creates a new link (directory entry) at `newpath` for the existing file at `oldpath`. In the
12413da5c369Sopenharmony_ci/// case of a relative `oldpath`, the path is interpreted relative to the directory associated
12423da5c369Sopenharmony_ci/// with file descriptor `olddirfd` instead of the current working directory and similiarly for
12433da5c369Sopenharmony_ci/// `newpath` and file descriptor `newdirfd`. In case `flag` is LinkatFlags::SymlinkFollow and
12443da5c369Sopenharmony_ci/// `oldpath` names a symoblic link, a new link for the target of the symbolic link is created.
12453da5c369Sopenharmony_ci/// If either `olddirfd` or `newdirfd` is `None`, `AT_FDCWD` is used respectively where `oldpath`
12463da5c369Sopenharmony_ci/// and/or `newpath` is then interpreted relative to the current working directory of the calling
12473da5c369Sopenharmony_ci/// process. If either `oldpath` or `newpath` is absolute, then `dirfd` is ignored.
12483da5c369Sopenharmony_ci///
12493da5c369Sopenharmony_ci/// # References
12503da5c369Sopenharmony_ci/// See also [linkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html)
12513da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] // RedoxFS does not support symlinks yet
12523da5c369Sopenharmony_cipub fn linkat<P: ?Sized + NixPath>(
12533da5c369Sopenharmony_ci    olddirfd: Option<RawFd>,
12543da5c369Sopenharmony_ci    oldpath: &P,
12553da5c369Sopenharmony_ci    newdirfd: Option<RawFd>,
12563da5c369Sopenharmony_ci    newpath: &P,
12573da5c369Sopenharmony_ci    flag: LinkatFlags,
12583da5c369Sopenharmony_ci) -> Result<()> {
12593da5c369Sopenharmony_ci
12603da5c369Sopenharmony_ci    let atflag =
12613da5c369Sopenharmony_ci        match flag {
12623da5c369Sopenharmony_ci            LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW,
12633da5c369Sopenharmony_ci            LinkatFlags::NoSymlinkFollow => AtFlags::empty(),
12643da5c369Sopenharmony_ci        };
12653da5c369Sopenharmony_ci
12663da5c369Sopenharmony_ci    let res =
12673da5c369Sopenharmony_ci        oldpath.with_nix_path(|oldcstr| {
12683da5c369Sopenharmony_ci            newpath.with_nix_path(|newcstr| {
12693da5c369Sopenharmony_ci            unsafe {
12703da5c369Sopenharmony_ci                libc::linkat(
12713da5c369Sopenharmony_ci                    at_rawfd(olddirfd),
12723da5c369Sopenharmony_ci                    oldcstr.as_ptr(),
12733da5c369Sopenharmony_ci                    at_rawfd(newdirfd),
12743da5c369Sopenharmony_ci                    newcstr.as_ptr(),
12753da5c369Sopenharmony_ci                    atflag.bits() as libc::c_int
12763da5c369Sopenharmony_ci                    )
12773da5c369Sopenharmony_ci                }
12783da5c369Sopenharmony_ci            })
12793da5c369Sopenharmony_ci        })??;
12803da5c369Sopenharmony_ci    Errno::result(res).map(drop)
12813da5c369Sopenharmony_ci}
12823da5c369Sopenharmony_ci
12833da5c369Sopenharmony_ci
12843da5c369Sopenharmony_ci/// Remove a directory entry
12853da5c369Sopenharmony_ci///
12863da5c369Sopenharmony_ci/// See also [unlink(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html)
12873da5c369Sopenharmony_cipub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> {
12883da5c369Sopenharmony_ci    let res = path.with_nix_path(|cstr| {
12893da5c369Sopenharmony_ci        unsafe {
12903da5c369Sopenharmony_ci            libc::unlink(cstr.as_ptr())
12913da5c369Sopenharmony_ci        }
12923da5c369Sopenharmony_ci    })?;
12933da5c369Sopenharmony_ci    Errno::result(res).map(drop)
12943da5c369Sopenharmony_ci}
12953da5c369Sopenharmony_ci
12963da5c369Sopenharmony_ci/// Flags for `unlinkat` function.
12973da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug)]
12983da5c369Sopenharmony_cipub enum UnlinkatFlags {
12993da5c369Sopenharmony_ci    RemoveDir,
13003da5c369Sopenharmony_ci    NoRemoveDir,
13013da5c369Sopenharmony_ci}
13023da5c369Sopenharmony_ci
13033da5c369Sopenharmony_ci/// Remove a directory entry
13043da5c369Sopenharmony_ci///
13053da5c369Sopenharmony_ci/// In the case of a relative path, the directory entry to be removed is determined relative to
13063da5c369Sopenharmony_ci/// the directory associated with the file descriptor `dirfd` or the current working directory
13073da5c369Sopenharmony_ci/// if `dirfd` is `None`. In the case of an absolute `path` `dirfd` is ignored. If `flag` is
13083da5c369Sopenharmony_ci/// `UnlinkatFlags::RemoveDir` then removal of the directory entry specified by `dirfd` and `path`
13093da5c369Sopenharmony_ci/// is performed.
13103da5c369Sopenharmony_ci///
13113da5c369Sopenharmony_ci/// # References
13123da5c369Sopenharmony_ci/// See also [unlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html)
13133da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))]
13143da5c369Sopenharmony_cipub fn unlinkat<P: ?Sized + NixPath>(
13153da5c369Sopenharmony_ci    dirfd: Option<RawFd>,
13163da5c369Sopenharmony_ci    path: &P,
13173da5c369Sopenharmony_ci    flag: UnlinkatFlags,
13183da5c369Sopenharmony_ci) -> Result<()> {
13193da5c369Sopenharmony_ci    let atflag =
13203da5c369Sopenharmony_ci        match flag {
13213da5c369Sopenharmony_ci            UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR,
13223da5c369Sopenharmony_ci            UnlinkatFlags::NoRemoveDir => AtFlags::empty(),
13233da5c369Sopenharmony_ci        };
13243da5c369Sopenharmony_ci    let res = path.with_nix_path(|cstr| {
13253da5c369Sopenharmony_ci        unsafe {
13263da5c369Sopenharmony_ci            libc::unlinkat(at_rawfd(dirfd), cstr.as_ptr(), atflag.bits() as libc::c_int)
13273da5c369Sopenharmony_ci        }
13283da5c369Sopenharmony_ci    })?;
13293da5c369Sopenharmony_ci    Errno::result(res).map(drop)
13303da5c369Sopenharmony_ci}
13313da5c369Sopenharmony_ci
13323da5c369Sopenharmony_ci
13333da5c369Sopenharmony_ci#[inline]
13343da5c369Sopenharmony_ci#[cfg(not(target_os = "fuchsia"))]
13353da5c369Sopenharmony_cipub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> {
13363da5c369Sopenharmony_ci    let res = path.with_nix_path(|cstr| {
13373da5c369Sopenharmony_ci        unsafe { libc::chroot(cstr.as_ptr()) }
13383da5c369Sopenharmony_ci    })?;
13393da5c369Sopenharmony_ci
13403da5c369Sopenharmony_ci    Errno::result(res).map(drop)
13413da5c369Sopenharmony_ci}
13423da5c369Sopenharmony_ci
13433da5c369Sopenharmony_ci/// Commit filesystem caches to disk
13443da5c369Sopenharmony_ci///
13453da5c369Sopenharmony_ci/// See also [sync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html)
13463da5c369Sopenharmony_ci#[cfg(any(
13473da5c369Sopenharmony_ci    target_os = "dragonfly",
13483da5c369Sopenharmony_ci    target_os = "freebsd",
13493da5c369Sopenharmony_ci    target_os = "linux",
13503da5c369Sopenharmony_ci    target_os = "netbsd",
13513da5c369Sopenharmony_ci    target_os = "openbsd"
13523da5c369Sopenharmony_ci))]
13533da5c369Sopenharmony_cipub fn sync() {
13543da5c369Sopenharmony_ci    unsafe { libc::sync() };
13553da5c369Sopenharmony_ci}
13563da5c369Sopenharmony_ci
13573da5c369Sopenharmony_ci/// Commit filesystem caches containing file referred to by the open file
13583da5c369Sopenharmony_ci/// descriptor `fd` to disk
13593da5c369Sopenharmony_ci///
13603da5c369Sopenharmony_ci/// See also [syncfs(2)](https://man7.org/linux/man-pages/man2/sync.2.html)
13613da5c369Sopenharmony_ci#[cfg(target_os = "linux")]
13623da5c369Sopenharmony_cipub fn syncfs(fd: RawFd) -> Result<()> {
13633da5c369Sopenharmony_ci    let res = unsafe { libc::syncfs(fd) };
13643da5c369Sopenharmony_ci
13653da5c369Sopenharmony_ci    Errno::result(res).map(drop)
13663da5c369Sopenharmony_ci}
13673da5c369Sopenharmony_ci
13683da5c369Sopenharmony_ci/// Synchronize changes to a file
13693da5c369Sopenharmony_ci///
13703da5c369Sopenharmony_ci/// See also [fsync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html)
13713da5c369Sopenharmony_ci#[inline]
13723da5c369Sopenharmony_cipub fn fsync(fd: RawFd) -> Result<()> {
13733da5c369Sopenharmony_ci    let res = unsafe { libc::fsync(fd) };
13743da5c369Sopenharmony_ci
13753da5c369Sopenharmony_ci    Errno::result(res).map(drop)
13763da5c369Sopenharmony_ci}
13773da5c369Sopenharmony_ci
13783da5c369Sopenharmony_ci/// Synchronize the data of a file
13793da5c369Sopenharmony_ci///
13803da5c369Sopenharmony_ci/// See also
13813da5c369Sopenharmony_ci/// [fdatasync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html)
13823da5c369Sopenharmony_ci#[cfg(any(target_os = "linux",
13833da5c369Sopenharmony_ci          target_os = "android",
13843da5c369Sopenharmony_ci          target_os = "emscripten",
13853da5c369Sopenharmony_ci          target_os = "freebsd",
13863da5c369Sopenharmony_ci          target_os = "fuchsia",
13873da5c369Sopenharmony_ci          target_os = "netbsd",
13883da5c369Sopenharmony_ci          target_os = "openbsd",
13893da5c369Sopenharmony_ci          target_os = "illumos",
13903da5c369Sopenharmony_ci          target_os = "solaris"))]
13913da5c369Sopenharmony_ci#[inline]
13923da5c369Sopenharmony_cipub fn fdatasync(fd: RawFd) -> Result<()> {
13933da5c369Sopenharmony_ci    let res = unsafe { libc::fdatasync(fd) };
13943da5c369Sopenharmony_ci
13953da5c369Sopenharmony_ci    Errno::result(res).map(drop)
13963da5c369Sopenharmony_ci}
13973da5c369Sopenharmony_ci}
13983da5c369Sopenharmony_ci
13993da5c369Sopenharmony_cifeature! {
14003da5c369Sopenharmony_ci#![feature = "user"]
14013da5c369Sopenharmony_ci
14023da5c369Sopenharmony_ci/// Get a real user ID
14033da5c369Sopenharmony_ci///
14043da5c369Sopenharmony_ci/// See also [getuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html)
14053da5c369Sopenharmony_ci// POSIX requires that getuid is always successful, so no need to check return
14063da5c369Sopenharmony_ci// value or errno.
14073da5c369Sopenharmony_ci#[inline]
14083da5c369Sopenharmony_cipub fn getuid() -> Uid {
14093da5c369Sopenharmony_ci    Uid(unsafe { libc::getuid() })
14103da5c369Sopenharmony_ci}
14113da5c369Sopenharmony_ci
14123da5c369Sopenharmony_ci/// Get the effective user ID
14133da5c369Sopenharmony_ci///
14143da5c369Sopenharmony_ci/// See also [geteuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html)
14153da5c369Sopenharmony_ci// POSIX requires that geteuid is always successful, so no need to check return
14163da5c369Sopenharmony_ci// value or errno.
14173da5c369Sopenharmony_ci#[inline]
14183da5c369Sopenharmony_cipub fn geteuid() -> Uid {
14193da5c369Sopenharmony_ci    Uid(unsafe { libc::geteuid() })
14203da5c369Sopenharmony_ci}
14213da5c369Sopenharmony_ci
14223da5c369Sopenharmony_ci/// Get the real group ID
14233da5c369Sopenharmony_ci///
14243da5c369Sopenharmony_ci/// See also [getgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html)
14253da5c369Sopenharmony_ci// POSIX requires that getgid is always successful, so no need to check return
14263da5c369Sopenharmony_ci// value or errno.
14273da5c369Sopenharmony_ci#[inline]
14283da5c369Sopenharmony_cipub fn getgid() -> Gid {
14293da5c369Sopenharmony_ci    Gid(unsafe { libc::getgid() })
14303da5c369Sopenharmony_ci}
14313da5c369Sopenharmony_ci
14323da5c369Sopenharmony_ci/// Get the effective group ID
14333da5c369Sopenharmony_ci///
14343da5c369Sopenharmony_ci/// See also [getegid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getegid.html)
14353da5c369Sopenharmony_ci// POSIX requires that getegid is always successful, so no need to check return
14363da5c369Sopenharmony_ci// value or errno.
14373da5c369Sopenharmony_ci#[inline]
14383da5c369Sopenharmony_cipub fn getegid() -> Gid {
14393da5c369Sopenharmony_ci    Gid(unsafe { libc::getegid() })
14403da5c369Sopenharmony_ci}
14413da5c369Sopenharmony_ci
14423da5c369Sopenharmony_ci/// Set the effective user ID
14433da5c369Sopenharmony_ci///
14443da5c369Sopenharmony_ci/// See also [seteuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/seteuid.html)
14453da5c369Sopenharmony_ci#[inline]
14463da5c369Sopenharmony_cipub fn seteuid(euid: Uid) -> Result<()> {
14473da5c369Sopenharmony_ci    let res = unsafe { libc::seteuid(euid.into()) };
14483da5c369Sopenharmony_ci
14493da5c369Sopenharmony_ci    Errno::result(res).map(drop)
14503da5c369Sopenharmony_ci}
14513da5c369Sopenharmony_ci
14523da5c369Sopenharmony_ci/// Set the effective group ID
14533da5c369Sopenharmony_ci///
14543da5c369Sopenharmony_ci/// See also [setegid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setegid.html)
14553da5c369Sopenharmony_ci#[inline]
14563da5c369Sopenharmony_cipub fn setegid(egid: Gid) -> Result<()> {
14573da5c369Sopenharmony_ci    let res = unsafe { libc::setegid(egid.into()) };
14583da5c369Sopenharmony_ci
14593da5c369Sopenharmony_ci    Errno::result(res).map(drop)
14603da5c369Sopenharmony_ci}
14613da5c369Sopenharmony_ci
14623da5c369Sopenharmony_ci/// Set the user ID
14633da5c369Sopenharmony_ci///
14643da5c369Sopenharmony_ci/// See also [setuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setuid.html)
14653da5c369Sopenharmony_ci#[inline]
14663da5c369Sopenharmony_cipub fn setuid(uid: Uid) -> Result<()> {
14673da5c369Sopenharmony_ci    let res = unsafe { libc::setuid(uid.into()) };
14683da5c369Sopenharmony_ci
14693da5c369Sopenharmony_ci    Errno::result(res).map(drop)
14703da5c369Sopenharmony_ci}
14713da5c369Sopenharmony_ci
14723da5c369Sopenharmony_ci/// Set the group ID
14733da5c369Sopenharmony_ci///
14743da5c369Sopenharmony_ci/// See also [setgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setgid.html)
14753da5c369Sopenharmony_ci#[inline]
14763da5c369Sopenharmony_cipub fn setgid(gid: Gid) -> Result<()> {
14773da5c369Sopenharmony_ci    let res = unsafe { libc::setgid(gid.into()) };
14783da5c369Sopenharmony_ci
14793da5c369Sopenharmony_ci    Errno::result(res).map(drop)
14803da5c369Sopenharmony_ci}
14813da5c369Sopenharmony_ci}
14823da5c369Sopenharmony_ci
14833da5c369Sopenharmony_cifeature! {
14843da5c369Sopenharmony_ci#![all(feature = "fs", feature = "user")]
14853da5c369Sopenharmony_ci/// Set the user identity used for filesystem checks per-thread.
14863da5c369Sopenharmony_ci/// On both success and failure, this call returns the previous filesystem user
14873da5c369Sopenharmony_ci/// ID of the caller.
14883da5c369Sopenharmony_ci///
14893da5c369Sopenharmony_ci/// See also [setfsuid(2)](https://man7.org/linux/man-pages/man2/setfsuid.2.html)
14903da5c369Sopenharmony_ci#[cfg(any(target_os = "linux", target_os = "android"))]
14913da5c369Sopenharmony_cipub fn setfsuid(uid: Uid) -> Uid {
14923da5c369Sopenharmony_ci    let prev_fsuid = unsafe { libc::setfsuid(uid.into()) };
14933da5c369Sopenharmony_ci    Uid::from_raw(prev_fsuid as uid_t)
14943da5c369Sopenharmony_ci}
14953da5c369Sopenharmony_ci
14963da5c369Sopenharmony_ci/// Set the group identity used for filesystem checks per-thread.
14973da5c369Sopenharmony_ci/// On both success and failure, this call returns the previous filesystem group
14983da5c369Sopenharmony_ci/// ID of the caller.
14993da5c369Sopenharmony_ci///
15003da5c369Sopenharmony_ci/// See also [setfsgid(2)](https://man7.org/linux/man-pages/man2/setfsgid.2.html)
15013da5c369Sopenharmony_ci#[cfg(any(target_os = "linux", target_os = "android"))]
15023da5c369Sopenharmony_cipub fn setfsgid(gid: Gid) -> Gid {
15033da5c369Sopenharmony_ci    let prev_fsgid = unsafe { libc::setfsgid(gid.into()) };
15043da5c369Sopenharmony_ci    Gid::from_raw(prev_fsgid as gid_t)
15053da5c369Sopenharmony_ci}
15063da5c369Sopenharmony_ci}
15073da5c369Sopenharmony_ci
15083da5c369Sopenharmony_cifeature! {
15093da5c369Sopenharmony_ci#![feature = "user"]
15103da5c369Sopenharmony_ci
15113da5c369Sopenharmony_ci/// Get the list of supplementary group IDs of the calling process.
15123da5c369Sopenharmony_ci///
15133da5c369Sopenharmony_ci/// [Further reading](https://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html)
15143da5c369Sopenharmony_ci///
15153da5c369Sopenharmony_ci/// **Note:** This function is not available for Apple platforms. On those
15163da5c369Sopenharmony_ci/// platforms, checking group membership should be achieved via communication
15173da5c369Sopenharmony_ci/// with the `opendirectoryd` service.
15183da5c369Sopenharmony_ci#[cfg(not(any(target_os = "ios", target_os = "macos")))]
15193da5c369Sopenharmony_cipub fn getgroups() -> Result<Vec<Gid>> {
15203da5c369Sopenharmony_ci    // First get the maximum number of groups. The value returned
15213da5c369Sopenharmony_ci    // shall always be greater than or equal to one and less than or
15223da5c369Sopenharmony_ci    // equal to the value of {NGROUPS_MAX} + 1.
15233da5c369Sopenharmony_ci    let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) {
15243da5c369Sopenharmony_ci        Ok(Some(n)) => (n + 1) as usize,
15253da5c369Sopenharmony_ci        Ok(None) | Err(_) => <usize>::max_value(),
15263da5c369Sopenharmony_ci    };
15273da5c369Sopenharmony_ci
15283da5c369Sopenharmony_ci    // Next, get the number of groups so we can size our Vec
15293da5c369Sopenharmony_ci    let ngroups = unsafe { libc::getgroups(0, ptr::null_mut()) };
15303da5c369Sopenharmony_ci
15313da5c369Sopenharmony_ci    // If there are no supplementary groups, return early.
15323da5c369Sopenharmony_ci    // This prevents a potential buffer over-read if the number of groups
15333da5c369Sopenharmony_ci    // increases from zero before the next call. It would return the total
15343da5c369Sopenharmony_ci    // number of groups beyond the capacity of the buffer.
15353da5c369Sopenharmony_ci    if ngroups == 0 {
15363da5c369Sopenharmony_ci        return Ok(Vec::new());
15373da5c369Sopenharmony_ci    }
15383da5c369Sopenharmony_ci
15393da5c369Sopenharmony_ci    // Now actually get the groups. We try multiple times in case the number of
15403da5c369Sopenharmony_ci    // groups has changed since the first call to getgroups() and the buffer is
15413da5c369Sopenharmony_ci    // now too small.
15423da5c369Sopenharmony_ci    let mut groups = Vec::<Gid>::with_capacity(Errno::result(ngroups)? as usize);
15433da5c369Sopenharmony_ci    loop {
15443da5c369Sopenharmony_ci        // FIXME: On the platforms we currently support, the `Gid` struct has
15453da5c369Sopenharmony_ci        // the same representation in memory as a bare `gid_t`. This is not
15463da5c369Sopenharmony_ci        // necessarily the case on all Rust platforms, though. See RFC 1785.
15473da5c369Sopenharmony_ci        let ngroups = unsafe {
15483da5c369Sopenharmony_ci            libc::getgroups(groups.capacity() as c_int, groups.as_mut_ptr() as *mut gid_t)
15493da5c369Sopenharmony_ci        };
15503da5c369Sopenharmony_ci
15513da5c369Sopenharmony_ci        match Errno::result(ngroups) {
15523da5c369Sopenharmony_ci            Ok(s) => {
15533da5c369Sopenharmony_ci                unsafe { groups.set_len(s as usize) };
15543da5c369Sopenharmony_ci                return Ok(groups);
15553da5c369Sopenharmony_ci            },
15563da5c369Sopenharmony_ci            Err(Errno::EINVAL) => {
15573da5c369Sopenharmony_ci                // EINVAL indicates that the buffer size was too
15583da5c369Sopenharmony_ci                // small, resize it up to ngroups_max as limit.
15593da5c369Sopenharmony_ci                reserve_double_buffer_size(&mut groups, ngroups_max)
15603da5c369Sopenharmony_ci                    .or(Err(Errno::EINVAL))?;
15613da5c369Sopenharmony_ci            },
15623da5c369Sopenharmony_ci            Err(e) => return Err(e)
15633da5c369Sopenharmony_ci        }
15643da5c369Sopenharmony_ci    }
15653da5c369Sopenharmony_ci}
15663da5c369Sopenharmony_ci
15673da5c369Sopenharmony_ci/// Set the list of supplementary group IDs for the calling process.
15683da5c369Sopenharmony_ci///
15693da5c369Sopenharmony_ci/// [Further reading](https://man7.org/linux/man-pages/man2/getgroups.2.html)
15703da5c369Sopenharmony_ci///
15713da5c369Sopenharmony_ci/// **Note:** This function is not available for Apple platforms. On those
15723da5c369Sopenharmony_ci/// platforms, group membership management should be achieved via communication
15733da5c369Sopenharmony_ci/// with the `opendirectoryd` service.
15743da5c369Sopenharmony_ci///
15753da5c369Sopenharmony_ci/// # Examples
15763da5c369Sopenharmony_ci///
15773da5c369Sopenharmony_ci/// `setgroups` can be used when dropping privileges from the root user to a
15783da5c369Sopenharmony_ci/// specific user and group. For example, given the user `www-data` with UID
15793da5c369Sopenharmony_ci/// `33` and the group `backup` with the GID `34`, one could switch the user as
15803da5c369Sopenharmony_ci/// follows:
15813da5c369Sopenharmony_ci///
15823da5c369Sopenharmony_ci/// ```rust,no_run
15833da5c369Sopenharmony_ci/// # use std::error::Error;
15843da5c369Sopenharmony_ci/// # use nix::unistd::*;
15853da5c369Sopenharmony_ci/// #
15863da5c369Sopenharmony_ci/// # fn try_main() -> Result<(), Box<dyn Error>> {
15873da5c369Sopenharmony_ci/// let uid = Uid::from_raw(33);
15883da5c369Sopenharmony_ci/// let gid = Gid::from_raw(34);
15893da5c369Sopenharmony_ci/// setgroups(&[gid])?;
15903da5c369Sopenharmony_ci/// setgid(gid)?;
15913da5c369Sopenharmony_ci/// setuid(uid)?;
15923da5c369Sopenharmony_ci/// #
15933da5c369Sopenharmony_ci/// #     Ok(())
15943da5c369Sopenharmony_ci/// # }
15953da5c369Sopenharmony_ci/// #
15963da5c369Sopenharmony_ci/// # try_main().unwrap();
15973da5c369Sopenharmony_ci/// ```
15983da5c369Sopenharmony_ci#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))]
15993da5c369Sopenharmony_cipub fn setgroups(groups: &[Gid]) -> Result<()> {
16003da5c369Sopenharmony_ci    cfg_if! {
16013da5c369Sopenharmony_ci        if #[cfg(any(target_os = "dragonfly",
16023da5c369Sopenharmony_ci                     target_os = "freebsd",
16033da5c369Sopenharmony_ci                     target_os = "illumos",
16043da5c369Sopenharmony_ci                     target_os = "ios",
16053da5c369Sopenharmony_ci                     target_os = "macos",
16063da5c369Sopenharmony_ci                     target_os = "netbsd",
16073da5c369Sopenharmony_ci                     target_os = "illumos",
16083da5c369Sopenharmony_ci                     target_os = "openbsd"))] {
16093da5c369Sopenharmony_ci            type setgroups_ngroups_t = c_int;
16103da5c369Sopenharmony_ci        } else {
16113da5c369Sopenharmony_ci            type setgroups_ngroups_t = size_t;
16123da5c369Sopenharmony_ci        }
16133da5c369Sopenharmony_ci    }
16143da5c369Sopenharmony_ci    // FIXME: On the platforms we currently support, the `Gid` struct has the
16153da5c369Sopenharmony_ci    // same representation in memory as a bare `gid_t`. This is not necessarily
16163da5c369Sopenharmony_ci    // the case on all Rust platforms, though. See RFC 1785.
16173da5c369Sopenharmony_ci    let res = unsafe {
16183da5c369Sopenharmony_ci        libc::setgroups(groups.len() as setgroups_ngroups_t, groups.as_ptr() as *const gid_t)
16193da5c369Sopenharmony_ci    };
16203da5c369Sopenharmony_ci
16213da5c369Sopenharmony_ci    Errno::result(res).map(drop)
16223da5c369Sopenharmony_ci}
16233da5c369Sopenharmony_ci
16243da5c369Sopenharmony_ci/// Calculate the supplementary group access list.
16253da5c369Sopenharmony_ci///
16263da5c369Sopenharmony_ci/// Gets the group IDs of all groups that `user` is a member of. The additional
16273da5c369Sopenharmony_ci/// group `group` is also added to the list.
16283da5c369Sopenharmony_ci///
16293da5c369Sopenharmony_ci/// [Further reading](https://man7.org/linux/man-pages/man3/getgrouplist.3.html)
16303da5c369Sopenharmony_ci///
16313da5c369Sopenharmony_ci/// **Note:** This function is not available for Apple platforms. On those
16323da5c369Sopenharmony_ci/// platforms, checking group membership should be achieved via communication
16333da5c369Sopenharmony_ci/// with the `opendirectoryd` service.
16343da5c369Sopenharmony_ci///
16353da5c369Sopenharmony_ci/// # Errors
16363da5c369Sopenharmony_ci///
16373da5c369Sopenharmony_ci/// Although the `getgrouplist()` call does not return any specific
16383da5c369Sopenharmony_ci/// errors on any known platforms, this implementation will return a system
16393da5c369Sopenharmony_ci/// error of `EINVAL` if the number of groups to be fetched exceeds the
16403da5c369Sopenharmony_ci/// `NGROUPS_MAX` sysconf value. This mimics the behaviour of `getgroups()`
16413da5c369Sopenharmony_ci/// and `setgroups()`. Additionally, while some implementations will return a
16423da5c369Sopenharmony_ci/// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation
16433da5c369Sopenharmony_ci/// will only ever return the complete list or else an error.
16443da5c369Sopenharmony_ci#[cfg(not(any(target_os = "illumos",
16453da5c369Sopenharmony_ci              target_os = "ios",
16463da5c369Sopenharmony_ci              target_os = "macos",
16473da5c369Sopenharmony_ci              target_os = "redox")))]
16483da5c369Sopenharmony_cipub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
16493da5c369Sopenharmony_ci    let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) {
16503da5c369Sopenharmony_ci        Ok(Some(n)) => n as c_int,
16513da5c369Sopenharmony_ci        Ok(None) | Err(_) => <c_int>::max_value(),
16523da5c369Sopenharmony_ci    };
16533da5c369Sopenharmony_ci    use std::cmp::min;
16543da5c369Sopenharmony_ci    let mut groups = Vec::<Gid>::with_capacity(min(ngroups_max, 8) as usize);
16553da5c369Sopenharmony_ci    cfg_if! {
16563da5c369Sopenharmony_ci        if #[cfg(any(target_os = "ios", target_os = "macos"))] {
16573da5c369Sopenharmony_ci            type getgrouplist_group_t = c_int;
16583da5c369Sopenharmony_ci        } else {
16593da5c369Sopenharmony_ci            type getgrouplist_group_t = gid_t;
16603da5c369Sopenharmony_ci        }
16613da5c369Sopenharmony_ci    }
16623da5c369Sopenharmony_ci    let gid: gid_t = group.into();
16633da5c369Sopenharmony_ci    loop {
16643da5c369Sopenharmony_ci        let mut ngroups = groups.capacity() as i32;
16653da5c369Sopenharmony_ci        let ret = unsafe {
16663da5c369Sopenharmony_ci            libc::getgrouplist(user.as_ptr(),
16673da5c369Sopenharmony_ci                               gid as getgrouplist_group_t,
16683da5c369Sopenharmony_ci                               groups.as_mut_ptr() as *mut getgrouplist_group_t,
16693da5c369Sopenharmony_ci                               &mut ngroups)
16703da5c369Sopenharmony_ci        };
16713da5c369Sopenharmony_ci
16723da5c369Sopenharmony_ci        // BSD systems only return 0 or -1, Linux returns ngroups on success.
16733da5c369Sopenharmony_ci        if ret >= 0 {
16743da5c369Sopenharmony_ci            unsafe { groups.set_len(ngroups as usize) };
16753da5c369Sopenharmony_ci            return Ok(groups);
16763da5c369Sopenharmony_ci        } else if ret == -1 {
16773da5c369Sopenharmony_ci            // Returns -1 if ngroups is too small, but does not set errno.
16783da5c369Sopenharmony_ci            // BSD systems will still fill the groups buffer with as many
16793da5c369Sopenharmony_ci            // groups as possible, but Linux manpages do not mention this
16803da5c369Sopenharmony_ci            // behavior.
16813da5c369Sopenharmony_ci            reserve_double_buffer_size(&mut groups, ngroups_max as usize)
16823da5c369Sopenharmony_ci                .map_err(|_| Errno::EINVAL)?;
16833da5c369Sopenharmony_ci        }
16843da5c369Sopenharmony_ci    }
16853da5c369Sopenharmony_ci}
16863da5c369Sopenharmony_ci
16873da5c369Sopenharmony_ci/// Initialize the supplementary group access list.
16883da5c369Sopenharmony_ci///
16893da5c369Sopenharmony_ci/// Sets the supplementary group IDs for the calling process using all groups
16903da5c369Sopenharmony_ci/// that `user` is a member of. The additional group `group` is also added to
16913da5c369Sopenharmony_ci/// the list.
16923da5c369Sopenharmony_ci///
16933da5c369Sopenharmony_ci/// [Further reading](https://man7.org/linux/man-pages/man3/initgroups.3.html)
16943da5c369Sopenharmony_ci///
16953da5c369Sopenharmony_ci/// **Note:** This function is not available for Apple platforms. On those
16963da5c369Sopenharmony_ci/// platforms, group membership management should be achieved via communication
16973da5c369Sopenharmony_ci/// with the `opendirectoryd` service.
16983da5c369Sopenharmony_ci///
16993da5c369Sopenharmony_ci/// # Examples
17003da5c369Sopenharmony_ci///
17013da5c369Sopenharmony_ci/// `initgroups` can be used when dropping privileges from the root user to
17023da5c369Sopenharmony_ci/// another user. For example, given the user `www-data`, we could look up the
17033da5c369Sopenharmony_ci/// UID and GID for the user in the system's password database (usually found
17043da5c369Sopenharmony_ci/// in `/etc/passwd`). If the `www-data` user's UID and GID were `33` and `33`,
17053da5c369Sopenharmony_ci/// respectively, one could switch the user as follows:
17063da5c369Sopenharmony_ci///
17073da5c369Sopenharmony_ci/// ```rust,no_run
17083da5c369Sopenharmony_ci/// # use std::error::Error;
17093da5c369Sopenharmony_ci/// # use std::ffi::CString;
17103da5c369Sopenharmony_ci/// # use nix::unistd::*;
17113da5c369Sopenharmony_ci/// #
17123da5c369Sopenharmony_ci/// # fn try_main() -> Result<(), Box<dyn Error>> {
17133da5c369Sopenharmony_ci/// let user = CString::new("www-data").unwrap();
17143da5c369Sopenharmony_ci/// let uid = Uid::from_raw(33);
17153da5c369Sopenharmony_ci/// let gid = Gid::from_raw(33);
17163da5c369Sopenharmony_ci/// initgroups(&user, gid)?;
17173da5c369Sopenharmony_ci/// setgid(gid)?;
17183da5c369Sopenharmony_ci/// setuid(uid)?;
17193da5c369Sopenharmony_ci/// #
17203da5c369Sopenharmony_ci/// #     Ok(())
17213da5c369Sopenharmony_ci/// # }
17223da5c369Sopenharmony_ci/// #
17233da5c369Sopenharmony_ci/// # try_main().unwrap();
17243da5c369Sopenharmony_ci/// ```
17253da5c369Sopenharmony_ci#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "haiku")))]
17263da5c369Sopenharmony_cipub fn initgroups(user: &CStr, group: Gid) -> Result<()> {
17273da5c369Sopenharmony_ci    cfg_if! {
17283da5c369Sopenharmony_ci        if #[cfg(any(target_os = "ios", target_os = "macos"))] {
17293da5c369Sopenharmony_ci            type initgroups_group_t = c_int;
17303da5c369Sopenharmony_ci        } else {
17313da5c369Sopenharmony_ci            type initgroups_group_t = gid_t;
17323da5c369Sopenharmony_ci        }
17333da5c369Sopenharmony_ci    }
17343da5c369Sopenharmony_ci    let gid: gid_t = group.into();
17353da5c369Sopenharmony_ci    let res = unsafe { libc::initgroups(user.as_ptr(), gid as initgroups_group_t) };
17363da5c369Sopenharmony_ci
17373da5c369Sopenharmony_ci    Errno::result(res).map(drop)
17383da5c369Sopenharmony_ci}
17393da5c369Sopenharmony_ci}
17403da5c369Sopenharmony_ci
17413da5c369Sopenharmony_cifeature! {
17423da5c369Sopenharmony_ci#![feature = "signal"]
17433da5c369Sopenharmony_ci
17443da5c369Sopenharmony_ci/// Suspend the thread until a signal is received.
17453da5c369Sopenharmony_ci///
17463da5c369Sopenharmony_ci/// See also [pause(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html).
17473da5c369Sopenharmony_ci#[inline]
17483da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))]
17493da5c369Sopenharmony_cipub fn pause() {
17503da5c369Sopenharmony_ci    unsafe { libc::pause() };
17513da5c369Sopenharmony_ci}
17523da5c369Sopenharmony_ci
17533da5c369Sopenharmony_cipub mod alarm {
17543da5c369Sopenharmony_ci    //! Alarm signal scheduling.
17553da5c369Sopenharmony_ci    //!
17563da5c369Sopenharmony_ci    //! Scheduling an alarm will trigger a `SIGALRM` signal when the time has
17573da5c369Sopenharmony_ci    //! elapsed, which has to be caught, because the default action for the
17583da5c369Sopenharmony_ci    //! signal is to terminate the program. This signal also can't be ignored
17593da5c369Sopenharmony_ci    //! because the system calls like `pause` will not be interrupted, see the
17603da5c369Sopenharmony_ci    //! second example below.
17613da5c369Sopenharmony_ci    //!
17623da5c369Sopenharmony_ci    //! # Examples
17633da5c369Sopenharmony_ci    //!
17643da5c369Sopenharmony_ci    //! Canceling an alarm:
17653da5c369Sopenharmony_ci    //!
17663da5c369Sopenharmony_ci    //! ```
17673da5c369Sopenharmony_ci    //! use nix::unistd::alarm;
17683da5c369Sopenharmony_ci    //!
17693da5c369Sopenharmony_ci    //! // Set an alarm for 60 seconds from now.
17703da5c369Sopenharmony_ci    //! alarm::set(60);
17713da5c369Sopenharmony_ci    //!
17723da5c369Sopenharmony_ci    //! // Cancel the above set alarm, which returns the number of seconds left
17733da5c369Sopenharmony_ci    //! // of the previously set alarm.
17743da5c369Sopenharmony_ci    //! assert_eq!(alarm::cancel(), Some(60));
17753da5c369Sopenharmony_ci    //! ```
17763da5c369Sopenharmony_ci    //!
17773da5c369Sopenharmony_ci    //! Scheduling an alarm and waiting for the signal:
17783da5c369Sopenharmony_ci    //!
17793da5c369Sopenharmony_ci#![cfg_attr(target_os = "redox", doc = " ```rust,ignore")]
17803da5c369Sopenharmony_ci#![cfg_attr(not(target_os = "redox"), doc = " ```rust")]
17813da5c369Sopenharmony_ci    //! use std::time::{Duration, Instant};
17823da5c369Sopenharmony_ci    //!
17833da5c369Sopenharmony_ci    //! use nix::unistd::{alarm, pause};
17843da5c369Sopenharmony_ci    //! use nix::sys::signal::*;
17853da5c369Sopenharmony_ci    //!
17863da5c369Sopenharmony_ci    //! // We need to setup an empty signal handler to catch the alarm signal,
17873da5c369Sopenharmony_ci    //! // otherwise the program will be terminated once the signal is delivered.
17883da5c369Sopenharmony_ci    //! extern fn signal_handler(_: nix::libc::c_int) { }
17893da5c369Sopenharmony_ci    //! let sa = SigAction::new(
17903da5c369Sopenharmony_ci    //!     SigHandler::Handler(signal_handler),
17913da5c369Sopenharmony_ci    //!     SaFlags::SA_RESTART,
17923da5c369Sopenharmony_ci    //!     SigSet::empty()
17933da5c369Sopenharmony_ci    //! );
17943da5c369Sopenharmony_ci    //! unsafe {
17953da5c369Sopenharmony_ci    //!     sigaction(Signal::SIGALRM, &sa);
17963da5c369Sopenharmony_ci    //! }
17973da5c369Sopenharmony_ci    //!
17983da5c369Sopenharmony_ci    //! let start = Instant::now();
17993da5c369Sopenharmony_ci    //!
18003da5c369Sopenharmony_ci    //! // Set an alarm for 1 second from now.
18013da5c369Sopenharmony_ci    //! alarm::set(1);
18023da5c369Sopenharmony_ci    //!
18033da5c369Sopenharmony_ci    //! // Pause the process until the alarm signal is received.
18043da5c369Sopenharmony_ci    //! let mut sigset = SigSet::empty();
18053da5c369Sopenharmony_ci    //! sigset.add(Signal::SIGALRM);
18063da5c369Sopenharmony_ci    //! sigset.wait();
18073da5c369Sopenharmony_ci    //!
18083da5c369Sopenharmony_ci    //! assert!(start.elapsed() >= Duration::from_secs(1));
18093da5c369Sopenharmony_ci    //! ```
18103da5c369Sopenharmony_ci    //!
18113da5c369Sopenharmony_ci    //! # References
18123da5c369Sopenharmony_ci    //!
18133da5c369Sopenharmony_ci    //! See also [alarm(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/alarm.html).
18143da5c369Sopenharmony_ci
18153da5c369Sopenharmony_ci    /// Schedule an alarm signal.
18163da5c369Sopenharmony_ci    ///
18173da5c369Sopenharmony_ci    /// This will cause the system to generate a `SIGALRM` signal for the
18183da5c369Sopenharmony_ci    /// process after the specified number of seconds have elapsed.
18193da5c369Sopenharmony_ci    ///
18203da5c369Sopenharmony_ci    /// Returns the leftover time of a previously set alarm if there was one.
18213da5c369Sopenharmony_ci    pub fn set(secs: libc::c_uint) -> Option<libc::c_uint> {
18223da5c369Sopenharmony_ci        assert!(secs != 0, "passing 0 to `alarm::set` is not allowed, to cancel an alarm use `alarm::cancel`");
18233da5c369Sopenharmony_ci        alarm(secs)
18243da5c369Sopenharmony_ci    }
18253da5c369Sopenharmony_ci
18263da5c369Sopenharmony_ci    /// Cancel an previously set alarm signal.
18273da5c369Sopenharmony_ci    ///
18283da5c369Sopenharmony_ci    /// Returns the leftover time of a previously set alarm if there was one.
18293da5c369Sopenharmony_ci    pub fn cancel() -> Option<libc::c_uint> {
18303da5c369Sopenharmony_ci        alarm(0)
18313da5c369Sopenharmony_ci    }
18323da5c369Sopenharmony_ci
18333da5c369Sopenharmony_ci    fn alarm(secs: libc::c_uint) -> Option<libc::c_uint> {
18343da5c369Sopenharmony_ci        match unsafe { libc::alarm(secs) } {
18353da5c369Sopenharmony_ci            0 => None,
18363da5c369Sopenharmony_ci            secs => Some(secs),
18373da5c369Sopenharmony_ci        }
18383da5c369Sopenharmony_ci    }
18393da5c369Sopenharmony_ci}
18403da5c369Sopenharmony_ci}
18413da5c369Sopenharmony_ci
18423da5c369Sopenharmony_ci/// Suspend execution for an interval of time
18433da5c369Sopenharmony_ci///
18443da5c369Sopenharmony_ci/// See also [sleep(2)](https://pubs.opengroup.org/onlinepubs/009695399/functions/sleep.html#tag_03_705_05)
18453da5c369Sopenharmony_ci// Per POSIX, does not fail
18463da5c369Sopenharmony_ci#[inline]
18473da5c369Sopenharmony_cipub fn sleep(seconds: c_uint) -> c_uint {
18483da5c369Sopenharmony_ci    unsafe { libc::sleep(seconds) }
18493da5c369Sopenharmony_ci}
18503da5c369Sopenharmony_ci
18513da5c369Sopenharmony_cifeature! {
18523da5c369Sopenharmony_ci#![feature = "acct"]
18533da5c369Sopenharmony_ci
18543da5c369Sopenharmony_ci#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
18553da5c369Sopenharmony_cipub mod acct {
18563da5c369Sopenharmony_ci    use crate::{Result, NixPath};
18573da5c369Sopenharmony_ci    use crate::errno::Errno;
18583da5c369Sopenharmony_ci    use std::ptr;
18593da5c369Sopenharmony_ci
18603da5c369Sopenharmony_ci    /// Enable process accounting
18613da5c369Sopenharmony_ci    ///
18623da5c369Sopenharmony_ci    /// See also [acct(2)](https://linux.die.net/man/2/acct)
18633da5c369Sopenharmony_ci    pub fn enable<P: ?Sized + NixPath>(filename: &P) -> Result<()> {
18643da5c369Sopenharmony_ci        let res = filename.with_nix_path(|cstr| {
18653da5c369Sopenharmony_ci            unsafe { libc::acct(cstr.as_ptr()) }
18663da5c369Sopenharmony_ci        })?;
18673da5c369Sopenharmony_ci
18683da5c369Sopenharmony_ci        Errno::result(res).map(drop)
18693da5c369Sopenharmony_ci    }
18703da5c369Sopenharmony_ci
18713da5c369Sopenharmony_ci    /// Disable process accounting
18723da5c369Sopenharmony_ci    pub fn disable() -> Result<()> {
18733da5c369Sopenharmony_ci        let res = unsafe { libc::acct(ptr::null()) };
18743da5c369Sopenharmony_ci
18753da5c369Sopenharmony_ci        Errno::result(res).map(drop)
18763da5c369Sopenharmony_ci    }
18773da5c369Sopenharmony_ci}
18783da5c369Sopenharmony_ci}
18793da5c369Sopenharmony_ci
18803da5c369Sopenharmony_cifeature! {
18813da5c369Sopenharmony_ci#![feature = "fs"]
18823da5c369Sopenharmony_ci/// Creates a regular file which persists even after process termination
18833da5c369Sopenharmony_ci///
18843da5c369Sopenharmony_ci/// * `template`: a path whose 6 rightmost characters must be X, e.g. `/tmp/tmpfile_XXXXXX`
18853da5c369Sopenharmony_ci/// * returns: tuple of file descriptor and filename
18863da5c369Sopenharmony_ci///
18873da5c369Sopenharmony_ci/// Err is returned either if no temporary filename could be created or the template doesn't
18883da5c369Sopenharmony_ci/// end with XXXXXX
18893da5c369Sopenharmony_ci///
18903da5c369Sopenharmony_ci/// See also [mkstemp(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkstemp.html)
18913da5c369Sopenharmony_ci///
18923da5c369Sopenharmony_ci/// # Example
18933da5c369Sopenharmony_ci///
18943da5c369Sopenharmony_ci/// ```rust
18953da5c369Sopenharmony_ci/// use nix::unistd;
18963da5c369Sopenharmony_ci///
18973da5c369Sopenharmony_ci/// let _ = match unistd::mkstemp("/tmp/tempfile_XXXXXX") {
18983da5c369Sopenharmony_ci///     Ok((fd, path)) => {
18993da5c369Sopenharmony_ci///         unistd::unlink(path.as_path()).unwrap(); // flag file to be deleted at app termination
19003da5c369Sopenharmony_ci///         fd
19013da5c369Sopenharmony_ci///     }
19023da5c369Sopenharmony_ci///     Err(e) => panic!("mkstemp failed: {}", e)
19033da5c369Sopenharmony_ci/// };
19043da5c369Sopenharmony_ci/// // do something with fd
19053da5c369Sopenharmony_ci/// ```
19063da5c369Sopenharmony_ci#[inline]
19073da5c369Sopenharmony_cipub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> {
19083da5c369Sopenharmony_ci    let mut path = template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})?;
19093da5c369Sopenharmony_ci    let p = path.as_mut_ptr() as *mut _;
19103da5c369Sopenharmony_ci    let fd = unsafe { libc::mkstemp(p) };
19113da5c369Sopenharmony_ci    let last = path.pop(); // drop the trailing nul
19123da5c369Sopenharmony_ci    debug_assert!(last == Some(b'\0'));
19133da5c369Sopenharmony_ci    let pathname = OsString::from_vec(path);
19143da5c369Sopenharmony_ci    Errno::result(fd)?;
19153da5c369Sopenharmony_ci    Ok((fd, PathBuf::from(pathname)))
19163da5c369Sopenharmony_ci}
19173da5c369Sopenharmony_ci}
19183da5c369Sopenharmony_ci
19193da5c369Sopenharmony_cifeature! {
19203da5c369Sopenharmony_ci#![all(feature = "fs", feature = "feature")]
19213da5c369Sopenharmony_ci
19223da5c369Sopenharmony_ci/// Variable names for `pathconf`
19233da5c369Sopenharmony_ci///
19243da5c369Sopenharmony_ci/// Nix uses the same naming convention for these variables as the
19253da5c369Sopenharmony_ci/// [getconf(1)](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility.
19263da5c369Sopenharmony_ci/// That is, `PathconfVar` variables have the same name as the abstract
19273da5c369Sopenharmony_ci/// variables  shown in the `pathconf(2)` man page.  Usually, it's the same as
19283da5c369Sopenharmony_ci/// the C variable name without the leading `_PC_`.
19293da5c369Sopenharmony_ci///
19303da5c369Sopenharmony_ci/// POSIX 1003.1-2008 standardizes all of these variables, but some OSes choose
19313da5c369Sopenharmony_ci/// not to implement variables that cannot change at runtime.
19323da5c369Sopenharmony_ci///
19333da5c369Sopenharmony_ci/// # References
19343da5c369Sopenharmony_ci///
19353da5c369Sopenharmony_ci/// - [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)
19363da5c369Sopenharmony_ci/// - [limits.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)
19373da5c369Sopenharmony_ci/// - [unistd.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html)
19383da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
19393da5c369Sopenharmony_ci#[repr(i32)]
19403da5c369Sopenharmony_ci#[non_exhaustive]
19413da5c369Sopenharmony_cipub enum PathconfVar {
19423da5c369Sopenharmony_ci    #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux",
19433da5c369Sopenharmony_ci              target_os = "netbsd", target_os = "openbsd", target_os = "redox"))]
19443da5c369Sopenharmony_ci    /// Minimum number of bits needed to represent, as a signed integer value,
19453da5c369Sopenharmony_ci    /// the maximum size of a regular file allowed in the specified directory.
19463da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
19473da5c369Sopenharmony_ci    FILESIZEBITS = libc::_PC_FILESIZEBITS,
19483da5c369Sopenharmony_ci    /// Maximum number of links to a single file.
19493da5c369Sopenharmony_ci    LINK_MAX = libc::_PC_LINK_MAX,
19503da5c369Sopenharmony_ci    /// Maximum number of bytes in a terminal canonical input line.
19513da5c369Sopenharmony_ci    MAX_CANON = libc::_PC_MAX_CANON,
19523da5c369Sopenharmony_ci    /// Minimum number of bytes for which space is available in a terminal input
19533da5c369Sopenharmony_ci    /// queue; therefore, the maximum number of bytes a conforming application
19543da5c369Sopenharmony_ci    /// may require to be typed as input before reading them.
19553da5c369Sopenharmony_ci    MAX_INPUT = libc::_PC_MAX_INPUT,
19563da5c369Sopenharmony_ci    /// Maximum number of bytes in a filename (not including the terminating
19573da5c369Sopenharmony_ci    /// null of a filename string).
19583da5c369Sopenharmony_ci    NAME_MAX = libc::_PC_NAME_MAX,
19593da5c369Sopenharmony_ci    /// Maximum number of bytes the implementation will store as a pathname in a
19603da5c369Sopenharmony_ci    /// user-supplied buffer of unspecified size, including the terminating null
19613da5c369Sopenharmony_ci    /// character. Minimum number the implementation will accept as the maximum
19623da5c369Sopenharmony_ci    /// number of bytes in a pathname.
19633da5c369Sopenharmony_ci    PATH_MAX = libc::_PC_PATH_MAX,
19643da5c369Sopenharmony_ci    /// Maximum number of bytes that is guaranteed to be atomic when writing to
19653da5c369Sopenharmony_ci    /// a pipe.
19663da5c369Sopenharmony_ci    PIPE_BUF = libc::_PC_PIPE_BUF,
19673da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "illumos",
19683da5c369Sopenharmony_ci              target_os = "linux", target_os = "netbsd", target_os = "openbsd",
19693da5c369Sopenharmony_ci              target_os = "redox", target_os = "solaris"))]
19703da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
19713da5c369Sopenharmony_ci    /// Symbolic links can be created.
19723da5c369Sopenharmony_ci    POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS,
19733da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
19743da5c369Sopenharmony_ci              target_os = "linux", target_os = "openbsd", target_os = "redox"))]
19753da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
19763da5c369Sopenharmony_ci    /// Minimum number of bytes of storage actually allocated for any portion of
19773da5c369Sopenharmony_ci    /// a file.
19783da5c369Sopenharmony_ci    POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN,
19793da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
19803da5c369Sopenharmony_ci              target_os = "linux", target_os = "openbsd"))]
19813da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
19823da5c369Sopenharmony_ci    /// Recommended increment for file transfer sizes between the
19833da5c369Sopenharmony_ci    /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values.
19843da5c369Sopenharmony_ci    POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE,
19853da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
19863da5c369Sopenharmony_ci              target_os = "linux", target_os = "openbsd", target_os = "redox"))]
19873da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
19883da5c369Sopenharmony_ci    /// Maximum recommended file transfer size.
19893da5c369Sopenharmony_ci    POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE,
19903da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
19913da5c369Sopenharmony_ci              target_os = "linux", target_os = "openbsd", target_os = "redox"))]
19923da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
19933da5c369Sopenharmony_ci    /// Minimum recommended file transfer size.
19943da5c369Sopenharmony_ci    POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE,
19953da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
19963da5c369Sopenharmony_ci              target_os = "linux", target_os = "openbsd", target_os = "redox"))]
19973da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
19983da5c369Sopenharmony_ci    ///  Recommended file transfer buffer alignment.
19993da5c369Sopenharmony_ci    POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN,
20003da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
20013da5c369Sopenharmony_ci              target_os = "illumos", target_os = "linux", target_os = "netbsd",
20023da5c369Sopenharmony_ci              target_os = "openbsd", target_os = "redox", target_os = "solaris"))]
20033da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
20043da5c369Sopenharmony_ci    /// Maximum number of bytes in a symbolic link.
20053da5c369Sopenharmony_ci    SYMLINK_MAX = libc::_PC_SYMLINK_MAX,
20063da5c369Sopenharmony_ci    /// The use of `chown` and `fchown` is restricted to a process with
20073da5c369Sopenharmony_ci    /// appropriate privileges, and to changing the group ID of a file only to
20083da5c369Sopenharmony_ci    /// the effective group ID of the process or to one of its supplementary
20093da5c369Sopenharmony_ci    /// group IDs.
20103da5c369Sopenharmony_ci    _POSIX_CHOWN_RESTRICTED = libc::_PC_CHOWN_RESTRICTED,
20113da5c369Sopenharmony_ci    /// Pathname components longer than {NAME_MAX} generate an error.
20123da5c369Sopenharmony_ci    _POSIX_NO_TRUNC = libc::_PC_NO_TRUNC,
20133da5c369Sopenharmony_ci    /// This symbol shall be defined to be the value of a character that shall
20143da5c369Sopenharmony_ci    /// disable terminal special character handling.
20153da5c369Sopenharmony_ci    _POSIX_VDISABLE = libc::_PC_VDISABLE,
20163da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
20173da5c369Sopenharmony_ci              target_os = "illumos", target_os = "linux", target_os = "openbsd",
20183da5c369Sopenharmony_ci              target_os = "redox", target_os = "solaris"))]
20193da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
20203da5c369Sopenharmony_ci    /// Asynchronous input or output operations may be performed for the
20213da5c369Sopenharmony_ci    /// associated file.
20223da5c369Sopenharmony_ci    _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO,
20233da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
20243da5c369Sopenharmony_ci              target_os = "illumos", target_os = "linux", target_os = "openbsd",
20253da5c369Sopenharmony_ci              target_os = "redox", target_os = "solaris"))]
20263da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
20273da5c369Sopenharmony_ci    /// Prioritized input or output operations may be performed for the
20283da5c369Sopenharmony_ci    /// associated file.
20293da5c369Sopenharmony_ci    _POSIX_PRIO_IO = libc::_PC_PRIO_IO,
20303da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
20313da5c369Sopenharmony_ci              target_os = "illumos", target_os = "linux", target_os = "netbsd",
20323da5c369Sopenharmony_ci              target_os = "openbsd", target_os = "redox", target_os = "solaris"))]
20333da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
20343da5c369Sopenharmony_ci    /// Synchronized input or output operations may be performed for the
20353da5c369Sopenharmony_ci    /// associated file.
20363da5c369Sopenharmony_ci    _POSIX_SYNC_IO = libc::_PC_SYNC_IO,
20373da5c369Sopenharmony_ci    #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))]
20383da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
20393da5c369Sopenharmony_ci    /// The resolution in nanoseconds for all file timestamps.
20403da5c369Sopenharmony_ci    _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION
20413da5c369Sopenharmony_ci}
20423da5c369Sopenharmony_ci
20433da5c369Sopenharmony_ci/// Like `pathconf`, but works with file descriptors instead of paths (see
20443da5c369Sopenharmony_ci/// [fpathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html))
20453da5c369Sopenharmony_ci///
20463da5c369Sopenharmony_ci/// # Parameters
20473da5c369Sopenharmony_ci///
20483da5c369Sopenharmony_ci/// - `fd`:   The file descriptor whose variable should be interrogated
20493da5c369Sopenharmony_ci/// - `var`:  The pathconf variable to lookup
20503da5c369Sopenharmony_ci///
20513da5c369Sopenharmony_ci/// # Returns
20523da5c369Sopenharmony_ci///
20533da5c369Sopenharmony_ci/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its
20543da5c369Sopenharmony_ci///     implementation level (for option variables).  Implementation levels are
20553da5c369Sopenharmony_ci///     usually a decimal-coded date, such as 200112 for POSIX 2001.12
20563da5c369Sopenharmony_ci/// - `Ok(None)`: the variable has no limit (for limit variables) or is
20573da5c369Sopenharmony_ci///     unsupported (for option variables)
20583da5c369Sopenharmony_ci/// - `Err(x)`: an error occurred
20593da5c369Sopenharmony_cipub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>> {
20603da5c369Sopenharmony_ci    let raw = unsafe {
20613da5c369Sopenharmony_ci        Errno::clear();
20623da5c369Sopenharmony_ci        libc::fpathconf(fd, var as c_int)
20633da5c369Sopenharmony_ci    };
20643da5c369Sopenharmony_ci    if raw == -1 {
20653da5c369Sopenharmony_ci        if errno::errno() == 0 {
20663da5c369Sopenharmony_ci            Ok(None)
20673da5c369Sopenharmony_ci        } else {
20683da5c369Sopenharmony_ci            Err(Errno::last())
20693da5c369Sopenharmony_ci        }
20703da5c369Sopenharmony_ci    } else {
20713da5c369Sopenharmony_ci        Ok(Some(raw))
20723da5c369Sopenharmony_ci    }
20733da5c369Sopenharmony_ci}
20743da5c369Sopenharmony_ci
20753da5c369Sopenharmony_ci/// Get path-dependent configurable system variables (see
20763da5c369Sopenharmony_ci/// [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html))
20773da5c369Sopenharmony_ci///
20783da5c369Sopenharmony_ci/// Returns the value of a path-dependent configurable system variable.  Most
20793da5c369Sopenharmony_ci/// supported variables also have associated compile-time constants, but POSIX
20803da5c369Sopenharmony_ci/// allows their values to change at runtime.  There are generally two types of
20813da5c369Sopenharmony_ci/// `pathconf` variables: options and limits.  See [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) for more details.
20823da5c369Sopenharmony_ci///
20833da5c369Sopenharmony_ci/// # Parameters
20843da5c369Sopenharmony_ci///
20853da5c369Sopenharmony_ci/// - `path`: Lookup the value of `var` for this file or directory
20863da5c369Sopenharmony_ci/// - `var`:  The `pathconf` variable to lookup
20873da5c369Sopenharmony_ci///
20883da5c369Sopenharmony_ci/// # Returns
20893da5c369Sopenharmony_ci///
20903da5c369Sopenharmony_ci/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its
20913da5c369Sopenharmony_ci///     implementation level (for option variables).  Implementation levels are
20923da5c369Sopenharmony_ci///     usually a decimal-coded date, such as 200112 for POSIX 2001.12
20933da5c369Sopenharmony_ci/// - `Ok(None)`: the variable has no limit (for limit variables) or is
20943da5c369Sopenharmony_ci///     unsupported (for option variables)
20953da5c369Sopenharmony_ci/// - `Err(x)`: an error occurred
20963da5c369Sopenharmony_cipub fn pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Option<c_long>> {
20973da5c369Sopenharmony_ci    let raw = path.with_nix_path(|cstr| {
20983da5c369Sopenharmony_ci        unsafe {
20993da5c369Sopenharmony_ci            Errno::clear();
21003da5c369Sopenharmony_ci            libc::pathconf(cstr.as_ptr(), var as c_int)
21013da5c369Sopenharmony_ci        }
21023da5c369Sopenharmony_ci    })?;
21033da5c369Sopenharmony_ci    if raw == -1 {
21043da5c369Sopenharmony_ci        if errno::errno() == 0 {
21053da5c369Sopenharmony_ci            Ok(None)
21063da5c369Sopenharmony_ci        } else {
21073da5c369Sopenharmony_ci            Err(Errno::last())
21083da5c369Sopenharmony_ci        }
21093da5c369Sopenharmony_ci    } else {
21103da5c369Sopenharmony_ci        Ok(Some(raw))
21113da5c369Sopenharmony_ci    }
21123da5c369Sopenharmony_ci}
21133da5c369Sopenharmony_ci}
21143da5c369Sopenharmony_ci
21153da5c369Sopenharmony_cifeature! {
21163da5c369Sopenharmony_ci#![feature = "feature"]
21173da5c369Sopenharmony_ci
21183da5c369Sopenharmony_ci/// Variable names for `sysconf`
21193da5c369Sopenharmony_ci///
21203da5c369Sopenharmony_ci/// Nix uses the same naming convention for these variables as the
21213da5c369Sopenharmony_ci/// [getconf(1)](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility.
21223da5c369Sopenharmony_ci/// That is, `SysconfVar` variables have the same name as the abstract variables
21233da5c369Sopenharmony_ci/// shown in the `sysconf(3)` man page.  Usually, it's the same as the C
21243da5c369Sopenharmony_ci/// variable name without the leading `_SC_`.
21253da5c369Sopenharmony_ci///
21263da5c369Sopenharmony_ci/// All of these symbols are standardized by POSIX 1003.1-2008, but haven't been
21273da5c369Sopenharmony_ci/// implemented by all platforms.
21283da5c369Sopenharmony_ci///
21293da5c369Sopenharmony_ci/// # References
21303da5c369Sopenharmony_ci///
21313da5c369Sopenharmony_ci/// - [sysconf(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html)
21323da5c369Sopenharmony_ci/// - [unistd.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html)
21333da5c369Sopenharmony_ci/// - [limits.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)
21343da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
21353da5c369Sopenharmony_ci#[repr(i32)]
21363da5c369Sopenharmony_ci#[non_exhaustive]
21373da5c369Sopenharmony_cipub enum SysconfVar {
21383da5c369Sopenharmony_ci    /// Maximum number of I/O operations in a single list I/O call supported by
21393da5c369Sopenharmony_ci    /// the implementation.
21403da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
21413da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
21423da5c369Sopenharmony_ci    AIO_LISTIO_MAX = libc::_SC_AIO_LISTIO_MAX,
21433da5c369Sopenharmony_ci    /// Maximum number of outstanding asynchronous I/O operations supported by
21443da5c369Sopenharmony_ci    /// the implementation.
21453da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
21463da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
21473da5c369Sopenharmony_ci    AIO_MAX = libc::_SC_AIO_MAX,
21483da5c369Sopenharmony_ci    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
21493da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
21503da5c369Sopenharmony_ci              target_os="openbsd"))]
21513da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
21523da5c369Sopenharmony_ci    /// The maximum amount by which a process can decrease its asynchronous I/O
21533da5c369Sopenharmony_ci    /// priority level from its own scheduling priority.
21543da5c369Sopenharmony_ci    AIO_PRIO_DELTA_MAX = libc::_SC_AIO_PRIO_DELTA_MAX,
21553da5c369Sopenharmony_ci    /// Maximum length of argument to the exec functions including environment data.
21563da5c369Sopenharmony_ci    ARG_MAX = libc::_SC_ARG_MAX,
21573da5c369Sopenharmony_ci    /// Maximum number of functions that may be registered with `atexit`.
21583da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
21593da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
21603da5c369Sopenharmony_ci    ATEXIT_MAX = libc::_SC_ATEXIT_MAX,
21613da5c369Sopenharmony_ci    /// Maximum obase values allowed by the bc utility.
21623da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
21633da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
21643da5c369Sopenharmony_ci    BC_BASE_MAX = libc::_SC_BC_BASE_MAX,
21653da5c369Sopenharmony_ci    /// Maximum number of elements permitted in an array by the bc utility.
21663da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
21673da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
21683da5c369Sopenharmony_ci    BC_DIM_MAX = libc::_SC_BC_DIM_MAX,
21693da5c369Sopenharmony_ci    /// Maximum scale value allowed by the bc utility.
21703da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
21713da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
21723da5c369Sopenharmony_ci    BC_SCALE_MAX = libc::_SC_BC_SCALE_MAX,
21733da5c369Sopenharmony_ci    /// Maximum length of a string constant accepted by the bc utility.
21743da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
21753da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
21763da5c369Sopenharmony_ci    BC_STRING_MAX = libc::_SC_BC_STRING_MAX,
21773da5c369Sopenharmony_ci    /// Maximum number of simultaneous processes per real user ID.
21783da5c369Sopenharmony_ci    CHILD_MAX = libc::_SC_CHILD_MAX,
21793da5c369Sopenharmony_ci    // The number of clock ticks per second.
21803da5c369Sopenharmony_ci    CLK_TCK = libc::_SC_CLK_TCK,
21813da5c369Sopenharmony_ci    /// Maximum number of weights that can be assigned to an entry of the
21823da5c369Sopenharmony_ci    /// LC_COLLATE order keyword in the locale definition file
21833da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
21843da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
21853da5c369Sopenharmony_ci    COLL_WEIGHTS_MAX = libc::_SC_COLL_WEIGHTS_MAX,
21863da5c369Sopenharmony_ci    /// Maximum number of timer expiration overruns.
21873da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
21883da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
21893da5c369Sopenharmony_ci    DELAYTIMER_MAX = libc::_SC_DELAYTIMER_MAX,
21903da5c369Sopenharmony_ci    /// Maximum number of expressions that can be nested within parentheses by
21913da5c369Sopenharmony_ci    /// the expr utility.
21923da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
21933da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
21943da5c369Sopenharmony_ci    EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX,
21953da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
21963da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
21973da5c369Sopenharmony_ci              target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
21983da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
21993da5c369Sopenharmony_ci    /// Maximum length of a host name (not including the terminating null) as
22003da5c369Sopenharmony_ci    /// returned from the `gethostname` function
22013da5c369Sopenharmony_ci    HOST_NAME_MAX = libc::_SC_HOST_NAME_MAX,
22023da5c369Sopenharmony_ci    /// Maximum number of iovec structures that one process has available for
22033da5c369Sopenharmony_ci    /// use with `readv` or `writev`.
22043da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
22053da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22063da5c369Sopenharmony_ci    IOV_MAX = libc::_SC_IOV_MAX,
22073da5c369Sopenharmony_ci    /// Unless otherwise noted, the maximum length, in bytes, of a utility's
22083da5c369Sopenharmony_ci    /// input line (either standard input or another file), when the utility is
22093da5c369Sopenharmony_ci    /// described as processing text files. The length includes room for the
22103da5c369Sopenharmony_ci    /// trailing newline.
22113da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
22123da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22133da5c369Sopenharmony_ci    LINE_MAX = libc::_SC_LINE_MAX,
22143da5c369Sopenharmony_ci    /// Maximum length of a login name.
22153da5c369Sopenharmony_ci    #[cfg(not(target_os = "haiku"))]
22163da5c369Sopenharmony_ci    LOGIN_NAME_MAX = libc::_SC_LOGIN_NAME_MAX,
22173da5c369Sopenharmony_ci    /// Maximum number of simultaneous supplementary group IDs per process.
22183da5c369Sopenharmony_ci    NGROUPS_MAX = libc::_SC_NGROUPS_MAX,
22193da5c369Sopenharmony_ci    /// Initial size of `getgrgid_r` and `getgrnam_r` data buffers
22203da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
22213da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22223da5c369Sopenharmony_ci    GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX,
22233da5c369Sopenharmony_ci    /// Initial size of `getpwuid_r` and `getpwnam_r` data buffers
22243da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
22253da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22263da5c369Sopenharmony_ci    GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX,
22273da5c369Sopenharmony_ci    /// The maximum number of open message queue descriptors a process may hold.
22283da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
22293da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22303da5c369Sopenharmony_ci    MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX,
22313da5c369Sopenharmony_ci    /// The maximum number of message priorities supported by the implementation.
22323da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
22333da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22343da5c369Sopenharmony_ci    MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX,
22353da5c369Sopenharmony_ci    /// A value one greater than the maximum value that the system may assign to
22363da5c369Sopenharmony_ci    /// a newly-created file descriptor.
22373da5c369Sopenharmony_ci    OPEN_MAX = libc::_SC_OPEN_MAX,
22383da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
22393da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="openbsd"))]
22403da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22413da5c369Sopenharmony_ci    /// The implementation supports the Advisory Information option.
22423da5c369Sopenharmony_ci    _POSIX_ADVISORY_INFO = libc::_SC_ADVISORY_INFO,
22433da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
22443da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
22453da5c369Sopenharmony_ci              target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
22463da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22473da5c369Sopenharmony_ci    /// The implementation supports barriers.
22483da5c369Sopenharmony_ci    _POSIX_BARRIERS = libc::_SC_BARRIERS,
22493da5c369Sopenharmony_ci    /// The implementation supports asynchronous input and output.
22503da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
22513da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22523da5c369Sopenharmony_ci    _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO,
22533da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
22543da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
22553da5c369Sopenharmony_ci              target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
22563da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22573da5c369Sopenharmony_ci    /// The implementation supports clock selection.
22583da5c369Sopenharmony_ci    _POSIX_CLOCK_SELECTION = libc::_SC_CLOCK_SELECTION,
22593da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
22603da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
22613da5c369Sopenharmony_ci              target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
22623da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22633da5c369Sopenharmony_ci    /// The implementation supports the Process CPU-Time Clocks option.
22643da5c369Sopenharmony_ci    _POSIX_CPUTIME = libc::_SC_CPUTIME,
22653da5c369Sopenharmony_ci    /// The implementation supports the File Synchronization option.
22663da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
22673da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22683da5c369Sopenharmony_ci    _POSIX_FSYNC = libc::_SC_FSYNC,
22693da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
22703da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
22713da5c369Sopenharmony_ci              target_os="openbsd", target_os = "solaris"))]
22723da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22733da5c369Sopenharmony_ci    /// The implementation supports the IPv6 option.
22743da5c369Sopenharmony_ci    _POSIX_IPV6 = libc::_SC_IPV6,
22753da5c369Sopenharmony_ci    /// The implementation supports job control.
22763da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
22773da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22783da5c369Sopenharmony_ci    _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL,
22793da5c369Sopenharmony_ci    /// The implementation supports memory mapped Files.
22803da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
22813da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22823da5c369Sopenharmony_ci    _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES,
22833da5c369Sopenharmony_ci    /// The implementation supports the Process Memory Locking option.
22843da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
22853da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22863da5c369Sopenharmony_ci    _POSIX_MEMLOCK = libc::_SC_MEMLOCK,
22873da5c369Sopenharmony_ci    /// The implementation supports the Range Memory Locking option.
22883da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
22893da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22903da5c369Sopenharmony_ci    _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE,
22913da5c369Sopenharmony_ci    /// The implementation supports memory protection.
22923da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
22933da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22943da5c369Sopenharmony_ci    _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION,
22953da5c369Sopenharmony_ci    /// The implementation supports the Message Passing option.
22963da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
22973da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
22983da5c369Sopenharmony_ci    _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING,
22993da5c369Sopenharmony_ci    /// The implementation supports the Monotonic Clock option.
23003da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
23013da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23023da5c369Sopenharmony_ci    _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK,
23033da5c369Sopenharmony_ci    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
23043da5c369Sopenharmony_ci              target_os = "illumos", target_os = "ios", target_os="linux",
23053da5c369Sopenharmony_ci              target_os = "macos", target_os="openbsd", target_os = "solaris"))]
23063da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23073da5c369Sopenharmony_ci    /// The implementation supports the Prioritized Input and Output option.
23083da5c369Sopenharmony_ci    _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO,
23093da5c369Sopenharmony_ci    /// The implementation supports the Process Scheduling option.
23103da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
23113da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23123da5c369Sopenharmony_ci    _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING,
23133da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
23143da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
23153da5c369Sopenharmony_ci              target_os="openbsd", target_os = "solaris"))]
23163da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23173da5c369Sopenharmony_ci    /// The implementation supports the Raw Sockets option.
23183da5c369Sopenharmony_ci    _POSIX_RAW_SOCKETS = libc::_SC_RAW_SOCKETS,
23193da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
23203da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
23213da5c369Sopenharmony_ci              target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
23223da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23233da5c369Sopenharmony_ci    /// The implementation supports read-write locks.
23243da5c369Sopenharmony_ci    _POSIX_READER_WRITER_LOCKS = libc::_SC_READER_WRITER_LOCKS,
23253da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd",
23263da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
23273da5c369Sopenharmony_ci              target_os = "openbsd"))]
23283da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23293da5c369Sopenharmony_ci    /// The implementation supports realtime signals.
23303da5c369Sopenharmony_ci    _POSIX_REALTIME_SIGNALS = libc::_SC_REALTIME_SIGNALS,
23313da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
23323da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
23333da5c369Sopenharmony_ci              target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
23343da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23353da5c369Sopenharmony_ci    /// The implementation supports the Regular Expression Handling option.
23363da5c369Sopenharmony_ci    _POSIX_REGEXP = libc::_SC_REGEXP,
23373da5c369Sopenharmony_ci    /// Each process has a saved set-user-ID and a saved set-group-ID.
23383da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
23393da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23403da5c369Sopenharmony_ci    _POSIX_SAVED_IDS = libc::_SC_SAVED_IDS,
23413da5c369Sopenharmony_ci    /// The implementation supports semaphores.
23423da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
23433da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23443da5c369Sopenharmony_ci    _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES,
23453da5c369Sopenharmony_ci    /// The implementation supports the Shared Memory Objects option.
23463da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
23473da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23483da5c369Sopenharmony_ci    _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS,
23493da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
23503da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="netbsd",
23513da5c369Sopenharmony_ci              target_os="openbsd"))]
23523da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23533da5c369Sopenharmony_ci    /// The implementation supports the POSIX shell.
23543da5c369Sopenharmony_ci    _POSIX_SHELL = libc::_SC_SHELL,
23553da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
23563da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="netbsd",
23573da5c369Sopenharmony_ci              target_os="openbsd"))]
23583da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23593da5c369Sopenharmony_ci    /// The implementation supports the Spawn option.
23603da5c369Sopenharmony_ci    _POSIX_SPAWN = libc::_SC_SPAWN,
23613da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
23623da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="netbsd",
23633da5c369Sopenharmony_ci              target_os="openbsd"))]
23643da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23653da5c369Sopenharmony_ci    /// The implementation supports spin locks.
23663da5c369Sopenharmony_ci    _POSIX_SPIN_LOCKS = libc::_SC_SPIN_LOCKS,
23673da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
23683da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="openbsd"))]
23693da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23703da5c369Sopenharmony_ci    /// The implementation supports the Process Sporadic Server option.
23713da5c369Sopenharmony_ci    _POSIX_SPORADIC_SERVER = libc::_SC_SPORADIC_SERVER,
23723da5c369Sopenharmony_ci    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
23733da5c369Sopenharmony_ci              target_os="openbsd"))]
23743da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23753da5c369Sopenharmony_ci    _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX,
23763da5c369Sopenharmony_ci    /// The implementation supports the Synchronized Input and Output option.
23773da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
23783da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23793da5c369Sopenharmony_ci    _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO,
23803da5c369Sopenharmony_ci    /// The implementation supports the Thread Stack Address Attribute option.
23813da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
23823da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23833da5c369Sopenharmony_ci    _POSIX_THREAD_ATTR_STACKADDR = libc::_SC_THREAD_ATTR_STACKADDR,
23843da5c369Sopenharmony_ci    /// The implementation supports the Thread Stack Size Attribute option.
23853da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
23863da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23873da5c369Sopenharmony_ci    _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE,
23883da5c369Sopenharmony_ci    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
23893da5c369Sopenharmony_ci              target_os="netbsd", target_os="openbsd"))]
23903da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23913da5c369Sopenharmony_ci    /// The implementation supports the Thread CPU-Time Clocks option.
23923da5c369Sopenharmony_ci    _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME,
23933da5c369Sopenharmony_ci    /// The implementation supports the Non-Robust Mutex Priority Inheritance
23943da5c369Sopenharmony_ci    /// option.
23953da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
23963da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
23973da5c369Sopenharmony_ci    _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT,
23983da5c369Sopenharmony_ci    /// The implementation supports the Non-Robust Mutex Priority Protection option.
23993da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
24003da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24013da5c369Sopenharmony_ci    _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT,
24023da5c369Sopenharmony_ci    /// The implementation supports the Thread Execution Scheduling option.
24033da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
24043da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24053da5c369Sopenharmony_ci    _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING,
24063da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
24073da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="netbsd",
24083da5c369Sopenharmony_ci              target_os="openbsd"))]
24093da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24103da5c369Sopenharmony_ci    /// The implementation supports the Thread Process-Shared Synchronization
24113da5c369Sopenharmony_ci    /// option.
24123da5c369Sopenharmony_ci    _POSIX_THREAD_PROCESS_SHARED = libc::_SC_THREAD_PROCESS_SHARED,
24133da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))]
24143da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24153da5c369Sopenharmony_ci    /// The implementation supports the Robust Mutex Priority Inheritance option.
24163da5c369Sopenharmony_ci    _POSIX_THREAD_ROBUST_PRIO_INHERIT = libc::_SC_THREAD_ROBUST_PRIO_INHERIT,
24173da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))]
24183da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24193da5c369Sopenharmony_ci    /// The implementation supports the Robust Mutex Priority Protection option.
24203da5c369Sopenharmony_ci    _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT,
24213da5c369Sopenharmony_ci    /// The implementation supports thread-safe functions.
24223da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
24233da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24243da5c369Sopenharmony_ci    _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS,
24253da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
24263da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="openbsd"))]
24273da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24283da5c369Sopenharmony_ci    /// The implementation supports the Thread Sporadic Server option.
24293da5c369Sopenharmony_ci    _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER,
24303da5c369Sopenharmony_ci    /// The implementation supports threads.
24313da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
24323da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24333da5c369Sopenharmony_ci    _POSIX_THREADS = libc::_SC_THREADS,
24343da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
24353da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="openbsd"))]
24363da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24373da5c369Sopenharmony_ci    /// The implementation supports timeouts.
24383da5c369Sopenharmony_ci    _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS,
24393da5c369Sopenharmony_ci    /// The implementation supports timers.
24403da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
24413da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24423da5c369Sopenharmony_ci    _POSIX_TIMERS = libc::_SC_TIMERS,
24433da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
24443da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="openbsd"))]
24453da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24463da5c369Sopenharmony_ci    /// The implementation supports the Trace option.
24473da5c369Sopenharmony_ci    _POSIX_TRACE = libc::_SC_TRACE,
24483da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
24493da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="openbsd"))]
24503da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24513da5c369Sopenharmony_ci    /// The implementation supports the Trace Event Filter option.
24523da5c369Sopenharmony_ci    _POSIX_TRACE_EVENT_FILTER = libc::_SC_TRACE_EVENT_FILTER,
24533da5c369Sopenharmony_ci    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
24543da5c369Sopenharmony_ci              target_os="openbsd"))]
24553da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24563da5c369Sopenharmony_ci    _POSIX_TRACE_EVENT_NAME_MAX = libc::_SC_TRACE_EVENT_NAME_MAX,
24573da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
24583da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="openbsd"))]
24593da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24603da5c369Sopenharmony_ci    /// The implementation supports the Trace Inherit option.
24613da5c369Sopenharmony_ci    _POSIX_TRACE_INHERIT = libc::_SC_TRACE_INHERIT,
24623da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
24633da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="openbsd"))]
24643da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24653da5c369Sopenharmony_ci    /// The implementation supports the Trace Log option.
24663da5c369Sopenharmony_ci    _POSIX_TRACE_LOG = libc::_SC_TRACE_LOG,
24673da5c369Sopenharmony_ci    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
24683da5c369Sopenharmony_ci              target_os="openbsd"))]
24693da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24703da5c369Sopenharmony_ci    _POSIX_TRACE_NAME_MAX = libc::_SC_TRACE_NAME_MAX,
24713da5c369Sopenharmony_ci    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
24723da5c369Sopenharmony_ci              target_os="openbsd"))]
24733da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24743da5c369Sopenharmony_ci    _POSIX_TRACE_SYS_MAX = libc::_SC_TRACE_SYS_MAX,
24753da5c369Sopenharmony_ci    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
24763da5c369Sopenharmony_ci              target_os="openbsd"))]
24773da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24783da5c369Sopenharmony_ci    _POSIX_TRACE_USER_EVENT_MAX = libc::_SC_TRACE_USER_EVENT_MAX,
24793da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
24803da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="openbsd"))]
24813da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24823da5c369Sopenharmony_ci    /// The implementation supports the Typed Memory Objects option.
24833da5c369Sopenharmony_ci    _POSIX_TYPED_MEMORY_OBJECTS = libc::_SC_TYPED_MEMORY_OBJECTS,
24843da5c369Sopenharmony_ci    /// Integer value indicating version of this standard (C-language binding)
24853da5c369Sopenharmony_ci    /// to which the implementation conforms. For implementations conforming to
24863da5c369Sopenharmony_ci    /// POSIX.1-2008, the value shall be 200809L.
24873da5c369Sopenharmony_ci    _POSIX_VERSION = libc::_SC_VERSION,
24883da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
24893da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="netbsd",
24903da5c369Sopenharmony_ci              target_os="openbsd"))]
24913da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24923da5c369Sopenharmony_ci    /// The implementation provides a C-language compilation environment with
24933da5c369Sopenharmony_ci    /// 32-bit `int`, `long`, `pointer`, and `off_t` types.
24943da5c369Sopenharmony_ci    _POSIX_V6_ILP32_OFF32 = libc::_SC_V6_ILP32_OFF32,
24953da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
24963da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="netbsd",
24973da5c369Sopenharmony_ci              target_os="openbsd"))]
24983da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
24993da5c369Sopenharmony_ci    /// The implementation provides a C-language compilation environment with
25003da5c369Sopenharmony_ci    /// 32-bit `int`, `long`, and pointer types and an `off_t` type using at
25013da5c369Sopenharmony_ci    /// least 64 bits.
25023da5c369Sopenharmony_ci    _POSIX_V6_ILP32_OFFBIG = libc::_SC_V6_ILP32_OFFBIG,
25033da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
25043da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="netbsd",
25053da5c369Sopenharmony_ci              target_os="openbsd"))]
25063da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25073da5c369Sopenharmony_ci    /// The implementation provides a C-language compilation environment with
25083da5c369Sopenharmony_ci    /// 32-bit `int` and 64-bit `long`, `pointer`, and `off_t` types.
25093da5c369Sopenharmony_ci    _POSIX_V6_LP64_OFF64 = libc::_SC_V6_LP64_OFF64,
25103da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
25113da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="netbsd",
25123da5c369Sopenharmony_ci              target_os="openbsd"))]
25133da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25143da5c369Sopenharmony_ci    /// The implementation provides a C-language compilation environment with an
25153da5c369Sopenharmony_ci    /// `int` type using at least 32 bits and `long`, pointer, and `off_t` types
25163da5c369Sopenharmony_ci    /// using at least 64 bits.
25173da5c369Sopenharmony_ci    _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG,
25183da5c369Sopenharmony_ci    /// The implementation supports the C-Language Binding option.
25193da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
25203da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25213da5c369Sopenharmony_ci    _POSIX2_C_BIND = libc::_SC_2_C_BIND,
25223da5c369Sopenharmony_ci    /// The implementation supports the C-Language Development Utilities option.
25233da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
25243da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25253da5c369Sopenharmony_ci    _POSIX2_C_DEV = libc::_SC_2_C_DEV,
25263da5c369Sopenharmony_ci    /// The implementation supports the Terminal Characteristics option.
25273da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
25283da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25293da5c369Sopenharmony_ci    _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM,
25303da5c369Sopenharmony_ci    /// The implementation supports the FORTRAN Development Utilities option.
25313da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
25323da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25333da5c369Sopenharmony_ci    _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV,
25343da5c369Sopenharmony_ci    /// The implementation supports the FORTRAN Runtime Utilities option.
25353da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
25363da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25373da5c369Sopenharmony_ci    _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN,
25383da5c369Sopenharmony_ci    /// The implementation supports the creation of locales by the localedef
25393da5c369Sopenharmony_ci    /// utility.
25403da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
25413da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25423da5c369Sopenharmony_ci    _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF,
25433da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
25443da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="netbsd",
25453da5c369Sopenharmony_ci              target_os="openbsd"))]
25463da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25473da5c369Sopenharmony_ci    /// The implementation supports the Batch Environment Services and Utilities
25483da5c369Sopenharmony_ci    /// option.
25493da5c369Sopenharmony_ci    _POSIX2_PBS = libc::_SC_2_PBS,
25503da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
25513da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="netbsd",
25523da5c369Sopenharmony_ci              target_os="openbsd"))]
25533da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25543da5c369Sopenharmony_ci    /// The implementation supports the Batch Accounting option.
25553da5c369Sopenharmony_ci    _POSIX2_PBS_ACCOUNTING = libc::_SC_2_PBS_ACCOUNTING,
25563da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
25573da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="netbsd",
25583da5c369Sopenharmony_ci              target_os="openbsd"))]
25593da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25603da5c369Sopenharmony_ci    /// The implementation supports the Batch Checkpoint/Restart option.
25613da5c369Sopenharmony_ci    _POSIX2_PBS_CHECKPOINT = libc::_SC_2_PBS_CHECKPOINT,
25623da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
25633da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="netbsd",
25643da5c369Sopenharmony_ci              target_os="openbsd"))]
25653da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25663da5c369Sopenharmony_ci    /// The implementation supports the Locate Batch Job Request option.
25673da5c369Sopenharmony_ci    _POSIX2_PBS_LOCATE = libc::_SC_2_PBS_LOCATE,
25683da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
25693da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="netbsd",
25703da5c369Sopenharmony_ci              target_os="openbsd"))]
25713da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25723da5c369Sopenharmony_ci    /// The implementation supports the Batch Job Message Request option.
25733da5c369Sopenharmony_ci    _POSIX2_PBS_MESSAGE = libc::_SC_2_PBS_MESSAGE,
25743da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
25753da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="netbsd",
25763da5c369Sopenharmony_ci              target_os="openbsd"))]
25773da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25783da5c369Sopenharmony_ci    /// The implementation supports the Track Batch Job Request option.
25793da5c369Sopenharmony_ci    _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK,
25803da5c369Sopenharmony_ci    /// The implementation supports the Software Development Utilities option.
25813da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
25823da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25833da5c369Sopenharmony_ci    _POSIX2_SW_DEV = libc::_SC_2_SW_DEV,
25843da5c369Sopenharmony_ci    /// The implementation supports the User Portability Utilities option.
25853da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
25863da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25873da5c369Sopenharmony_ci    _POSIX2_UPE = libc::_SC_2_UPE,
25883da5c369Sopenharmony_ci    /// Integer value indicating version of the Shell and Utilities volume of
25893da5c369Sopenharmony_ci    /// POSIX.1 to which the implementation conforms.
25903da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
25913da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
25923da5c369Sopenharmony_ci    _POSIX2_VERSION = libc::_SC_2_VERSION,
25933da5c369Sopenharmony_ci    /// The size of a system page in bytes.
25943da5c369Sopenharmony_ci    ///
25953da5c369Sopenharmony_ci    /// POSIX also defines an alias named `PAGESIZE`, but Rust does not allow two
25963da5c369Sopenharmony_ci    /// enum constants to have the same value, so nix omits `PAGESIZE`.
25973da5c369Sopenharmony_ci    PAGE_SIZE = libc::_SC_PAGE_SIZE,
25983da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
25993da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26003da5c369Sopenharmony_ci    PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS,
26013da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
26023da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26033da5c369Sopenharmony_ci    PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX,
26043da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
26053da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26063da5c369Sopenharmony_ci    PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN,
26073da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
26083da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26093da5c369Sopenharmony_ci    PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX,
26103da5c369Sopenharmony_ci    #[cfg(not(target_os = "haiku"))]
26113da5c369Sopenharmony_ci    RE_DUP_MAX = libc::_SC_RE_DUP_MAX,
26123da5c369Sopenharmony_ci    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
26133da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
26143da5c369Sopenharmony_ci              target_os="openbsd"))]
26153da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26163da5c369Sopenharmony_ci    RTSIG_MAX = libc::_SC_RTSIG_MAX,
26173da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
26183da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26193da5c369Sopenharmony_ci    SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX,
26203da5c369Sopenharmony_ci    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
26213da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
26223da5c369Sopenharmony_ci              target_os="openbsd"))]
26233da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26243da5c369Sopenharmony_ci    SEM_VALUE_MAX = libc::_SC_SEM_VALUE_MAX,
26253da5c369Sopenharmony_ci    #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd",
26263da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
26273da5c369Sopenharmony_ci              target_os = "openbsd"))]
26283da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26293da5c369Sopenharmony_ci    SIGQUEUE_MAX = libc::_SC_SIGQUEUE_MAX,
26303da5c369Sopenharmony_ci    STREAM_MAX = libc::_SC_STREAM_MAX,
26313da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
26323da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="netbsd",
26333da5c369Sopenharmony_ci              target_os="openbsd"))]
26343da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26353da5c369Sopenharmony_ci    SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX,
26363da5c369Sopenharmony_ci    #[cfg(not(target_os = "redox"))]
26373da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26383da5c369Sopenharmony_ci    TIMER_MAX = libc::_SC_TIMER_MAX,
26393da5c369Sopenharmony_ci    TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX,
26403da5c369Sopenharmony_ci    TZNAME_MAX = libc::_SC_TZNAME_MAX,
26413da5c369Sopenharmony_ci    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
26423da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
26433da5c369Sopenharmony_ci              target_os="openbsd"))]
26443da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26453da5c369Sopenharmony_ci    /// The implementation supports the X/Open Encryption Option Group.
26463da5c369Sopenharmony_ci    _XOPEN_CRYPT = libc::_SC_XOPEN_CRYPT,
26473da5c369Sopenharmony_ci    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
26483da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
26493da5c369Sopenharmony_ci              target_os="openbsd"))]
26503da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26513da5c369Sopenharmony_ci    /// The implementation supports the Issue 4, Version 2 Enhanced
26523da5c369Sopenharmony_ci    /// Internationalization Option Group.
26533da5c369Sopenharmony_ci    _XOPEN_ENH_I18N = libc::_SC_XOPEN_ENH_I18N,
26543da5c369Sopenharmony_ci    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
26553da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
26563da5c369Sopenharmony_ci              target_os="openbsd"))]
26573da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26583da5c369Sopenharmony_ci    _XOPEN_LEGACY = libc::_SC_XOPEN_LEGACY,
26593da5c369Sopenharmony_ci    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
26603da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
26613da5c369Sopenharmony_ci              target_os="openbsd"))]
26623da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26633da5c369Sopenharmony_ci    /// The implementation supports the X/Open Realtime Option Group.
26643da5c369Sopenharmony_ci    _XOPEN_REALTIME = libc::_SC_XOPEN_REALTIME,
26653da5c369Sopenharmony_ci    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
26663da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
26673da5c369Sopenharmony_ci              target_os="openbsd"))]
26683da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26693da5c369Sopenharmony_ci    /// The implementation supports the X/Open Realtime Threads Option Group.
26703da5c369Sopenharmony_ci    _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS,
26713da5c369Sopenharmony_ci    /// The implementation supports the Issue 4, Version 2 Shared Memory Option
26723da5c369Sopenharmony_ci    /// Group.
26733da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
26743da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26753da5c369Sopenharmony_ci    _XOPEN_SHM = libc::_SC_XOPEN_SHM,
26763da5c369Sopenharmony_ci    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
26773da5c369Sopenharmony_ci              target_os="linux", target_os = "macos", target_os="openbsd"))]
26783da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26793da5c369Sopenharmony_ci    /// The implementation supports the XSI STREAMS Option Group.
26803da5c369Sopenharmony_ci    _XOPEN_STREAMS = libc::_SC_XOPEN_STREAMS,
26813da5c369Sopenharmony_ci    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
26823da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
26833da5c369Sopenharmony_ci              target_os="openbsd"))]
26843da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26853da5c369Sopenharmony_ci    /// The implementation supports the XSI option
26863da5c369Sopenharmony_ci    _XOPEN_UNIX = libc::_SC_XOPEN_UNIX,
26873da5c369Sopenharmony_ci    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
26883da5c369Sopenharmony_ci              target_os = "ios", target_os="linux", target_os = "macos",
26893da5c369Sopenharmony_ci              target_os="openbsd"))]
26903da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
26913da5c369Sopenharmony_ci    /// Integer value indicating version of the X/Open Portability Guide to
26923da5c369Sopenharmony_ci    /// which the implementation conforms.
26933da5c369Sopenharmony_ci    _XOPEN_VERSION = libc::_SC_XOPEN_VERSION,
26943da5c369Sopenharmony_ci    /// The number of pages of physical memory. Note that it is possible for
26953da5c369Sopenharmony_ci    /// the product of this value to overflow.
26963da5c369Sopenharmony_ci    #[cfg(any(target_os="android", target_os="linux"))]
26973da5c369Sopenharmony_ci    _PHYS_PAGES = libc::_SC_PHYS_PAGES,
26983da5c369Sopenharmony_ci    /// The number of currently available pages of physical memory.
26993da5c369Sopenharmony_ci    #[cfg(any(target_os="android", target_os="linux"))]
27003da5c369Sopenharmony_ci    _AVPHYS_PAGES = libc::_SC_AVPHYS_PAGES,
27013da5c369Sopenharmony_ci    /// The number of processors configured.
27023da5c369Sopenharmony_ci    #[cfg(any(target_os="android", target_os="linux"))]
27033da5c369Sopenharmony_ci    _NPROCESSORS_CONF = libc::_SC_NPROCESSORS_CONF,
27043da5c369Sopenharmony_ci    /// The number of processors currently online (available).
27053da5c369Sopenharmony_ci    #[cfg(any(target_os="android", target_os="linux"))]
27063da5c369Sopenharmony_ci    _NPROCESSORS_ONLN = libc::_SC_NPROCESSORS_ONLN,
27073da5c369Sopenharmony_ci}
27083da5c369Sopenharmony_ci
27093da5c369Sopenharmony_ci/// Get configurable system variables (see
27103da5c369Sopenharmony_ci/// [sysconf(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html))
27113da5c369Sopenharmony_ci///
27123da5c369Sopenharmony_ci/// Returns the value of a configurable system variable.  Most supported
27133da5c369Sopenharmony_ci/// variables also have associated compile-time constants, but POSIX
27143da5c369Sopenharmony_ci/// allows their values to change at runtime.  There are generally two types of
27153da5c369Sopenharmony_ci/// sysconf variables: options and limits.  See sysconf(3) for more details.
27163da5c369Sopenharmony_ci///
27173da5c369Sopenharmony_ci/// # Returns
27183da5c369Sopenharmony_ci///
27193da5c369Sopenharmony_ci/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its
27203da5c369Sopenharmony_ci///     implementation level (for option variables).  Implementation levels are
27213da5c369Sopenharmony_ci///     usually a decimal-coded date, such as 200112 for POSIX 2001.12
27223da5c369Sopenharmony_ci/// - `Ok(None)`: the variable has no limit (for limit variables) or is
27233da5c369Sopenharmony_ci///     unsupported (for option variables)
27243da5c369Sopenharmony_ci/// - `Err(x)`: an error occurred
27253da5c369Sopenharmony_cipub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> {
27263da5c369Sopenharmony_ci    let raw = unsafe {
27273da5c369Sopenharmony_ci        Errno::clear();
27283da5c369Sopenharmony_ci        libc::sysconf(var as c_int)
27293da5c369Sopenharmony_ci    };
27303da5c369Sopenharmony_ci    if raw == -1 {
27313da5c369Sopenharmony_ci        if errno::errno() == 0 {
27323da5c369Sopenharmony_ci            Ok(None)
27333da5c369Sopenharmony_ci        } else {
27343da5c369Sopenharmony_ci            Err(Errno::last())
27353da5c369Sopenharmony_ci        }
27363da5c369Sopenharmony_ci    } else {
27373da5c369Sopenharmony_ci        Ok(Some(raw))
27383da5c369Sopenharmony_ci    }
27393da5c369Sopenharmony_ci}
27403da5c369Sopenharmony_ci}
27413da5c369Sopenharmony_ci
27423da5c369Sopenharmony_cifeature! {
27433da5c369Sopenharmony_ci#![feature = "fs"]
27443da5c369Sopenharmony_ci
27453da5c369Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))]
27463da5c369Sopenharmony_cimod pivot_root {
27473da5c369Sopenharmony_ci    use crate::{Result, NixPath};
27483da5c369Sopenharmony_ci    use crate::errno::Errno;
27493da5c369Sopenharmony_ci
27503da5c369Sopenharmony_ci    pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
27513da5c369Sopenharmony_ci            new_root: &P1, put_old: &P2) -> Result<()> {
27523da5c369Sopenharmony_ci        let res = new_root.with_nix_path(|new_root| {
27533da5c369Sopenharmony_ci            put_old.with_nix_path(|put_old| {
27543da5c369Sopenharmony_ci                unsafe {
27553da5c369Sopenharmony_ci                    libc::syscall(libc::SYS_pivot_root, new_root.as_ptr(), put_old.as_ptr())
27563da5c369Sopenharmony_ci                }
27573da5c369Sopenharmony_ci            })
27583da5c369Sopenharmony_ci        })??;
27593da5c369Sopenharmony_ci
27603da5c369Sopenharmony_ci        Errno::result(res).map(drop)
27613da5c369Sopenharmony_ci    }
27623da5c369Sopenharmony_ci}
27633da5c369Sopenharmony_ci}
27643da5c369Sopenharmony_ci
27653da5c369Sopenharmony_ci#[cfg(any(
27663da5c369Sopenharmony_ci    target_os = "android",
27673da5c369Sopenharmony_ci    target_os = "dragonfly",
27683da5c369Sopenharmony_ci    target_os = "freebsd",
27693da5c369Sopenharmony_ci    target_os = "linux",
27703da5c369Sopenharmony_ci    target_os = "openbsd"
27713da5c369Sopenharmony_ci))]
27723da5c369Sopenharmony_cimod setres {
27733da5c369Sopenharmony_ci    feature! {
27743da5c369Sopenharmony_ci    #![feature = "user"]
27753da5c369Sopenharmony_ci
27763da5c369Sopenharmony_ci    use crate::Result;
27773da5c369Sopenharmony_ci    use crate::errno::Errno;
27783da5c369Sopenharmony_ci    use super::{Uid, Gid};
27793da5c369Sopenharmony_ci
27803da5c369Sopenharmony_ci    /// Sets the real, effective, and saved uid.
27813da5c369Sopenharmony_ci    /// ([see setresuid(2)](https://man7.org/linux/man-pages/man2/setresuid.2.html))
27823da5c369Sopenharmony_ci    ///
27833da5c369Sopenharmony_ci    /// * `ruid`: real user id
27843da5c369Sopenharmony_ci    /// * `euid`: effective user id
27853da5c369Sopenharmony_ci    /// * `suid`: saved user id
27863da5c369Sopenharmony_ci    /// * returns: Ok or libc error code.
27873da5c369Sopenharmony_ci    ///
27883da5c369Sopenharmony_ci    /// Err is returned if the user doesn't have permission to set this UID.
27893da5c369Sopenharmony_ci    #[inline]
27903da5c369Sopenharmony_ci    pub fn setresuid(ruid: Uid, euid: Uid, suid: Uid) -> Result<()> {
27913da5c369Sopenharmony_ci        let res = unsafe { libc::setresuid(ruid.into(), euid.into(), suid.into()) };
27923da5c369Sopenharmony_ci
27933da5c369Sopenharmony_ci        Errno::result(res).map(drop)
27943da5c369Sopenharmony_ci    }
27953da5c369Sopenharmony_ci
27963da5c369Sopenharmony_ci    /// Sets the real, effective, and saved gid.
27973da5c369Sopenharmony_ci    /// ([see setresuid(2)](https://man7.org/linux/man-pages/man2/setresuid.2.html))
27983da5c369Sopenharmony_ci    ///
27993da5c369Sopenharmony_ci    /// * `rgid`: real group id
28003da5c369Sopenharmony_ci    /// * `egid`: effective group id
28013da5c369Sopenharmony_ci    /// * `sgid`: saved group id
28023da5c369Sopenharmony_ci    /// * returns: Ok or libc error code.
28033da5c369Sopenharmony_ci    ///
28043da5c369Sopenharmony_ci    /// Err is returned if the user doesn't have permission to set this GID.
28053da5c369Sopenharmony_ci    #[inline]
28063da5c369Sopenharmony_ci    pub fn setresgid(rgid: Gid, egid: Gid, sgid: Gid) -> Result<()> {
28073da5c369Sopenharmony_ci        let res = unsafe { libc::setresgid(rgid.into(), egid.into(), sgid.into()) };
28083da5c369Sopenharmony_ci
28093da5c369Sopenharmony_ci        Errno::result(res).map(drop)
28103da5c369Sopenharmony_ci    }
28113da5c369Sopenharmony_ci    }
28123da5c369Sopenharmony_ci}
28133da5c369Sopenharmony_ci
28143da5c369Sopenharmony_ci#[cfg(any(
28153da5c369Sopenharmony_ci    target_os = "android",
28163da5c369Sopenharmony_ci    target_os = "dragonfly",
28173da5c369Sopenharmony_ci    target_os = "freebsd",
28183da5c369Sopenharmony_ci    target_os = "linux",
28193da5c369Sopenharmony_ci    target_os = "openbsd"
28203da5c369Sopenharmony_ci))]
28213da5c369Sopenharmony_cimod getres {
28223da5c369Sopenharmony_ci    feature! {
28233da5c369Sopenharmony_ci    #![feature = "user"]
28243da5c369Sopenharmony_ci
28253da5c369Sopenharmony_ci    use crate::Result;
28263da5c369Sopenharmony_ci    use crate::errno::Errno;
28273da5c369Sopenharmony_ci    use super::{Uid, Gid};
28283da5c369Sopenharmony_ci
28293da5c369Sopenharmony_ci    /// Real, effective and saved user IDs.
28303da5c369Sopenharmony_ci    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
28313da5c369Sopenharmony_ci    pub struct ResUid {
28323da5c369Sopenharmony_ci        pub real: Uid,
28333da5c369Sopenharmony_ci        pub effective: Uid,
28343da5c369Sopenharmony_ci        pub saved: Uid
28353da5c369Sopenharmony_ci    }
28363da5c369Sopenharmony_ci
28373da5c369Sopenharmony_ci    /// Real, effective and saved group IDs.
28383da5c369Sopenharmony_ci    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
28393da5c369Sopenharmony_ci    pub struct ResGid {
28403da5c369Sopenharmony_ci        pub real: Gid,
28413da5c369Sopenharmony_ci        pub effective: Gid,
28423da5c369Sopenharmony_ci        pub saved: Gid
28433da5c369Sopenharmony_ci    }
28443da5c369Sopenharmony_ci
28453da5c369Sopenharmony_ci    /// Gets the real, effective, and saved user IDs.
28463da5c369Sopenharmony_ci    ///
28473da5c369Sopenharmony_ci    /// ([see getresuid(2)](http://man7.org/linux/man-pages/man2/getresuid.2.html))
28483da5c369Sopenharmony_ci    ///
28493da5c369Sopenharmony_ci    /// #Returns
28503da5c369Sopenharmony_ci    ///
28513da5c369Sopenharmony_ci    /// - `Ok((Uid, Uid, Uid))`: tuple of real, effective and saved uids on success.
28523da5c369Sopenharmony_ci    /// - `Err(x)`: libc error code on failure.
28533da5c369Sopenharmony_ci    ///
28543da5c369Sopenharmony_ci    #[inline]
28553da5c369Sopenharmony_ci    pub fn getresuid() -> Result<ResUid> {
28563da5c369Sopenharmony_ci        let mut ruid = libc::uid_t::max_value();
28573da5c369Sopenharmony_ci        let mut euid = libc::uid_t::max_value();
28583da5c369Sopenharmony_ci        let mut suid = libc::uid_t::max_value();
28593da5c369Sopenharmony_ci        let res = unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) };
28603da5c369Sopenharmony_ci
28613da5c369Sopenharmony_ci        Errno::result(res).map(|_| ResUid{ real: Uid(ruid), effective: Uid(euid), saved: Uid(suid) })
28623da5c369Sopenharmony_ci    }
28633da5c369Sopenharmony_ci
28643da5c369Sopenharmony_ci    /// Gets the real, effective, and saved group IDs.
28653da5c369Sopenharmony_ci    ///
28663da5c369Sopenharmony_ci    /// ([see getresgid(2)](http://man7.org/linux/man-pages/man2/getresgid.2.html))
28673da5c369Sopenharmony_ci    ///
28683da5c369Sopenharmony_ci    /// #Returns
28693da5c369Sopenharmony_ci    ///
28703da5c369Sopenharmony_ci    /// - `Ok((Gid, Gid, Gid))`: tuple of real, effective and saved gids on success.
28713da5c369Sopenharmony_ci    /// - `Err(x)`: libc error code on failure.
28723da5c369Sopenharmony_ci    ///
28733da5c369Sopenharmony_ci    #[inline]
28743da5c369Sopenharmony_ci    pub fn getresgid() -> Result<ResGid> {
28753da5c369Sopenharmony_ci        let mut rgid = libc::gid_t::max_value();
28763da5c369Sopenharmony_ci        let mut egid = libc::gid_t::max_value();
28773da5c369Sopenharmony_ci        let mut sgid = libc::gid_t::max_value();
28783da5c369Sopenharmony_ci        let res = unsafe { libc::getresgid(&mut rgid, &mut egid, &mut sgid) };
28793da5c369Sopenharmony_ci
28803da5c369Sopenharmony_ci        Errno::result(res).map(|_| ResGid { real: Gid(rgid), effective: Gid(egid), saved: Gid(sgid) } )
28813da5c369Sopenharmony_ci    }
28823da5c369Sopenharmony_ci    }
28833da5c369Sopenharmony_ci}
28843da5c369Sopenharmony_ci
28853da5c369Sopenharmony_ci#[cfg(feature = "fs")]
28863da5c369Sopenharmony_cilibc_bitflags! {
28873da5c369Sopenharmony_ci    /// Options for access()
28883da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
28893da5c369Sopenharmony_ci    pub struct AccessFlags : c_int {
28903da5c369Sopenharmony_ci        /// Test for existence of file.
28913da5c369Sopenharmony_ci        F_OK;
28923da5c369Sopenharmony_ci        /// Test for read permission.
28933da5c369Sopenharmony_ci        R_OK;
28943da5c369Sopenharmony_ci        /// Test for write permission.
28953da5c369Sopenharmony_ci        W_OK;
28963da5c369Sopenharmony_ci        /// Test for execute (search) permission.
28973da5c369Sopenharmony_ci        X_OK;
28983da5c369Sopenharmony_ci    }
28993da5c369Sopenharmony_ci}
29003da5c369Sopenharmony_ci
29013da5c369Sopenharmony_cifeature! {
29023da5c369Sopenharmony_ci#![feature = "fs"]
29033da5c369Sopenharmony_ci
29043da5c369Sopenharmony_ci/// Checks the file named by `path` for accessibility according to the flags given by `amode`
29053da5c369Sopenharmony_ci/// See [access(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html)
29063da5c369Sopenharmony_cipub fn access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()> {
29073da5c369Sopenharmony_ci    let res = path.with_nix_path(|cstr| {
29083da5c369Sopenharmony_ci        unsafe {
29093da5c369Sopenharmony_ci            libc::access(cstr.as_ptr(), amode.bits)
29103da5c369Sopenharmony_ci        }
29113da5c369Sopenharmony_ci    })?;
29123da5c369Sopenharmony_ci    Errno::result(res).map(drop)
29133da5c369Sopenharmony_ci}
29143da5c369Sopenharmony_ci
29153da5c369Sopenharmony_ci/// Checks the file named by `path` for accessibility according to the flags given by `mode`
29163da5c369Sopenharmony_ci///
29173da5c369Sopenharmony_ci/// If `dirfd` has a value, then `path` is relative to directory associated with the file descriptor.
29183da5c369Sopenharmony_ci///
29193da5c369Sopenharmony_ci/// If `dirfd` is `None`, then `path` is relative to the current working directory.
29203da5c369Sopenharmony_ci///
29213da5c369Sopenharmony_ci/// # References
29223da5c369Sopenharmony_ci///
29233da5c369Sopenharmony_ci/// [faccessat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/faccessat.html)
29243da5c369Sopenharmony_ci// redox: does not appear to support the *at family of syscalls.
29253da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))]
29263da5c369Sopenharmony_cipub fn faccessat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: AccessFlags, flags: AtFlags) -> Result<()> {
29273da5c369Sopenharmony_ci    let res = path.with_nix_path(|cstr| {
29283da5c369Sopenharmony_ci        unsafe {
29293da5c369Sopenharmony_ci            libc::faccessat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits(), flags.bits())
29303da5c369Sopenharmony_ci        }
29313da5c369Sopenharmony_ci    })?;
29323da5c369Sopenharmony_ci    Errno::result(res).map(drop)
29333da5c369Sopenharmony_ci}
29343da5c369Sopenharmony_ci
29353da5c369Sopenharmony_ci/// Checks the file named by `path` for accessibility according to the flags given
29363da5c369Sopenharmony_ci/// by `mode` using effective UID, effective GID and supplementary group lists.
29373da5c369Sopenharmony_ci///
29383da5c369Sopenharmony_ci/// # References
29393da5c369Sopenharmony_ci///
29403da5c369Sopenharmony_ci/// * [FreeBSD man page](https://www.freebsd.org/cgi/man.cgi?query=eaccess&sektion=2&n=1)
29413da5c369Sopenharmony_ci/// * [Linux man page](https://man7.org/linux/man-pages/man3/euidaccess.3.html)
29423da5c369Sopenharmony_ci#[cfg(any(
29433da5c369Sopenharmony_ci    all(target_os = "linux", not(target_env = "uclibc")),
29443da5c369Sopenharmony_ci    target_os = "freebsd",
29453da5c369Sopenharmony_ci    target_os = "dragonfly"
29463da5c369Sopenharmony_ci))]
29473da5c369Sopenharmony_cipub fn eaccess<P: ?Sized + NixPath>(path: &P, mode: AccessFlags) -> Result<()> {
29483da5c369Sopenharmony_ci    let res = path.with_nix_path(|cstr| {
29493da5c369Sopenharmony_ci        unsafe {
29503da5c369Sopenharmony_ci            libc::eaccess(cstr.as_ptr(), mode.bits)
29513da5c369Sopenharmony_ci        }
29523da5c369Sopenharmony_ci    })?;
29533da5c369Sopenharmony_ci    Errno::result(res).map(drop)
29543da5c369Sopenharmony_ci}
29553da5c369Sopenharmony_ci}
29563da5c369Sopenharmony_ci
29573da5c369Sopenharmony_cifeature! {
29583da5c369Sopenharmony_ci#![feature = "user"]
29593da5c369Sopenharmony_ci
29603da5c369Sopenharmony_ci/// Representation of a User, based on `libc::passwd`
29613da5c369Sopenharmony_ci///
29623da5c369Sopenharmony_ci/// The reason some fields in this struct are `String` and others are `CString` is because some
29633da5c369Sopenharmony_ci/// fields are based on the user's locale, which could be non-UTF8, while other fields are
29643da5c369Sopenharmony_ci/// guaranteed to conform to [`NAME_REGEX`](https://serverfault.com/a/73101/407341), which only
29653da5c369Sopenharmony_ci/// contains ASCII.
29663da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
29673da5c369Sopenharmony_ci#[derive(Debug, Clone, Eq, PartialEq)]
29683da5c369Sopenharmony_cipub struct User {
29693da5c369Sopenharmony_ci    /// Username
29703da5c369Sopenharmony_ci    pub name: String,
29713da5c369Sopenharmony_ci    /// User password (probably hashed)
29723da5c369Sopenharmony_ci    pub passwd: CString,
29733da5c369Sopenharmony_ci    /// User ID
29743da5c369Sopenharmony_ci    pub uid: Uid,
29753da5c369Sopenharmony_ci    /// Group ID
29763da5c369Sopenharmony_ci    pub gid: Gid,
29773da5c369Sopenharmony_ci    /// User information
29783da5c369Sopenharmony_ci    #[cfg(not(all(target_os = "android", target_pointer_width = "32")))]
29793da5c369Sopenharmony_ci    pub gecos: CString,
29803da5c369Sopenharmony_ci    /// Home directory
29813da5c369Sopenharmony_ci    pub dir: PathBuf,
29823da5c369Sopenharmony_ci    /// Path to shell
29833da5c369Sopenharmony_ci    pub shell: PathBuf,
29843da5c369Sopenharmony_ci    /// Login class
29853da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "android",
29863da5c369Sopenharmony_ci                  target_os = "fuchsia",
29873da5c369Sopenharmony_ci                  target_os = "haiku",
29883da5c369Sopenharmony_ci                  target_os = "illumos",
29893da5c369Sopenharmony_ci                  target_os = "linux",
29903da5c369Sopenharmony_ci                  target_os = "solaris")))]
29913da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
29923da5c369Sopenharmony_ci    pub class: CString,
29933da5c369Sopenharmony_ci    /// Last password change
29943da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "android",
29953da5c369Sopenharmony_ci                  target_os = "fuchsia",
29963da5c369Sopenharmony_ci                  target_os = "haiku",
29973da5c369Sopenharmony_ci                  target_os = "illumos",
29983da5c369Sopenharmony_ci                  target_os = "linux",
29993da5c369Sopenharmony_ci                  target_os = "solaris")))]
30003da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
30013da5c369Sopenharmony_ci    pub change: libc::time_t,
30023da5c369Sopenharmony_ci    /// Expiration time of account
30033da5c369Sopenharmony_ci    #[cfg(not(any(target_os = "android",
30043da5c369Sopenharmony_ci                  target_os = "fuchsia",
30053da5c369Sopenharmony_ci                  target_os = "haiku",
30063da5c369Sopenharmony_ci                  target_os = "illumos",
30073da5c369Sopenharmony_ci                  target_os = "linux",
30083da5c369Sopenharmony_ci                  target_os = "solaris")))]
30093da5c369Sopenharmony_ci    #[cfg_attr(docsrs, doc(cfg(all())))]
30103da5c369Sopenharmony_ci    pub expire: libc::time_t
30113da5c369Sopenharmony_ci}
30123da5c369Sopenharmony_ci
30133da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] //RedoxFS does not support passwd
30143da5c369Sopenharmony_ciimpl From<&libc::passwd> for User {
30153da5c369Sopenharmony_ci    fn from(pw: &libc::passwd) -> User {
30163da5c369Sopenharmony_ci        unsafe {
30173da5c369Sopenharmony_ci            User {
30183da5c369Sopenharmony_ci                name: if pw.pw_name.is_null() { Default::default() } else { CStr::from_ptr(pw.pw_name).to_string_lossy().into_owned() },
30193da5c369Sopenharmony_ci                passwd: if pw.pw_passwd.is_null() { Default::default() } else { CString::new(CStr::from_ptr(pw.pw_passwd).to_bytes()).unwrap() },
30203da5c369Sopenharmony_ci                #[cfg(not(all(target_os = "android", target_pointer_width = "32")))]
30213da5c369Sopenharmony_ci                gecos: if pw.pw_gecos.is_null() { Default::default() } else { CString::new(CStr::from_ptr(pw.pw_gecos).to_bytes()).unwrap() },
30223da5c369Sopenharmony_ci                dir: if pw.pw_dir.is_null() { Default::default() } else { PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_dir).to_bytes())) },
30233da5c369Sopenharmony_ci                shell: if pw.pw_shell.is_null() { Default::default() } else { PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_shell).to_bytes())) },
30243da5c369Sopenharmony_ci                uid: Uid::from_raw(pw.pw_uid),
30253da5c369Sopenharmony_ci                gid: Gid::from_raw(pw.pw_gid),
30263da5c369Sopenharmony_ci                #[cfg(not(any(target_os = "android",
30273da5c369Sopenharmony_ci                              target_os = "fuchsia",
30283da5c369Sopenharmony_ci                              target_os = "haiku",
30293da5c369Sopenharmony_ci                              target_os = "illumos",
30303da5c369Sopenharmony_ci                              target_os = "linux",
30313da5c369Sopenharmony_ci                              target_os = "solaris")))]
30323da5c369Sopenharmony_ci                class: CString::new(CStr::from_ptr(pw.pw_class).to_bytes()).unwrap(),
30333da5c369Sopenharmony_ci                #[cfg(not(any(target_os = "android",
30343da5c369Sopenharmony_ci                              target_os = "fuchsia",
30353da5c369Sopenharmony_ci                              target_os = "haiku",
30363da5c369Sopenharmony_ci                              target_os = "illumos",
30373da5c369Sopenharmony_ci                              target_os = "linux",
30383da5c369Sopenharmony_ci                              target_os = "solaris")))]
30393da5c369Sopenharmony_ci                change: pw.pw_change,
30403da5c369Sopenharmony_ci                #[cfg(not(any(target_os = "android",
30413da5c369Sopenharmony_ci                              target_os = "fuchsia",
30423da5c369Sopenharmony_ci                              target_os = "haiku",
30433da5c369Sopenharmony_ci                              target_os = "illumos",
30443da5c369Sopenharmony_ci                              target_os = "linux",
30453da5c369Sopenharmony_ci                              target_os = "solaris")))]
30463da5c369Sopenharmony_ci                expire: pw.pw_expire
30473da5c369Sopenharmony_ci            }
30483da5c369Sopenharmony_ci        }
30493da5c369Sopenharmony_ci    }
30503da5c369Sopenharmony_ci}
30513da5c369Sopenharmony_ci
30523da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
30533da5c369Sopenharmony_ciimpl From<User> for libc::passwd {
30543da5c369Sopenharmony_ci    fn from(u: User) -> Self {
30553da5c369Sopenharmony_ci        let name = match CString::new(u.name) {
30563da5c369Sopenharmony_ci            Ok(n) => n.into_raw(),
30573da5c369Sopenharmony_ci            Err(_) => CString::new("").unwrap().into_raw(),
30583da5c369Sopenharmony_ci        };
30593da5c369Sopenharmony_ci        let dir = match u.dir.into_os_string().into_string() {
30603da5c369Sopenharmony_ci            Ok(s) => CString::new(s.as_str()).unwrap().into_raw(),
30613da5c369Sopenharmony_ci            Err(_) => CString::new("").unwrap().into_raw(),
30623da5c369Sopenharmony_ci        };
30633da5c369Sopenharmony_ci        let shell = match u.shell.into_os_string().into_string() {
30643da5c369Sopenharmony_ci            Ok(s) => CString::new(s.as_str()).unwrap().into_raw(),
30653da5c369Sopenharmony_ci            Err(_) => CString::new("").unwrap().into_raw(),
30663da5c369Sopenharmony_ci        };
30673da5c369Sopenharmony_ci        Self {
30683da5c369Sopenharmony_ci            pw_name: name,
30693da5c369Sopenharmony_ci            pw_passwd: u.passwd.into_raw(),
30703da5c369Sopenharmony_ci            #[cfg(not(all(target_os = "android", target_pointer_width = "32")))]
30713da5c369Sopenharmony_ci            pw_gecos: u.gecos.into_raw(),
30723da5c369Sopenharmony_ci            pw_dir: dir,
30733da5c369Sopenharmony_ci            pw_shell: shell,
30743da5c369Sopenharmony_ci            pw_uid: u.uid.0,
30753da5c369Sopenharmony_ci            pw_gid: u.gid.0,
30763da5c369Sopenharmony_ci            #[cfg(not(any(target_os = "android",
30773da5c369Sopenharmony_ci                          target_os = "fuchsia",
30783da5c369Sopenharmony_ci                          target_os = "haiku",
30793da5c369Sopenharmony_ci                          target_os = "illumos",
30803da5c369Sopenharmony_ci                          target_os = "linux",
30813da5c369Sopenharmony_ci                          target_os = "solaris")))]
30823da5c369Sopenharmony_ci            pw_class: u.class.into_raw(),
30833da5c369Sopenharmony_ci            #[cfg(not(any(target_os = "android",
30843da5c369Sopenharmony_ci                          target_os = "fuchsia",
30853da5c369Sopenharmony_ci                          target_os = "haiku",
30863da5c369Sopenharmony_ci                          target_os = "illumos",
30873da5c369Sopenharmony_ci                          target_os = "linux",
30883da5c369Sopenharmony_ci                          target_os = "solaris")))]
30893da5c369Sopenharmony_ci            pw_change: u.change,
30903da5c369Sopenharmony_ci            #[cfg(not(any(target_os = "android",
30913da5c369Sopenharmony_ci                          target_os = "fuchsia",
30923da5c369Sopenharmony_ci                          target_os = "haiku",
30933da5c369Sopenharmony_ci                          target_os = "illumos",
30943da5c369Sopenharmony_ci                          target_os = "linux",
30953da5c369Sopenharmony_ci                          target_os = "solaris")))]
30963da5c369Sopenharmony_ci            pw_expire: u.expire,
30973da5c369Sopenharmony_ci            #[cfg(target_os = "illumos")]
30983da5c369Sopenharmony_ci            pw_age: CString::new("").unwrap().into_raw(),
30993da5c369Sopenharmony_ci            #[cfg(target_os = "illumos")]
31003da5c369Sopenharmony_ci            pw_comment: CString::new("").unwrap().into_raw(),
31013da5c369Sopenharmony_ci            #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
31023da5c369Sopenharmony_ci            pw_fields: 0,
31033da5c369Sopenharmony_ci        }
31043da5c369Sopenharmony_ci    }
31053da5c369Sopenharmony_ci}
31063da5c369Sopenharmony_ci
31073da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
31083da5c369Sopenharmony_ciimpl User {
31093da5c369Sopenharmony_ci    fn from_anything<F>(f: F) -> Result<Option<Self>>
31103da5c369Sopenharmony_ci    where
31113da5c369Sopenharmony_ci        F: Fn(*mut libc::passwd,
31123da5c369Sopenharmony_ci              *mut c_char,
31133da5c369Sopenharmony_ci              libc::size_t,
31143da5c369Sopenharmony_ci              *mut *mut libc::passwd) -> libc::c_int
31153da5c369Sopenharmony_ci    {
31163da5c369Sopenharmony_ci        let buflimit = 1048576;
31173da5c369Sopenharmony_ci        let bufsize = match sysconf(SysconfVar::GETPW_R_SIZE_MAX) {
31183da5c369Sopenharmony_ci            Ok(Some(n)) => n as usize,
31193da5c369Sopenharmony_ci            Ok(None) | Err(_) => 16384,
31203da5c369Sopenharmony_ci        };
31213da5c369Sopenharmony_ci
31223da5c369Sopenharmony_ci        let mut cbuf = Vec::with_capacity(bufsize);
31233da5c369Sopenharmony_ci        let mut pwd = mem::MaybeUninit::<libc::passwd>::uninit();
31243da5c369Sopenharmony_ci        let mut res = ptr::null_mut();
31253da5c369Sopenharmony_ci
31263da5c369Sopenharmony_ci        loop {
31273da5c369Sopenharmony_ci            let error = f(pwd.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res);
31283da5c369Sopenharmony_ci            if error == 0 {
31293da5c369Sopenharmony_ci                if res.is_null() {
31303da5c369Sopenharmony_ci                    return Ok(None);
31313da5c369Sopenharmony_ci                } else {
31323da5c369Sopenharmony_ci                    let pwd = unsafe { pwd.assume_init() };
31333da5c369Sopenharmony_ci                    return Ok(Some(User::from(&pwd)));
31343da5c369Sopenharmony_ci                }
31353da5c369Sopenharmony_ci            } else if Errno::last() == Errno::ERANGE {
31363da5c369Sopenharmony_ci                // Trigger the internal buffer resizing logic.
31373da5c369Sopenharmony_ci                reserve_double_buffer_size(&mut cbuf, buflimit)?;
31383da5c369Sopenharmony_ci            } else {
31393da5c369Sopenharmony_ci                return Err(Errno::last());
31403da5c369Sopenharmony_ci            }
31413da5c369Sopenharmony_ci        }
31423da5c369Sopenharmony_ci    }
31433da5c369Sopenharmony_ci
31443da5c369Sopenharmony_ci    /// Get a user by UID.
31453da5c369Sopenharmony_ci    ///
31463da5c369Sopenharmony_ci    /// Internally, this function calls
31473da5c369Sopenharmony_ci    /// [getpwuid_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
31483da5c369Sopenharmony_ci    ///
31493da5c369Sopenharmony_ci    /// # Examples
31503da5c369Sopenharmony_ci    ///
31513da5c369Sopenharmony_ci    /// ```
31523da5c369Sopenharmony_ci    /// use nix::unistd::{Uid, User};
31533da5c369Sopenharmony_ci    /// // Returns an Result<Option<User>>, thus the double unwrap.
31543da5c369Sopenharmony_ci    /// let res = User::from_uid(Uid::from_raw(0)).unwrap().unwrap();
31553da5c369Sopenharmony_ci    /// assert_eq!(res.name, "root");
31563da5c369Sopenharmony_ci    /// ```
31573da5c369Sopenharmony_ci    pub fn from_uid(uid: Uid) -> Result<Option<Self>> {
31583da5c369Sopenharmony_ci        User::from_anything(|pwd, cbuf, cap, res| {
31593da5c369Sopenharmony_ci            unsafe { libc::getpwuid_r(uid.0, pwd, cbuf, cap, res) }
31603da5c369Sopenharmony_ci        })
31613da5c369Sopenharmony_ci    }
31623da5c369Sopenharmony_ci
31633da5c369Sopenharmony_ci    /// Get a user by name.
31643da5c369Sopenharmony_ci    ///
31653da5c369Sopenharmony_ci    /// Internally, this function calls
31663da5c369Sopenharmony_ci    /// [getpwnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
31673da5c369Sopenharmony_ci    ///
31683da5c369Sopenharmony_ci    /// # Examples
31693da5c369Sopenharmony_ci    ///
31703da5c369Sopenharmony_ci    /// ```
31713da5c369Sopenharmony_ci    /// use nix::unistd::User;
31723da5c369Sopenharmony_ci    /// // Returns an Result<Option<User>>, thus the double unwrap.
31733da5c369Sopenharmony_ci    /// let res = User::from_name("root").unwrap().unwrap();
31743da5c369Sopenharmony_ci    /// assert_eq!(res.name, "root");
31753da5c369Sopenharmony_ci    /// ```
31763da5c369Sopenharmony_ci    pub fn from_name(name: &str) -> Result<Option<Self>> {
31773da5c369Sopenharmony_ci        let name = match CString::new(name) {
31783da5c369Sopenharmony_ci            Ok(c_str) => c_str,
31793da5c369Sopenharmony_ci            Err(_nul_error) => return Ok(None),
31803da5c369Sopenharmony_ci        };
31813da5c369Sopenharmony_ci        User::from_anything(|pwd, cbuf, cap, res| {
31823da5c369Sopenharmony_ci            unsafe { libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res) }
31833da5c369Sopenharmony_ci        })
31843da5c369Sopenharmony_ci    }
31853da5c369Sopenharmony_ci}
31863da5c369Sopenharmony_ci
31873da5c369Sopenharmony_ci/// Representation of a Group, based on `libc::group`
31883da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
31893da5c369Sopenharmony_ci#[derive(Debug, Clone, Eq, PartialEq)]
31903da5c369Sopenharmony_cipub struct Group {
31913da5c369Sopenharmony_ci    /// Group name
31923da5c369Sopenharmony_ci    pub name: String,
31933da5c369Sopenharmony_ci    /// Group password
31943da5c369Sopenharmony_ci    pub passwd: CString,
31953da5c369Sopenharmony_ci    /// Group ID
31963da5c369Sopenharmony_ci    pub gid: Gid,
31973da5c369Sopenharmony_ci    /// List of Group members
31983da5c369Sopenharmony_ci    pub mem: Vec<String>
31993da5c369Sopenharmony_ci}
32003da5c369Sopenharmony_ci
32013da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
32023da5c369Sopenharmony_ciimpl From<&libc::group> for Group {
32033da5c369Sopenharmony_ci    fn from(gr: &libc::group) -> Group {
32043da5c369Sopenharmony_ci        unsafe {
32053da5c369Sopenharmony_ci            Group {
32063da5c369Sopenharmony_ci                name: CStr::from_ptr(gr.gr_name).to_string_lossy().into_owned(),
32073da5c369Sopenharmony_ci                passwd: CString::new(CStr::from_ptr(gr.gr_passwd).to_bytes()).unwrap(),
32083da5c369Sopenharmony_ci                gid: Gid::from_raw(gr.gr_gid),
32093da5c369Sopenharmony_ci                mem: Group::members(gr.gr_mem)
32103da5c369Sopenharmony_ci            }
32113da5c369Sopenharmony_ci        }
32123da5c369Sopenharmony_ci    }
32133da5c369Sopenharmony_ci}
32143da5c369Sopenharmony_ci
32153da5c369Sopenharmony_ci#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
32163da5c369Sopenharmony_ciimpl Group {
32173da5c369Sopenharmony_ci    unsafe fn members(mem: *mut *mut c_char) -> Vec<String> {
32183da5c369Sopenharmony_ci        let mut ret = Vec::new();
32193da5c369Sopenharmony_ci
32203da5c369Sopenharmony_ci        for i in 0.. {
32213da5c369Sopenharmony_ci            let u = mem.offset(i);
32223da5c369Sopenharmony_ci            if (*u).is_null() {
32233da5c369Sopenharmony_ci                break;
32243da5c369Sopenharmony_ci            } else {
32253da5c369Sopenharmony_ci                let s = CStr::from_ptr(*u).to_string_lossy().into_owned();
32263da5c369Sopenharmony_ci                ret.push(s);
32273da5c369Sopenharmony_ci            }
32283da5c369Sopenharmony_ci        }
32293da5c369Sopenharmony_ci
32303da5c369Sopenharmony_ci        ret
32313da5c369Sopenharmony_ci    }
32323da5c369Sopenharmony_ci
32333da5c369Sopenharmony_ci    fn from_anything<F>(f: F) -> Result<Option<Self>>
32343da5c369Sopenharmony_ci    where
32353da5c369Sopenharmony_ci        F: Fn(*mut libc::group,
32363da5c369Sopenharmony_ci              *mut c_char,
32373da5c369Sopenharmony_ci              libc::size_t,
32383da5c369Sopenharmony_ci              *mut *mut libc::group) -> libc::c_int
32393da5c369Sopenharmony_ci    {
32403da5c369Sopenharmony_ci        let buflimit = 1048576;
32413da5c369Sopenharmony_ci        let bufsize = match sysconf(SysconfVar::GETGR_R_SIZE_MAX) {
32423da5c369Sopenharmony_ci            Ok(Some(n)) => n as usize,
32433da5c369Sopenharmony_ci            Ok(None) | Err(_) => 16384,
32443da5c369Sopenharmony_ci        };
32453da5c369Sopenharmony_ci
32463da5c369Sopenharmony_ci        let mut cbuf = Vec::with_capacity(bufsize);
32473da5c369Sopenharmony_ci        let mut grp = mem::MaybeUninit::<libc::group>::uninit();
32483da5c369Sopenharmony_ci        let mut res = ptr::null_mut();
32493da5c369Sopenharmony_ci
32503da5c369Sopenharmony_ci        loop {
32513da5c369Sopenharmony_ci            let error = f(grp.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res);
32523da5c369Sopenharmony_ci            if error == 0 {
32533da5c369Sopenharmony_ci                if res.is_null() {
32543da5c369Sopenharmony_ci                    return Ok(None);
32553da5c369Sopenharmony_ci                } else {
32563da5c369Sopenharmony_ci                    let grp = unsafe { grp.assume_init() };
32573da5c369Sopenharmony_ci                    return Ok(Some(Group::from(&grp)));
32583da5c369Sopenharmony_ci                }
32593da5c369Sopenharmony_ci            } else if Errno::last() == Errno::ERANGE {
32603da5c369Sopenharmony_ci                // Trigger the internal buffer resizing logic.
32613da5c369Sopenharmony_ci                reserve_double_buffer_size(&mut cbuf, buflimit)?;
32623da5c369Sopenharmony_ci            } else {
32633da5c369Sopenharmony_ci                return Err(Errno::last());
32643da5c369Sopenharmony_ci            }
32653da5c369Sopenharmony_ci        }
32663da5c369Sopenharmony_ci    }
32673da5c369Sopenharmony_ci
32683da5c369Sopenharmony_ci    /// Get a group by GID.
32693da5c369Sopenharmony_ci    ///
32703da5c369Sopenharmony_ci    /// Internally, this function calls
32713da5c369Sopenharmony_ci    /// [getgrgid_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
32723da5c369Sopenharmony_ci    ///
32733da5c369Sopenharmony_ci    /// # Examples
32743da5c369Sopenharmony_ci    ///
32753da5c369Sopenharmony_ci    // Disable this test on all OS except Linux as root group may not exist.
32763da5c369Sopenharmony_ci    #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")]
32773da5c369Sopenharmony_ci    #[cfg_attr(target_os = "linux", doc = " ```")]
32783da5c369Sopenharmony_ci    /// use nix::unistd::{Gid, Group};
32793da5c369Sopenharmony_ci    /// // Returns an Result<Option<Group>>, thus the double unwrap.
32803da5c369Sopenharmony_ci    /// let res = Group::from_gid(Gid::from_raw(0)).unwrap().unwrap();
32813da5c369Sopenharmony_ci    /// assert!(res.name == "root");
32823da5c369Sopenharmony_ci    /// ```
32833da5c369Sopenharmony_ci    pub fn from_gid(gid: Gid) -> Result<Option<Self>> {
32843da5c369Sopenharmony_ci        Group::from_anything(|grp, cbuf, cap, res| {
32853da5c369Sopenharmony_ci            unsafe { libc::getgrgid_r(gid.0, grp, cbuf, cap, res) }
32863da5c369Sopenharmony_ci        })
32873da5c369Sopenharmony_ci    }
32883da5c369Sopenharmony_ci
32893da5c369Sopenharmony_ci    /// Get a group by name.
32903da5c369Sopenharmony_ci    ///
32913da5c369Sopenharmony_ci    /// Internally, this function calls
32923da5c369Sopenharmony_ci    /// [getgrnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
32933da5c369Sopenharmony_ci    ///
32943da5c369Sopenharmony_ci    /// # Examples
32953da5c369Sopenharmony_ci    ///
32963da5c369Sopenharmony_ci    // Disable this test on all OS except Linux as root group may not exist.
32973da5c369Sopenharmony_ci    #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")]
32983da5c369Sopenharmony_ci    #[cfg_attr(target_os = "linux", doc = " ```")]
32993da5c369Sopenharmony_ci    /// use nix::unistd::Group;
33003da5c369Sopenharmony_ci    /// // Returns an Result<Option<Group>>, thus the double unwrap.
33013da5c369Sopenharmony_ci    /// let res = Group::from_name("root").unwrap().unwrap();
33023da5c369Sopenharmony_ci    /// assert!(res.name == "root");
33033da5c369Sopenharmony_ci    /// ```
33043da5c369Sopenharmony_ci    pub fn from_name(name: &str) -> Result<Option<Self>> {
33053da5c369Sopenharmony_ci        let name = match CString::new(name) {
33063da5c369Sopenharmony_ci            Ok(c_str) => c_str,
33073da5c369Sopenharmony_ci            Err(_nul_error) => return Ok(None),
33083da5c369Sopenharmony_ci        };
33093da5c369Sopenharmony_ci        Group::from_anything(|grp, cbuf, cap, res| {
33103da5c369Sopenharmony_ci            unsafe { libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res) }
33113da5c369Sopenharmony_ci        })
33123da5c369Sopenharmony_ci    }
33133da5c369Sopenharmony_ci}
33143da5c369Sopenharmony_ci}
33153da5c369Sopenharmony_ci
33163da5c369Sopenharmony_cifeature! {
33173da5c369Sopenharmony_ci#![feature = "term"]
33183da5c369Sopenharmony_ci
33193da5c369Sopenharmony_ci/// Get the name of the terminal device that is open on file descriptor fd
33203da5c369Sopenharmony_ci/// (see [`ttyname(3)`](https://man7.org/linux/man-pages/man3/ttyname.3.html)).
33213da5c369Sopenharmony_ci#[cfg(not(target_os = "fuchsia"))]
33223da5c369Sopenharmony_cipub fn ttyname(fd: RawFd) -> Result<PathBuf> {
33233da5c369Sopenharmony_ci    const PATH_MAX: usize = libc::PATH_MAX as usize;
33243da5c369Sopenharmony_ci    let mut buf = vec![0_u8; PATH_MAX];
33253da5c369Sopenharmony_ci    let c_buf = buf.as_mut_ptr() as *mut libc::c_char;
33263da5c369Sopenharmony_ci
33273da5c369Sopenharmony_ci    let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) };
33283da5c369Sopenharmony_ci    if ret != 0 {
33293da5c369Sopenharmony_ci        return Err(Errno::from_i32(ret));
33303da5c369Sopenharmony_ci    }
33313da5c369Sopenharmony_ci
33323da5c369Sopenharmony_ci    let nul = buf.iter().position(|c| *c == b'\0').unwrap();
33333da5c369Sopenharmony_ci    buf.truncate(nul);
33343da5c369Sopenharmony_ci    Ok(OsString::from_vec(buf).into())
33353da5c369Sopenharmony_ci}
33363da5c369Sopenharmony_ci}
33373da5c369Sopenharmony_ci
33383da5c369Sopenharmony_cifeature! {
33393da5c369Sopenharmony_ci#![all(feature = "socket", feature = "user")]
33403da5c369Sopenharmony_ci
33413da5c369Sopenharmony_ci/// Get the effective user ID and group ID associated with a Unix domain socket.
33423da5c369Sopenharmony_ci///
33433da5c369Sopenharmony_ci/// See also [getpeereid(3)](https://www.freebsd.org/cgi/man.cgi?query=getpeereid)
33443da5c369Sopenharmony_ci#[cfg(any(
33453da5c369Sopenharmony_ci    target_os = "macos",
33463da5c369Sopenharmony_ci    target_os = "ios",
33473da5c369Sopenharmony_ci    target_os = "freebsd",
33483da5c369Sopenharmony_ci    target_os = "openbsd",
33493da5c369Sopenharmony_ci    target_os = "netbsd",
33503da5c369Sopenharmony_ci    target_os = "dragonfly",
33513da5c369Sopenharmony_ci))]
33523da5c369Sopenharmony_cipub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> {
33533da5c369Sopenharmony_ci    let mut uid = 1;
33543da5c369Sopenharmony_ci    let mut gid = 1;
33553da5c369Sopenharmony_ci
33563da5c369Sopenharmony_ci    let ret = unsafe { libc::getpeereid(fd, &mut uid, &mut gid) };
33573da5c369Sopenharmony_ci
33583da5c369Sopenharmony_ci    Errno::result(ret).map(|_| (Uid(uid), Gid(gid)))
33593da5c369Sopenharmony_ci}
33603da5c369Sopenharmony_ci}
33613da5c369Sopenharmony_ci
33623da5c369Sopenharmony_cifeature! {
33633da5c369Sopenharmony_ci#![all(feature = "fs")]
33643da5c369Sopenharmony_ci
33653da5c369Sopenharmony_ci/// Set the file flags.
33663da5c369Sopenharmony_ci///
33673da5c369Sopenharmony_ci/// See also [chflags(2)](https://www.freebsd.org/cgi/man.cgi?query=chflags&sektion=2)
33683da5c369Sopenharmony_ci#[cfg(any(
33693da5c369Sopenharmony_ci    target_os = "openbsd",
33703da5c369Sopenharmony_ci    target_os = "netbsd",
33713da5c369Sopenharmony_ci    target_os = "freebsd",
33723da5c369Sopenharmony_ci    target_os = "dragonfly",
33733da5c369Sopenharmony_ci    target_os = "macos",
33743da5c369Sopenharmony_ci    target_os = "ios"
33753da5c369Sopenharmony_ci))]
33763da5c369Sopenharmony_cipub fn chflags<P: ?Sized + NixPath>(path: &P, flags: FileFlag) -> Result<()> {
33773da5c369Sopenharmony_ci    let res = path.with_nix_path(|cstr| unsafe {
33783da5c369Sopenharmony_ci        libc::chflags(cstr.as_ptr(), flags.bits())
33793da5c369Sopenharmony_ci    })?;
33803da5c369Sopenharmony_ci
33813da5c369Sopenharmony_ci    Errno::result(res).map(drop)
33823da5c369Sopenharmony_ci}
33833da5c369Sopenharmony_ci}
3384