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