Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/third_party/rust/nix/src/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 123 kB image not shown  

Quelle  unistd.rs   Sprache: unbekannt

 
//! Safe wrappers around functions found in libc "unistd.h" header

use crate::errno::Errno;

#[cfg(any(
    all(feature = "fs", not(target_os = "redox")),
    all(feature = "process", linux_android)
))]
use crate::fcntl::at_rawfd;
#[cfg(not(target_os = "redox"))]
#[cfg(feature = "fs")]
use crate::fcntl::AtFlags;

#[cfg(feature = "fs")]
#[cfg(any(
    linux_android,
    freebsdlike,
    solarish,
    netbsdlike,
    target_os = "emscripten",
    target_os = "fuchsia",
    target_os = "hurd",
    target_os = "redox",
))]
use crate::fcntl::OFlag;
#[cfg(all(feature = "fs", bsd))]
use crate::sys::stat::FileFlag;
#[cfg(feature = "fs")]
use crate::sys::stat::Mode;
use crate::{Error, NixPath, Result};
#[cfg(not(target_os = "redox"))]
use cfg_if::cfg_if;
use libc::{
    c_char, c_int, c_long, c_uint, gid_t, mode_t, off_t, pid_t, size_t, uid_t,
};
use std::convert::Infallible;
#[cfg(not(target_os = "redox"))]
use std::ffi::CString;
use std::ffi::{CStr, OsStr, OsString};
use std::os::unix::ffi::{OsStrExt, OsStringExt};
use std::os::unix::io::{AsFd, AsRawFd, OwnedFd, RawFd};
use std::path::PathBuf;
use std::{fmt, mem, ptr};

feature! {
    #![feature = "fs"]
    #[cfg(linux_android)]
    pub use self::pivot_root::*;
}

#[cfg(any(freebsdlike, linux_android, target_os = "openbsd"))]
pub use self::setres::*;

#[cfg(any(freebsdlike, linux_android, target_os = "openbsd"))]
pub use self::getres::*;

feature! {
#![feature = "user"]

/// User identifier
///
/// Newtype pattern around `uid_t` (which is just alias). It prevents bugs caused by accidentally
/// passing wrong value.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Uid(uid_t);

impl Uid {
    /// Creates `Uid` from raw `uid_t`.
    pub const fn from_raw(uid: uid_t) -> Self {
        Uid(uid)
    }

    /// Returns Uid of calling process. This is practically a more Rusty alias for `getuid`.
    #[doc(alias("getuid"))]
    pub fn current() -> Self {
        getuid()
    }

    /// Returns effective Uid of calling process. This is practically a more Rusty alias for `geteuid`.
    #[doc(alias("geteuid"))]
    pub fn effective() -> Self {
        geteuid()
    }

    /// Returns true if the `Uid` represents privileged user - root. (If it equals zero.)
    pub const fn is_root(self) -> bool {
        self.0 == ROOT.0
    }

    /// Get the raw `uid_t` wrapped by `self`.
    pub const fn as_raw(self) -> uid_t {
        self.0
    }
}

impl From<Uid> for uid_t {
    fn from(uid: Uid) -> Self {
        uid.0
    }
}

impl From<uid_t> for Uid {
    fn from(uid: uid_t) -> Self {
        Uid(uid)
    }
}

impl fmt::Display for Uid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

/// Constant for UID = 0
pub const ROOT: Uid = Uid(0);

/// Group identifier
///
/// Newtype pattern around `gid_t` (which is just alias). It prevents bugs caused by accidentally
/// passing wrong value.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Gid(gid_t);

impl Gid {
    /// Creates `Gid` from raw `gid_t`.
    pub const fn from_raw(gid: gid_t) -> Self {
        Gid(gid)
    }

    /// Returns Gid of calling process. This is practically a more Rusty alias for `getgid`.
    #[doc(alias("getgid"))]
    pub fn current() -> Self {
        getgid()
    }

    /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getegid`.
    #[doc(alias("getegid"))]
    pub fn effective() -> Self {
        getegid()
    }

    /// Get the raw `gid_t` wrapped by `self`.
    pub const fn as_raw(self) -> gid_t {
        self.0
    }
}

impl From<Gid> for gid_t {
    fn from(gid: Gid) -> Self {
        gid.0
    }
}

impl From<gid_t> for Gid {
    fn from(gid: gid_t) -> Self {
        Gid(gid)
    }
}

impl fmt::Display for Gid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}
}

feature! {
#![feature = "process"]
/// Process identifier
///
/// Newtype pattern around `pid_t` (which is just alias). It prevents bugs caused by accidentally
/// passing wrong value.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Pid(pid_t);

impl Pid {
    /// Creates `Pid` from raw `pid_t`.
    pub const fn from_raw(pid: pid_t) -> Self {
        Pid(pid)
    }

    /// Returns PID of calling process
    #[doc(alias("getpid"))]
    pub fn this() -> Self {
        getpid()
    }

    /// Returns PID of parent of calling process
    #[doc(alias("getppid"))]
    pub fn parent() -> Self {
        getppid()
    }

    /// Get the raw `pid_t` wrapped by `self`.
    pub const fn as_raw(self) -> pid_t {
        self.0
    }
}

impl From<Pid> for pid_t {
    fn from(pid: Pid) -> Self {
        pid.0
    }
}

impl fmt::Display for Pid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

/// Represents the successful result of calling `fork`
///
/// When `fork` is called, the process continues execution in the parent process
/// and in the new child.  This return type can be examined to determine whether
/// you are now executing in the parent process or in the child.
#[derive(Clone, Copy, Debug)]
pub enum ForkResult {
    /// This is the parent process of the fork.
    Parent {
        /// The PID of the fork's child process
        child: Pid
    },
    /// This is the child process of the fork.
    Child,
}

impl ForkResult {
    /// Return `true` if this is the child process of the `fork()`
    #[inline]
    pub fn is_child(self) -> bool {
        matches!(self, ForkResult::Child)
    }

    /// Returns `true` if this is the parent process of the `fork()`
    #[inline]
    pub fn is_parent(self) -> bool {
        !self.is_child()
    }
}

/// Create a new child process duplicating the parent process ([see
/// fork(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html)).
///
/// After successfully calling the fork system call, a second process will
/// be created which is identical to the original except for the pid and the
/// return value of this function.  As an example:
///
/// ```
/// use nix::{sys::wait::waitpid,unistd::{fork, ForkResult, write}};
///
/// match unsafe{fork()} {
///    Ok(ForkResult::Parent { child, .. }) => {
///        println!("Continuing execution in parent process, new child has pid: {}", child);
///        waitpid(child, None).unwrap();
///    }
///    Ok(ForkResult::Child) => {
///        // Unsafe to use `println!` (or `unwrap`) here. See Safety.
///        write(std::io::stdout(), "I'm a new child process\n".as_bytes()).ok();
///        unsafe { libc::_exit(0) };
///    }
///    Err(_) => println!("Fork failed"),
/// }
/// ```
///
/// This will print something like the following (order nondeterministic).  The
/// thing to note is that you end up with two processes continuing execution
/// immediately after the fork call but with different match arms.
///
/// ```text
/// Continuing execution in parent process, new child has pid: 1234
/// I'm a new child process
/// ```
///
/// # Safety
///
/// In a multithreaded program, only [async-signal-safe] functions like `pause`
/// and `_exit` may be called by the child (the parent isn't restricted). Note
/// that memory allocation may **not** be async-signal-safe and thus must be
/// prevented.
///
/// Those functions are only a small subset of your operating system's API, so
/// special care must be taken to only invoke code you can control and audit.
///
/// [async-signal-safe]: https://man7.org/linux/man-pages/man7/signal-safety.7.html
#[inline]
pub unsafe fn fork() -> Result<ForkResult> {
    use self::ForkResult::*;
    let res = unsafe { libc::fork() };

    Errno::result(res).map(|res| match res {
        0 => Child,
        res => Parent { child: Pid(res) },
    })
}

/// Get the pid of this process (see
/// [getpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpid.html)).
///
/// Since you are running code, there is always a pid to return, so there
/// is no error case that needs to be handled.
#[inline]
pub fn getpid() -> Pid {
    Pid(unsafe { libc::getpid() })
}

/// Get the pid of this processes' parent (see
/// [getpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getppid.html)).
///
/// There is always a parent pid to return, so there is no error case that needs
/// to be handled.
#[inline]
pub fn getppid() -> Pid {
    Pid(unsafe { libc::getppid() }) // no error handling, according to man page: "These functions are always successful."
}

/// Set a process group ID (see
/// [setpgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html)).
///
/// Set the process group id (PGID) of a particular process.  If a pid of zero
/// is specified, then the pid of the calling process is used.  Process groups
/// may be used to group together a set of processes in order for the OS to
/// apply some operations across the group.
///
/// `setsid()` may be used to create a new process group.
#[inline]
pub fn setpgid(pid: Pid, pgid: Pid) -> Result<()> {
    let res = unsafe { libc::setpgid(pid.into(), pgid.into()) };
    Errno::result(res).map(drop)
}
/// Get process group
///
/// See Also [`getpgid`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgid.html)
#[inline]
pub fn getpgid(pid: Option<Pid>) -> Result<Pid> {
    let res = unsafe { libc::getpgid(pid.unwrap_or(Pid(0)).into()) };
    Errno::result(res).map(Pid)
}

/// Create new session and set process group id (see
/// [setsid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html)).
#[inline]
pub fn setsid() -> Result<Pid> {
    Errno::result(unsafe { libc::setsid() }).map(Pid)
}

/// Get the process group ID of a session leader
/// [getsid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsid.html).
///
/// Obtain the process group ID of the process that is the session leader of the process specified
/// by pid. If pid is zero, it specifies the calling process.
#[inline]
#[cfg(not(target_os = "redox"))]
pub fn getsid(pid: Option<Pid>) -> Result<Pid> {
    let res = unsafe { libc::getsid(pid.unwrap_or(Pid(0)).into()) };
    Errno::result(res).map(Pid)
}
}

feature! {
#![all(feature = "process", feature = "term")]
/// Get the terminal foreground process group (see
/// [tcgetpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetpgrp.html)).
///
/// Get the group process id (GPID) of the foreground process group on the
/// terminal associated to file descriptor (FD).
#[inline]
pub fn tcgetpgrp<F: AsFd>(fd: F) -> Result<Pid> {
    let res = unsafe { libc::tcgetpgrp(fd.as_fd().as_raw_fd()) };
    Errno::result(res).map(Pid)
}
/// Set the terminal foreground process group (see
/// [tcgetpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetpgrp.html)).
///
/// Get the group process id (PGID) to the foreground process group on the
/// terminal associated to file descriptor (FD).
#[inline]
pub fn tcsetpgrp<F: AsFd>(fd: F, pgrp: Pid) -> Result<()> {
    let res = unsafe { libc::tcsetpgrp(fd.as_fd().as_raw_fd(), pgrp.into()) };
    Errno::result(res).map(drop)
}
}

feature! {
#![feature = "process"]
/// Get the group id of the calling process (see
///[getpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html)).
///
/// Get the process group id (PGID) of the calling process.
/// According to the man page it is always successful.
#[inline]
pub fn getpgrp() -> Pid {
    Pid(unsafe { libc::getpgrp() })
}

/// Get the caller's thread ID (see
/// [gettid(2)](https://man7.org/linux/man-pages/man2/gettid.2.html).
///
/// This function is only available on Linux based systems.  In a single
/// threaded process, the main thread will have the same ID as the process.  In
/// a multithreaded process, each thread will have a unique thread id but the
/// same process ID.
///
/// No error handling is required as a thread id should always exist for any
/// process, even if threads are not being used.
#[cfg(linux_android)]
#[inline]
pub fn gettid() -> Pid {
    Pid(unsafe { libc::syscall(libc::SYS_gettid) as pid_t })
}
}

feature! {
#![feature = "fs"]
/// Create a copy of the specified file descriptor (see
/// [dup(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)).
///
/// The new file descriptor will have a new index but refer to the same
/// resource as the old file descriptor and the old and new file descriptors may
/// be used interchangeably.  The new and old file descriptor share the same
/// underlying resource, offset, and file status flags.  The actual index used
/// for the file descriptor will be the lowest fd index that is available.
///
/// The two file descriptors do not share file descriptor flags (e.g. `OFlag::FD_CLOEXEC`).
#[inline]
pub fn dup(oldfd: RawFd) -> Result<RawFd> {
    let res = unsafe { libc::dup(oldfd) };

    Errno::result(res)
}

/// Create a copy of the specified file descriptor using the specified fd (see
/// [dup(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)).
///
/// This function behaves similar to `dup()` except that it will try to use the
/// specified fd instead of allocating a new one.  See the man pages for more
/// detail on the exact behavior of this function.
#[inline]
pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd> {
    let res = unsafe { libc::dup2(oldfd, newfd) };

    Errno::result(res)
}

/// Create a new copy of the specified file descriptor using the specified fd
/// and flags (see [`dup(2)`](https://man7.org/linux/man-pages/man2/dup.2.html)).
///
/// This function behaves similar to `dup2()` but allows for flags to be
/// specified.
#[cfg(any(
    netbsdlike,
    solarish,
    target_os = "freebsd",
    target_os = "fuchsia",
    target_os = "hurd",
    target_os = "linux"
))]
pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
    let res = unsafe { libc::dup3(oldfd, newfd, flags.bits()) };

    Errno::result(res)
}

