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