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