nix/
unistd.rs

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