nix/
unistd.rs

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