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