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