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