/// Change the current working directory of the calling process (see
/// [chdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html)).
///
/// This function may fail in a number of different scenarios.  See the man
/// pages for additional details on possible failure cases.
#[inline]
pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> {
    let res =
        path.with_nix_path(|cstr| unsafe { libc::chdir(cstr.as_ptr()) })?;

    Errno::result(res).map(drop)
}

/// Change the current working directory of the process to the one
/// given as an open file descriptor (see
/// [fchdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html)).
///
/// This function may fail in a number of different scenarios.  See the man
/// pages for additional details on possible failure cases.
#[inline]
#[cfg(not(target_os = "fuchsia"))]
pub fn fchdir(dirfd: RawFd) -> Result<()> {
    let res = unsafe { libc::fchdir(dirfd) };

    Errno::result(res).map(drop)
}

/// Creates new directory `path` with access rights `mode`.  (see [mkdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html))
///
/// # Errors
///
/// There are several situations where mkdir might fail:
///
/// - current user has insufficient rights in the parent directory
/// - the path already exists
/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X)
///
/// # Example
///
/// ```rust
/// use nix::unistd;
/// use nix::sys::stat;
/// use tempfile::tempdir;
///
/// let tmp_dir1 = tempdir().unwrap();
/// let tmp_dir2 = tmp_dir1.path().join("new_dir");
///
/// // create new directory and give read, write and execute rights to the owner
/// match unistd::mkdir(&tmp_dir2, stat::Mode::S_IRWXU) {
///    Ok(_) => println!("created {:?}", tmp_dir2),
///    Err(err) => println!("Error creating directory: {}", err),
/// }
/// ```
#[inline]
pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
    let res = path.with_nix_path(|cstr| unsafe {
        libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t)
    })?;

    Errno::result(res).map(drop)
}

