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