nix/
unistd.rs

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