/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`.
///
/// # Errors
///
/// There are several situations where mkfifo might fail:
///
/// - current user has insufficient rights in the parent directory
/// - the path already exists
/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X)
///
/// For a full list consult
/// [posix specification](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html)
///
/// # Example
///
/// ```rust
/// use nix::unistd;
/// use nix::sys::stat;
/// use tempfile::tempdir;
///
/// let tmp_dir = tempdir().unwrap();
/// let fifo_path = tmp_dir.path().join("foo.pipe");
///
/// // create new fifo and give read, write and execute rights to the owner
/// match unistd::mkfifo(&fifo_path, stat::Mode::S_IRWXU) {
///    Ok(_) => println!("created {:?}", fifo_path),
///    Err(err) => println!("Error creating fifo: {}", err),
/// }
/// ```
#[inline]
#[cfg(not(target_os = "redox"))] // RedoxFS does not support fifo yet
pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
    let res = path.with_nix_path(|cstr| unsafe {
        libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t)
    })?;

    Errno::result(res).map(drop)
}

/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`.
///
/// If `dirfd` has a value, then `path` is relative to directory associated with the file descriptor.
///
/// If `dirfd` is `None`, then `path` is relative to the current working directory.
///
/// # References
///
/// [mkfifoat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifoat.html).
// mkfifoat is not implemented in OSX or android
#[inline]
#[cfg(not(any(
    apple_targets,
    target_os = "haiku",
    target_os = "android",
    target_os = "redox"
)))]
pub fn mkfifoat<P: ?Sized + NixPath>(
    dirfd: Option<RawFd>,
    path: &P,
    mode: Mode,
) -> Result<()> {
    let res = path.with_nix_path(|cstr| unsafe {
        libc::mkfifoat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits() as mode_t)
    })?;

    Errno::result(res).map(drop)
}

/// Creates a symbolic link at `path2` which points to `path1`.
///
/// If `dirfd` has a value, then `path2` is relative to directory associated
/// with the file descriptor.
///
/// If `dirfd` is `None`, then `path2` is relative to the current working
/// directory. This is identical to `libc::symlink(path1, path2)`.
///
/// See also [symlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html).
#[cfg(not(target_os = "redox"))]
pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
    path1: &P1,
    dirfd: Option<RawFd>,
    path2: &P2,
) -> Result<()> {
    let res = path1.with_nix_path(|path1| {
        path2.with_nix_path(|path2| unsafe {
            libc::symlinkat(
                path1.as_ptr(),
                dirfd.unwrap_or(libc::AT_FDCWD),
                path2.as_ptr(),
            )
        })
    })??;
    Errno::result(res).map(drop)
}
}

// Double the buffer capacity up to limit. In case it already has
// reached the limit, return Errno::ERANGE.
#[cfg(any(feature = "fs", feature = "user"))]
fn reserve_double_buffer_size<T>(buf: &mut Vec<T>, limit: usize) -> Result<()> {
    use std::cmp::min;

    if buf.capacity() >= limit {
        return Err(Errno::ERANGE);
    }

    let capacity = min(buf.capacity() * 2, limit);
    buf.reserve(capacity);

    Ok(())
}

feature! {
#![feature = "fs"]

/// Returns the current directory as a `PathBuf`
///
/// Err is returned if the current user doesn't have the permission to read or search a component
/// of the current path.
///
/// # Example
///
/// ```rust
/// use nix::unistd;
///
/// // assume that we are allowed to get current directory
/// let dir = unistd::getcwd().unwrap();
/// println!("The current directory is {:?}", dir);
/// ```
#[inline]
pub fn getcwd() -> Result<PathBuf> {
    let mut buf = Vec::<u8>::with_capacity(512);
    loop {
        unsafe {
            let ptr = buf.as_mut_ptr().cast();

            // The buffer must be large enough to store the absolute pathname plus
            // a terminating null byte, or else null is returned.
            // To safely handle this we start with a reasonable size (512 bytes)
            // and double the buffer size upon every error
            if !libc::getcwd(ptr, buf.capacity()).is_null() {
                let len = CStr::from_ptr(buf.as_ptr().cast())
                    .to_bytes()
                    .len();
                buf.set_len(len);
                buf.shrink_to_fit();
                return Ok(PathBuf::from(OsString::from_vec(buf)));
            } else {
                let error = Errno::last();
                // ERANGE means buffer was too small to store directory name
                if error != Errno::ERANGE {
                    return Err(error);
                }
            }

            #[cfg(not(target_os = "hurd"))]
            const PATH_MAX: usize = libc::PATH_MAX as usize;
            #[cfg(target_os = "hurd")]
            const PATH_MAX: usize = 1024; // Hurd does not define a hard limit, so try a guess first

            // Trigger the internal buffer resizing logic.
            reserve_double_buffer_size(&mut buf, PATH_MAX)?;
        }
    }
}
}

feature! {
#![all(feature = "user", feature = "fs")]

/// Computes the raw UID and GID values to pass to a `*chown` call.
// The cast is not unnecessary on all platforms.
#[allow(clippy::unnecessary_cast)]
fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (uid_t, gid_t) {
    // According to the POSIX specification, -1 is used to indicate that owner and group
    // are not to be changed.  Since uid_t and gid_t are unsigned types, we have to wrap
    // around to get -1.
    let uid = owner
        .map(Into::into)
        .unwrap_or_else(|| (0 as uid_t).wrapping_sub(1));
    let gid = group
        .map(Into::into)
        .unwrap_or_else(|| (0 as gid_t).wrapping_sub(1));
    (uid, gid)
}

/// Change the ownership of the file at `path` to be owned by the specified
/// `owner` (user) and `group` (see
/// [chown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html)).
///
/// The owner/group for the provided path name will not be modified if `None` is
/// provided for that argument.  Ownership change will be attempted for the path
/// only if `Some` owner/group is provided.
#[inline]
pub fn chown<P: ?Sized + NixPath>(
    path: &P,
    owner: Option<Uid>,
    group: Option<Gid>,
) -> Result<()> {
    let res = path.with_nix_path(|cstr| {
        let (uid, gid) = chown_raw_ids(owner, group);
        unsafe { libc::chown(cstr.as_ptr(), uid, gid) }
    })?;

    Errno::result(res).map(drop)
}

/// Change the ownership of the file referred to by the open file descriptor `fd` to be owned by
/// the specified `owner` (user) and `group` (see
/// [fchown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchown.html)).
///
/// The owner/group for the provided file will not be modified if `None` is
/// provided for that argument.  Ownership change will be attempted for the path
/// only if `Some` owner/group is provided.
#[inline]
pub fn fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
    let (uid, gid) = chown_raw_ids(owner, group);
    let res = unsafe { libc::fchown(fd, uid, gid) };
    Errno::result(res).map(drop)
}

// Just a wrapper around `AtFlags` so that we can help our users migrate.
#[allow(missing_docs)]
#[cfg(not(target_os = "redox"))]
pub type FchownatFlags = AtFlags;
#[allow(missing_docs)]
#[cfg(not(target_os = "redox"))]
impl FchownatFlags {
    #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")]
    #[allow(non_upper_case_globals)]
    pub const FollowSymlink: FchownatFlags = FchownatFlags::empty();
    #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")]
    #[allow(non_upper_case_globals)]
    pub const NoFollowSymlink: FchownatFlags = FchownatFlags::AT_SYMLINK_NOFOLLOW;
}

