nix/
unistd.rs

1//! Safe wrappers around functions found in libc "unistd.h" header
2
3#[cfg(not(target_os = "redox"))]
4use cfg_if::cfg_if;
5use crate::errno::{self, Errno};
6use crate::{Error, Result, NixPath};
7#[cfg(not(target_os = "redox"))]
8#[cfg(feature = "fs")]
9use crate::fcntl::{AtFlags, at_rawfd};
10use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t,
11           uid_t, gid_t, mode_t, PATH_MAX};
12#[cfg(feature = "fs")]
13use crate::fcntl::{FdFlag, OFlag, fcntl, FcntlArg::F_SETFD};
14use std::{fmt, mem, ptr};
15use std::convert::Infallible;
16use std::ffi::{CStr, OsString};
17#[cfg(not(target_os = "redox"))]
18use std::ffi::{CString, OsStr};
19use std::os::unix::ffi::OsStringExt;
20#[cfg(not(target_os = "redox"))]
21use std::os::unix::ffi::OsStrExt;
22use std::os::unix::io::RawFd;
23use std::path::PathBuf;
24#[cfg(feature = "fs")]
25use crate::sys::stat::Mode;
26
27feature! {
28    #![feature = "fs"]
29    #[cfg(any(target_os = "android", target_os = "linux"))]
30    pub use self::pivot_root::*;
31}
32
33#[cfg(any(target_os = "android",
34          target_os = "dragonfly",
35          target_os = "freebsd",
36          target_os = "linux",
37          target_os = "openbsd"))]
38pub use self::setres::*;
39
40#[cfg(any(target_os = "android",
41          target_os = "dragonfly",
42          target_os = "freebsd",
43          target_os = "linux",
44          target_os = "openbsd"))]
45pub use self::getres::*;
46
47feature! {
48#![feature = "user"]
49
50/// User identifier
51///
52/// Newtype pattern around `uid_t` (which is just alias). It prevents bugs caused by accidentally
53/// passing wrong value.
54#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
55pub struct Uid(uid_t);
56
57impl Uid {
58    /// Creates `Uid` from raw `uid_t`.
59    pub const fn from_raw(uid: uid_t) -> Self {
60        Uid(uid)
61    }
62
63    /// Returns Uid of calling process. This is practically a more Rusty alias for `getuid`.
64    pub fn current() -> Self {
65        getuid()
66    }
67
68    /// Returns effective Uid of calling process. This is practically a more Rusty alias for `geteuid`.
69    pub fn effective() -> Self {
70        geteuid()
71    }
72
73    /// Returns true if the `Uid` represents privileged user - root. (If it equals zero.)
74    pub const fn is_root(self) -> bool {
75        self.0 == ROOT.0
76    }
77
78    /// Get the raw `uid_t` wrapped by `self`.
79    pub const fn as_raw(self) -> uid_t {
80        self.0
81    }
82}
83
84impl From<Uid> for uid_t {
85    fn from(uid: Uid) -> Self {
86        uid.0
87    }
88}
89
90impl fmt::Display for Uid {
91    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92        fmt::Display::fmt(&self.0, f)
93    }
94}
95
96/// Constant for UID = 0
97pub const ROOT: Uid = Uid(0);
98
99/// Group identifier
100///
101/// Newtype pattern around `gid_t` (which is just alias). It prevents bugs caused by accidentally
102/// passing wrong value.
103#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
104pub struct Gid(gid_t);
105
106impl Gid {
107    /// Creates `Gid` from raw `gid_t`.
108    pub const fn from_raw(gid: gid_t) -> Self {
109        Gid(gid)
110    }
111
112    /// Returns Gid of calling process. This is practically a more Rusty alias for `getgid`.
113    pub fn current() -> Self {
114        getgid()
115    }
116
117    /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getegid`.
118    pub fn effective() -> Self {
119        getegid()
120    }
121
122    /// Get the raw `gid_t` wrapped by `self`.
123    pub const fn as_raw(self) -> gid_t {
124        self.0
125    }
126}
127
128impl From<Gid> for gid_t {
129    fn from(gid: Gid) -> Self {
130        gid.0
131    }
132}
133
134impl fmt::Display for Gid {
135    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
136        fmt::Display::fmt(&self.0, f)
137    }
138}
139}
140
141feature! {
142#![feature = "process"]
143/// Process identifier
144///
145/// Newtype pattern around `pid_t` (which is just alias). It prevents bugs caused by accidentally
146/// passing wrong value.
147#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
148pub struct Pid(pid_t);
149
150impl Pid {
151    /// Creates `Pid` from raw `pid_t`.
152    pub const fn from_raw(pid: pid_t) -> Self {
153        Pid(pid)
154    }
155
156    /// Returns PID of calling process
157    pub fn this() -> Self {
158        getpid()
159    }
160
161    /// Returns PID of parent of calling process
162    pub fn parent() -> Self {
163        getppid()
164    }
165
166    /// Get the raw `pid_t` wrapped by `self`.
167    pub const fn as_raw(self) -> pid_t {
168        self.0
169    }
170}
171
172impl From<Pid> for pid_t {
173    fn from(pid: Pid) -> Self {
174        pid.0
175    }
176}
177
178impl fmt::Display for Pid {
179    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
180        fmt::Display::fmt(&self.0, f)
181    }
182}
183
184
185/// Represents the successful result of calling `fork`
186///
187/// When `fork` is called, the process continues execution in the parent process
188/// and in the new child.  This return type can be examined to determine whether
189/// you are now executing in the parent process or in the child.
190#[derive(Clone, Copy, Debug)]
191pub enum ForkResult {
192    Parent { child: Pid },
193    Child,
194}
195
196impl ForkResult {
197
198    /// Return `true` if this is the child process of the `fork()`
199    #[inline]
200    pub fn is_child(self) -> bool {
201        matches!(self, ForkResult::Child)
202    }
203
204    /// Returns `true` if this is the parent process of the `fork()`
205    #[inline]
206    pub fn is_parent(self) -> bool {
207        !self.is_child()
208    }
209}
210
211/// Create a new child process duplicating the parent process ([see
212/// fork(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html)).
213///
214/// After successfully calling the fork system call, a second process will
215/// be created which is identical to the original except for the pid and the
216/// return value of this function.  As an example:
217///
218/// ```
219/// use nix::{sys::wait::waitpid,unistd::{fork, ForkResult, write}};
220///
221/// match unsafe{fork()} {
222///    Ok(ForkResult::Parent { child, .. }) => {
223///        println!("Continuing execution in parent process, new child has pid: {}", child);
224///        waitpid(child, None).unwrap();
225///    }
226///    Ok(ForkResult::Child) => {
227///        // Unsafe to use `println!` (or `unwrap`) here. See Safety.
228///        write(libc::STDOUT_FILENO, "I'm a new child process\n".as_bytes()).ok();
229///        unsafe { libc::_exit(0) };
230///    }
231///    Err(_) => println!("Fork failed"),
232/// }
233/// ```
234///
235/// This will print something like the following (order nondeterministic).  The
236/// thing to note is that you end up with two processes continuing execution
237/// immediately after the fork call but with different match arms.
238///
239/// ```text
240/// Continuing execution in parent process, new child has pid: 1234
241/// I'm a new child process
242/// ```
243///
244/// # Safety
245///
246/// In a multithreaded program, only [async-signal-safe] functions like `pause`
247/// and `_exit` may be called by the child (the parent isn't restricted). Note
248/// that memory allocation may **not** be async-signal-safe and thus must be
249/// prevented.
250///
251/// Those functions are only a small subset of your operating system's API, so
252/// special care must be taken to only invoke code you can control and audit.
253///
254/// [async-signal-safe]: https://man7.org/linux/man-pages/man7/signal-safety.7.html
255#[inline]
256pub unsafe fn fork() -> Result<ForkResult> {
257    use self::ForkResult::*;
258    let res = libc::fork();
259
260    Errno::result(res).map(|res| match res {
261        0 => Child,
262        res => Parent { child: Pid(res) },
263    })
264}
265
266/// Get the pid of this process (see
267/// [getpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpid.html)).
268///
269/// Since you are running code, there is always a pid to return, so there
270/// is no error case that needs to be handled.
271#[inline]
272pub fn getpid() -> Pid {
273    Pid(unsafe { libc::getpid() })
274}
275
276/// Get the pid of this processes' parent (see
277/// [getpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getppid.html)).
278///
279/// There is always a parent pid to return, so there is no error case that needs
280/// to be handled.
281#[inline]
282pub fn getppid() -> Pid {
283    Pid(unsafe { libc::getppid() }) // no error handling, according to man page: "These functions are always successful."
284}
285
286/// Set a process group ID (see
287/// [setpgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html)).
288///
289/// Set the process group id (PGID) of a particular process.  If a pid of zero
290/// is specified, then the pid of the calling process is used.  Process groups
291/// may be used to group together a set of processes in order for the OS to
292/// apply some operations across the group.
293///
294/// `setsid()` may be used to create a new process group.
295#[inline]
296pub fn setpgid(pid: Pid, pgid: Pid) -> Result<()> {
297    let res = unsafe { libc::setpgid(pid.into(), pgid.into()) };
298    Errno::result(res).map(drop)
299}
300#[inline]
301pub fn getpgid(pid: Option<Pid>) -> Result<Pid> {
302    let res = unsafe { libc::getpgid(pid.unwrap_or(Pid(0)).into()) };
303    Errno::result(res).map(Pid)
304}
305
306/// Create new session and set process group id (see
307/// [setsid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html)).
308#[inline]
309pub fn setsid() -> Result<Pid> {
310    Errno::result(unsafe { libc::setsid() }).map(Pid)
311}
312
313/// Get the process group ID of a session leader
314/// [getsid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsid.html).
315///
316/// Obtain the process group ID of the process that is the session leader of the process specified
317/// by pid. If pid is zero, it specifies the calling process.
318#[inline]
319#[cfg(not(target_os = "redox"))]
320pub fn getsid(pid: Option<Pid>) -> Result<Pid> {
321    let res = unsafe { libc::getsid(pid.unwrap_or(Pid(0)).into()) };
322    Errno::result(res).map(Pid)
323}
324}
325
326feature! {
327#![all(feature = "process", feature = "term")]
328/// Get the terminal foreground process group (see
329/// [tcgetpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetpgrp.html)).
330///
331/// Get the group process id (GPID) of the foreground process group on the
332/// terminal associated to file descriptor (FD).
333#[inline]
334pub fn tcgetpgrp(fd: c_int) -> Result<Pid> {
335    let res = unsafe { libc::tcgetpgrp(fd) };
336    Errno::result(res).map(Pid)
337}
338/// Set the terminal foreground process group (see
339/// [tcgetpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetpgrp.html)).
340///
341/// Get the group process id (PGID) to the foreground process group on the
342/// terminal associated to file descriptor (FD).
343#[inline]
344pub fn tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()> {
345    let res = unsafe { libc::tcsetpgrp(fd, pgrp.into()) };
346    Errno::result(res).map(drop)
347}
348}
349
350feature! {
351#![feature = "process"]
352/// Get the group id of the calling process (see
353///[getpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html)).
354///
355/// Get the process group id (PGID) of the calling process.
356/// According to the man page it is always successful.
357#[inline]
358pub fn getpgrp() -> Pid {
359    Pid(unsafe { libc::getpgrp() })
360}
361
362/// Get the caller's thread ID (see
363/// [gettid(2)](https://man7.org/linux/man-pages/man2/gettid.2.html).
364///
365/// This function is only available on Linux based systems.  In a single
366/// threaded process, the main thread will have the same ID as the process.  In
367/// a multithreaded process, each thread will have a unique thread id but the
368/// same process ID.
369///
370/// No error handling is required as a thread id should always exist for any
371/// process, even if threads are not being used.
372#[cfg(any(target_os = "linux", target_os = "android"))]
373#[inline]
374pub fn gettid() -> Pid {
375    Pid(unsafe { libc::syscall(libc::SYS_gettid) as pid_t })
376}
377}
378
379feature! {
380#![feature = "fs"]
381/// Create a copy of the specified file descriptor (see
382/// [dup(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)).
383///
384/// The new file descriptor will be have a new index but refer to the same
385/// resource as the old file descriptor and the old and new file descriptors may
386/// be used interchangeably.  The new and old file descriptor share the same
387/// underlying resource, offset, and file status flags.  The actual index used
388/// for the file descriptor will be the lowest fd index that is available.
389///
390/// The two file descriptors do not share file descriptor flags (e.g. `OFlag::FD_CLOEXEC`).
391#[inline]
392pub fn dup(oldfd: RawFd) -> Result<RawFd> {
393    let res = unsafe { libc::dup(oldfd) };
394
395    Errno::result(res)
396}
397
398/// Create a copy of the specified file descriptor using the specified fd (see
399/// [dup(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)).
400///
401/// This function behaves similar to `dup()` except that it will try to use the
402/// specified fd instead of allocating a new one.  See the man pages for more
403/// detail on the exact behavior of this function.
404#[inline]
405pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd> {
406    let res = unsafe { libc::dup2(oldfd, newfd) };
407
408    Errno::result(res)
409}
410
411/// Create a new copy of the specified file descriptor using the specified fd
412/// and flags (see [dup(2)](https://man7.org/linux/man-pages/man2/dup.2.html)).
413///
414/// This function behaves similar to `dup2()` but allows for flags to be
415/// specified.
416pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
417    dup3_polyfill(oldfd, newfd, flags)
418}
419
420#[inline]
421fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
422    if oldfd == newfd {
423        return Err(Errno::EINVAL);
424    }
425
426    let fd = dup2(oldfd, newfd)?;
427
428    if flags.contains(OFlag::O_CLOEXEC) {
429        if let Err(e) = fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC)) {
430            let _ = close(fd);
431            return Err(e);
432        }
433    }
434
435    Ok(fd)
436}
437
438/// Change the current working directory of the calling process (see
439/// [chdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html)).
440///
441/// This function may fail in a number of different scenarios.  See the man
442/// pages for additional details on possible failure cases.
443#[inline]
444pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> {
445    let res = path.with_nix_path(|cstr| {
446        unsafe { libc::chdir(cstr.as_ptr()) }
447    })?;
448
449    Errno::result(res).map(drop)
450}
451
452/// Change the current working directory of the process to the one
453/// given as an open file descriptor (see
454/// [fchdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html)).
455///
456/// This function may fail in a number of different scenarios.  See the man
457/// pages for additional details on possible failure cases.
458#[inline]
459#[cfg(not(target_os = "fuchsia"))]
460pub fn fchdir(dirfd: RawFd) -> Result<()> {
461    let res = unsafe { libc::fchdir(dirfd) };
462
463    Errno::result(res).map(drop)
464}
465
466/// Creates new directory `path` with access rights `mode`.  (see [mkdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html))
467///
468/// # Errors
469///
470/// There are several situations where mkdir might fail:
471///
472/// - current user has insufficient rights in the parent directory
473/// - the path already exists
474/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X)
475///
476/// # Example
477///
478/// ```rust
479/// use nix::unistd;
480/// use nix::sys::stat;
481/// use tempfile::tempdir;
482///
483/// let tmp_dir1 = tempdir().unwrap();
484/// let tmp_dir2 = tmp_dir1.path().join("new_dir");
485///
486/// // create new directory and give read, write and execute rights to the owner
487/// match unistd::mkdir(&tmp_dir2, stat::Mode::S_IRWXU) {
488///    Ok(_) => println!("created {:?}", tmp_dir2),
489///    Err(err) => println!("Error creating directory: {}", err),
490/// }
491/// ```
492#[inline]
493pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
494    let res = path.with_nix_path(|cstr| {
495        unsafe { libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t) }
496    })?;
497
498    Errno::result(res).map(drop)
499}
500
501/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`.
502///
503/// # Errors
504///
505/// There are several situations where mkfifo might fail:
506///
507/// - current user has insufficient rights in the parent directory
508/// - the path already exists
509/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X)
510///
511/// For a full list consult
512/// [posix specification](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html)
513///
514/// # Example
515///
516/// ```rust
517/// use nix::unistd;
518/// use nix::sys::stat;
519/// use tempfile::tempdir;
520///
521/// let tmp_dir = tempdir().unwrap();
522/// let fifo_path = tmp_dir.path().join("foo.pipe");
523///
524/// // create new fifo and give read, write and execute rights to the owner
525/// match unistd::mkfifo(&fifo_path, stat::Mode::S_IRWXU) {
526///    Ok(_) => println!("created {:?}", fifo_path),
527///    Err(err) => println!("Error creating fifo: {}", err),
528/// }
529/// ```
530#[inline]
531#[cfg(not(target_os = "redox"))] // RedoxFS does not support fifo yet
532pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
533    let res = path.with_nix_path(|cstr| {
534        unsafe { libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t) }
535    })?;
536
537    Errno::result(res).map(drop)
538}
539
540/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`.
541///
542/// If `dirfd` has a value, then `path` is relative to directory associated with the file descriptor.
543///
544/// If `dirfd` is `None`, then `path` is relative to the current working directory.
545///
546/// # References
547///
548/// [mkfifoat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifoat.html).
549// mkfifoat is not implemented in OSX or android
550#[inline]
551#[cfg(not(any(
552    target_os = "macos", target_os = "ios",
553    target_os = "android", target_os = "redox")))]
554pub fn mkfifoat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: Mode) -> Result<()> {
555    let res = path.with_nix_path(|cstr| unsafe {
556        libc::mkfifoat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits() as mode_t)
557    })?;
558
559    Errno::result(res).map(drop)
560}
561
562/// Creates a symbolic link at `path2` which points to `path1`.
563///
564/// If `dirfd` has a value, then `path2` is relative to directory associated
565/// with the file descriptor.
566///
567/// If `dirfd` is `None`, then `path2` is relative to the current working
568/// directory. This is identical to `libc::symlink(path1, path2)`.
569///
570/// See also [symlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html).
571#[cfg(not(target_os = "redox"))]
572pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
573    path1: &P1,
574    dirfd: Option<RawFd>,
575    path2: &P2) -> Result<()> {
576    let res =
577        path1.with_nix_path(|path1| {
578            path2.with_nix_path(|path2| {
579                unsafe {
580                    libc::symlinkat(
581                        path1.as_ptr(),
582                        dirfd.unwrap_or(libc::AT_FDCWD),
583                        path2.as_ptr()
584                    )
585                }
586            })
587        })??;
588    Errno::result(res).map(drop)
589}
590}
591
592// Double the buffer capacity up to limit. In case it already has
593// reached the limit, return Errno::ERANGE.
594#[cfg(any(feature = "fs", feature = "user"))]
595fn reserve_double_buffer_size<T>(buf: &mut Vec<T>, limit: usize) -> Result<()> {
596    use std::cmp::min;
597
598    if buf.capacity() >= limit {
599        return Err(Errno::ERANGE)
600    }
601
602    let capacity = min(buf.capacity() * 2, limit);
603    buf.reserve(capacity);
604
605    Ok(())
606}
607
608feature! {
609#![feature = "fs"]
610
611/// Returns the current directory as a `PathBuf`
612///
613/// Err is returned if the current user doesn't have the permission to read or search a component
614/// of the current path.
615///
616/// # Example
617///
618/// ```rust
619/// use nix::unistd;
620///
621/// // assume that we are allowed to get current directory
622/// let dir = unistd::getcwd().unwrap();
623/// println!("The current directory is {:?}", dir);
624/// ```
625#[inline]
626pub fn getcwd() -> Result<PathBuf> {
627    let mut buf = Vec::with_capacity(512);
628    loop {
629        unsafe {
630            let ptr = buf.as_mut_ptr() as *mut c_char;
631
632            // The buffer must be large enough to store the absolute pathname plus
633            // a terminating null byte, or else null is returned.
634            // To safely handle this we start with a reasonable size (512 bytes)
635            // and double the buffer size upon every error
636            if !libc::getcwd(ptr, buf.capacity()).is_null() {
637                let len = CStr::from_ptr(buf.as_ptr() as *const c_char).to_bytes().len();
638                buf.set_len(len);
639                buf.shrink_to_fit();
640                return Ok(PathBuf::from(OsString::from_vec(buf)));
641            } else {
642                let error = Errno::last();
643                // ERANGE means buffer was too small to store directory name
644                if error != Errno::ERANGE {
645                    return Err(error);
646                }
647           }
648
649            // Trigger the internal buffer resizing logic.
650            reserve_double_buffer_size(&mut buf, PATH_MAX as usize)?;
651        }
652    }
653}
654}
655
656feature! {
657#![all(feature = "user", feature = "fs")]
658
659/// Computes the raw UID and GID values to pass to a `*chown` call.
660// The cast is not unnecessary on all platforms.
661#[allow(clippy::unnecessary_cast)]
662fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc::gid_t) {
663    // According to the POSIX specification, -1 is used to indicate that owner and group
664    // are not to be changed.  Since uid_t and gid_t are unsigned types, we have to wrap
665    // around to get -1.
666    let uid = owner.map(Into::into)
667        .unwrap_or_else(|| (0 as uid_t).wrapping_sub(1));
668    let gid = group.map(Into::into)
669        .unwrap_or_else(|| (0 as gid_t).wrapping_sub(1));
670    (uid, gid)
671}
672
673/// Change the ownership of the file at `path` to be owned by the specified
674/// `owner` (user) and `group` (see
675/// [chown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html)).
676///
677/// The owner/group for the provided path name will not be modified if `None` is
678/// provided for that argument.  Ownership change will be attempted for the path
679/// only if `Some` owner/group is provided.
680#[inline]
681pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
682    let res = path.with_nix_path(|cstr| {
683        let (uid, gid) = chown_raw_ids(owner, group);
684        unsafe { libc::chown(cstr.as_ptr(), uid, gid) }
685    })?;
686
687    Errno::result(res).map(drop)
688}
689
690/// Change the ownership of the file referred to by the open file descriptor `fd` to be owned by
691/// the specified `owner` (user) and `group` (see
692/// [fchown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchown.html)).
693///
694/// The owner/group for the provided file will not be modified if `None` is
695/// provided for that argument.  Ownership change will be attempted for the path
696/// only if `Some` owner/group is provided.
697#[inline]
698pub fn fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
699    let (uid, gid) = chown_raw_ids(owner, group);
700    let res = unsafe { libc::fchown(fd, uid, gid) };
701    Errno::result(res).map(drop)
702}
703
704/// Flags for `fchownat` function.
705#[derive(Clone, Copy, Debug)]
706pub enum FchownatFlags {
707    FollowSymlink,
708    NoFollowSymlink,
709}
710
711/// Change the ownership of the file at `path` to be owned by the specified
712/// `owner` (user) and `group`.
713///
714/// The owner/group for the provided path name will not be modified if `None` is
715/// provided for that argument.  Ownership change will be attempted for the path
716/// only if `Some` owner/group is provided.
717///
718/// The file to be changed is determined relative to the directory associated
719/// with the file descriptor `dirfd` or the current working directory
720/// if `dirfd` is `None`.
721///
722/// If `flag` is `FchownatFlags::NoFollowSymlink` and `path` names a symbolic link,
723/// then the mode of the symbolic link is changed.
724///
725/// `fchownat(None, path, mode, FchownatFlags::NoFollowSymlink)` is identical to
726/// a call `libc::lchown(path, mode)`.  That's why `lchmod` is unimplemented in
727/// the `nix` crate.
728///
729/// # References
730///
731/// [fchownat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html).
732#[cfg(not(target_os = "redox"))]
733pub fn fchownat<P: ?Sized + NixPath>(
734    dirfd: Option<RawFd>,
735    path: &P,
736    owner: Option<Uid>,
737    group: Option<Gid>,
738    flag: FchownatFlags,
739) -> Result<()> {
740    let atflag =
741        match flag {
742            FchownatFlags::FollowSymlink => AtFlags::empty(),
743            FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
744        };
745    let res = path.with_nix_path(|cstr| unsafe {
746        let (uid, gid) = chown_raw_ids(owner, group);
747        libc::fchownat(at_rawfd(dirfd), cstr.as_ptr(), uid, gid,
748                       atflag.bits() as libc::c_int)
749    })?;
750
751    Errno::result(res).map(drop)
752}
753}
754
755feature! {
756#![feature = "process"]
757fn to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*const c_char> {
758    use std::iter::once;
759    args.iter()
760        .map(|s| s.as_ref().as_ptr())
761        .chain(once(ptr::null()))
762        .collect()
763}
764
765/// Replace the current process image with a new one (see
766/// [exec(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
767///
768/// See the `::nix::unistd::execve` system call for additional details.  `execv`
769/// performs the same action but does not allow for customization of the
770/// environment for the new process.
771#[inline]
772pub fn execv<S: AsRef<CStr>>(path: &CStr, argv: &[S]) -> Result<Infallible> {
773    let args_p = to_exec_array(argv);
774
775    unsafe {
776        libc::execv(path.as_ptr(), args_p.as_ptr())
777    };
778
779    Err(Errno::last())
780}
781
782
783/// Replace the current process image with a new one (see
784/// [execve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
785///
786/// The execve system call allows for another process to be "called" which will
787/// replace the current process image.  That is, this process becomes the new
788/// command that is run. On success, this function will not return. Instead,
789/// the new program will run until it exits.
790///
791/// `::nix::unistd::execv` and `::nix::unistd::execve` take as arguments a slice
792/// of `::std::ffi::CString`s for `args` and `env` (for `execve`). Each element
793/// in the `args` list is an argument to the new process. Each element in the
794/// `env` list should be a string in the form "key=value".
795#[inline]
796pub fn execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(path: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> {
797    let args_p = to_exec_array(args);
798    let env_p = to_exec_array(env);
799
800    unsafe {
801        libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
802    };
803
804    Err(Errno::last())
805}
806
807/// Replace the current process image with a new one and replicate shell `PATH`
808/// searching behavior (see
809/// [exec(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
810///
811/// See `::nix::unistd::execve` for additional details.  `execvp` behaves the
812/// same as execv except that it will examine the `PATH` environment variables
813/// for file names not specified with a leading slash.  For example, `execv`
814/// would not work if "bash" was specified for the path argument, but `execvp`
815/// would assuming that a bash executable was on the system `PATH`.
816#[inline]
817pub fn execvp<S: AsRef<CStr>>(filename: &CStr, args: &[S]) -> Result<Infallible> {
818    let args_p = to_exec_array(args);
819
820    unsafe {
821        libc::execvp(filename.as_ptr(), args_p.as_ptr())
822    };
823
824    Err(Errno::last())
825}
826
827/// Replace the current process image with a new one and replicate shell `PATH`
828/// searching behavior (see
829/// [`execvpe(3)`](https://man7.org/linux/man-pages/man3/exec.3.html)).
830///
831/// This functions like a combination of `execvp(2)` and `execve(2)` to pass an
832/// environment and have a search path. See these two for additional
833/// information.
834#[cfg(any(target_os = "haiku",
835          target_os = "linux",
836          target_os = "openbsd"))]
837pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(filename: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> {
838    let args_p = to_exec_array(args);
839    let env_p = to_exec_array(env);
840
841    unsafe {
842        libc::execvpe(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
843    };
844
845    Err(Errno::last())
846}
847
848/// Replace the current process image with a new one (see
849/// [fexecve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html)).
850///
851/// The `fexecve` function allows for another process to be "called" which will
852/// replace the current process image.  That is, this process becomes the new
853/// command that is run. On success, this function will not return. Instead,
854/// the new program will run until it exits.
855///
856/// This function is similar to `execve`, except that the program to be executed
857/// is referenced as a file descriptor instead of a path.
858#[cfg(any(target_os = "android",
859          target_os = "linux",
860          target_os = "dragonfly",
861          target_os = "freebsd"))]
862#[inline]
863pub fn fexecve<SA: AsRef<CStr> ,SE: AsRef<CStr>>(fd: RawFd, args: &[SA], env: &[SE]) -> Result<Infallible> {
864    let args_p = to_exec_array(args);
865    let env_p = to_exec_array(env);
866
867    unsafe {
868        libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr())
869    };
870
871    Err(Errno::last())
872}
873
874/// Execute program relative to a directory file descriptor (see
875/// [execveat(2)](https://man7.org/linux/man-pages/man2/execveat.2.html)).
876///
877/// The `execveat` function allows for another process to be "called" which will
878/// replace the current process image.  That is, this process becomes the new
879/// command that is run. On success, this function will not return. Instead,
880/// the new program will run until it exits.
881///
882/// This function is similar to `execve`, except that the program to be executed
883/// is referenced as a file descriptor to the base directory plus a path.
884#[cfg(any(target_os = "android", target_os = "linux"))]
885#[inline]
886pub fn execveat<SA: AsRef<CStr>,SE: AsRef<CStr>>(dirfd: RawFd, pathname: &CStr, args: &[SA],
887                env: &[SE], flags: super::fcntl::AtFlags) -> Result<Infallible> {
888    let args_p = to_exec_array(args);
889    let env_p = to_exec_array(env);
890
891    unsafe {
892        libc::syscall(libc::SYS_execveat, dirfd, pathname.as_ptr(),
893                      args_p.as_ptr(), env_p.as_ptr(), flags);
894    };
895
896    Err(Errno::last())
897}
898
899/// Daemonize this process by detaching from the controlling terminal (see
900/// [daemon(3)](https://man7.org/linux/man-pages/man3/daemon.3.html)).
901///
902/// When a process is launched it is typically associated with a parent and it,
903/// in turn, by its controlling terminal/process.  In order for a process to run
904/// in the "background" it must daemonize itself by detaching itself.  Under
905/// posix, this is done by doing the following:
906///
907/// 1. Parent process (this one) forks
908/// 2. Parent process exits
909/// 3. Child process continues to run.
910///
911/// `nochdir`:
912///
913/// * `nochdir = true`: The current working directory after daemonizing will
914///    be the current working directory.
915/// *  `nochdir = false`: The current working directory after daemonizing will
916///    be the root direcory, `/`.
917///
918/// `noclose`:
919///
920/// * `noclose = true`: The process' current stdin, stdout, and stderr file
921///   descriptors will remain identical after daemonizing.
922/// * `noclose = false`: The process' stdin, stdout, and stderr will point to
923///   `/dev/null` after daemonizing.
924#[cfg(any(target_os = "android",
925          target_os = "dragonfly",
926          target_os = "freebsd",
927          target_os = "illumos",
928          target_os = "linux",
929          target_os = "netbsd",
930          target_os = "openbsd",
931          target_os = "solaris"))]
932pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
933    let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) };
934    Errno::result(res).map(drop)
935}
936}
937
938feature! {
939#![feature = "hostname"]
940
941/// Set the system host name (see
942/// [sethostname(2)](https://man7.org/linux/man-pages/man2/gethostname.2.html)).
943///
944/// Given a name, attempt to update the system host name to the given string.
945/// On some systems, the host name is limited to as few as 64 bytes.  An error
946/// will be returned if the name is not valid or the current process does not
947/// have permissions to update the host name.
948#[cfg(not(target_os = "redox"))]
949pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> {
950    // Handle some differences in type of the len arg across platforms.
951    cfg_if! {
952        if #[cfg(any(target_os = "dragonfly",
953                     target_os = "freebsd",
954                     target_os = "illumos",
955                     target_os = "ios",
956                     target_os = "macos",
957                     target_os = "solaris", ))] {
958            type sethostname_len_t = c_int;
959        } else {
960            type sethostname_len_t = size_t;
961        }
962    }
963    let ptr = name.as_ref().as_bytes().as_ptr() as *const c_char;
964    let len = name.as_ref().len() as sethostname_len_t;
965
966    let res = unsafe { libc::sethostname(ptr, len) };
967    Errno::result(res).map(drop)
968}
969
970/// Get the host name and store it in the provided buffer, returning a pointer
971/// the `CStr` in that buffer on success (see
972/// [gethostname(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html)).
973///
974/// This function call attempts to get the host name for the running system and
975/// store it in a provided buffer.  The buffer will be populated with bytes up
976/// to the length of the provided slice including a NUL terminating byte.  If
977/// the hostname is longer than the length provided, no error will be provided.
978/// The posix specification does not specify whether implementations will
979/// null-terminate in this case, but the nix implementation will ensure that the
980/// buffer is null terminated in this case.
981///
982/// ```no_run
983/// use nix::unistd;
984///
985/// let mut buf = [0u8; 64];
986/// let hostname_cstr = unistd::gethostname(&mut buf).expect("Failed getting hostname");
987/// let hostname = hostname_cstr.to_str().expect("Hostname wasn't valid UTF-8");
988/// println!("Hostname: {}", hostname);
989/// ```
990pub fn gethostname(buffer: &mut [u8]) -> Result<&CStr> {
991    let ptr = buffer.as_mut_ptr() as *mut c_char;
992    let len = buffer.len() as size_t;
993
994    let res = unsafe { libc::gethostname(ptr, len) };
995    Errno::result(res).map(|_| {
996        buffer[len - 1] = 0; // ensure always null-terminated
997        unsafe { CStr::from_ptr(buffer.as_ptr() as *const c_char) }
998    })
999}
1000}
1001
1002/// Close a raw file descriptor
1003///
1004/// Be aware that many Rust types implicitly close-on-drop, including
1005/// `std::fs::File`.  Explicitly closing them with this method too can result in
1006/// a double-close condition, which can cause confusing `EBADF` errors in
1007/// seemingly unrelated code.  Caveat programmer.  See also
1008/// [close(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html).
1009///
1010/// # Examples
1011///
1012/// ```no_run
1013/// use std::os::unix::io::AsRawFd;
1014/// use nix::unistd::close;
1015///
1016/// let f = tempfile::tempfile().unwrap();
1017/// close(f.as_raw_fd()).unwrap();   // Bad!  f will also close on drop!
1018/// ```
1019///
1020/// ```rust
1021/// use std::os::unix::io::IntoRawFd;
1022/// use nix::unistd::close;
1023///
1024/// let f = tempfile::tempfile().unwrap();
1025/// close(f.into_raw_fd()).unwrap(); // Good.  into_raw_fd consumes f
1026/// ```
1027pub fn close(fd: RawFd) -> Result<()> {
1028    let res = unsafe { libc::close(fd) };
1029    Errno::result(res).map(drop)
1030}
1031
1032/// Read from a raw file descriptor.
1033///
1034/// See also [read(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html)
1035pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> {
1036    let res = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) };
1037
1038    Errno::result(res).map(|r| r as usize)
1039}
1040
1041/// Write to a raw file descriptor.
1042///
1043/// See also [write(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html)
1044pub fn write(fd: RawFd, buf: &[u8]) -> Result<usize> {
1045    let res = unsafe { libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) };
1046
1047    Errno::result(res).map(|r| r as usize)
1048}
1049
1050feature! {
1051#![feature = "fs"]
1052
1053/// Directive that tells [`lseek`] and [`lseek64`] what the offset is relative to.
1054///
1055/// [`lseek`]: ./fn.lseek.html
1056/// [`lseek64`]: ./fn.lseek64.html
1057#[repr(i32)]
1058#[derive(Clone, Copy, Debug)]
1059pub enum Whence {
1060    /// Specify an offset relative to the start of the file.
1061    SeekSet = libc::SEEK_SET,
1062    /// Specify an offset relative to the current file location.
1063    SeekCur = libc::SEEK_CUR,
1064    /// Specify an offset relative to the end of the file.
1065    SeekEnd = libc::SEEK_END,
1066    /// Specify an offset relative to the next location in the file greater than or
1067    /// equal to offset that contains some data. If offset points to
1068    /// some data, then the file offset is set to offset.
1069    #[cfg(any(target_os = "dragonfly",
1070              target_os = "freebsd",
1071              target_os = "illumos",
1072              target_os = "linux",
1073              target_os = "solaris"))]
1074    SeekData = libc::SEEK_DATA,
1075    /// Specify an offset relative to the next hole in the file greater than
1076    /// or equal to offset. If offset points into the middle of a hole, then
1077    /// the file offset should be set to offset. If there is no hole past offset,
1078    /// then the file offset should be adjusted to the end of the file (i.e., there
1079    /// is an implicit hole at the end of any file).
1080    #[cfg(any(target_os = "dragonfly",
1081              target_os = "freebsd",
1082              target_os = "illumos",
1083              target_os = "linux",
1084              target_os = "solaris"))]
1085    SeekHole = libc::SEEK_HOLE
1086}
1087
1088/// Move the read/write file offset.
1089///
1090/// See also [lseek(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html)
1091pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result<off_t> {
1092    let res = unsafe { libc::lseek(fd, offset, whence as i32) };
1093
1094    Errno::result(res).map(|r| r as off_t)
1095}
1096
1097#[cfg(any(target_os = "linux", target_os = "android"))]
1098pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result<libc::off64_t> {
1099    let res = unsafe { libc::lseek64(fd, offset, whence as i32) };
1100
1101    Errno::result(res).map(|r| r as libc::off64_t)
1102}
1103}
1104
1105/// Create an interprocess channel.
1106///
1107/// See also [pipe(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html)
1108pub fn pipe() -> std::result::Result<(RawFd, RawFd), Error> {
1109    unsafe {
1110        let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit();
1111
1112        let res = libc::pipe(fds.as_mut_ptr() as *mut c_int);
1113
1114        Error::result(res)?;
1115
1116        Ok((fds.assume_init()[0], fds.assume_init()[1]))
1117    }
1118}
1119
1120feature! {
1121#![feature = "fs"]
1122/// Like `pipe`, but allows setting certain file descriptor flags.
1123///
1124/// The following flags are supported, and will be set atomically as the pipe is
1125/// created:
1126///
1127/// - `O_CLOEXEC`:    Set the close-on-exec flag for the new file descriptors.
1128#[cfg_attr(target_os = "linux", doc = "- `O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode.")]
1129#[cfg_attr(target_os = "netbsd", doc = "- `O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`.")]
1130/// - `O_NONBLOCK`:   Set the non-blocking flag for the ends of the pipe.
1131///
1132/// See also [pipe(2)](https://man7.org/linux/man-pages/man2/pipe.2.html)
1133#[cfg(any(target_os = "android",
1134          target_os = "dragonfly",
1135          target_os = "emscripten",
1136          target_os = "freebsd",
1137          target_os = "illumos",
1138          target_os = "linux",
1139          target_os = "redox",
1140          target_os = "netbsd",
1141          target_os = "openbsd",
1142          target_os = "solaris"))]
1143pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
1144    let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit();
1145
1146    let res = unsafe {
1147        libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits())
1148    };
1149
1150    Errno::result(res)?;
1151
1152    unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) }
1153}
1154
1155/// Truncate a file to a specified length
1156///
1157/// See also
1158/// [truncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html)
1159#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
1160pub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> {
1161    let res = path.with_nix_path(|cstr| {
1162        unsafe {
1163            libc::truncate(cstr.as_ptr(), len)
1164        }
1165    })?;
1166
1167    Errno::result(res).map(drop)
1168}
1169
1170/// Truncate a file to a specified length
1171///
1172/// See also
1173/// [ftruncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html)
1174pub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> {
1175    Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop)
1176}
1177
1178pub fn isatty(fd: RawFd) -> Result<bool> {
1179    unsafe {
1180        // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so
1181        // we return `Ok(false)`
1182        if libc::isatty(fd) == 1 {
1183            Ok(true)
1184        } else {
1185            match Errno::last() {
1186                Errno::ENOTTY => Ok(false),
1187                err => Err(err),
1188            }
1189       }
1190    }
1191}
1192
1193/// Flags for `linkat` function.
1194#[derive(Clone, Copy, Debug)]
1195pub enum LinkatFlags {
1196    SymlinkFollow,
1197    NoSymlinkFollow,
1198}
1199
1200/// Link one file to another file
1201///
1202/// Creates a new link (directory entry) at `newpath` for the existing file at `oldpath`. In the
1203/// case of a relative `oldpath`, the path is interpreted relative to the directory associated
1204/// with file descriptor `olddirfd` instead of the current working directory and similiarly for
1205/// `newpath` and file descriptor `newdirfd`. In case `flag` is LinkatFlags::SymlinkFollow and
1206/// `oldpath` names a symoblic link, a new link for the target of the symbolic link is created.
1207/// If either `olddirfd` or `newdirfd` is `None`, `AT_FDCWD` is used respectively where `oldpath`
1208/// and/or `newpath` is then interpreted relative to the current working directory of the calling
1209/// process. If either `oldpath` or `newpath` is absolute, then `dirfd` is ignored.
1210///
1211/// # References
1212/// See also [linkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html)
1213#[cfg(not(target_os = "redox"))] // RedoxFS does not support symlinks yet
1214pub fn linkat<P: ?Sized + NixPath>(
1215    olddirfd: Option<RawFd>,
1216    oldpath: &P,
1217    newdirfd: Option<RawFd>,
1218    newpath: &P,
1219    flag: LinkatFlags,
1220) -> Result<()> {
1221
1222    let atflag =
1223        match flag {
1224            LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW,
1225            LinkatFlags::NoSymlinkFollow => AtFlags::empty(),
1226        };
1227
1228    let res =
1229        oldpath.with_nix_path(|oldcstr| {
1230            newpath.with_nix_path(|newcstr| {
1231            unsafe {
1232                libc::linkat(
1233                    at_rawfd(olddirfd),
1234                    oldcstr.as_ptr(),
1235                    at_rawfd(newdirfd),
1236                    newcstr.as_ptr(),
1237                    atflag.bits() as libc::c_int
1238                    )
1239                }
1240            })
1241        })??;
1242    Errno::result(res).map(drop)
1243}
1244
1245
1246/// Remove a directory entry
1247///
1248/// See also [unlink(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html)
1249pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> {
1250    let res = path.with_nix_path(|cstr| {
1251        unsafe {
1252            libc::unlink(cstr.as_ptr())
1253        }
1254    })?;
1255    Errno::result(res).map(drop)
1256}
1257
1258/// Flags for `unlinkat` function.
1259#[derive(Clone, Copy, Debug)]
1260pub enum UnlinkatFlags {
1261    RemoveDir,
1262    NoRemoveDir,
1263}
1264
1265/// Remove a directory entry
1266///
1267/// In the case of a relative path, the directory entry to be removed is determined relative to
1268/// the directory associated with the file descriptor `dirfd` or the current working directory
1269/// if `dirfd` is `None`. In the case of an absolute `path` `dirfd` is ignored. If `flag` is
1270/// `UnlinkatFlags::RemoveDir` then removal of the directory entry specified by `dirfd` and `path`
1271/// is performed.
1272///
1273/// # References
1274/// See also [unlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html)
1275#[cfg(not(target_os = "redox"))]
1276pub fn unlinkat<P: ?Sized + NixPath>(
1277    dirfd: Option<RawFd>,
1278    path: &P,
1279    flag: UnlinkatFlags,
1280) -> Result<()> {
1281    let atflag =
1282        match flag {
1283            UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR,
1284            UnlinkatFlags::NoRemoveDir => AtFlags::empty(),
1285        };
1286    let res = path.with_nix_path(|cstr| {
1287        unsafe {
1288            libc::unlinkat(at_rawfd(dirfd), cstr.as_ptr(), atflag.bits() as libc::c_int)
1289        }
1290    })?;
1291    Errno::result(res).map(drop)
1292}
1293
1294
1295#[inline]
1296#[cfg(not(target_os = "fuchsia"))]
1297pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> {
1298    let res = path.with_nix_path(|cstr| {
1299        unsafe { libc::chroot(cstr.as_ptr()) }
1300    })?;
1301
1302    Errno::result(res).map(drop)
1303}
1304
1305/// Commit filesystem caches to disk
1306///
1307/// See also [sync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html)
1308#[cfg(any(
1309    target_os = "dragonfly",
1310    target_os = "freebsd",
1311    target_os = "linux",
1312    target_os = "netbsd",
1313    target_os = "openbsd"
1314))]
1315pub fn sync() {
1316    unsafe { libc::sync() };
1317}
1318
1319/// Synchronize changes to a file
1320///
1321/// See also [fsync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html)
1322#[inline]
1323pub fn fsync(fd: RawFd) -> Result<()> {
1324    let res = unsafe { libc::fsync(fd) };
1325
1326    Errno::result(res).map(drop)
1327}
1328
1329/// Synchronize the data of a file
1330///
1331/// See also
1332/// [fdatasync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html)
1333#[cfg(any(target_os = "linux",
1334          target_os = "android",
1335          target_os = "emscripten",
1336          target_os = "freebsd",
1337          target_os = "fuchsia",
1338          target_os = "netbsd",
1339          target_os = "openbsd",
1340          target_os = "illumos",
1341          target_os = "solaris"))]
1342#[inline]
1343pub fn fdatasync(fd: RawFd) -> Result<()> {
1344    let res = unsafe { libc::fdatasync(fd) };
1345
1346    Errno::result(res).map(drop)
1347}
1348}
1349
1350feature! {
1351#![feature = "user"]
1352
1353/// Get a real user ID
1354///
1355/// See also [getuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html)
1356// POSIX requires that getuid is always successful, so no need to check return
1357// value or errno.
1358#[inline]
1359pub fn getuid() -> Uid {
1360    Uid(unsafe { libc::getuid() })
1361}
1362
1363/// Get the effective user ID
1364///
1365/// See also [geteuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html)
1366// POSIX requires that geteuid is always successful, so no need to check return
1367// value or errno.
1368#[inline]
1369pub fn geteuid() -> Uid {
1370    Uid(unsafe { libc::geteuid() })
1371}
1372
1373/// Get the real group ID
1374///
1375/// See also [getgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html)
1376// POSIX requires that getgid is always successful, so no need to check return
1377// value or errno.
1378#[inline]
1379pub fn getgid() -> Gid {
1380    Gid(unsafe { libc::getgid() })
1381}
1382
1383/// Get the effective group ID
1384///
1385/// See also [getegid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getegid.html)
1386// POSIX requires that getegid is always successful, so no need to check return
1387// value or errno.
1388#[inline]
1389pub fn getegid() -> Gid {
1390    Gid(unsafe { libc::getegid() })
1391}
1392
1393/// Set the effective user ID
1394///
1395/// See also [seteuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/seteuid.html)
1396#[inline]
1397pub fn seteuid(euid: Uid) -> Result<()> {
1398    let res = unsafe { libc::seteuid(euid.into()) };
1399
1400    Errno::result(res).map(drop)
1401}
1402
1403/// Set the effective group ID
1404///
1405/// See also [setegid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setegid.html)
1406#[inline]
1407pub fn setegid(egid: Gid) -> Result<()> {
1408    let res = unsafe { libc::setegid(egid.into()) };
1409
1410    Errno::result(res).map(drop)
1411}
1412
1413/// Set the user ID
1414///
1415/// See also [setuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setuid.html)
1416#[inline]
1417pub fn setuid(uid: Uid) -> Result<()> {
1418    let res = unsafe { libc::setuid(uid.into()) };
1419
1420    Errno::result(res).map(drop)
1421}
1422
1423/// Set the group ID
1424///
1425/// See also [setgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setgid.html)
1426#[inline]
1427pub fn setgid(gid: Gid) -> Result<()> {
1428    let res = unsafe { libc::setgid(gid.into()) };
1429
1430    Errno::result(res).map(drop)
1431}
1432}
1433
1434feature! {
1435#![all(feature = "fs", feature = "user")]
1436/// Set the user identity used for filesystem checks per-thread.
1437/// On both success and failure, this call returns the previous filesystem user
1438/// ID of the caller.
1439///
1440/// See also [setfsuid(2)](https://man7.org/linux/man-pages/man2/setfsuid.2.html)
1441#[cfg(any(target_os = "linux", target_os = "android"))]
1442pub fn setfsuid(uid: Uid) -> Uid {
1443    let prev_fsuid = unsafe { libc::setfsuid(uid.into()) };
1444    Uid::from_raw(prev_fsuid as uid_t)
1445}
1446
1447/// Set the group identity used for filesystem checks per-thread.
1448/// On both success and failure, this call returns the previous filesystem group
1449/// ID of the caller.
1450///
1451/// See also [setfsgid(2)](https://man7.org/linux/man-pages/man2/setfsgid.2.html)
1452#[cfg(any(target_os = "linux", target_os = "android"))]
1453pub fn setfsgid(gid: Gid) -> Gid {
1454    let prev_fsgid = unsafe { libc::setfsgid(gid.into()) };
1455    Gid::from_raw(prev_fsgid as gid_t)
1456}
1457}
1458
1459feature! {
1460#![feature = "user"]
1461
1462/// Get the list of supplementary group IDs of the calling process.
1463///
1464/// [Further reading](https://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html)
1465///
1466/// **Note:** This function is not available for Apple platforms. On those
1467/// platforms, checking group membership should be achieved via communication
1468/// with the `opendirectoryd` service.
1469#[cfg(not(any(target_os = "ios", target_os = "macos")))]
1470pub fn getgroups() -> Result<Vec<Gid>> {
1471    // First get the maximum number of groups. The value returned
1472    // shall always be greater than or equal to one and less than or
1473    // equal to the value of {NGROUPS_MAX} + 1.
1474    let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) {
1475        Ok(Some(n)) => (n + 1) as usize,
1476        Ok(None) | Err(_) => <usize>::max_value(),
1477    };
1478
1479    // Next, get the number of groups so we can size our Vec
1480    let ngroups = unsafe { libc::getgroups(0, ptr::null_mut()) };
1481
1482    // If there are no supplementary groups, return early.
1483    // This prevents a potential buffer over-read if the number of groups
1484    // increases from zero before the next call. It would return the total
1485    // number of groups beyond the capacity of the buffer.
1486    if ngroups == 0 {
1487        return Ok(Vec::new());
1488    }
1489
1490    // Now actually get the groups. We try multiple times in case the number of
1491    // groups has changed since the first call to getgroups() and the buffer is
1492    // now too small.
1493    let mut groups = Vec::<Gid>::with_capacity(Errno::result(ngroups)? as usize);
1494    loop {
1495        // FIXME: On the platforms we currently support, the `Gid` struct has
1496        // the same representation in memory as a bare `gid_t`. This is not
1497        // necessarily the case on all Rust platforms, though. See RFC 1785.
1498        let ngroups = unsafe {
1499            libc::getgroups(groups.capacity() as c_int, groups.as_mut_ptr() as *mut gid_t)
1500        };
1501
1502        match Errno::result(ngroups) {
1503            Ok(s) => {
1504                unsafe { groups.set_len(s as usize) };
1505                return Ok(groups);
1506            },
1507            Err(Errno::EINVAL) => {
1508                // EINVAL indicates that the buffer size was too
1509                // small, resize it up to ngroups_max as limit.
1510                reserve_double_buffer_size(&mut groups, ngroups_max)
1511                    .or(Err(Errno::EINVAL))?;
1512            },
1513            Err(e) => return Err(e)
1514        }
1515    }
1516}
1517
1518/// Set the list of supplementary group IDs for the calling process.
1519///
1520/// [Further reading](https://man7.org/linux/man-pages/man2/getgroups.2.html)
1521///
1522/// **Note:** This function is not available for Apple platforms. On those
1523/// platforms, group membership management should be achieved via communication
1524/// with the `opendirectoryd` service.
1525///
1526/// # Examples
1527///
1528/// `setgroups` can be used when dropping privileges from the root user to a
1529/// specific user and group. For example, given the user `www-data` with UID
1530/// `33` and the group `backup` with the GID `34`, one could switch the user as
1531/// follows:
1532///
1533/// ```rust,no_run
1534/// # use std::error::Error;
1535/// # use nix::unistd::*;
1536/// #
1537/// # fn try_main() -> Result<(), Box<Error>> {
1538/// let uid = Uid::from_raw(33);
1539/// let gid = Gid::from_raw(34);
1540/// setgroups(&[gid])?;
1541/// setgid(gid)?;
1542/// setuid(uid)?;
1543/// #
1544/// #     Ok(())
1545/// # }
1546/// #
1547/// # try_main().unwrap();
1548/// ```
1549#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
1550pub fn setgroups(groups: &[Gid]) -> Result<()> {
1551    cfg_if! {
1552        if #[cfg(any(target_os = "dragonfly",
1553                     target_os = "freebsd",
1554                     target_os = "illumos",
1555                     target_os = "ios",
1556                     target_os = "macos",
1557                     target_os = "netbsd",
1558                     target_os = "illumos",
1559                     target_os = "openbsd"))] {
1560            type setgroups_ngroups_t = c_int;
1561        } else {
1562            type setgroups_ngroups_t = size_t;
1563        }
1564    }
1565    // FIXME: On the platforms we currently support, the `Gid` struct has the
1566    // same representation in memory as a bare `gid_t`. This is not necessarily
1567    // the case on all Rust platforms, though. See RFC 1785.
1568    let res = unsafe {
1569        libc::setgroups(groups.len() as setgroups_ngroups_t, groups.as_ptr() as *const gid_t)
1570    };
1571
1572    Errno::result(res).map(drop)
1573}
1574
1575/// Calculate the supplementary group access list.
1576///
1577/// Gets the group IDs of all groups that `user` is a member of. The additional
1578/// group `group` is also added to the list.
1579///
1580/// [Further reading](https://man7.org/linux/man-pages/man3/getgrouplist.3.html)
1581///
1582/// **Note:** This function is not available for Apple platforms. On those
1583/// platforms, checking group membership should be achieved via communication
1584/// with the `opendirectoryd` service.
1585///
1586/// # Errors
1587///
1588/// Although the `getgrouplist()` call does not return any specific
1589/// errors on any known platforms, this implementation will return a system
1590/// error of `EINVAL` if the number of groups to be fetched exceeds the
1591/// `NGROUPS_MAX` sysconf value. This mimics the behaviour of `getgroups()`
1592/// and `setgroups()`. Additionally, while some implementations will return a
1593/// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation
1594/// will only ever return the complete list or else an error.
1595#[cfg(not(any(target_os = "illumos",
1596              target_os = "ios",
1597              target_os = "macos",
1598              target_os = "redox")))]
1599pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
1600    let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) {
1601        Ok(Some(n)) => n as c_int,
1602        Ok(None) | Err(_) => <c_int>::max_value(),
1603    };
1604    use std::cmp::min;
1605    let mut groups = Vec::<Gid>::with_capacity(min(ngroups_max, 8) as usize);
1606    cfg_if! {
1607        if #[cfg(any(target_os = "ios", target_os = "macos"))] {
1608            type getgrouplist_group_t = c_int;
1609        } else {
1610            type getgrouplist_group_t = gid_t;
1611        }
1612    }
1613    let gid: gid_t = group.into();
1614    loop {
1615        let mut ngroups = groups.capacity() as i32;
1616        let ret = unsafe {
1617            libc::getgrouplist(user.as_ptr(),
1618                               gid as getgrouplist_group_t,
1619                               groups.as_mut_ptr() as *mut getgrouplist_group_t,
1620                               &mut ngroups)
1621        };
1622
1623        // BSD systems only return 0 or -1, Linux returns ngroups on success.
1624        if ret >= 0 {
1625            unsafe { groups.set_len(ngroups as usize) };
1626            return Ok(groups);
1627        } else if ret == -1 {
1628            // Returns -1 if ngroups is too small, but does not set errno.
1629            // BSD systems will still fill the groups buffer with as many
1630            // groups as possible, but Linux manpages do not mention this
1631            // behavior.
1632            reserve_double_buffer_size(&mut groups, ngroups_max as usize)
1633                .map_err(|_| Errno::EINVAL)?;
1634        }
1635    }
1636}
1637
1638/// Initialize the supplementary group access list.
1639///
1640/// Sets the supplementary group IDs for the calling process using all groups
1641/// that `user` is a member of. The additional group `group` is also added to
1642/// the list.
1643///
1644/// [Further reading](https://man7.org/linux/man-pages/man3/initgroups.3.html)
1645///
1646/// **Note:** This function is not available for Apple platforms. On those
1647/// platforms, group membership management should be achieved via communication
1648/// with the `opendirectoryd` service.
1649///
1650/// # Examples
1651///
1652/// `initgroups` can be used when dropping privileges from the root user to
1653/// another user. For example, given the user `www-data`, we could look up the
1654/// UID and GID for the user in the system's password database (usually found
1655/// in `/etc/passwd`). If the `www-data` user's UID and GID were `33` and `33`,
1656/// respectively, one could switch the user as follows:
1657///
1658/// ```rust,no_run
1659/// # use std::error::Error;
1660/// # use std::ffi::CString;
1661/// # use nix::unistd::*;
1662/// #
1663/// # fn try_main() -> Result<(), Box<Error>> {
1664/// let user = CString::new("www-data").unwrap();
1665/// let uid = Uid::from_raw(33);
1666/// let gid = Gid::from_raw(33);
1667/// initgroups(&user, gid)?;
1668/// setgid(gid)?;
1669/// setuid(uid)?;
1670/// #
1671/// #     Ok(())
1672/// # }
1673/// #
1674/// # try_main().unwrap();
1675/// ```
1676#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
1677pub fn initgroups(user: &CStr, group: Gid) -> Result<()> {
1678    cfg_if! {
1679        if #[cfg(any(target_os = "ios", target_os = "macos"))] {
1680            type initgroups_group_t = c_int;
1681        } else {
1682            type initgroups_group_t = gid_t;
1683        }
1684    }
1685    let gid: gid_t = group.into();
1686    let res = unsafe { libc::initgroups(user.as_ptr(), gid as initgroups_group_t) };
1687
1688    Errno::result(res).map(drop)
1689}
1690}
1691
1692feature! {
1693#![feature = "signal"]
1694
1695/// Suspend the thread until a signal is received.
1696///
1697/// See also [pause(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html).
1698#[inline]
1699#[cfg(not(target_os = "redox"))]
1700pub fn pause() {
1701    unsafe { libc::pause() };
1702}
1703
1704pub mod alarm {
1705    //! Alarm signal scheduling.
1706    //!
1707    //! Scheduling an alarm will trigger a `SIGALRM` signal when the time has
1708    //! elapsed, which has to be caught, because the default action for the
1709    //! signal is to terminate the program. This signal also can't be ignored
1710    //! because the system calls like `pause` will not be interrupted, see the
1711    //! second example below.
1712    //!
1713    //! # Examples
1714    //!
1715    //! Canceling an alarm:
1716    //!
1717    //! ```
1718    //! use nix::unistd::alarm;
1719    //!
1720    //! // Set an alarm for 60 seconds from now.
1721    //! alarm::set(60);
1722    //!
1723    //! // Cancel the above set alarm, which returns the number of seconds left
1724    //! // of the previously set alarm.
1725    //! assert_eq!(alarm::cancel(), Some(60));
1726    //! ```
1727    //!
1728    //! Scheduling an alarm and waiting for the signal:
1729    //!
1730#![cfg_attr(target_os = "redox", doc = " ```rust,ignore")]
1731#![cfg_attr(not(target_os = "redox"), doc = " ```rust")]
1732    //! use std::time::{Duration, Instant};
1733    //!
1734    //! use nix::unistd::{alarm, pause};
1735    //! use nix::sys::signal::*;
1736    //!
1737    //! // We need to setup an empty signal handler to catch the alarm signal,
1738    //! // otherwise the program will be terminated once the signal is delivered.
1739    //! extern fn signal_handler(_: nix::libc::c_int) { }
1740    //! let sa = SigAction::new(
1741    //!     SigHandler::Handler(signal_handler),
1742    //!     SaFlags::SA_RESTART,
1743    //!     SigSet::empty()
1744    //! );
1745    //! unsafe {
1746    //!     sigaction(Signal::SIGALRM, &sa);
1747    //! }
1748    //!
1749    //! let start = Instant::now();
1750    //!
1751    //! // Set an alarm for 1 second from now.
1752    //! alarm::set(1);
1753    //!
1754    //! // Pause the process until the alarm signal is received.
1755    //! let mut sigset = SigSet::empty();
1756    //! sigset.add(Signal::SIGALRM);
1757    //! sigset.wait();
1758    //!
1759    //! assert!(start.elapsed() >= Duration::from_secs(1));
1760    //! ```
1761    //!
1762    //! # References
1763    //!
1764    //! See also [alarm(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/alarm.html).
1765
1766    /// Schedule an alarm signal.
1767    ///
1768    /// This will cause the system to generate a `SIGALRM` signal for the
1769    /// process after the specified number of seconds have elapsed.
1770    ///
1771    /// Returns the leftover time of a previously set alarm if there was one.
1772    pub fn set(secs: libc::c_uint) -> Option<libc::c_uint> {
1773        assert!(secs != 0, "passing 0 to `alarm::set` is not allowed, to cancel an alarm use `alarm::cancel`");
1774        alarm(secs)
1775    }
1776
1777    /// Cancel an previously set alarm signal.
1778    ///
1779    /// Returns the leftover time of a previously set alarm if there was one.
1780    pub fn cancel() -> Option<libc::c_uint> {
1781        alarm(0)
1782    }
1783
1784    fn alarm(secs: libc::c_uint) -> Option<libc::c_uint> {
1785        match unsafe { libc::alarm(secs) } {
1786            0 => None,
1787            secs => Some(secs),
1788        }
1789    }
1790}
1791}
1792
1793/// Suspend execution for an interval of time
1794///
1795/// See also [sleep(2)](https://pubs.opengroup.org/onlinepubs/009695399/functions/sleep.html#tag_03_705_05)
1796// Per POSIX, does not fail
1797#[inline]
1798pub fn sleep(seconds: c_uint) -> c_uint {
1799    unsafe { libc::sleep(seconds) }
1800}
1801
1802feature! {
1803#![feature = "acct"]
1804
1805#[cfg(not(target_os = "redox"))]
1806pub mod acct {
1807    use crate::{Result, NixPath};
1808    use crate::errno::Errno;
1809    use std::ptr;
1810
1811    /// Enable process accounting
1812    ///
1813    /// See also [acct(2)](https://linux.die.net/man/2/acct)
1814    pub fn enable<P: ?Sized + NixPath>(filename: &P) -> Result<()> {
1815        let res = filename.with_nix_path(|cstr| {
1816            unsafe { libc::acct(cstr.as_ptr()) }
1817        })?;
1818
1819        Errno::result(res).map(drop)
1820    }
1821
1822    /// Disable process accounting
1823    pub fn disable() -> Result<()> {
1824        let res = unsafe { libc::acct(ptr::null()) };
1825
1826        Errno::result(res).map(drop)
1827    }
1828}
1829}
1830
1831feature! {
1832#![feature = "fs"]
1833/// Creates a regular file which persists even after process termination
1834///
1835/// * `template`: a path whose 6 rightmost characters must be X, e.g. `/tmp/tmpfile_XXXXXX`
1836/// * returns: tuple of file descriptor and filename
1837///
1838/// Err is returned either if no temporary filename could be created or the template doesn't
1839/// end with XXXXXX
1840///
1841/// See also [mkstemp(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkstemp.html)
1842///
1843/// # Example
1844///
1845/// ```rust
1846/// use nix::unistd;
1847///
1848/// let _ = match unistd::mkstemp("/tmp/tempfile_XXXXXX") {
1849///     Ok((fd, path)) => {
1850///         unistd::unlink(path.as_path()).unwrap(); // flag file to be deleted at app termination
1851///         fd
1852///     }
1853///     Err(e) => panic!("mkstemp failed: {}", e)
1854/// };
1855/// // do something with fd
1856/// ```
1857#[inline]
1858pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> {
1859    let mut path = template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})?;
1860    let p = path.as_mut_ptr() as *mut _;
1861    let fd = unsafe { libc::mkstemp(p) };
1862    let last = path.pop(); // drop the trailing nul
1863    debug_assert!(last == Some(b'\0'));
1864    let pathname = OsString::from_vec(path);
1865    Errno::result(fd)?;
1866    Ok((fd, PathBuf::from(pathname)))
1867}
1868}
1869
1870feature! {
1871#![all(feature = "fs", feature = "feature")]
1872
1873/// Variable names for `pathconf`
1874///
1875/// Nix uses the same naming convention for these variables as the
1876/// [getconf(1)](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility.
1877/// That is, `PathconfVar` variables have the same name as the abstract
1878/// variables  shown in the `pathconf(2)` man page.  Usually, it's the same as
1879/// the C variable name without the leading `_PC_`.
1880///
1881/// POSIX 1003.1-2008 standardizes all of these variables, but some OSes choose
1882/// not to implement variables that cannot change at runtime.
1883///
1884/// # References
1885///
1886/// - [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)
1887/// - [limits.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)
1888/// - [unistd.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html)
1889#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1890#[repr(i32)]
1891#[non_exhaustive]
1892pub enum PathconfVar {
1893    #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux",
1894              target_os = "netbsd", target_os = "openbsd", target_os = "redox"))]
1895    /// Minimum number of bits needed to represent, as a signed integer value,
1896    /// the maximum size of a regular file allowed in the specified directory.
1897    #[cfg_attr(docsrs, doc(cfg(all())))]
1898    FILESIZEBITS = libc::_PC_FILESIZEBITS,
1899    /// Maximum number of links to a single file.
1900    LINK_MAX = libc::_PC_LINK_MAX,
1901    /// Maximum number of bytes in a terminal canonical input line.
1902    MAX_CANON = libc::_PC_MAX_CANON,
1903    /// Minimum number of bytes for which space is available in a terminal input
1904    /// queue; therefore, the maximum number of bytes a conforming application
1905    /// may require to be typed as input before reading them.
1906    MAX_INPUT = libc::_PC_MAX_INPUT,
1907    /// Maximum number of bytes in a filename (not including the terminating
1908    /// null of a filename string).
1909    NAME_MAX = libc::_PC_NAME_MAX,
1910    /// Maximum number of bytes the implementation will store as a pathname in a
1911    /// user-supplied buffer of unspecified size, including the terminating null
1912    /// character. Minimum number the implementation will accept as the maximum
1913    /// number of bytes in a pathname.
1914    PATH_MAX = libc::_PC_PATH_MAX,
1915    /// Maximum number of bytes that is guaranteed to be atomic when writing to
1916    /// a pipe.
1917    PIPE_BUF = libc::_PC_PIPE_BUF,
1918    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "illumos",
1919              target_os = "linux", target_os = "netbsd", target_os = "openbsd",
1920              target_os = "redox", target_os = "solaris"))]
1921    #[cfg_attr(docsrs, doc(cfg(all())))]
1922    /// Symbolic links can be created.
1923    POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS,
1924    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
1925              target_os = "linux", target_os = "openbsd", target_os = "redox"))]
1926    #[cfg_attr(docsrs, doc(cfg(all())))]
1927    /// Minimum number of bytes of storage actually allocated for any portion of
1928    /// a file.
1929    POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN,
1930    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
1931              target_os = "linux", target_os = "openbsd"))]
1932    #[cfg_attr(docsrs, doc(cfg(all())))]
1933    /// Recommended increment for file transfer sizes between the
1934    /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values.
1935    POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE,
1936    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
1937              target_os = "linux", target_os = "openbsd", target_os = "redox"))]
1938    #[cfg_attr(docsrs, doc(cfg(all())))]
1939    /// Maximum recommended file transfer size.
1940    POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE,
1941    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
1942              target_os = "linux", target_os = "openbsd", target_os = "redox"))]
1943    #[cfg_attr(docsrs, doc(cfg(all())))]
1944    /// Minimum recommended file transfer size.
1945    POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE,
1946    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
1947              target_os = "linux", target_os = "openbsd", target_os = "redox"))]
1948    #[cfg_attr(docsrs, doc(cfg(all())))]
1949    ///  Recommended file transfer buffer alignment.
1950    POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN,
1951    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
1952              target_os = "illumos", target_os = "linux", target_os = "netbsd",
1953              target_os = "openbsd", target_os = "redox", target_os = "solaris"))]
1954    #[cfg_attr(docsrs, doc(cfg(all())))]
1955    /// Maximum number of bytes in a symbolic link.
1956    SYMLINK_MAX = libc::_PC_SYMLINK_MAX,
1957    /// The use of `chown` and `fchown` is restricted to a process with
1958    /// appropriate privileges, and to changing the group ID of a file only to
1959    /// the effective group ID of the process or to one of its supplementary
1960    /// group IDs.
1961    _POSIX_CHOWN_RESTRICTED = libc::_PC_CHOWN_RESTRICTED,
1962    /// Pathname components longer than {NAME_MAX} generate an error.
1963    _POSIX_NO_TRUNC = libc::_PC_NO_TRUNC,
1964    /// This symbol shall be defined to be the value of a character that shall
1965    /// disable terminal special character handling.
1966    _POSIX_VDISABLE = libc::_PC_VDISABLE,
1967    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
1968              target_os = "illumos", target_os = "linux", target_os = "openbsd",
1969              target_os = "redox", target_os = "solaris"))]
1970    #[cfg_attr(docsrs, doc(cfg(all())))]
1971    /// Asynchronous input or output operations may be performed for the
1972    /// associated file.
1973    _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO,
1974    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
1975              target_os = "illumos", target_os = "linux", target_os = "openbsd",
1976              target_os = "redox", target_os = "solaris"))]
1977    #[cfg_attr(docsrs, doc(cfg(all())))]
1978    /// Prioritized input or output operations may be performed for the
1979    /// associated file.
1980    _POSIX_PRIO_IO = libc::_PC_PRIO_IO,
1981    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
1982              target_os = "illumos", target_os = "linux", target_os = "netbsd",
1983              target_os = "openbsd", target_os = "redox", target_os = "solaris"))]
1984    #[cfg_attr(docsrs, doc(cfg(all())))]
1985    /// Synchronized input or output operations may be performed for the
1986    /// associated file.
1987    _POSIX_SYNC_IO = libc::_PC_SYNC_IO,
1988    #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))]
1989    #[cfg_attr(docsrs, doc(cfg(all())))]
1990    /// The resolution in nanoseconds for all file timestamps.
1991    _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION
1992}
1993
1994/// Like `pathconf`, but works with file descriptors instead of paths (see
1995/// [fpathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html))
1996///
1997/// # Parameters
1998///
1999/// - `fd`:   The file descriptor whose variable should be interrogated
2000/// - `var`:  The pathconf variable to lookup
2001///
2002/// # Returns
2003///
2004/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its
2005///     implementation level (for option variables).  Implementation levels are
2006///     usually a decimal-coded date, such as 200112 for POSIX 2001.12
2007/// - `Ok(None)`: the variable has no limit (for limit variables) or is
2008///     unsupported (for option variables)
2009/// - `Err(x)`: an error occurred
2010pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>> {
2011    let raw = unsafe {
2012        Errno::clear();
2013        libc::fpathconf(fd, var as c_int)
2014    };
2015    if raw == -1 {
2016        if errno::errno() == 0 {
2017            Ok(None)
2018        } else {
2019            Err(Errno::last())
2020        }
2021    } else {
2022        Ok(Some(raw))
2023    }
2024}
2025
2026/// Get path-dependent configurable system variables (see
2027/// [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html))
2028///
2029/// Returns the value of a path-dependent configurable system variable.  Most
2030/// supported variables also have associated compile-time constants, but POSIX
2031/// allows their values to change at runtime.  There are generally two types of
2032/// `pathconf` variables: options and limits.  See [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) for more details.
2033///
2034/// # Parameters
2035///
2036/// - `path`: Lookup the value of `var` for this file or directory
2037/// - `var`:  The `pathconf` variable to lookup
2038///
2039/// # Returns
2040///
2041/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its
2042///     implementation level (for option variables).  Implementation levels are
2043///     usually a decimal-coded date, such as 200112 for POSIX 2001.12
2044/// - `Ok(None)`: the variable has no limit (for limit variables) or is
2045///     unsupported (for option variables)
2046/// - `Err(x)`: an error occurred
2047pub fn pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Option<c_long>> {
2048    let raw = path.with_nix_path(|cstr| {
2049        unsafe {
2050            Errno::clear();
2051            libc::pathconf(cstr.as_ptr(), var as c_int)
2052        }
2053    })?;
2054    if raw == -1 {
2055        if errno::errno() == 0 {
2056            Ok(None)
2057        } else {
2058            Err(Errno::last())
2059        }
2060    } else {
2061        Ok(Some(raw))
2062    }
2063}
2064}
2065
2066feature! {
2067#![feature = "feature"]
2068
2069/// Variable names for `sysconf`
2070///
2071/// Nix uses the same naming convention for these variables as the
2072/// [getconf(1)](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility.
2073/// That is, `SysconfVar` variables have the same name as the abstract variables
2074/// shown in the `sysconf(3)` man page.  Usually, it's the same as the C
2075/// variable name without the leading `_SC_`.
2076///
2077/// All of these symbols are standardized by POSIX 1003.1-2008, but haven't been
2078/// implemented by all platforms.
2079///
2080/// # References
2081///
2082/// - [sysconf(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html)
2083/// - [unistd.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html)
2084/// - [limits.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)
2085#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2086#[repr(i32)]
2087#[non_exhaustive]
2088pub enum SysconfVar {
2089    /// Maximum number of I/O operations in a single list I/O call supported by
2090    /// the implementation.
2091    #[cfg(not(target_os = "redox"))]
2092    #[cfg_attr(docsrs, doc(cfg(all())))]
2093    AIO_LISTIO_MAX = libc::_SC_AIO_LISTIO_MAX,
2094    /// Maximum number of outstanding asynchronous I/O operations supported by
2095    /// the implementation.
2096    #[cfg(not(target_os = "redox"))]
2097    #[cfg_attr(docsrs, doc(cfg(all())))]
2098    AIO_MAX = libc::_SC_AIO_MAX,
2099    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
2100              target_os = "ios", target_os="linux", target_os = "macos",
2101              target_os="openbsd"))]
2102    #[cfg_attr(docsrs, doc(cfg(all())))]
2103    /// The maximum amount by which a process can decrease its asynchronous I/O
2104    /// priority level from its own scheduling priority.
2105    AIO_PRIO_DELTA_MAX = libc::_SC_AIO_PRIO_DELTA_MAX,
2106    /// Maximum length of argument to the exec functions including environment data.
2107    ARG_MAX = libc::_SC_ARG_MAX,
2108    /// Maximum number of functions that may be registered with `atexit`.
2109    #[cfg(not(target_os = "redox"))]
2110    #[cfg_attr(docsrs, doc(cfg(all())))]
2111    ATEXIT_MAX = libc::_SC_ATEXIT_MAX,
2112    /// Maximum obase values allowed by the bc utility.
2113    #[cfg(not(target_os = "redox"))]
2114    #[cfg_attr(docsrs, doc(cfg(all())))]
2115    BC_BASE_MAX = libc::_SC_BC_BASE_MAX,
2116    /// Maximum number of elements permitted in an array by the bc utility.
2117    #[cfg(not(target_os = "redox"))]
2118    #[cfg_attr(docsrs, doc(cfg(all())))]
2119    BC_DIM_MAX = libc::_SC_BC_DIM_MAX,
2120    /// Maximum scale value allowed by the bc utility.
2121    #[cfg(not(target_os = "redox"))]
2122    #[cfg_attr(docsrs, doc(cfg(all())))]
2123    BC_SCALE_MAX = libc::_SC_BC_SCALE_MAX,
2124    /// Maximum length of a string constant accepted by the bc utility.
2125    #[cfg(not(target_os = "redox"))]
2126    #[cfg_attr(docsrs, doc(cfg(all())))]
2127    BC_STRING_MAX = libc::_SC_BC_STRING_MAX,
2128    /// Maximum number of simultaneous processes per real user ID.
2129    CHILD_MAX = libc::_SC_CHILD_MAX,
2130    // The number of clock ticks per second.
2131    CLK_TCK = libc::_SC_CLK_TCK,
2132    /// Maximum number of weights that can be assigned to an entry of the
2133    /// LC_COLLATE order keyword in the locale definition file
2134    #[cfg(not(target_os = "redox"))]
2135    #[cfg_attr(docsrs, doc(cfg(all())))]
2136    COLL_WEIGHTS_MAX = libc::_SC_COLL_WEIGHTS_MAX,
2137    /// Maximum number of timer expiration overruns.
2138    #[cfg(not(target_os = "redox"))]
2139    #[cfg_attr(docsrs, doc(cfg(all())))]
2140    DELAYTIMER_MAX = libc::_SC_DELAYTIMER_MAX,
2141    /// Maximum number of expressions that can be nested within parentheses by
2142    /// the expr utility.
2143    #[cfg(not(target_os = "redox"))]
2144    #[cfg_attr(docsrs, doc(cfg(all())))]
2145    EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX,
2146    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
2147              target_os = "ios", target_os="linux", target_os = "macos",
2148              target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
2149    #[cfg_attr(docsrs, doc(cfg(all())))]
2150    /// Maximum length of a host name (not including the terminating null) as
2151    /// returned from the `gethostname` function
2152    HOST_NAME_MAX = libc::_SC_HOST_NAME_MAX,
2153    /// Maximum number of iovec structures that one process has available for
2154    /// use with `readv` or `writev`.
2155    #[cfg(not(target_os = "redox"))]
2156    #[cfg_attr(docsrs, doc(cfg(all())))]
2157    IOV_MAX = libc::_SC_IOV_MAX,
2158    /// Unless otherwise noted, the maximum length, in bytes, of a utility's
2159    /// input line (either standard input or another file), when the utility is
2160    /// described as processing text files. The length includes room for the
2161    /// trailing newline.
2162    #[cfg(not(target_os = "redox"))]
2163    #[cfg_attr(docsrs, doc(cfg(all())))]
2164    LINE_MAX = libc::_SC_LINE_MAX,
2165    /// Maximum length of a login name.
2166    LOGIN_NAME_MAX = libc::_SC_LOGIN_NAME_MAX,
2167    /// Maximum number of simultaneous supplementary group IDs per process.
2168    NGROUPS_MAX = libc::_SC_NGROUPS_MAX,
2169    /// Initial size of `getgrgid_r` and `getgrnam_r` data buffers
2170    #[cfg(not(target_os = "redox"))]
2171    #[cfg_attr(docsrs, doc(cfg(all())))]
2172    GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX,
2173    /// Initial size of `getpwuid_r` and `getpwnam_r` data buffers
2174    #[cfg(not(target_os = "redox"))]
2175    #[cfg_attr(docsrs, doc(cfg(all())))]
2176    GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX,
2177    /// The maximum number of open message queue descriptors a process may hold.
2178    #[cfg(not(target_os = "redox"))]
2179    #[cfg_attr(docsrs, doc(cfg(all())))]
2180    MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX,
2181    /// The maximum number of message priorities supported by the implementation.
2182    #[cfg(not(target_os = "redox"))]
2183    #[cfg_attr(docsrs, doc(cfg(all())))]
2184    MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX,
2185    /// A value one greater than the maximum value that the system may assign to
2186    /// a newly-created file descriptor.
2187    OPEN_MAX = libc::_SC_OPEN_MAX,
2188    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2189              target_os="linux", target_os = "macos", target_os="openbsd"))]
2190    #[cfg_attr(docsrs, doc(cfg(all())))]
2191    /// The implementation supports the Advisory Information option.
2192    _POSIX_ADVISORY_INFO = libc::_SC_ADVISORY_INFO,
2193    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
2194              target_os = "ios", target_os="linux", target_os = "macos",
2195              target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
2196    #[cfg_attr(docsrs, doc(cfg(all())))]
2197    /// The implementation supports barriers.
2198    _POSIX_BARRIERS = libc::_SC_BARRIERS,
2199    /// The implementation supports asynchronous input and output.
2200    #[cfg(not(target_os = "redox"))]
2201    #[cfg_attr(docsrs, doc(cfg(all())))]
2202    _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO,
2203    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
2204              target_os = "ios", target_os="linux", target_os = "macos",
2205              target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
2206    #[cfg_attr(docsrs, doc(cfg(all())))]
2207    /// The implementation supports clock selection.
2208    _POSIX_CLOCK_SELECTION = libc::_SC_CLOCK_SELECTION,
2209    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
2210              target_os = "ios", target_os="linux", target_os = "macos",
2211              target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
2212    #[cfg_attr(docsrs, doc(cfg(all())))]
2213    /// The implementation supports the Process CPU-Time Clocks option.
2214    _POSIX_CPUTIME = libc::_SC_CPUTIME,
2215    /// The implementation supports the File Synchronization option.
2216    #[cfg(not(target_os = "redox"))]
2217    #[cfg_attr(docsrs, doc(cfg(all())))]
2218    _POSIX_FSYNC = libc::_SC_FSYNC,
2219    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
2220              target_os = "ios", target_os="linux", target_os = "macos",
2221              target_os="openbsd", target_os = "solaris"))]
2222    #[cfg_attr(docsrs, doc(cfg(all())))]
2223    /// The implementation supports the IPv6 option.
2224    _POSIX_IPV6 = libc::_SC_IPV6,
2225    /// The implementation supports job control.
2226    #[cfg(not(target_os = "redox"))]
2227    #[cfg_attr(docsrs, doc(cfg(all())))]
2228    _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL,
2229    /// The implementation supports memory mapped Files.
2230    #[cfg(not(target_os = "redox"))]
2231    #[cfg_attr(docsrs, doc(cfg(all())))]
2232    _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES,
2233    /// The implementation supports the Process Memory Locking option.
2234    #[cfg(not(target_os = "redox"))]
2235    #[cfg_attr(docsrs, doc(cfg(all())))]
2236    _POSIX_MEMLOCK = libc::_SC_MEMLOCK,
2237    /// The implementation supports the Range Memory Locking option.
2238    #[cfg(not(target_os = "redox"))]
2239    #[cfg_attr(docsrs, doc(cfg(all())))]
2240    _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE,
2241    /// The implementation supports memory protection.
2242    #[cfg(not(target_os = "redox"))]
2243    #[cfg_attr(docsrs, doc(cfg(all())))]
2244    _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION,
2245    /// The implementation supports the Message Passing option.
2246    #[cfg(not(target_os = "redox"))]
2247    #[cfg_attr(docsrs, doc(cfg(all())))]
2248    _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING,
2249    /// The implementation supports the Monotonic Clock option.
2250    #[cfg(not(target_os = "redox"))]
2251    #[cfg_attr(docsrs, doc(cfg(all())))]
2252    _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK,
2253    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
2254              target_os = "illumos", target_os = "ios", target_os="linux",
2255              target_os = "macos", target_os="openbsd", target_os = "solaris"))]
2256    #[cfg_attr(docsrs, doc(cfg(all())))]
2257    /// The implementation supports the Prioritized Input and Output option.
2258    _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO,
2259    /// The implementation supports the Process Scheduling option.
2260    #[cfg(not(target_os = "redox"))]
2261    #[cfg_attr(docsrs, doc(cfg(all())))]
2262    _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING,
2263    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
2264              target_os = "ios", target_os="linux", target_os = "macos",
2265              target_os="openbsd", target_os = "solaris"))]
2266    #[cfg_attr(docsrs, doc(cfg(all())))]
2267    /// The implementation supports the Raw Sockets option.
2268    _POSIX_RAW_SOCKETS = libc::_SC_RAW_SOCKETS,
2269    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
2270              target_os = "ios", target_os="linux", target_os = "macos",
2271              target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
2272    #[cfg_attr(docsrs, doc(cfg(all())))]
2273    /// The implementation supports read-write locks.
2274    _POSIX_READER_WRITER_LOCKS = libc::_SC_READER_WRITER_LOCKS,
2275    #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd",
2276              target_os = "ios", target_os="linux", target_os = "macos",
2277              target_os = "openbsd"))]
2278    #[cfg_attr(docsrs, doc(cfg(all())))]
2279    /// The implementation supports realtime signals.
2280    _POSIX_REALTIME_SIGNALS = libc::_SC_REALTIME_SIGNALS,
2281    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "illumos",
2282              target_os = "ios", target_os="linux", target_os = "macos",
2283              target_os="netbsd", target_os="openbsd", target_os = "solaris"))]
2284    #[cfg_attr(docsrs, doc(cfg(all())))]
2285    /// The implementation supports the Regular Expression Handling option.
2286    _POSIX_REGEXP = libc::_SC_REGEXP,
2287    /// Each process has a saved set-user-ID and a saved set-group-ID.
2288    #[cfg(not(target_os = "redox"))]
2289    #[cfg_attr(docsrs, doc(cfg(all())))]
2290    _POSIX_SAVED_IDS = libc::_SC_SAVED_IDS,
2291    /// The implementation supports semaphores.
2292    #[cfg(not(target_os = "redox"))]
2293    #[cfg_attr(docsrs, doc(cfg(all())))]
2294    _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES,
2295    /// The implementation supports the Shared Memory Objects option.
2296    #[cfg(not(target_os = "redox"))]
2297    #[cfg_attr(docsrs, doc(cfg(all())))]
2298    _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS,
2299    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2300              target_os="linux", target_os = "macos", target_os="netbsd",
2301              target_os="openbsd"))]
2302    #[cfg_attr(docsrs, doc(cfg(all())))]
2303    /// The implementation supports the POSIX shell.
2304    _POSIX_SHELL = libc::_SC_SHELL,
2305    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2306              target_os="linux", target_os = "macos", target_os="netbsd",
2307              target_os="openbsd"))]
2308    #[cfg_attr(docsrs, doc(cfg(all())))]
2309    /// The implementation supports the Spawn option.
2310    _POSIX_SPAWN = libc::_SC_SPAWN,
2311    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2312              target_os="linux", target_os = "macos", target_os="netbsd",
2313              target_os="openbsd"))]
2314    #[cfg_attr(docsrs, doc(cfg(all())))]
2315    /// The implementation supports spin locks.
2316    _POSIX_SPIN_LOCKS = libc::_SC_SPIN_LOCKS,
2317    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2318              target_os="linux", target_os = "macos", target_os="openbsd"))]
2319    #[cfg_attr(docsrs, doc(cfg(all())))]
2320    /// The implementation supports the Process Sporadic Server option.
2321    _POSIX_SPORADIC_SERVER = libc::_SC_SPORADIC_SERVER,
2322    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
2323              target_os="openbsd"))]
2324    #[cfg_attr(docsrs, doc(cfg(all())))]
2325    _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX,
2326    /// The implementation supports the Synchronized Input and Output option.
2327    #[cfg(not(target_os = "redox"))]
2328    #[cfg_attr(docsrs, doc(cfg(all())))]
2329    _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO,
2330    /// The implementation supports the Thread Stack Address Attribute option.
2331    #[cfg(not(target_os = "redox"))]
2332    #[cfg_attr(docsrs, doc(cfg(all())))]
2333    _POSIX_THREAD_ATTR_STACKADDR = libc::_SC_THREAD_ATTR_STACKADDR,
2334    /// The implementation supports the Thread Stack Size Attribute option.
2335    #[cfg(not(target_os = "redox"))]
2336    #[cfg_attr(docsrs, doc(cfg(all())))]
2337    _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE,
2338    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
2339              target_os="netbsd", target_os="openbsd"))]
2340    #[cfg_attr(docsrs, doc(cfg(all())))]
2341    /// The implementation supports the Thread CPU-Time Clocks option.
2342    _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME,
2343    /// The implementation supports the Non-Robust Mutex Priority Inheritance
2344    /// option.
2345    #[cfg(not(target_os = "redox"))]
2346    #[cfg_attr(docsrs, doc(cfg(all())))]
2347    _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT,
2348    /// The implementation supports the Non-Robust Mutex Priority Protection option.
2349    #[cfg(not(target_os = "redox"))]
2350    #[cfg_attr(docsrs, doc(cfg(all())))]
2351    _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT,
2352    /// The implementation supports the Thread Execution Scheduling option.
2353    #[cfg(not(target_os = "redox"))]
2354    #[cfg_attr(docsrs, doc(cfg(all())))]
2355    _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING,
2356    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2357              target_os="linux", target_os = "macos", target_os="netbsd",
2358              target_os="openbsd"))]
2359    #[cfg_attr(docsrs, doc(cfg(all())))]
2360    /// The implementation supports the Thread Process-Shared Synchronization
2361    /// option.
2362    _POSIX_THREAD_PROCESS_SHARED = libc::_SC_THREAD_PROCESS_SHARED,
2363    #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))]
2364    #[cfg_attr(docsrs, doc(cfg(all())))]
2365    /// The implementation supports the Robust Mutex Priority Inheritance option.
2366    _POSIX_THREAD_ROBUST_PRIO_INHERIT = libc::_SC_THREAD_ROBUST_PRIO_INHERIT,
2367    #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))]
2368    #[cfg_attr(docsrs, doc(cfg(all())))]
2369    /// The implementation supports the Robust Mutex Priority Protection option.
2370    _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT,
2371    /// The implementation supports thread-safe functions.
2372    #[cfg(not(target_os = "redox"))]
2373    #[cfg_attr(docsrs, doc(cfg(all())))]
2374    _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS,
2375    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2376              target_os="linux", target_os = "macos", target_os="openbsd"))]
2377    #[cfg_attr(docsrs, doc(cfg(all())))]
2378    /// The implementation supports the Thread Sporadic Server option.
2379    _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER,
2380    /// The implementation supports threads.
2381    #[cfg(not(target_os = "redox"))]
2382    #[cfg_attr(docsrs, doc(cfg(all())))]
2383    _POSIX_THREADS = libc::_SC_THREADS,
2384    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2385              target_os="linux", target_os = "macos", target_os="openbsd"))]
2386    #[cfg_attr(docsrs, doc(cfg(all())))]
2387    /// The implementation supports timeouts.
2388    _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS,
2389    /// The implementation supports timers.
2390    #[cfg(not(target_os = "redox"))]
2391    #[cfg_attr(docsrs, doc(cfg(all())))]
2392    _POSIX_TIMERS = libc::_SC_TIMERS,
2393    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2394              target_os="linux", target_os = "macos", target_os="openbsd"))]
2395    #[cfg_attr(docsrs, doc(cfg(all())))]
2396    /// The implementation supports the Trace option.
2397    _POSIX_TRACE = libc::_SC_TRACE,
2398    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2399              target_os="linux", target_os = "macos", target_os="openbsd"))]
2400    #[cfg_attr(docsrs, doc(cfg(all())))]
2401    /// The implementation supports the Trace Event Filter option.
2402    _POSIX_TRACE_EVENT_FILTER = libc::_SC_TRACE_EVENT_FILTER,
2403    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
2404              target_os="openbsd"))]
2405    #[cfg_attr(docsrs, doc(cfg(all())))]
2406    _POSIX_TRACE_EVENT_NAME_MAX = libc::_SC_TRACE_EVENT_NAME_MAX,
2407    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2408              target_os="linux", target_os = "macos", target_os="openbsd"))]
2409    #[cfg_attr(docsrs, doc(cfg(all())))]
2410    /// The implementation supports the Trace Inherit option.
2411    _POSIX_TRACE_INHERIT = libc::_SC_TRACE_INHERIT,
2412    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2413              target_os="linux", target_os = "macos", target_os="openbsd"))]
2414    #[cfg_attr(docsrs, doc(cfg(all())))]
2415    /// The implementation supports the Trace Log option.
2416    _POSIX_TRACE_LOG = libc::_SC_TRACE_LOG,
2417    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
2418              target_os="openbsd"))]
2419    #[cfg_attr(docsrs, doc(cfg(all())))]
2420    _POSIX_TRACE_NAME_MAX = libc::_SC_TRACE_NAME_MAX,
2421    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
2422              target_os="openbsd"))]
2423    #[cfg_attr(docsrs, doc(cfg(all())))]
2424    _POSIX_TRACE_SYS_MAX = libc::_SC_TRACE_SYS_MAX,
2425    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
2426              target_os="openbsd"))]
2427    #[cfg_attr(docsrs, doc(cfg(all())))]
2428    _POSIX_TRACE_USER_EVENT_MAX = libc::_SC_TRACE_USER_EVENT_MAX,
2429    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2430              target_os="linux", target_os = "macos", target_os="openbsd"))]
2431    #[cfg_attr(docsrs, doc(cfg(all())))]
2432    /// The implementation supports the Typed Memory Objects option.
2433    _POSIX_TYPED_MEMORY_OBJECTS = libc::_SC_TYPED_MEMORY_OBJECTS,
2434    /// Integer value indicating version of this standard (C-language binding)
2435    /// to which the implementation conforms. For implementations conforming to
2436    /// POSIX.1-2008, the value shall be 200809L.
2437    _POSIX_VERSION = libc::_SC_VERSION,
2438    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2439              target_os="linux", target_os = "macos", target_os="netbsd",
2440              target_os="openbsd"))]
2441    #[cfg_attr(docsrs, doc(cfg(all())))]
2442    /// The implementation provides a C-language compilation environment with
2443    /// 32-bit `int`, `long`, `pointer`, and `off_t` types.
2444    _POSIX_V6_ILP32_OFF32 = libc::_SC_V6_ILP32_OFF32,
2445    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2446              target_os="linux", target_os = "macos", target_os="netbsd",
2447              target_os="openbsd"))]
2448    #[cfg_attr(docsrs, doc(cfg(all())))]
2449    /// The implementation provides a C-language compilation environment with
2450    /// 32-bit `int`, `long`, and pointer types and an `off_t` type using at
2451    /// least 64 bits.
2452    _POSIX_V6_ILP32_OFFBIG = libc::_SC_V6_ILP32_OFFBIG,
2453    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2454              target_os="linux", target_os = "macos", target_os="netbsd",
2455              target_os="openbsd"))]
2456    #[cfg_attr(docsrs, doc(cfg(all())))]
2457    /// The implementation provides a C-language compilation environment with
2458    /// 32-bit `int` and 64-bit `long`, `pointer`, and `off_t` types.
2459    _POSIX_V6_LP64_OFF64 = libc::_SC_V6_LP64_OFF64,
2460    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2461              target_os="linux", target_os = "macos", target_os="netbsd",
2462              target_os="openbsd"))]
2463    #[cfg_attr(docsrs, doc(cfg(all())))]
2464    /// The implementation provides a C-language compilation environment with an
2465    /// `int` type using at least 32 bits and `long`, pointer, and `off_t` types
2466    /// using at least 64 bits.
2467    _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG,
2468    /// The implementation supports the C-Language Binding option.
2469    #[cfg(not(target_os = "redox"))]
2470    #[cfg_attr(docsrs, doc(cfg(all())))]
2471    _POSIX2_C_BIND = libc::_SC_2_C_BIND,
2472    /// The implementation supports the C-Language Development Utilities option.
2473    #[cfg(not(target_os = "redox"))]
2474    #[cfg_attr(docsrs, doc(cfg(all())))]
2475    _POSIX2_C_DEV = libc::_SC_2_C_DEV,
2476    /// The implementation supports the Terminal Characteristics option.
2477    #[cfg(not(target_os = "redox"))]
2478    #[cfg_attr(docsrs, doc(cfg(all())))]
2479    _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM,
2480    /// The implementation supports the FORTRAN Development Utilities option.
2481    #[cfg(not(target_os = "redox"))]
2482    #[cfg_attr(docsrs, doc(cfg(all())))]
2483    _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV,
2484    /// The implementation supports the FORTRAN Runtime Utilities option.
2485    #[cfg(not(target_os = "redox"))]
2486    #[cfg_attr(docsrs, doc(cfg(all())))]
2487    _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN,
2488    /// The implementation supports the creation of locales by the localedef
2489    /// utility.
2490    #[cfg(not(target_os = "redox"))]
2491    #[cfg_attr(docsrs, doc(cfg(all())))]
2492    _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF,
2493    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2494              target_os="linux", target_os = "macos", target_os="netbsd",
2495              target_os="openbsd"))]
2496    #[cfg_attr(docsrs, doc(cfg(all())))]
2497    /// The implementation supports the Batch Environment Services and Utilities
2498    /// option.
2499    _POSIX2_PBS = libc::_SC_2_PBS,
2500    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2501              target_os="linux", target_os = "macos", target_os="netbsd",
2502              target_os="openbsd"))]
2503    #[cfg_attr(docsrs, doc(cfg(all())))]
2504    /// The implementation supports the Batch Accounting option.
2505    _POSIX2_PBS_ACCOUNTING = libc::_SC_2_PBS_ACCOUNTING,
2506    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2507              target_os="linux", target_os = "macos", target_os="netbsd",
2508              target_os="openbsd"))]
2509    #[cfg_attr(docsrs, doc(cfg(all())))]
2510    /// The implementation supports the Batch Checkpoint/Restart option.
2511    _POSIX2_PBS_CHECKPOINT = libc::_SC_2_PBS_CHECKPOINT,
2512    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2513              target_os="linux", target_os = "macos", target_os="netbsd",
2514              target_os="openbsd"))]
2515    #[cfg_attr(docsrs, doc(cfg(all())))]
2516    /// The implementation supports the Locate Batch Job Request option.
2517    _POSIX2_PBS_LOCATE = libc::_SC_2_PBS_LOCATE,
2518    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2519              target_os="linux", target_os = "macos", target_os="netbsd",
2520              target_os="openbsd"))]
2521    #[cfg_attr(docsrs, doc(cfg(all())))]
2522    /// The implementation supports the Batch Job Message Request option.
2523    _POSIX2_PBS_MESSAGE = libc::_SC_2_PBS_MESSAGE,
2524    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2525              target_os="linux", target_os = "macos", target_os="netbsd",
2526              target_os="openbsd"))]
2527    #[cfg_attr(docsrs, doc(cfg(all())))]
2528    /// The implementation supports the Track Batch Job Request option.
2529    _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK,
2530    /// The implementation supports the Software Development Utilities option.
2531    #[cfg(not(target_os = "redox"))]
2532    #[cfg_attr(docsrs, doc(cfg(all())))]
2533    _POSIX2_SW_DEV = libc::_SC_2_SW_DEV,
2534    /// The implementation supports the User Portability Utilities option.
2535    #[cfg(not(target_os = "redox"))]
2536    #[cfg_attr(docsrs, doc(cfg(all())))]
2537    _POSIX2_UPE = libc::_SC_2_UPE,
2538    /// Integer value indicating version of the Shell and Utilities volume of
2539    /// POSIX.1 to which the implementation conforms.
2540    #[cfg(not(target_os = "redox"))]
2541    #[cfg_attr(docsrs, doc(cfg(all())))]
2542    _POSIX2_VERSION = libc::_SC_2_VERSION,
2543    /// The size of a system page in bytes.
2544    ///
2545    /// POSIX also defines an alias named `PAGESIZE`, but Rust does not allow two
2546    /// enum constants to have the same value, so nix omits `PAGESIZE`.
2547    PAGE_SIZE = libc::_SC_PAGE_SIZE,
2548    #[cfg(not(target_os = "redox"))]
2549    #[cfg_attr(docsrs, doc(cfg(all())))]
2550    PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS,
2551    #[cfg(not(target_os = "redox"))]
2552    #[cfg_attr(docsrs, doc(cfg(all())))]
2553    PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX,
2554    #[cfg(not(target_os = "redox"))]
2555    #[cfg_attr(docsrs, doc(cfg(all())))]
2556    PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN,
2557    #[cfg(not(target_os = "redox"))]
2558    #[cfg_attr(docsrs, doc(cfg(all())))]
2559    PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX,
2560    RE_DUP_MAX = libc::_SC_RE_DUP_MAX,
2561    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
2562              target_os = "ios", target_os="linux", target_os = "macos",
2563              target_os="openbsd"))]
2564    #[cfg_attr(docsrs, doc(cfg(all())))]
2565    RTSIG_MAX = libc::_SC_RTSIG_MAX,
2566    #[cfg(not(target_os = "redox"))]
2567    #[cfg_attr(docsrs, doc(cfg(all())))]
2568    SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX,
2569    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
2570              target_os = "ios", target_os="linux", target_os = "macos",
2571              target_os="openbsd"))]
2572    #[cfg_attr(docsrs, doc(cfg(all())))]
2573    SEM_VALUE_MAX = libc::_SC_SEM_VALUE_MAX,
2574    #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd",
2575              target_os = "ios", target_os="linux", target_os = "macos",
2576              target_os = "openbsd"))]
2577    #[cfg_attr(docsrs, doc(cfg(all())))]
2578    SIGQUEUE_MAX = libc::_SC_SIGQUEUE_MAX,
2579    STREAM_MAX = libc::_SC_STREAM_MAX,
2580    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2581              target_os="linux", target_os = "macos", target_os="netbsd",
2582              target_os="openbsd"))]
2583    #[cfg_attr(docsrs, doc(cfg(all())))]
2584    SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX,
2585    #[cfg(not(target_os = "redox"))]
2586    #[cfg_attr(docsrs, doc(cfg(all())))]
2587    TIMER_MAX = libc::_SC_TIMER_MAX,
2588    TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX,
2589    TZNAME_MAX = libc::_SC_TZNAME_MAX,
2590    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
2591              target_os = "ios", target_os="linux", target_os = "macos",
2592              target_os="openbsd"))]
2593    #[cfg_attr(docsrs, doc(cfg(all())))]
2594    /// The implementation supports the X/Open Encryption Option Group.
2595    _XOPEN_CRYPT = libc::_SC_XOPEN_CRYPT,
2596    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
2597              target_os = "ios", target_os="linux", target_os = "macos",
2598              target_os="openbsd"))]
2599    #[cfg_attr(docsrs, doc(cfg(all())))]
2600    /// The implementation supports the Issue 4, Version 2 Enhanced
2601    /// Internationalization Option Group.
2602    _XOPEN_ENH_I18N = libc::_SC_XOPEN_ENH_I18N,
2603    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
2604              target_os = "ios", target_os="linux", target_os = "macos",
2605              target_os="openbsd"))]
2606    #[cfg_attr(docsrs, doc(cfg(all())))]
2607    _XOPEN_LEGACY = libc::_SC_XOPEN_LEGACY,
2608    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
2609              target_os = "ios", target_os="linux", target_os = "macos",
2610              target_os="openbsd"))]
2611    #[cfg_attr(docsrs, doc(cfg(all())))]
2612    /// The implementation supports the X/Open Realtime Option Group.
2613    _XOPEN_REALTIME = libc::_SC_XOPEN_REALTIME,
2614    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
2615              target_os = "ios", target_os="linux", target_os = "macos",
2616              target_os="openbsd"))]
2617    #[cfg_attr(docsrs, doc(cfg(all())))]
2618    /// The implementation supports the X/Open Realtime Threads Option Group.
2619    _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS,
2620    /// The implementation supports the Issue 4, Version 2 Shared Memory Option
2621    /// Group.
2622    #[cfg(not(target_os = "redox"))]
2623    #[cfg_attr(docsrs, doc(cfg(all())))]
2624    _XOPEN_SHM = libc::_SC_XOPEN_SHM,
2625    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
2626              target_os="linux", target_os = "macos", target_os="openbsd"))]
2627    #[cfg_attr(docsrs, doc(cfg(all())))]
2628    /// The implementation supports the XSI STREAMS Option Group.
2629    _XOPEN_STREAMS = libc::_SC_XOPEN_STREAMS,
2630    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
2631              target_os = "ios", target_os="linux", target_os = "macos",
2632              target_os="openbsd"))]
2633    #[cfg_attr(docsrs, doc(cfg(all())))]
2634    /// The implementation supports the XSI option
2635    _XOPEN_UNIX = libc::_SC_XOPEN_UNIX,
2636    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
2637              target_os = "ios", target_os="linux", target_os = "macos",
2638              target_os="openbsd"))]
2639    #[cfg_attr(docsrs, doc(cfg(all())))]
2640    /// Integer value indicating version of the X/Open Portability Guide to
2641    /// which the implementation conforms.
2642    _XOPEN_VERSION = libc::_SC_XOPEN_VERSION,
2643}
2644
2645/// Get configurable system variables (see
2646/// [sysconf(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html))
2647///
2648/// Returns the value of a configurable system variable.  Most supported
2649/// variables also have associated compile-time constants, but POSIX
2650/// allows their values to change at runtime.  There are generally two types of
2651/// sysconf variables: options and limits.  See sysconf(3) for more details.
2652///
2653/// # Returns
2654///
2655/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its
2656///     implementation level (for option variables).  Implementation levels are
2657///     usually a decimal-coded date, such as 200112 for POSIX 2001.12
2658/// - `Ok(None)`: the variable has no limit (for limit variables) or is
2659///     unsupported (for option variables)
2660/// - `Err(x)`: an error occurred
2661pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> {
2662    let raw = unsafe {
2663        Errno::clear();
2664        libc::sysconf(var as c_int)
2665    };
2666    if raw == -1 {
2667        if errno::errno() == 0 {
2668            Ok(None)
2669        } else {
2670            Err(Errno::last())
2671        }
2672    } else {
2673        Ok(Some(raw))
2674    }
2675}
2676}
2677
2678feature! {
2679#![feature = "fs"]
2680
2681#[cfg(any(target_os = "android", target_os = "linux"))]
2682mod pivot_root {
2683    use crate::{Result, NixPath};
2684    use crate::errno::Errno;
2685
2686    pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
2687            new_root: &P1, put_old: &P2) -> Result<()> {
2688        let res = new_root.with_nix_path(|new_root| {
2689            put_old.with_nix_path(|put_old| {
2690                unsafe {
2691                    libc::syscall(libc::SYS_pivot_root, new_root.as_ptr(), put_old.as_ptr())
2692                }
2693            })
2694        })??;
2695
2696        Errno::result(res).map(drop)
2697    }
2698}
2699}
2700
2701#[cfg(any(target_os = "android",
2702          target_os = "dragonfly",
2703          target_os = "freebsd",
2704          target_os = "linux",
2705          target_os = "openbsd"))]
2706mod setres {
2707    feature! {
2708    #![feature = "user"]
2709
2710    use crate::Result;
2711    use crate::errno::Errno;
2712    use super::{Uid, Gid};
2713
2714    /// Sets the real, effective, and saved uid.
2715    /// ([see setresuid(2)](https://man7.org/linux/man-pages/man2/setresuid.2.html))
2716    ///
2717    /// * `ruid`: real user id
2718    /// * `euid`: effective user id
2719    /// * `suid`: saved user id
2720    /// * returns: Ok or libc error code.
2721    ///
2722    /// Err is returned if the user doesn't have permission to set this UID.
2723    #[inline]
2724    pub fn setresuid(ruid: Uid, euid: Uid, suid: Uid) -> Result<()> {
2725        let res = unsafe { libc::setresuid(ruid.into(), euid.into(), suid.into()) };
2726
2727        Errno::result(res).map(drop)
2728    }
2729
2730    /// Sets the real, effective, and saved gid.
2731    /// ([see setresuid(2)](https://man7.org/linux/man-pages/man2/setresuid.2.html))
2732    ///
2733    /// * `rgid`: real group id
2734    /// * `egid`: effective group id
2735    /// * `sgid`: saved group id
2736    /// * returns: Ok or libc error code.
2737    ///
2738    /// Err is returned if the user doesn't have permission to set this GID.
2739    #[inline]
2740    pub fn setresgid(rgid: Gid, egid: Gid, sgid: Gid) -> Result<()> {
2741        let res = unsafe { libc::setresgid(rgid.into(), egid.into(), sgid.into()) };
2742
2743        Errno::result(res).map(drop)
2744    }
2745    }
2746}
2747
2748#[cfg(any(target_os = "android",
2749          target_os = "dragonfly",
2750          target_os = "freebsd",
2751          target_os = "linux",
2752          target_os = "openbsd"))]
2753mod getres {
2754    feature! {
2755    #![feature = "user"]
2756
2757    use crate::Result;
2758    use crate::errno::Errno;
2759    use super::{Uid, Gid};
2760
2761    /// Real, effective and saved user IDs.
2762    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
2763    pub struct ResUid {
2764        pub real: Uid,
2765        pub effective: Uid,
2766        pub saved: Uid
2767    }
2768
2769    /// Real, effective and saved group IDs.
2770    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
2771    pub struct ResGid {
2772        pub real: Gid,
2773        pub effective: Gid,
2774        pub saved: Gid
2775    }
2776
2777    /// Gets the real, effective, and saved user IDs.
2778    ///
2779    /// ([see getresuid(2)](http://man7.org/linux/man-pages/man2/getresuid.2.html))
2780    ///
2781    /// #Returns
2782    ///
2783    /// - `Ok((Uid, Uid, Uid))`: tuple of real, effective and saved uids on success.
2784    /// - `Err(x)`: libc error code on failure.
2785    ///
2786    #[inline]
2787    pub fn getresuid() -> Result<ResUid> {
2788        let mut ruid = libc::uid_t::max_value();
2789        let mut euid = libc::uid_t::max_value();
2790        let mut suid = libc::uid_t::max_value();
2791        let res = unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) };
2792
2793        Errno::result(res).map(|_| ResUid{ real: Uid(ruid), effective: Uid(euid), saved: Uid(suid) })
2794    }
2795
2796    /// Gets the real, effective, and saved group IDs.
2797    ///
2798    /// ([see getresgid(2)](http://man7.org/linux/man-pages/man2/getresgid.2.html))
2799    ///
2800    /// #Returns
2801    ///
2802    /// - `Ok((Gid, Gid, Gid))`: tuple of real, effective and saved gids on success.
2803    /// - `Err(x)`: libc error code on failure.
2804    ///
2805    #[inline]
2806    pub fn getresgid() -> Result<ResGid> {
2807        let mut rgid = libc::gid_t::max_value();
2808        let mut egid = libc::gid_t::max_value();
2809        let mut sgid = libc::gid_t::max_value();
2810        let res = unsafe { libc::getresgid(&mut rgid, &mut egid, &mut sgid) };
2811
2812        Errno::result(res).map(|_| ResGid { real: Gid(rgid), effective: Gid(egid), saved: Gid(sgid) } )
2813    }
2814    }
2815}
2816
2817#[cfg(feature = "fs")]
2818libc_bitflags!{
2819    /// Options for access()
2820    #[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
2821    pub struct AccessFlags : c_int {
2822        /// Test for existence of file.
2823        F_OK;
2824        /// Test for read permission.
2825        R_OK;
2826        /// Test for write permission.
2827        W_OK;
2828        /// Test for execute (search) permission.
2829        X_OK;
2830    }
2831}
2832
2833feature! {
2834#![feature = "fs"]
2835
2836/// Checks the file named by `path` for accessibility according to the flags given by `amode`
2837/// See [access(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html)
2838pub fn access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()> {
2839    let res = path.with_nix_path(|cstr| {
2840        unsafe {
2841            libc::access(cstr.as_ptr(), amode.bits)
2842        }
2843    })?;
2844    Errno::result(res).map(drop)
2845}
2846}
2847
2848feature! {
2849#![feature = "user"]
2850
2851/// Representation of a User, based on `libc::passwd`
2852///
2853/// The reason some fields in this struct are `String` and others are `CString` is because some
2854/// fields are based on the user's locale, which could be non-UTF8, while other fields are
2855/// guaranteed to conform to [`NAME_REGEX`](https://serverfault.com/a/73101/407341), which only
2856/// contains ASCII.
2857#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
2858#[derive(Debug, Clone, Eq, PartialEq)]
2859pub struct User {
2860    /// Username
2861    pub name: String,
2862    /// User password (probably encrypted)
2863    pub passwd: CString,
2864    /// User ID
2865    pub uid: Uid,
2866    /// Group ID
2867    pub gid: Gid,
2868    /// User information
2869    #[cfg(not(all(target_os = "android", target_pointer_width = "32")))]
2870    pub gecos: CString,
2871    /// Home directory
2872    pub dir: PathBuf,
2873    /// Path to shell
2874    pub shell: PathBuf,
2875    /// Login class
2876    #[cfg(not(any(target_os = "android",
2877                  target_os = "fuchsia",
2878                  target_os = "illumos",
2879                  target_os = "linux",
2880                  target_os = "solaris")))]
2881    #[cfg_attr(docsrs, doc(cfg(all())))]
2882    pub class: CString,
2883    /// Last password change
2884    #[cfg(not(any(target_os = "android",
2885                  target_os = "fuchsia",
2886                  target_os = "illumos",
2887                  target_os = "linux",
2888                  target_os = "solaris")))]
2889    #[cfg_attr(docsrs, doc(cfg(all())))]
2890    pub change: libc::time_t,
2891    /// Expiration time of account
2892    #[cfg(not(any(target_os = "android",
2893                  target_os = "fuchsia",
2894                  target_os = "illumos",
2895                  target_os = "linux",
2896                  target_os = "solaris")))]
2897    #[cfg_attr(docsrs, doc(cfg(all())))]
2898    pub expire: libc::time_t
2899}
2900
2901#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
2902impl From<&libc::passwd> for User {
2903    fn from(pw: &libc::passwd) -> User {
2904        unsafe {
2905            User {
2906                name: if pw.pw_name.is_null() { Default::default() } else { CStr::from_ptr(pw.pw_name).to_string_lossy().into_owned() },
2907                passwd: if pw.pw_passwd.is_null() { Default::default() } else { CString::new(CStr::from_ptr(pw.pw_passwd).to_bytes()).unwrap() },
2908                #[cfg(not(all(target_os = "android", target_pointer_width = "32")))]
2909                gecos: if pw.pw_gecos.is_null() { Default::default() } else { CString::new(CStr::from_ptr(pw.pw_gecos).to_bytes()).unwrap() },
2910                dir: if pw.pw_dir.is_null() { Default::default() } else { PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_dir).to_bytes())) },
2911                shell: if pw.pw_shell.is_null() { Default::default() } else { PathBuf::from(OsStr::from_bytes(CStr::from_ptr(pw.pw_shell).to_bytes())) },
2912                uid: Uid::from_raw(pw.pw_uid),
2913                gid: Gid::from_raw(pw.pw_gid),
2914                #[cfg(not(any(target_os = "android",
2915                              target_os = "fuchsia",
2916                              target_os = "illumos",
2917                              target_os = "linux",
2918                              target_os = "solaris")))]
2919                class: CString::new(CStr::from_ptr(pw.pw_class).to_bytes()).unwrap(),
2920                #[cfg(not(any(target_os = "android",
2921                              target_os = "fuchsia",
2922                              target_os = "illumos",
2923                              target_os = "linux",
2924                              target_os = "solaris")))]
2925                change: pw.pw_change,
2926                #[cfg(not(any(target_os = "android",
2927                              target_os = "fuchsia",
2928                              target_os = "illumos",
2929                              target_os = "linux",
2930                              target_os = "solaris")))]
2931                expire: pw.pw_expire
2932            }
2933        }
2934    }
2935}
2936
2937#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
2938impl From<User> for libc::passwd {
2939    fn from(u: User) -> Self {
2940        let name = match CString::new(u.name) {
2941            Ok(n) => n.into_raw(),
2942            Err(_) => CString::new("").unwrap().into_raw(),
2943        };
2944        let dir = match u.dir.into_os_string().into_string() {
2945            Ok(s) => CString::new(s.as_str()).unwrap().into_raw(),
2946            Err(_) => CString::new("").unwrap().into_raw(),
2947        };
2948        let shell = match u.shell.into_os_string().into_string() {
2949            Ok(s) => CString::new(s.as_str()).unwrap().into_raw(),
2950            Err(_) => CString::new("").unwrap().into_raw(),
2951        };
2952        Self {
2953            pw_name: name,
2954            pw_passwd: u.passwd.into_raw(),
2955            #[cfg(not(all(target_os = "android", target_pointer_width = "32")))]
2956            pw_gecos: u.gecos.into_raw(),
2957            pw_dir: dir,
2958            pw_shell: shell,
2959            pw_uid: u.uid.0,
2960            pw_gid: u.gid.0,
2961            #[cfg(not(any(target_os = "android",
2962                          target_os = "fuchsia",
2963                          target_os = "illumos",
2964                          target_os = "linux",
2965                          target_os = "solaris")))]
2966            pw_class: u.class.into_raw(),
2967            #[cfg(not(any(target_os = "android",
2968                          target_os = "fuchsia",
2969                          target_os = "illumos",
2970                          target_os = "linux",
2971                          target_os = "solaris")))]
2972            pw_change: u.change,
2973            #[cfg(not(any(target_os = "android",
2974                          target_os = "fuchsia",
2975                          target_os = "illumos",
2976                          target_os = "linux",
2977                          target_os = "solaris")))]
2978            pw_expire: u.expire,
2979            #[cfg(target_os = "illumos")]
2980            pw_age: CString::new("").unwrap().into_raw(),
2981            #[cfg(target_os = "illumos")]
2982            pw_comment: CString::new("").unwrap().into_raw(),
2983            #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
2984            pw_fields: 0,
2985        }
2986    }
2987}
2988
2989#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
2990impl User {
2991    fn from_anything<F>(f: F) -> Result<Option<Self>>
2992    where
2993        F: Fn(*mut libc::passwd,
2994              *mut c_char,
2995              libc::size_t,
2996              *mut *mut libc::passwd) -> libc::c_int
2997    {
2998        let buflimit = 1048576;
2999        let bufsize = match sysconf(SysconfVar::GETPW_R_SIZE_MAX) {
3000            Ok(Some(n)) => n as usize,
3001            Ok(None) | Err(_) => 16384,
3002        };
3003
3004        let mut cbuf = Vec::with_capacity(bufsize);
3005        let mut pwd = mem::MaybeUninit::<libc::passwd>::uninit();
3006        let mut res = ptr::null_mut();
3007
3008        loop {
3009            let error = f(pwd.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res);
3010            if error == 0 {
3011                if res.is_null() {
3012                    return Ok(None);
3013                } else {
3014                    let pwd = unsafe { pwd.assume_init() };
3015                    return Ok(Some(User::from(&pwd)));
3016                }
3017            } else if Errno::last() == Errno::ERANGE {
3018                // Trigger the internal buffer resizing logic.
3019                reserve_double_buffer_size(&mut cbuf, buflimit)?;
3020            } else {
3021                return Err(Errno::last());
3022            }
3023        }
3024    }
3025
3026    /// Get a user by UID.
3027    ///
3028    /// Internally, this function calls
3029    /// [getpwuid_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
3030    ///
3031    /// # Examples
3032    ///
3033    /// ```
3034    /// use nix::unistd::{Uid, User};
3035    /// // Returns an Result<Option<User>>, thus the double unwrap.
3036    /// let res = User::from_uid(Uid::from_raw(0)).unwrap().unwrap();
3037    /// assert!(res.name == "root");
3038    /// ```
3039    pub fn from_uid(uid: Uid) -> Result<Option<Self>> {
3040        User::from_anything(|pwd, cbuf, cap, res| {
3041            unsafe { libc::getpwuid_r(uid.0, pwd, cbuf, cap, res) }
3042        })
3043    }
3044
3045    /// Get a user by name.
3046    ///
3047    /// Internally, this function calls
3048    /// [getpwnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
3049    ///
3050    /// # Examples
3051    ///
3052    /// ```
3053    /// use nix::unistd::User;
3054    /// // Returns an Result<Option<User>>, thus the double unwrap.
3055    /// let res = User::from_name("root").unwrap().unwrap();
3056    /// assert!(res.name == "root");
3057    /// ```
3058    pub fn from_name(name: &str) -> Result<Option<Self>> {
3059        let name = match CString::new(name) {
3060            Ok(c_str) => c_str,
3061            Err(_nul_error) => return Ok(None),
3062        };
3063        User::from_anything(|pwd, cbuf, cap, res| {
3064            unsafe { libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res) }
3065        })
3066    }
3067}
3068
3069/// Representation of a Group, based on `libc::group`
3070#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
3071#[derive(Debug, Clone, Eq, PartialEq)]
3072pub struct Group {
3073    /// Group name
3074    pub name: String,
3075    /// Group password
3076    pub passwd: CString,
3077    /// Group ID
3078    pub gid: Gid,
3079    /// List of Group members
3080    pub mem: Vec<String>
3081}
3082
3083#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
3084impl From<&libc::group> for Group {
3085    fn from(gr: &libc::group) -> Group {
3086        unsafe {
3087            Group {
3088                name: CStr::from_ptr(gr.gr_name).to_string_lossy().into_owned(),
3089                passwd: CString::new(CStr::from_ptr(gr.gr_passwd).to_bytes()).unwrap(),
3090                gid: Gid::from_raw(gr.gr_gid),
3091                mem: Group::members(gr.gr_mem)
3092            }
3093        }
3094    }
3095}
3096
3097#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
3098impl Group {
3099    unsafe fn members(mem: *mut *mut c_char) -> Vec<String> {
3100        let mut ret = Vec::new();
3101
3102        for i in 0.. {
3103            let u = mem.offset(i);
3104            if (*u).is_null() {
3105                break;
3106            } else {
3107                let s = CStr::from_ptr(*u).to_string_lossy().into_owned();
3108                ret.push(s);
3109            }
3110        }
3111
3112        ret
3113    }
3114
3115    fn from_anything<F>(f: F) -> Result<Option<Self>>
3116    where
3117        F: Fn(*mut libc::group,
3118              *mut c_char,
3119              libc::size_t,
3120              *mut *mut libc::group) -> libc::c_int
3121    {
3122        let buflimit = 1048576;
3123        let bufsize = match sysconf(SysconfVar::GETGR_R_SIZE_MAX) {
3124            Ok(Some(n)) => n as usize,
3125            Ok(None) | Err(_) => 16384,
3126        };
3127
3128        let mut cbuf = Vec::with_capacity(bufsize);
3129        let mut grp = mem::MaybeUninit::<libc::group>::uninit();
3130        let mut res = ptr::null_mut();
3131
3132        loop {
3133            let error = f(grp.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res);
3134            if error == 0 {
3135                if res.is_null() {
3136                    return Ok(None);
3137                } else {
3138                    let grp = unsafe { grp.assume_init() };
3139                    return Ok(Some(Group::from(&grp)));
3140                }
3141            } else if Errno::last() == Errno::ERANGE {
3142                // Trigger the internal buffer resizing logic.
3143                reserve_double_buffer_size(&mut cbuf, buflimit)?;
3144            } else {
3145                return Err(Errno::last());
3146            }
3147        }
3148    }
3149
3150    /// Get a group by GID.
3151    ///
3152    /// Internally, this function calls
3153    /// [getgrgid_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
3154    ///
3155    /// # Examples
3156    ///
3157    // Disable this test on all OS except Linux as root group may not exist.
3158    #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")]
3159    #[cfg_attr(target_os = "linux", doc = " ```")]
3160    /// use nix::unistd::{Gid, Group};
3161    /// // Returns an Result<Option<Group>>, thus the double unwrap.
3162    /// let res = Group::from_gid(Gid::from_raw(0)).unwrap().unwrap();
3163    /// assert!(res.name == "root");
3164    /// ```
3165    pub fn from_gid(gid: Gid) -> Result<Option<Self>> {
3166        Group::from_anything(|grp, cbuf, cap, res| {
3167            unsafe { libc::getgrgid_r(gid.0, grp, cbuf, cap, res) }
3168        })
3169    }
3170
3171    /// Get a group by name.
3172    ///
3173    /// Internally, this function calls
3174    /// [getgrnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
3175    ///
3176    /// # Examples
3177    ///
3178    // Disable this test on all OS except Linux as root group may not exist.
3179    #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")]
3180    #[cfg_attr(target_os = "linux", doc = " ```")]
3181    /// use nix::unistd::Group;
3182    /// // Returns an Result<Option<Group>>, thus the double unwrap.
3183    /// let res = Group::from_name("root").unwrap().unwrap();
3184    /// assert!(res.name == "root");
3185    /// ```
3186    pub fn from_name(name: &str) -> Result<Option<Self>> {
3187        let name = match CString::new(name) {
3188            Ok(c_str) => c_str,
3189            Err(_nul_error) => return Ok(None),
3190        };
3191        Group::from_anything(|grp, cbuf, cap, res| {
3192            unsafe { libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res) }
3193        })
3194    }
3195}
3196}
3197
3198feature! {
3199#![feature = "term"]
3200
3201/// Get the name of the terminal device that is open on file descriptor fd
3202/// (see [`ttyname(3)`](https://man7.org/linux/man-pages/man3/ttyname.3.html)).
3203#[cfg(not(target_os = "fuchsia"))]
3204pub fn ttyname(fd: RawFd) -> Result<PathBuf> {
3205    const PATH_MAX: usize = libc::PATH_MAX as usize;
3206    let mut buf = vec![0_u8; PATH_MAX];
3207    let c_buf = buf.as_mut_ptr() as *mut libc::c_char;
3208
3209    let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) };
3210    if ret != 0 {
3211        return Err(Errno::from_i32(ret));
3212    }
3213
3214    let nul = buf.iter().position(|c| *c == b'\0').unwrap();
3215    buf.truncate(nul);
3216    Ok(OsString::from_vec(buf).into())
3217}
3218}
3219
3220feature! {
3221#![all(feature = "socket", feature = "user")]
3222
3223/// Get the effective user ID and group ID associated with a Unix domain socket.
3224///
3225/// See also [getpeereid(3)](https://www.freebsd.org/cgi/man.cgi?query=getpeereid)
3226#[cfg(any(
3227    target_os = "macos",
3228    target_os = "ios",
3229    target_os = "freebsd",
3230    target_os = "openbsd",
3231    target_os = "netbsd",
3232    target_os = "dragonfly",
3233))]
3234pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> {
3235    let mut uid = 1;
3236    let mut gid = 1;
3237
3238    let ret = unsafe { libc::getpeereid(fd, &mut uid, &mut gid) };
3239
3240    Errno::result(ret).map(|_| (Uid(uid), Gid(gid)))
3241}
3242}