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