/// Change the ownership of the file at `path` to be owned by the specified
/// `owner` (user) and `group`.
///
/// The owner/group for the provided path name will not be modified if `None` is
/// provided for that argument.  Ownership change will be attempted for the path
/// only if `Some` owner/group is provided.
///
/// The file to be changed is determined relative to the directory associated
/// with the file descriptor `dirfd` or the current working directory
/// if `dirfd` is `None`.
///
/// If `flag` is `AtFlags::AT_SYMLINK_NOFOLLOW` and `path` names a symbolic link,
/// then the mode of the symbolic link is changed.
///
/// `fchownat(None, path, owner, group, AtFlags::AT_SYMLINK_NOFOLLOW)` is identical to
/// a call `libc::lchown(path, owner, group)`.  That's why `lchown` is unimplemented in
/// the `nix` crate.
///
/// # References
///
/// [fchownat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html).
#[cfg(not(target_os = "redox"))]
pub fn fchownat<P: ?Sized + NixPath>(
    dirfd: Option<RawFd>,
    path: &P,
    owner: Option<Uid>,
    group: Option<Gid>,
    flag: AtFlags,
) -> Result<()> {
    let res = path.with_nix_path(|cstr| unsafe {
        let (uid, gid) = chown_raw_ids(owner, group);
        libc::fchownat(
            at_rawfd(dirfd),
            cstr.as_ptr(),
            uid,
            gid,
            flag.bits()
        )
    })?;

    Errno::result(res).map(drop)
}
}

feature! {
#![feature = "process"]
fn to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*const c_char> {
    use std::iter::once;
    args.iter()
        .map(|s| s.as_ref().as_ptr())
        .chain(once(ptr::null()))
        .collect()
}

/// Replace the current process image with a new one (see
/// [exec(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
///
/// See the `::nix::unistd::execve` system call for additional details.  `execv`
/// performs the same action but does not allow for customization of the
/// environment for the new process.
#[inline]
pub fn execv<S: AsRef<CStr>>(path: &CStr, argv: &[S]) -> Result<Infallible> {
    let args_p = to_exec_array(argv);

    unsafe { libc::execv(path.as_ptr(), args_p.as_ptr()) };

    Err(Errno::last())
}

/// Replace the current process image with a new one (see
/// [execve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
///
/// The execve system call allows for another process to be "called" which will
/// replace the current process image.  That is, this process becomes the new
/// command that is run. On success, this function will not return. Instead,
/// the new program will run until it exits.
///
/// `::nix::unistd::execv` and `::nix::unistd::execve` take as arguments a slice
/// of `::std::ffi::CString`s for `args` and `env` (for `execve`). Each element
/// in the `args` list is an argument to the new process. Each element in the
/// `env` list should be a string in the form "key=value".
#[inline]
pub fn execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(
    path: &CStr,
    args: &[SA],
    env: &[SE],
) -> Result<Infallible> {
    let args_p = to_exec_array(args);
    let env_p = to_exec_array(env);

    unsafe { libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) };

    Err(Errno::last())
}

/// Replace the current process image with a new one and replicate shell `PATH`
/// searching behavior (see
/// [exec(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
///
/// See `::nix::unistd::execve` for additional details.  `execvp` behaves the
/// same as execv except that it will examine the `PATH` environment variables
/// for file names not specified with a leading slash.  For example, `execv`
/// would not work if "bash" was specified for the path argument, but `execvp`
/// would assuming that a bash executable was on the system `PATH`.
#[inline]
pub fn execvp<S: AsRef<CStr>>(
    filename: &CStr,
    args: &[S],
) -> Result<Infallible> {
    let args_p = to_exec_array(args);

    unsafe { libc::execvp(filename.as_ptr(), args_p.as_ptr()) };

    Err(Errno::last())
}

/// Replace the current process image with a new one and replicate shell `PATH`
/// searching behavior (see
/// [`execvpe(3)`](https://man7.org/linux/man-pages/man3/exec.3.html)).
///
/// This functions like a combination of `execvp(2)` and `execve(2)` to pass an
/// environment and have a search path. See these two for additional
/// information.
#[cfg(any(target_os = "haiku", target_os = "hurd", target_os = "linux", target_os = "openbsd"))]
pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(
    filename: &CStr,
    args: &[SA],
    env: &[SE],
) -> Result<Infallible> {
    let args_p = to_exec_array(args);
    let env_p = to_exec_array(env);

    unsafe {
        libc::execvpe(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
    };

    Err(Errno::last())
}

/// Replace the current process image with a new one (see
/// [fexecve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html)).
///
/// The `fexecve` function allows for another process to be "called" which will
/// replace the current process image.  That is, this process becomes the new
/// command that is run. On success, this function will not return. Instead,
/// the new program will run until it exits.
///
/// This function is similar to `execve`, except that the program to be executed
/// is referenced as a file descriptor instead of a path.
#[cfg(any(linux_android, freebsdlike, target_os = "hurd"))]
#[inline]
pub fn fexecve<SA: AsRef<CStr>, SE: AsRef<CStr>>(
    fd: RawFd,
    args: &[SA],
    env: &[SE],
) -> Result<Infallible> {
    let args_p = to_exec_array(args);
    let env_p = to_exec_array(env);

    unsafe { libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr()) };

    Err(Errno::last())
}

/// Execute program relative to a directory file descriptor (see
/// [execveat(2)](https://man7.org/linux/man-pages/man2/execveat.2.html)).
///
/// The `execveat` function allows for another process to be "called" which will
/// replace the current process image.  That is, this process becomes the new
/// command that is run. On success, this function will not return. Instead,
/// the new program will run until it exits.
///
/// This function is similar to `execve`, except that the program to be executed
/// is referenced as a file descriptor to the base directory plus a path.
#[cfg(linux_android)]
#[inline]
pub fn execveat<SA: AsRef<CStr>, SE: AsRef<CStr>>(
    dirfd: Option<RawFd>,
    pathname: &CStr,
    args: &[SA],
    env: &[SE],
    flags: super::fcntl::AtFlags,
) -> Result<Infallible> {
    let dirfd = at_rawfd(dirfd);
    let args_p = to_exec_array(args);
    let env_p = to_exec_array(env);

    unsafe {
        libc::syscall(
            libc::SYS_execveat,
            dirfd,
            pathname.as_ptr(),
            args_p.as_ptr(),
            env_p.as_ptr(),
            flags,
        );
    };

    Err(Errno::last())
}

/// Daemonize this process by detaching from the controlling terminal (see
/// [daemon(3)](https://man7.org/linux/man-pages/man3/daemon.3.html)).
///
/// When a process is launched it is typically associated with a parent and it,
/// in turn, by its controlling terminal/process.  In order for a process to run
/// in the "background" it must daemonize itself by detaching itself.  Under
/// posix, this is done by doing the following:
///
/// 1. Parent process (this one) forks
/// 2. Parent process exits
/// 3. Child process continues to run.
///
/// `nochdir`:
///
/// * `nochdir = true`: The current working directory after daemonizing will
///    be the current working directory.
/// *  `nochdir = false`: The current working directory after daemonizing will
///    be the root direcory, `/`.
///
/// `noclose`:
///
/// * `noclose = true`: The process' current stdin, stdout, and stderr file
///   descriptors will remain identical after daemonizing.
/// * `noclose = false`: The process' stdin, stdout, and stderr will point to
///   `/dev/null` after daemonizing.
#[cfg(any(
        linux_android,
        freebsdlike,
        solarish,
        netbsdlike
))]
pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
    let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) };
    Errno::result(res).map(drop)
}
}

feature! {
#![feature = "hostname"]

/// Set the system host name (see
/// [sethostname(2)](https://man7.org/linux/man-pages/man2/gethostname.2.html)).
///
/// Given a name, attempt to update the system host name to the given string.
/// On some systems, the host name is limited to as few as 64 bytes.  An error
/// will be returned if the name is not valid or the current process does not
/// have permissions to update the host name.
#[cfg(not(target_os = "redox"))]
pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> {
    // Handle some differences in type of the len arg across platforms.
    cfg_if! {
        if #[cfg(any(freebsdlike,
                     solarish,
                     apple_targets,
                     target_os = "aix"))] {
            type sethostname_len_t = c_int;
        } else {
            type sethostname_len_t = size_t;
        }
    }
    let ptr = name.as_ref().as_bytes().as_ptr().cast();
    let len = name.as_ref().len() as sethostname_len_t;

    let res = unsafe { libc::sethostname(ptr, len) };
    Errno::result(res).map(drop)
}

