nix/
unistd.rs

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