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