/// Get the host name and store it in an internally allocated buffer, returning an
/// `OsString` on success (see
/// [gethostname(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html)).
///
/// This function call attempts to get the host name for the running system and
/// store it in an internal buffer, returning it as an `OsString` if successful.
///
/// ```no_run
/// use nix::unistd;
///
/// let hostname = unistd::gethostname().expect("Failed getting hostname");
/// let hostname = hostname.into_string().expect("Hostname wasn't valid UTF-8");
/// println!("Hostname: {}", hostname);
/// ```
pub fn gethostname() -> Result<OsString> {
    // The capacity is the max length of a hostname plus the NUL terminator.
    let mut buffer: Vec<u8> = Vec::with_capacity(256);
    let ptr = buffer.as_mut_ptr().cast();
    let len = buffer.capacity() as size_t;

    let res = unsafe { libc::gethostname(ptr, len) };
    Errno::result(res).map(|_| {
        unsafe {
            buffer.as_mut_ptr().wrapping_add(len - 1).write(0); // ensure always null-terminated
            let len = CStr::from_ptr(buffer.as_ptr().cast()).len();
            buffer.set_len(len);
        }
        OsString::from_vec(buffer)
    })
}
}

/// Close a raw file descriptor
///
/// Be aware that many Rust types implicitly close-on-drop, including
/// `std::fs::File`.  Explicitly closing them with this method too can result in
/// a double-close condition, which can cause confusing `EBADF` errors in
/// seemingly unrelated code.  Caveat programmer.  See also
/// [close(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html).
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::io::AsRawFd;
/// use nix::unistd::close;
///
/// let f = tempfile::tempfile().unwrap();
/// close(f.as_raw_fd()).unwrap();   // Bad!  f will also close on drop!
/// ```
///
/// ```rust
/// use std::os::unix::io::IntoRawFd;
/// use nix::unistd::close;
///
/// let f = tempfile::tempfile().unwrap();
/// close(f.into_raw_fd()).unwrap(); // Good.  into_raw_fd consumes f
/// ```
pub fn close(fd: RawFd) -> Result<()> {
    let res = unsafe { libc::close(fd) };
    Errno::result(res).map(drop)
}

/// Read from a raw file descriptor.
///
/// See also [read(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html)
pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> {
    let res =
        unsafe { libc::read(fd, buf.as_mut_ptr().cast(), buf.len() as size_t) };

    Errno::result(res).map(|r| r as usize)
}

/// Write to a raw file descriptor.
///
/// See also [write(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html)
pub fn write<Fd: AsFd>(fd: Fd, buf: &[u8]) -> Result<usize> {
    let res = unsafe {
        libc::write(
            fd.as_fd().as_raw_fd(),
            buf.as_ptr().cast(),
            buf.len() as size_t,
        )
    };

    Errno::result(res).map(|r| r as usize)
}

feature! {
#![feature = "fs"]

/// Directive that tells [`lseek`] and [`lseek64`] what the offset is relative to.
///
/// [`lseek`]: ./fn.lseek.html
/// [`lseek64`]: ./fn.lseek64.html
#[repr(i32)]
#[derive(Clone, Copy, Debug)]
pub enum Whence {
    /// Specify an offset relative to the start of the file.
    SeekSet = libc::SEEK_SET,
    /// Specify an offset relative to the current file location.
    SeekCur = libc::SEEK_CUR,
    /// Specify an offset relative to the end of the file.
    SeekEnd = libc::SEEK_END,
    /// Specify an offset relative to the next location in the file greater than or
    /// equal to offset that contains some data. If offset points to
    /// some data, then the file offset is set to offset.
    #[cfg(any(
        freebsdlike,
        solarish,
        target_os = "linux",
    ))]
    SeekData = libc::SEEK_DATA,
    /// Specify an offset relative to the next hole in the file greater than
    /// or equal to offset. If offset points into the middle of a hole, then
    /// the file offset should be set to offset. If there is no hole past offset,
    /// then the file offset should be adjusted to the end of the file (i.e., there
    /// is an implicit hole at the end of any file).
    #[cfg(any(
        freebsdlike,
        solarish,
        target_os = "linux",
    ))]
    SeekHole = libc::SEEK_HOLE,
}

/// Move the read/write file offset.
///
/// See also [lseek(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html)
pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result<off_t> {
    let res = unsafe { libc::lseek(fd, offset, whence as i32) };

    Errno::result(res).map(|r| r as off_t)
}

/// Move the read/write file offset.
///
/// Unlike [`lseek`], it takes a 64-bit argument even on platforms where [`libc::off_t`] is
/// 32 bits.
#[cfg(linux_android)]
pub fn lseek64(
    fd: RawFd,
    offset: libc::off64_t,
    whence: Whence,
) -> Result<libc::off64_t> {
    let res = unsafe { libc::lseek64(fd, offset, whence as i32) };

    Errno::result(res).map(|r| r as libc::off64_t)
}
}

/// Create an interprocess channel.
///
/// See also [pipe(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html)
pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error> {
    let mut fds = mem::MaybeUninit::<[OwnedFd; 2]>::uninit();

    let res = unsafe { libc::pipe(fds.as_mut_ptr().cast()) };

    Error::result(res)?;

    let [read, write] = unsafe { fds.assume_init() };
    Ok((read, write))
}

feature! {
#![feature = "fs"]
/// Like `pipe`, but allows setting certain file descriptor flags.
///
/// The following flags are supported, and will be set atomically as the pipe is
/// created:
///
/// - `O_CLOEXEC`:    Set the close-on-exec flag for the new file descriptors.
#[cfg_attr(
    target_os = "linux",
    doc = "- `O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode."
)]
#[cfg_attr(
    target_os = "netbsd",
    doc = "- `O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`."
)]
/// - `O_NONBLOCK`:   Set the non-blocking flag for the ends of the pipe.
///
/// See also [pipe(2)](https://man7.org/linux/man-pages/man2/pipe.2.html)
#[cfg(any(
    linux_android,
    freebsdlike,
    solarish,
    target_os = "emscripten",
    target_os = "hurd",
    target_os = "redox",
    netbsdlike,
))]
pub fn pipe2(flags: OFlag) -> Result<(OwnedFd, OwnedFd)> {
    let mut fds = mem::MaybeUninit::<[OwnedFd; 2]>::uninit();

    let res =
        unsafe { libc::pipe2(fds.as_mut_ptr().cast(), flags.bits()) };

    Errno::result(res)?;

    let [read, write] = unsafe { fds.assume_init() };
    Ok((read, write))
}

/// Truncate a file to a specified length
///
/// See also
/// [truncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html)
#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
pub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> {
    let res = path
        .with_nix_path(|cstr| unsafe { libc::truncate(cstr.as_ptr(), len) })?;

    Errno::result(res).map(drop)
}

/// Truncate a file to a specified length
///
/// See also
/// [ftruncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html)
pub fn ftruncate<Fd: AsFd>(fd: Fd, len: off_t) -> Result<()> {
    Errno::result(unsafe { libc::ftruncate(fd.as_fd().as_raw_fd(), len) }).map(drop)
}

/// Determines if the file descriptor refers to a valid terminal type device.
pub fn isatty(fd: RawFd) -> Result<bool> {
    unsafe {
        // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so
        // we return `Ok(false)`
        if libc::isatty(fd) == 1 {
            Ok(true)
        } else {
            match Errno::last() {
                Errno::ENOTTY => Ok(false),
                err => Err(err),
            }
        }
    }
}

