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