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