#[allow(missing_docs)]
#[cfg(not(target_os = "redox"))]
pub type LinkatFlags = AtFlags;
#[allow(missing_docs)]
#[cfg(not(target_os = "redox"))]
impl LinkatFlags {
    #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")]
    #[allow(non_upper_case_globals)]
    pub const SymlinkFollow: LinkatFlags = LinkatFlags::AT_SYMLINK_FOLLOW;
    #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")]
    #[allow(non_upper_case_globals)]
    pub const NoSymlinkFollow: LinkatFlags = LinkatFlags::empty();
}

/// Link one file to another file
///
/// Creates a new link (directory entry) at `newpath` for the existing file at `oldpath`. In the
/// case of a relative `oldpath`, the path is interpreted relative to the directory associated
/// with file descriptor `olddirfd` instead of the current working directory and similiarly for
/// `newpath` and file descriptor `newdirfd`. In case `flag` is `AtFlags::AT_SYMLINK_FOLLOW` and
/// `oldpath` names a symoblic link, a new link for the target of the symbolic link is created.
/// If either `olddirfd` or `newdirfd` is `None`, `AT_FDCWD` is used respectively where `oldpath`
/// and/or `newpath` is then interpreted relative to the current working directory of the calling
/// process. If either `oldpath` or `newpath` is absolute, then `dirfd` is ignored.
///
/// # References
/// See also [linkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html)
#[cfg(not(target_os = "redox"))] // RedoxFS does not support symlinks yet
pub fn linkat<P: ?Sized + NixPath>(
    olddirfd: Option<RawFd>,
    oldpath: &P,
    newdirfd: Option<RawFd>,
    newpath: &P,
    flag: AtFlags,
) -> Result<()> {
    let res = oldpath.with_nix_path(|oldcstr| {
        newpath.with_nix_path(|newcstr| unsafe {
            libc::linkat(
                at_rawfd(olddirfd),
                oldcstr.as_ptr(),
                at_rawfd(newdirfd),
                newcstr.as_ptr(),
                flag.bits(),
            )
        })
    })??;
    Errno::result(res).map(drop)
}

/// Remove a directory entry
///
/// See also [unlink(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html)
pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> {
    let res =
        path.with_nix_path(|cstr| unsafe { libc::unlink(cstr.as_ptr()) })?;
    Errno::result(res).map(drop)
}

/// Flags for `unlinkat` function.
#[derive(Clone, Copy, Debug)]
pub enum UnlinkatFlags {
    /// Remove the directory entry as a directory, not a normal file
    RemoveDir,
    /// Remove the directory entry as a normal file, not a directory
    NoRemoveDir,
}

/// Remove a directory entry
///
/// In the case of a relative path, the directory entry to be removed is determined relative to
/// the directory associated with the file descriptor `dirfd` or the current working directory
/// if `dirfd` is `None`. In the case of an absolute `path` `dirfd` is ignored. If `flag` is
/// `UnlinkatFlags::RemoveDir` then removal of the directory entry specified by `dirfd` and `path`
/// is performed.
///
/// # References
/// See also [unlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html)
#[cfg(not(target_os = "redox"))]
pub fn unlinkat<P: ?Sized + NixPath>(
    dirfd: Option<RawFd>,
    path: &P,
    flag: UnlinkatFlags,
) -> Result<()> {
    let atflag = match flag {
        UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR,
        UnlinkatFlags::NoRemoveDir => AtFlags::empty(),
    };
    let res = path.with_nix_path(|cstr| unsafe {
        libc::unlinkat(
            at_rawfd(dirfd),
            cstr.as_ptr(),
            atflag.bits() as libc::c_int,
        )
    })?;
    Errno::result(res).map(drop)
}

/// Change a process's root directory
#[inline]
#[cfg(not(target_os = "fuchsia"))]
pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> {
    let res =
        path.with_nix_path(|cstr| unsafe { libc::chroot(cstr.as_ptr()) })?;

    Errno::result(res).map(drop)
}

/// Commit filesystem caches to disk
///
/// See also [sync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html)
#[cfg(any(bsd, linux_android, solarish, target_os = "haiku", target_os = "aix", target_os = "hurd"))]
pub fn sync() {
    unsafe { libc::sync() };
}

/// Commit filesystem caches containing file referred to by the open file
/// descriptor `fd` to disk
///
/// See also [syncfs(2)](https://man7.org/linux/man-pages/man2/sync.2.html)
#[cfg(any(linux_android, target_os = "hurd"))]
pub fn syncfs(fd: RawFd) -> Result<()> {
    let res = unsafe { libc::syncfs(fd) };

    Errno::result(res).map(drop)
}

/// Synchronize changes to a file
///
/// See also [fsync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html)
#[inline]
pub fn fsync(fd: RawFd) -> Result<()> {
    let res = unsafe { libc::fsync(fd) };

    Errno::result(res).map(drop)
}

/// Synchronize the data of a file
///
/// See also
/// [fdatasync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html)
#[cfg(any(
    linux_android,
    solarish,
    netbsdlike,
    apple_targets,
    target_os = "freebsd",
    target_os = "emscripten",
    target_os = "fuchsia",
    target_os = "aix",
    target_os = "hurd",
))]
#[inline]
pub fn fdatasync(fd: RawFd) -> Result<()> {
    cfg_if! {
        // apple libc supports fdatasync too, albeit not being present in its headers
        // [fdatasync](https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/vfs/vfs_syscalls.c#L7728)
        if #[cfg(apple_targets)] {
            extern "C" {
                fn fdatasync(fd: libc::c_int) -> libc::c_int;
            }
        } else {
            use libc::fdatasync as fdatasync;
        }
    }
    let res = unsafe { fdatasync(fd) };

    Errno::result(res).map(drop)
}
}

feature! {
#![feature = "user"]

/// Get a real user ID
///
/// See also [getuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html)
// POSIX requires that getuid is always successful, so no need to check return
// value or errno.
#[inline]
pub fn getuid() -> Uid {
    Uid(unsafe { libc::getuid() })
}

/// Get the effective user ID
///
/// See also [geteuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html)
// POSIX requires that geteuid is always successful, so no need to check return
// value or errno.
#[inline]
pub fn geteuid() -> Uid {
    Uid(unsafe { libc::geteuid() })
}

/// Get the real group ID
///
/// See also [getgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html)
// POSIX requires that getgid is always successful, so no need to check return
// value or errno.
#[inline]
pub fn getgid() -> Gid {
    Gid(unsafe { libc::getgid() })
}

/// Get the effective group ID
///
/// See also [getegid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getegid.html)
// POSIX requires that getegid is always successful, so no need to check return
// value or errno.
#[inline]
pub fn getegid() -> Gid {
    Gid(unsafe { libc::getegid() })
}

/// Set the effective user ID
///
/// See also [seteuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/seteuid.html)
#[inline]
pub fn seteuid(euid: Uid) -> Result<()> {
    let res = unsafe { libc::seteuid(euid.into()) };

    Errno::result(res).map(drop)
}

/// Set the effective group ID
///
/// See also [setegid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setegid.html)
#[inline]
pub fn setegid(egid: Gid) -> Result<()> {
    let res = unsafe { libc::setegid(egid.into()) };

    Errno::result(res).map(drop)
}

/// Set the user ID
///
/// See also [setuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setuid.html)
#[inline]
pub fn setuid(uid: Uid) -> Result<()> {
    let res = unsafe { libc::setuid(uid.into()) };

    Errno::result(res).map(drop)
}

/// Set the group ID
///
/// See also [setgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setgid.html)
#[inline]
pub fn setgid(gid: Gid) -> Result<()> {
    let res = unsafe { libc::setgid(gid.into()) };

    Errno::result(res).map(drop)
}
}

