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