1 //! Safe wrappers around functions found in libc "unistd.h" header
2 
3 #[cfg(not(target_os = "redox"))]
4 use cfg_if::cfg_if;
5 use crate::errno::{self, Errno};
6 use crate::{Error, Result, NixPath};
7 #[cfg(not(target_os = "redox"))]
8 use crate::fcntl::{AtFlags, at_rawfd};
9 use crate::fcntl::{FdFlag, OFlag, fcntl};
10 use crate::fcntl::FcntlArg::F_SETFD;
11 use 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};
13 use std::{fmt, mem, ptr};
14 use std::convert::Infallible;
15 use std::ffi::{CStr, OsString};
16 #[cfg(not(target_os = "redox"))]
17 use std::ffi::{CString, OsStr};
18 use std::os::unix::ffi::OsStringExt;
19 #[cfg(not(target_os = "redox"))]
20 use std::os::unix::ffi::OsStrExt;
21 use std::os::unix::io::RawFd;
22 use std::path::PathBuf;
23 use crate::sys::stat::Mode;
24 
25 #[cfg(any(target_os = "android", target_os = "linux"))]
26 pub use self::pivot_root::*;
27 
28 #[cfg(any(target_os = "android", target_os = "freebsd",
29           target_os = "linux", target_os = "openbsd"))]
30 pub use self::setres::*;
31 
32 #[cfg(any(target_os = "android", target_os = "linux"))]
33 pub 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)]
40 pub struct Uid(uid_t);
41 
42 impl Uid {
43     /// Creates `Uid` from raw `uid_t`.
from_raw(uid: uid_t) -> Self44     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`.
current() -> Self49     pub fn current() -> Self {
50         getuid()
51     }
52 
53     /// Returns effective Uid of calling process. This is practically a more Rusty alias for `geteuid`.
effective() -> Self54     pub fn effective() -> Self {
55         geteuid()
56     }
57 
58     /// Returns true if the `Uid` represents privileged user - root. (If it equals zero.)
is_root(self) -> bool59     pub const fn is_root(self) -> bool {
60         self.0 == ROOT.0
61     }
62 
63     /// Get the raw `uid_t` wrapped by `self`.
as_raw(self) -> uid_t64     pub const fn as_raw(self) -> uid_t {
65         self.0
66     }
67 }
68 
69 impl From<Uid> for uid_t {
from(uid: Uid) -> Self70     fn from(uid: Uid) -> Self {
71         uid.0
72     }
73 }
74 
75 impl fmt::Display for Uid {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result76     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77         fmt::Display::fmt(&self.0, f)
78     }
79 }
80 
81 /// Constant for UID = 0
82 pub 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)]
89 pub struct Gid(gid_t);
90 
91 impl Gid {
92     /// Creates `Gid` from raw `gid_t`.
from_raw(gid: gid_t) -> Self93     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`.
current() -> Self98     pub fn current() -> Self {
99         getgid()
100     }
101 
102     /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getegid`.
effective() -> Self103     pub fn effective() -> Self {
104         getegid()
105     }
106 
107     /// Get the raw `gid_t` wrapped by `self`.
as_raw(self) -> gid_t108     pub const fn as_raw(self) -> gid_t {
109         self.0
110     }
111 }
112 
113 impl From<Gid> for gid_t {
from(gid: Gid) -> Self114     fn from(gid: Gid) -> Self {
115         gid.0
116     }
117 }
118 
119 impl fmt::Display for Gid {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result120     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)]
130 pub struct Pid(pid_t);
131 
132 impl Pid {
133     /// Creates `Pid` from raw `pid_t`.
from_raw(pid: pid_t) -> Self134     pub const fn from_raw(pid: pid_t) -> Self {
135         Pid(pid)
136     }
137 
138     /// Returns PID of calling process
this() -> Self139     pub fn this() -> Self {
140         getpid()
141     }
142 
143     /// Returns PID of parent of calling process
parent() -> Self144     pub fn parent() -> Self {
145         getppid()
146     }
147 
148     /// Get the raw `pid_t` wrapped by `self`.
as_raw(self) -> pid_t149     pub const fn as_raw(self) -> pid_t {
150         self.0
151     }
152 }
153 
154 impl From<Pid> for pid_t {
from(pid: Pid) -> Self155     fn from(pid: Pid) -> Self {
156         pid.0
157     }
158 }
159 
160 impl fmt::Display for Pid {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result161     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)]
173 pub enum ForkResult {
174     Parent { child: Pid },
175     Child,
176 }
177 
178 impl ForkResult {
179 
180     /// Return `true` if this is the child process of the `fork()`
181     #[inline]
is_child(self) -> bool182     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]
is_parent(self) -> bool188     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]
fork() -> Result<ForkResult>238 pub 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]
getpid() -> Pid254 pub 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]
getppid() -> Pid264 pub 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]
setpgid(pid: Pid, pgid: Pid) -> Result<()>278 pub 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]
getpgid(pid: Option<Pid>) -> Result<Pid>283 pub 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]
setsid() -> Result<Pid>291 pub 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"))]
getsid(pid: Option<Pid>) -> Result<Pid>302 pub 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]
tcgetpgrp(fd: c_int) -> Result<Pid>314 pub 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]
tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()>324 pub 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]
getpgrp() -> Pid336 pub 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]
gettid() -> Pid352 pub 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]
dup(oldfd: RawFd) -> Result<RawFd>367 pub 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]
dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd>380 pub 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.
dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd>391 pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
392     dup3_polyfill(oldfd, newfd, flags)
393 }
394 
395 #[inline]
dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd>396 fn 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]
chdir<P: ?Sized + NixPath>(path: &P) -> Result<()>419 pub 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"))]
fchdir(dirfd: RawFd) -> Result<()>435 pub 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]
mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()>468 pub 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
mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()>507 pub 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")))]
mkfifoat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: Mode) -> Result<()>529 pub 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"))]
symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( path1: &P1, dirfd: Option<RawFd>, path2: &P2) -> Result<()>547 pub 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.
reserve_double_buffer_size<T>(buf: &mut Vec<T>, limit: usize) -> Result<()>568 fn 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]
getcwd() -> Result<PathBuf>596 pub 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)]
chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc::gid_t)628 fn 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]
chown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gid>) -> Result<()>647 pub 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]
fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<()>664 pub 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)]
672 pub 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"))]
fchownat<P: ?Sized + NixPath>( dirfd: Option<RawFd>, path: &P, owner: Option<Uid>, group: Option<Gid>, flag: FchownatFlags, ) -> Result<()>699 pub 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 
to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*const c_char>720 fn 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]
execv<S: AsRef<CStr>>(path: &CStr, argv: &[S]) -> Result<Infallible>732 pub 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]
execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(path: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible>756 pub 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]
execvp<S: AsRef<CStr>>(filename: &CStr, args: &[S]) -> Result<Infallible>777 pub 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"))]
execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(filename: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible>797 pub 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]
fexecve<SA: AsRef<CStr> ,SE: AsRef<CStr>>(fd: RawFd, args: &[SA], env: &[SE]) -> Result<Infallible>825 pub 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]
execveat<SA: AsRef<CStr>,SE: AsRef<CStr>>(dirfd: RawFd, pathname: &CStr, args: &[SA], env: &[SE], flags: super::fcntl::AtFlags) -> Result<Infallible>848 pub 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"))]
daemon(nochdir: bool, noclose: bool) -> Result<()>894 pub 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"))]
sethostname<S: AsRef<OsStr>>(name: S) -> Result<()>907 pub 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 /// ```
gethostname(buffer: &mut [u8]) -> Result<&CStr>948 pub 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 /// ```
close(fd: RawFd) -> Result<()>984 pub 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)
read(fd: RawFd, buf: &mut [u8]) -> Result<usize>992 pub 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)
write(fd: RawFd, buf: &[u8]) -> Result<usize>1001 pub 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)]
1013 pub 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)
lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result<off_t>1045 pub 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"))]
lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result<libc::off64_t>1052 pub 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)
pipe() -> std::result::Result<(RawFd, RawFd), Error>1061 pub 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"))]
pipe2(flags: OFlag) -> Result<(RawFd, RawFd)>1094 pub 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")))]
truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()>1111 pub 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)
ftruncate(fd: RawFd, len: off_t) -> Result<()>1125 pub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> {
1126     Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop)
1127 }
1128 
isatty(fd: RawFd) -> Result<bool>1129 pub 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)]
1146 pub 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
linkat<P: ?Sized + NixPath>( olddirfd: Option<RawFd>, oldpath: &P, newdirfd: Option<RawFd>, newpath: &P, flag: LinkatFlags, ) -> Result<()>1165 pub 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)
unlink<P: ?Sized + NixPath>(path: &P) -> Result<()>1200 pub 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)]
1211 pub 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"))]
unlinkat<P: ?Sized + NixPath>( dirfd: Option<RawFd>, path: &P, flag: UnlinkatFlags, ) -> Result<()>1227 pub 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"))]
chroot<P: ?Sized + NixPath>(path: &P) -> Result<()>1248 pub 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 ))]
sync()1266 pub 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]
fsync(fd: RawFd) -> Result<()>1274 pub 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]
fdatasync(fd: RawFd) -> Result<()>1292 pub 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]
getuid() -> Uid1304 pub 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]
geteuid() -> Uid1314 pub 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]
getgid() -> Gid1324 pub 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]
getegid() -> Gid1334 pub 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]
seteuid(euid: Uid) -> Result<()>1342 pub 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]
setegid(egid: Gid) -> Result<()>1352 pub 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]
setuid(uid: Uid) -> Result<()>1362 pub 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]
setgid(gid: Gid) -> Result<()>1372 pub 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"))]
setfsuid(uid: Uid) -> Uid1384 pub 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"))]
setfsgid(gid: Gid) -> Gid1395 pub 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")))]
getgroups() -> Result<Vec<Gid>>1408 pub 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")))]
setgroups(groups: &[Gid]) -> Result<()>1488 pub 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")))]
getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>>1537 pub 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")))]
initgroups(user: &CStr, group: Gid) -> Result<()>1615 pub 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"))]
pause()1634 pub fn pause() {
1635     unsafe { libc::pause() };
1636 }
1637 
1638 pub 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.
set(secs: libc::c_uint) -> Option<libc::c_uint>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.
cancel() -> Option<libc::c_uint>1714     pub fn cancel() -> Option<libc::c_uint> {
1715         alarm(0)
1716     }
1717 
alarm(secs: libc::c_uint) -> Option<libc::c_uint>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]
sleep(seconds: c_uint) -> c_uint1731 pub fn sleep(seconds: c_uint) -> c_uint {
1732     unsafe { libc::sleep(seconds) }
1733 }
1734 
1735 #[cfg(not(target_os = "redox"))]
1736 pub 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)
enable<P: ?Sized + NixPath>(filename: &P) -> Result<()>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
disable() -> Result<()>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]
mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)>1785 pub 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]
1815 pub 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
fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>>1921 pub 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
pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Option<c_long>>1958 pub 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]
1995 pub 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
sysconf(var: SysconfVar) -> Result<Option<c_long>>2460 pub 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"))]
2477 mod pivot_root {
2478     use crate::{Result, NixPath};
2479     use crate::errno::Errno;
2480 
pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( new_root: &P1, put_old: &P2) -> Result<()>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"))]
2497 mod 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]
setresuid(ruid: Uid, euid: Uid, suid: Uid) -> Result<()>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]
setresgid(rgid: Gid, egid: Gid, sgid: Gid) -> Result<()>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"))]
2536 mod 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]
getresuid() -> Result<ResUid>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]
getresgid() -> Result<ResGid>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 
2596 libc_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)
access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()>2612 pub 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, PartialEq)]
2629 pub 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
2669 impl From<&libc::passwd> for User {
from(pw: &libc::passwd) -> User2670     fn from(pw: &libc::passwd) -> User {
2671         unsafe {
2672             User {
2673                 name: CStr::from_ptr((*pw).pw_name).to_string_lossy().into_owned(),
2674                 passwd: CString::new(CStr::from_ptr((*pw).pw_passwd).to_bytes()).unwrap(),
2675                 #[cfg(not(all(target_os = "android", target_pointer_width = "32")))]
2676                 gecos: CString::new(CStr::from_ptr((*pw).pw_gecos).to_bytes()).unwrap(),
2677                 dir: PathBuf::from(OsStr::from_bytes(CStr::from_ptr((*pw).pw_dir).to_bytes())),
2678                 shell: 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
2705 impl From<User> for libc::passwd {
from(u: User) -> Self2706     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
2757 impl User {
from_anything<F>(f: F) -> Result<Option<Self>> where F: Fn(*mut libc::passwd, *mut libc::c_char, libc::size_t, *mut *mut libc::passwd) -> libc::c_int2758     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     /// ```
from_uid(uid: Uid) -> Result<Option<Self>>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     /// ```
from_name(name: &str) -> Result<Option<Self>>2825     pub fn from_name(name: &str) -> Result<Option<Self>> {
2826         let name = CString::new(name).unwrap();
2827         User::from_anything(|pwd, cbuf, cap, res| {
2828             unsafe { libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res) }
2829         })
2830     }
2831 }
2832 
2833 /// Representation of a Group, based on `libc::group`
2834 #[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
2835 #[derive(Debug, Clone, PartialEq)]
2836 pub struct Group {
2837     /// Group name
2838     pub name: String,
2839     /// Group password
2840     pub passwd: CString,
2841     /// Group ID
2842     pub gid: Gid,
2843     /// List of Group members
2844     pub mem: Vec<String>
2845 }
2846 
2847 #[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
2848 impl From<&libc::group> for Group {
from(gr: &libc::group) -> Group2849     fn from(gr: &libc::group) -> Group {
2850         unsafe {
2851             Group {
2852                 name: CStr::from_ptr((*gr).gr_name).to_string_lossy().into_owned(),
2853                 passwd: CString::new(CStr::from_ptr((*gr).gr_passwd).to_bytes()).unwrap(),
2854                 gid: Gid::from_raw((*gr).gr_gid),
2855                 mem: Group::members((*gr).gr_mem)
2856             }
2857         }
2858     }
2859 }
2860 
2861 #[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
2862 impl Group {
members(mem: *mut *mut c_char) -> Vec<String>2863     unsafe fn members(mem: *mut *mut c_char) -> Vec<String> {
2864         let mut ret = Vec::new();
2865 
2866         for i in 0.. {
2867             let u = mem.offset(i);
2868             if (*u).is_null() {
2869                 break;
2870             } else {
2871                 let s = CStr::from_ptr(*u).to_string_lossy().into_owned();
2872                 ret.push(s);
2873             }
2874         }
2875 
2876         ret
2877     }
2878 
from_anything<F>(f: F) -> Result<Option<Self>> where F: Fn(*mut libc::group, *mut libc::c_char, libc::size_t, *mut *mut libc::group) -> libc::c_int2879     fn from_anything<F>(f: F) -> Result<Option<Self>>
2880     where
2881         F: Fn(*mut libc::group,
2882               *mut libc::c_char,
2883               libc::size_t,
2884               *mut *mut libc::group) -> libc::c_int
2885     {
2886         let buflimit = 1048576;
2887         let bufsize = match sysconf(SysconfVar::GETGR_R_SIZE_MAX) {
2888             Ok(Some(n)) => n as usize,
2889             Ok(None) | Err(_) => 16384,
2890         };
2891 
2892         let mut cbuf = Vec::with_capacity(bufsize);
2893         let mut grp = mem::MaybeUninit::<libc::group>::uninit();
2894         let mut res = ptr::null_mut();
2895 
2896         loop {
2897             let error = f(grp.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res);
2898             if error == 0 {
2899                 if res.is_null() {
2900                     return Ok(None);
2901                 } else {
2902                     let grp = unsafe { grp.assume_init() };
2903                     return Ok(Some(Group::from(&grp)));
2904                 }
2905             } else if Errno::last() == Errno::ERANGE {
2906                 // Trigger the internal buffer resizing logic.
2907                 reserve_double_buffer_size(&mut cbuf, buflimit)?;
2908             } else {
2909                 return Err(Errno::last());
2910             }
2911         }
2912     }
2913 
2914     /// Get a group by GID.
2915     ///
2916     /// Internally, this function calls
2917     /// [getgrgid_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
2918     ///
2919     /// # Examples
2920     ///
2921     // Disable this test on all OS except Linux as root group may not exist.
2922     #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")]
2923     #[cfg_attr(target_os = "linux", doc = " ```")]
2924     /// use nix::unistd::{Gid, Group};
2925     /// // Returns an Result<Option<Group>>, thus the double unwrap.
2926     /// let res = Group::from_gid(Gid::from_raw(0)).unwrap().unwrap();
2927     /// assert!(res.name == "root");
2928     /// ```
from_gid(gid: Gid) -> Result<Option<Self>>2929     pub fn from_gid(gid: Gid) -> Result<Option<Self>> {
2930         Group::from_anything(|grp, cbuf, cap, res| {
2931             unsafe { libc::getgrgid_r(gid.0, grp, cbuf, cap, res) }
2932         })
2933     }
2934 
2935     /// Get a group by name.
2936     ///
2937     /// Internally, this function calls
2938     /// [getgrnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
2939     ///
2940     /// # Examples
2941     ///
2942     // Disable this test on all OS except Linux as root group may not exist.
2943     #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")]
2944     #[cfg_attr(target_os = "linux", doc = " ```")]
2945     /// use nix::unistd::Group;
2946     /// // Returns an Result<Option<Group>>, thus the double unwrap.
2947     /// let res = Group::from_name("root").unwrap().unwrap();
2948     /// assert!(res.name == "root");
2949     /// ```
from_name(name: &str) -> Result<Option<Self>>2950     pub fn from_name(name: &str) -> Result<Option<Self>> {
2951         let name = CString::new(name).unwrap();
2952         Group::from_anything(|grp, cbuf, cap, res| {
2953             unsafe { libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res) }
2954         })
2955     }
2956 }
2957 
2958 /// Get the name of the terminal device that is open on file descriptor fd
2959 /// (see [`ttyname(3)`](https://man7.org/linux/man-pages/man3/ttyname.3.html)).
2960 #[cfg(not(target_os = "fuchsia"))]
ttyname(fd: RawFd) -> Result<PathBuf>2961 pub fn ttyname(fd: RawFd) -> Result<PathBuf> {
2962     const PATH_MAX: usize = libc::PATH_MAX as usize;
2963     let mut buf = vec![0_u8; PATH_MAX];
2964     let c_buf = buf.as_mut_ptr() as *mut libc::c_char;
2965 
2966     let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) };
2967     if ret != 0 {
2968         return Err(Errno::from_i32(ret));
2969     }
2970 
2971     let nul = buf.iter().position(|c| *c == b'\0').unwrap();
2972     buf.truncate(nul);
2973     Ok(OsString::from_vec(buf).into())
2974 }
2975 
2976 /// Get the effective user ID and group ID associated with a Unix domain socket.
2977 ///
2978 /// See also [getpeereid(3)](https://www.freebsd.org/cgi/man.cgi?query=getpeereid)
2979 #[cfg(any(
2980     target_os = "macos",
2981     target_os = "ios",
2982     target_os = "freebsd",
2983     target_os = "openbsd",
2984     target_os = "netbsd",
2985     target_os = "dragonfly",
2986 ))]
getpeereid(fd: RawFd) -> Result<(Uid, Gid)>2987 pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> {
2988     let mut uid = 1;
2989     let mut gid = 1;
2990 
2991     let ret = unsafe { libc::getpeereid(fd, &mut uid, &mut gid) };
2992 
2993     Errno::result(ret).map(|_| (Uid(uid), Gid(gid)))
2994 }
2995