feature! {
#![all(feature = "fs", feature = "user")]
/// Set the user identity used for filesystem checks per-thread.
/// On both success and failure, this call returns the previous filesystem user
/// ID of the caller.
///
/// See also [setfsuid(2)](https://man7.org/linux/man-pages/man2/setfsuid.2.html)
#[cfg(linux_android)]
pub fn setfsuid(uid: Uid) -> Uid {
    let prev_fsuid = unsafe { libc::setfsuid(uid.into()) };
    Uid::from_raw(prev_fsuid as uid_t)
}

/// Set the group identity used for filesystem checks per-thread.
/// On both success and failure, this call returns the previous filesystem group
/// ID of the caller.
///
/// See also [setfsgid(2)](https://man7.org/linux/man-pages/man2/setfsgid.2.html)
#[cfg(linux_android)]
pub fn setfsgid(gid: Gid) -> Gid {
    let prev_fsgid = unsafe { libc::setfsgid(gid.into()) };
    Gid::from_raw(prev_fsgid as gid_t)
}
}

feature! {
#![feature = "user"]

/// Get the list of supplementary group IDs of the calling process.
///
/// [Further reading](https://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html)
///
/// **Note:** This function is not available for Apple platforms. On those
/// platforms, checking group membership should be achieved via communication
/// with the `opendirectoryd` service.
#[cfg(not(apple_targets))]
pub fn getgroups() -> Result<Vec<Gid>> {
    // First get the maximum number of groups. The value returned
    // shall always be greater than or equal to one and less than or
    // equal to the value of {NGROUPS_MAX} + 1.
    let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) {
        Ok(Some(n)) => (n + 1) as usize,
        Ok(None) | Err(_) => usize::MAX,
    };

    // Next, get the number of groups so we can size our Vec
    let ngroups = unsafe { libc::getgroups(0, ptr::null_mut()) };

    // If there are no supplementary groups, return early.
    // This prevents a potential buffer over-read if the number of groups
    // increases from zero before the next call. It would return the total
    // number of groups beyond the capacity of the buffer.
    if ngroups == 0 {
        return Ok(Vec::new());
    }

    // Now actually get the groups. We try multiple times in case the number of
    // groups has changed since the first call to getgroups() and the buffer is
    // now too small.
    let mut groups =
        Vec::<Gid>::with_capacity(Errno::result(ngroups)? as usize);
    loop {
        // FIXME: On the platforms we currently support, the `Gid` struct has
        // the same representation in memory as a bare `gid_t`. This is not
        // necessarily the case on all Rust platforms, though. See RFC 1785.
        let ngroups = unsafe {
            libc::getgroups(
                groups.capacity() as c_int,
                groups.as_mut_ptr().cast(),
            )
        };

        match Errno::result(ngroups) {
            Ok(s) => {
                unsafe { groups.set_len(s as usize) };
                return Ok(groups);
            }
            Err(Errno::EINVAL) => {
                // EINVAL indicates that the buffer size was too
                // small, resize it up to ngroups_max as limit.
                reserve_double_buffer_size(&mut groups, ngroups_max)
                    .or(Err(Errno::EINVAL))?;
            }
            Err(e) => return Err(e),
        }
    }
}

/// Set the list of supplementary group IDs for the calling process.
///
/// [Further reading](https://man7.org/linux/man-pages/man2/getgroups.2.html)
///
/// **Note:** This function is not available for Apple platforms. On those
/// platforms, group membership management should be achieved via communication
/// with the `opendirectoryd` service.
///
/// # Examples
///
/// `setgroups` can be used when dropping privileges from the root user to a
/// specific user and group. For example, given the user `www-data` with UID
/// `33` and the group `backup` with the GID `34`, one could switch the user as
/// follows:
///
/// ```rust,no_run
/// # use std::error::Error;
/// # use nix::unistd::*;
/// #
/// # fn try_main() -> Result<(), Box<dyn Error>> {
/// let uid = Uid::from_raw(33);
/// let gid = Gid::from_raw(34);
/// setgroups(&[gid])?;
/// setgid(gid)?;
/// setuid(uid)?;
/// #
/// #     Ok(())
/// # }
/// #
/// # try_main().unwrap();
/// ```
#[cfg(not(any(
    apple_targets,
    target_os = "redox",
    target_os = "haiku"
)))]
pub fn setgroups(groups: &[Gid]) -> Result<()> {
    cfg_if! {
        if #[cfg(any(bsd,
                     solarish,
                     target_os = "aix"))] {
            type setgroups_ngroups_t = c_int;
        } else {
            type setgroups_ngroups_t = size_t;
        }
    }
    // FIXME: On the platforms we currently support, the `Gid` struct has the
    // same representation in memory as a bare `gid_t`. This is not necessarily
    // the case on all Rust platforms, though. See RFC 1785.
    let res = unsafe {
        libc::setgroups(
            groups.len() as setgroups_ngroups_t,
            groups.as_ptr().cast(),
        )
    };

    Errno::result(res).map(drop)
}

/// Calculate the supplementary group access list.
///
/// Gets the group IDs of all groups that `user` is a member of. The additional
/// group `group` is also added to the list.
///
/// [Further reading](https://man7.org/linux/man-pages/man3/getgrouplist.3.html)
///
/// **Note:** This function is not available for Apple platforms. On those
/// platforms, checking group membership should be achieved via communication
/// with the `opendirectoryd` service.
///
/// # Errors
///
/// Although the `getgrouplist()` call does not return any specific
/// errors on any known platforms, this implementation will return a system
/// error of `EINVAL` if the number of groups to be fetched exceeds the
/// `NGROUPS_MAX` sysconf value. This mimics the behaviour of `getgroups()`
/// and `setgroups()`. Additionally, while some implementations will return a
/// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation
/// will only ever return the complete list or else an error.
#[cfg(not(any(
    target_os = "aix",
    solarish,
    apple_targets,
    target_os = "redox"
)))]
pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
    let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) {
        Ok(Some(n)) => n as c_int,
        Ok(None) | Err(_) => c_int::MAX,
    };
    use std::cmp::min;
    let mut groups = Vec::<Gid>::with_capacity(min(ngroups_max, 8) as usize);
    cfg_if! {
        if #[cfg(apple_targets)] {
            type getgrouplist_group_t = c_int;
        } else {
            type getgrouplist_group_t = gid_t;
        }
    }
    let gid: gid_t = group.into();
    loop {
        let mut ngroups = groups.capacity() as i32;
        let ret = unsafe {
            libc::getgrouplist(
                user.as_ptr(),
                gid as getgrouplist_group_t,
                groups.as_mut_ptr().cast(),
                &mut ngroups,
            )
        };

        // BSD systems only return 0 or -1, Linux returns ngroups on success.
        if ret >= 0 {
            unsafe { groups.set_len(ngroups as usize) };
            return Ok(groups);
        } else if ret == -1 {
            // Returns -1 if ngroups is too small, but does not set errno.
            // BSD systems will still fill the groups buffer with as many
            // groups as possible, but Linux manpages do not mention this
            // behavior.
            reserve_double_buffer_size(&mut groups, ngroups_max as usize)
                .map_err(|_| Errno::EINVAL)?;
        }
    }
}

/// Initialize the supplementary group access list.
///
/// Sets the supplementary group IDs for the calling process using all groups
/// that `user` is a member of. The additional group `group` is also added to
/// the list.
///
/// [Further reading](https://man7.org/linux/man-pages/man3/initgroups.3.html)
///
/// **Note:** This function is not available for Apple platforms. On those
/// platforms, group membership management should be achieved via communication
/// with the `opendirectoryd` service.
///
/// # Examples
///
/// `initgroups` can be used when dropping privileges from the root user to
/// another user. For example, given the user `www-data`, we could look up the
/// UID and GID for the user in the system's password database (usually found
/// in `/etc/passwd`). If the `www-data` user's UID and GID were `33` and `33`,
/// respectively, one could switch the user as follows:
///
/// ```rust,no_run
/// # use std::error::Error;
/// # use std::ffi::CString;
/// # use nix::unistd::*;
/// #
/// # fn try_main() -> Result<(), Box<dyn Error>> {
/// let user = CString::new("www-data").unwrap();
/// let uid = Uid::from_raw(33);
/// let gid = Gid::from_raw(33);
/// initgroups(&user, gid)?;
/// setgid(gid)?;
/// setuid(uid)?;
/// #
/// #     Ok(())
/// # }
/// #
/// # try_main().unwrap();
/// ```
#[cfg(not(any(
    apple_targets,
    target_os = "redox",
    target_os = "haiku"
)))]
pub fn initgroups(user: &CStr, group: Gid) -> Result<()> {
    cfg_if! {
        if #[cfg(apple_targets)] {
            type initgroups_group_t = c_int;
        } else {
            type initgroups_group_t = gid_t;
        }
    }
    let gid: gid_t = group.into();
    let res =
        unsafe { libc::initgroups(user.as_ptr(), gid as initgroups_group_t) };

    Errno::result(res).map(drop)
}
}

feature! {
#![feature = "signal"]

/// Suspend the thread until a signal is received.
///
/// See also [pause(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html).
#[inline]
#[cfg(not(target_os = "redox"))]
pub fn pause() {
    unsafe { libc::pause() };
}

pub mod alarm {
    //! Alarm signal scheduling.
    //!
    //! Scheduling an alarm will trigger a `SIGALRM` signal when the time has
    //! elapsed, which has to be caught, because the default action for the
    //! signal is to terminate the program. This signal also can't be ignored
    //! because the system calls like `pause` will not be interrupted, see the
    //! second example below.
    //!
    //! # Examples
    //!
    //! Canceling an alarm:
    //!
    //! ```
    //! use nix::unistd::alarm;
    //!
    //! // Set an alarm for 60 seconds from now.
    //! alarm::set(60);
    //!
    //! // Cancel the above set alarm, which returns the number of seconds left
    //! // of the previously set alarm.
    //! assert_eq!(alarm::cancel(), Some(60));
    //! ```
    //!
    //! Scheduling an alarm and waiting for the signal:
    //!
    #![cfg_attr(target_os = "redox", doc = " ```rust,ignore")]
    #![cfg_attr(not(target_os = "redox"), doc = " ```rust")]
    //! use std::time::{Duration, Instant};
    //!
    //! use nix::unistd::{alarm, pause};
    //! use nix::sys::signal::*;
    //!
    //! // We need to setup an empty signal handler to catch the alarm signal,
    //! // otherwise the program will be terminated once the signal is delivered.
    //! extern fn signal_handler(_: nix::libc::c_int) { }
    //! let sa = SigAction::new(
    //!     SigHandler::Handler(signal_handler),
    //!     SaFlags::SA_RESTART,
    //!     SigSet::empty()
    //! );
    //! unsafe {
    //!     sigaction(Signal::SIGALRM, &sa);
    //! }
    //!
    //! let start = Instant::now();
    //!
    //! // Set an alarm for 1 second from now.
    //! alarm::set(1);
    //!
    //! // Pause the process until the alarm signal is received.
    //! let mut sigset = SigSet::empty();
    //! sigset.add(Signal::SIGALRM);
    //! sigset.wait();
    //!
    //! assert!(start.elapsed() >= Duration::from_secs(1));
    //! ```
    //!
    //! # References
    //!
    //! See also [alarm(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/alarm.html).

    /// Schedule an alarm signal.
    ///
    /// This will cause the system to generate a `SIGALRM` signal for the
    /// process after the specified number of seconds have elapsed.
    ///
    /// Returns the leftover time of a previously set alarm if there was one.
    pub fn set(secs: libc::c_uint) -> Option<libc::c_uint> {
        assert!(secs != 0, "passing 0 to `alarm::set` is not allowed, to cancel an alarm use `alarm::cancel`");
        alarm(secs)
    }

    /// Cancel an previously set alarm signal.
    ///
    /// Returns the leftover time of a previously set alarm if there was one.
    pub fn cancel() -> Option<libc::c_uint> {
        alarm(0)
    }

    fn alarm(secs: libc::c_uint) -> Option<libc::c_uint> {
        match unsafe { libc::alarm(secs) } {
            0 => None,
            secs => Some(secs),
        }
    }
}
}

/// Suspend execution for an interval of time
///
/// See also [sleep(2)](https://pubs.opengroup.org/onlinepubs/009695399/functions/sleep.html#tag_03_705_05)
// Per POSIX, does not fail
#[inline]
pub fn sleep(seconds: c_uint) -> c_uint {
    unsafe { libc::sleep(seconds) }
}

feature! {
#![feature = "acct"]

/// Process accounting
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
pub mod acct {
    use crate::errno::Errno;
    use crate::{NixPath, Result};
    use std::ptr;

    /// Enable process accounting
    ///
    /// See also [acct(2)](https://linux.die.net/man/2/acct)
    pub fn enable<P: ?Sized + NixPath>(filename: &P) -> Result<()> {
        let res = filename
            .with_nix_path(|cstr| unsafe { libc::acct(cstr.as_ptr()) })?;

        Errno::result(res).map(drop)
    }

    /// Disable process accounting
    pub fn disable() -> Result<()> {
        let res = unsafe { libc::acct(ptr::null()) };

        Errno::result(res).map(drop)
    }
}
}

feature! {
#![feature = "fs"]
/// Creates a regular file which persists even after process termination
///
/// * `template`: a path whose 6 rightmost characters must be X, e.g. `/tmp/tmpfile_XXXXXX`
/// * returns: tuple of file descriptor and filename
///
/// Err is returned either if no temporary filename could be created or the template doesn't
/// end with XXXXXX
///
/// See also [mkstemp(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkstemp.html)
///
/// # Example
///
/// ```rust
/// use nix::unistd;
///
/// let _ = match unistd::mkstemp("/tmp/tempfile_XXXXXX") {
///     Ok((fd, path)) => {
///         unistd::unlink(path.as_path()).unwrap(); // flag file to be deleted at app termination
///         fd
///     }
///     Err(e) => panic!("mkstemp failed: {}", e)
/// };
/// // do something with fd
/// ```
#[inline]
pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> {
    let mut path =
        template.with_nix_path(|path| path.to_bytes_with_nul().to_owned())?;
    let p = path.as_mut_ptr().cast();
    let fd = unsafe { libc::mkstemp(p) };
    let last = path.pop(); // drop the trailing nul
    debug_assert!(last == Some(b'\0'));
    let pathname = OsString::from_vec(path);
    Errno::result(fd)?;
    Ok((fd, PathBuf::from(pathname)))
}
}

feature! {
#![all(feature = "fs", feature = "feature")]

/// Creates a directory which persists even after process termination
///
/// * `template`: a path whose rightmost characters contain some number of X, e.g. `/tmp/tmpdir_XXXXXX`
/// * returns: filename
///
/// Err is returned either if no temporary filename could be created or the template had insufficient X
///
/// See also [mkstemp(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdtemp.html)
///
/// ```
/// use nix::unistd;
///
/// match unistd::mkdtemp("/tmp/tempdir_XXXXXX") {
///     Ok(_path) => {
///         // do something with directory
///     }
///     Err(e) => panic!("mkdtemp failed: {}", e)
/// };
/// ```
pub fn mkdtemp<P: ?Sized + NixPath>(template: &P) -> Result<PathBuf> {
    let mut path = template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})?;
    let p = path.as_mut_ptr() as *mut _;
    let p = unsafe { libc::mkdtemp(p) };
    if p.is_null() {
        return Err(Errno::last());
    }
--> --------------------

--> maximum size reached

--> --------------------

[ Dauer der Verarbeitung: 0.41 Sekunden  (vorverarbeitet)  ]