diff options
Diffstat (limited to 'src/unistd.rs')
-rw-r--r-- | src/unistd.rs | 1313 |
1 files changed, 493 insertions, 820 deletions
diff --git a/src/unistd.rs b/src/unistd.rs index bb9f1c1..4502766 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -1,22 +1,29 @@ //! Safe wrappers around functions found in libc "unistd.h" header -use crate::errno::{self, Errno}; +use crate::errno::Errno; + +#[cfg(any( + all(feature = "fs", not(target_os = "redox")), + all(feature = "process", linux_android) +))] +use crate::fcntl::at_rawfd; #[cfg(not(target_os = "redox"))] #[cfg(feature = "fs")] -use crate::fcntl::{at_rawfd, AtFlags}; +use crate::fcntl::AtFlags; + #[cfg(feature = "fs")] -use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag}; -#[cfg(all( - feature = "fs", - any( - target_os = "openbsd", - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios" - ) +#[cfg(any( + linux_android, + freebsdlike, + solarish, + netbsdlike, + target_os = "emscripten", + target_os = "fuchsia", + target_os = "hurd", + target_os = "redox", ))] +use crate::fcntl::OFlag; +#[cfg(all(feature = "fs", bsd))] use crate::sys::stat::FileFlag; #[cfg(feature = "fs")] use crate::sys::stat::Mode; @@ -24,43 +31,27 @@ use crate::{Error, NixPath, Result}; #[cfg(not(target_os = "redox"))] use cfg_if::cfg_if; use libc::{ - self, c_char, c_int, c_long, c_uint, c_void, gid_t, mode_t, off_t, pid_t, - size_t, uid_t, PATH_MAX, + c_char, c_int, c_long, c_uint, gid_t, mode_t, off_t, pid_t, size_t, uid_t, }; use std::convert::Infallible; -use std::ffi::{CStr, OsString}; #[cfg(not(target_os = "redox"))] -use std::ffi::{CString, OsStr}; -#[cfg(not(target_os = "redox"))] -use std::os::unix::ffi::OsStrExt; -use std::os::unix::ffi::OsStringExt; -use std::os::unix::io::RawFd; -use std::os::unix::io::{AsFd, AsRawFd}; +use std::ffi::CString; +use std::ffi::{CStr, OsStr, OsString}; +use std::os::unix::ffi::{OsStrExt, OsStringExt}; +use std::os::unix::io::{AsFd, AsRawFd, OwnedFd, RawFd}; use std::path::PathBuf; use std::{fmt, mem, ptr}; feature! { #![feature = "fs"] - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] pub use self::pivot_root::*; } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] +#[cfg(any(freebsdlike, linux_android, target_os = "openbsd"))] pub use self::setres::*; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] +#[cfg(any(freebsdlike, linux_android, target_os = "openbsd"))] pub use self::getres::*; feature! { @@ -225,7 +216,12 @@ impl fmt::Display for Pid { /// you are now executing in the parent process or in the child. #[derive(Clone, Copy, Debug)] pub enum ForkResult { - Parent { child: Pid }, + /// This is the parent process of the fork. + Parent { + /// The PID of the fork's child process + child: Pid + }, + /// This is the child process of the fork. Child, } @@ -260,7 +256,7 @@ impl ForkResult { /// } /// Ok(ForkResult::Child) => { /// // Unsafe to use `println!` (or `unwrap`) here. See Safety. -/// write(libc::STDOUT_FILENO, "I'm a new child process\n".as_bytes()).ok(); +/// write(std::io::stdout(), "I'm a new child process\n".as_bytes()).ok(); /// unsafe { libc::_exit(0) }; /// } /// Err(_) => println!("Fork failed"), @@ -290,7 +286,7 @@ impl ForkResult { #[inline] pub unsafe fn fork() -> Result<ForkResult> { use self::ForkResult::*; - let res = libc::fork(); + let res = unsafe { libc::fork() }; Errno::result(res).map(|res| match res { 0 => Child, @@ -332,6 +328,9 @@ pub fn setpgid(pid: Pid, pgid: Pid) -> Result<()> { let res = unsafe { libc::setpgid(pid.into(), pgid.into()) }; Errno::result(res).map(drop) } +/// Get process group +/// +/// See Also [`getpgid`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgid.html) #[inline] pub fn getpgid(pid: Option<Pid>) -> Result<Pid> { let res = unsafe { libc::getpgid(pid.unwrap_or(Pid(0)).into()) }; @@ -366,8 +365,8 @@ feature! { /// Get the group process id (GPID) of the foreground process group on the /// terminal associated to file descriptor (FD). #[inline] -pub fn tcgetpgrp(fd: c_int) -> Result<Pid> { - let res = unsafe { libc::tcgetpgrp(fd) }; +pub fn tcgetpgrp<F: AsFd>(fd: F) -> Result<Pid> { + let res = unsafe { libc::tcgetpgrp(fd.as_fd().as_raw_fd()) }; Errno::result(res).map(Pid) } /// Set the terminal foreground process group (see @@ -376,8 +375,8 @@ pub fn tcgetpgrp(fd: c_int) -> Result<Pid> { /// Get the group process id (PGID) to the foreground process group on the /// terminal associated to file descriptor (FD). #[inline] -pub fn tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()> { - let res = unsafe { libc::tcsetpgrp(fd, pgrp.into()) }; +pub fn tcsetpgrp<F: AsFd>(fd: F, pgrp: Pid) -> Result<()> { + let res = unsafe { libc::tcsetpgrp(fd.as_fd().as_raw_fd(), pgrp.into()) }; Errno::result(res).map(drop) } } @@ -404,7 +403,7 @@ pub fn getpgrp() -> Pid { /// /// No error handling is required as a thread id should always exist for any /// process, even if threads are not being used. -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] #[inline] pub fn gettid() -> Pid { Pid(unsafe { libc::syscall(libc::SYS_gettid) as pid_t }) @@ -444,30 +443,22 @@ pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd> { } /// Create a new copy of the specified file descriptor using the specified fd -/// and flags (see [dup(2)](https://man7.org/linux/man-pages/man2/dup.2.html)). +/// and flags (see [`dup(2)`](https://man7.org/linux/man-pages/man2/dup.2.html)). /// /// This function behaves similar to `dup2()` but allows for flags to be /// specified. +#[cfg(any( + netbsdlike, + solarish, + target_os = "freebsd", + target_os = "fuchsia", + target_os = "hurd", + target_os = "linux" +))] pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> { - dup3_polyfill(oldfd, newfd, flags) -} - -#[inline] -fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> { - if oldfd == newfd { - return Err(Errno::EINVAL); - } + let res = unsafe { libc::dup3(oldfd, newfd, flags.bits()) }; - let fd = dup2(oldfd, newfd)?; - - if flags.contains(OFlag::O_CLOEXEC) { - if let Err(e) = fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC)) { - let _ = close(fd); - return Err(e); - } - } - - Ok(fd) + Errno::result(res) } /// Change the current working directory of the calling process (see @@ -583,8 +574,7 @@ pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { // mkfifoat is not implemented in OSX or android #[inline] #[cfg(not(any( - target_os = "macos", - target_os = "ios", + apple_targets, target_os = "haiku", target_os = "android", target_os = "redox" @@ -664,17 +654,17 @@ feature! { /// ``` #[inline] pub fn getcwd() -> Result<PathBuf> { - let mut buf = Vec::with_capacity(512); + let mut buf = Vec::<u8>::with_capacity(512); loop { unsafe { - let ptr = buf.as_mut_ptr() as *mut c_char; + let ptr = buf.as_mut_ptr().cast(); // The buffer must be large enough to store the absolute pathname plus // a terminating null byte, or else null is returned. // To safely handle this we start with a reasonable size (512 bytes) // and double the buffer size upon every error if !libc::getcwd(ptr, buf.capacity()).is_null() { - let len = CStr::from_ptr(buf.as_ptr() as *const c_char) + let len = CStr::from_ptr(buf.as_ptr().cast()) .to_bytes() .len(); buf.set_len(len); @@ -688,8 +678,13 @@ pub fn getcwd() -> Result<PathBuf> { } } + #[cfg(not(target_os = "hurd"))] + const PATH_MAX: usize = libc::PATH_MAX as usize; + #[cfg(target_os = "hurd")] + const PATH_MAX: usize = 1024; // Hurd does not define a hard limit, so try a guess first + // Trigger the internal buffer resizing logic. - reserve_double_buffer_size(&mut buf, PATH_MAX as usize)?; + reserve_double_buffer_size(&mut buf, PATH_MAX)?; } } } @@ -749,11 +744,19 @@ pub fn fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<()> { Errno::result(res).map(drop) } -/// Flags for `fchownat` function. -#[derive(Clone, Copy, Debug)] -pub enum FchownatFlags { - FollowSymlink, - NoFollowSymlink, +// Just a wrapper around `AtFlags` so that we can help our users migrate. +#[allow(missing_docs)] +#[cfg(not(target_os = "redox"))] +pub type FchownatFlags = AtFlags; +#[allow(missing_docs)] +#[cfg(not(target_os = "redox"))] +impl FchownatFlags { + #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")] + #[allow(non_upper_case_globals)] + pub const FollowSymlink: FchownatFlags = FchownatFlags::empty(); + #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")] + #[allow(non_upper_case_globals)] + pub const NoFollowSymlink: FchownatFlags = FchownatFlags::AT_SYMLINK_NOFOLLOW; } /// Change the ownership of the file at `path` to be owned by the specified @@ -767,10 +770,10 @@ pub enum FchownatFlags { /// with the file descriptor `dirfd` or the current working directory /// if `dirfd` is `None`. /// -/// If `flag` is `FchownatFlags::NoFollowSymlink` and `path` names a symbolic link, +/// If `flag` is `AtFlags::AT_SYMLINK_NOFOLLOW` and `path` names a symbolic link, /// then the mode of the symbolic link is changed. /// -/// `fchownat(None, path, owner, group, FchownatFlags::NoFollowSymlink)` is identical to +/// `fchownat(None, path, owner, group, AtFlags::AT_SYMLINK_NOFOLLOW)` is identical to /// a call `libc::lchown(path, owner, group)`. That's why `lchown` is unimplemented in /// the `nix` crate. /// @@ -783,12 +786,8 @@ pub fn fchownat<P: ?Sized + NixPath>( path: &P, owner: Option<Uid>, group: Option<Gid>, - flag: FchownatFlags, + flag: AtFlags, ) -> Result<()> { - let atflag = match flag { - FchownatFlags::FollowSymlink => AtFlags::empty(), - FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, - }; let res = path.with_nix_path(|cstr| unsafe { let (uid, gid) = chown_raw_ids(owner, group); libc::fchownat( @@ -796,7 +795,7 @@ pub fn fchownat<P: ?Sized + NixPath>( cstr.as_ptr(), uid, gid, - atflag.bits() as libc::c_int, + flag.bits() ) })?; @@ -883,7 +882,7 @@ pub fn execvp<S: AsRef<CStr>>( /// This functions like a combination of `execvp(2)` and `execve(2)` to pass an /// environment and have a search path. See these two for additional /// information. -#[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))] +#[cfg(any(target_os = "haiku", target_os = "hurd", target_os = "linux", target_os = "openbsd"))] pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>( filename: &CStr, args: &[SA], @@ -909,12 +908,7 @@ pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>( /// /// This function is similar to `execve`, except that the program to be executed /// is referenced as a file descriptor instead of a path. -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd" -))] +#[cfg(any(linux_android, freebsdlike, target_os = "hurd"))] #[inline] pub fn fexecve<SA: AsRef<CStr>, SE: AsRef<CStr>>( fd: RawFd, @@ -939,15 +933,16 @@ pub fn fexecve<SA: AsRef<CStr>, SE: AsRef<CStr>>( /// /// This function is similar to `execve`, except that the program to be executed /// is referenced as a file descriptor to the base directory plus a path. -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[inline] pub fn execveat<SA: AsRef<CStr>, SE: AsRef<CStr>>( - dirfd: RawFd, + dirfd: Option<RawFd>, pathname: &CStr, args: &[SA], env: &[SE], flags: super::fcntl::AtFlags, ) -> Result<Infallible> { + let dirfd = at_rawfd(dirfd); let args_p = to_exec_array(args); let env_p = to_exec_array(env); @@ -991,14 +986,10 @@ pub fn execveat<SA: AsRef<CStr>, SE: AsRef<CStr>>( /// * `noclose = false`: The process' stdin, stdout, and stderr will point to /// `/dev/null` after daemonizing. #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" + linux_android, + freebsdlike, + solarish, + netbsdlike ))] pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> { let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) }; @@ -1020,19 +1011,16 @@ feature! { pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> { // Handle some differences in type of the len arg across platforms. cfg_if! { - if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "aix", - target_os = "solaris", ))] { + if #[cfg(any(freebsdlike, + solarish, + apple_targets, + target_os = "aix"))] { type sethostname_len_t = c_int; } else { type sethostname_len_t = size_t; } } - let ptr = name.as_ref().as_bytes().as_ptr() as *const c_char; + let ptr = name.as_ref().as_bytes().as_ptr().cast(); let len = name.as_ref().len() as sethostname_len_t; let res = unsafe { libc::sethostname(ptr, len) }; @@ -1056,14 +1044,14 @@ pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> { pub fn gethostname() -> Result<OsString> { // The capacity is the max length of a hostname plus the NUL terminator. let mut buffer: Vec<u8> = Vec::with_capacity(256); - let ptr = buffer.as_mut_ptr() as *mut c_char; + let ptr = buffer.as_mut_ptr().cast(); let len = buffer.capacity() as size_t; let res = unsafe { libc::gethostname(ptr, len) }; Errno::result(res).map(|_| { unsafe { buffer.as_mut_ptr().wrapping_add(len - 1).write(0); // ensure always null-terminated - let len = CStr::from_ptr(buffer.as_ptr() as *const c_char).len(); + let len = CStr::from_ptr(buffer.as_ptr().cast()).len(); buffer.set_len(len); } OsString::from_vec(buffer) @@ -1105,9 +1093,8 @@ pub fn close(fd: RawFd) -> Result<()> { /// /// See also [read(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html) pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> { - let res = unsafe { - libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) - }; + let res = + unsafe { libc::read(fd, buf.as_mut_ptr().cast(), buf.len() as size_t) }; Errno::result(res).map(|r| r as usize) } @@ -1115,9 +1102,13 @@ pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> { /// Write to a raw file descriptor. /// /// See also [write(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html) -pub fn write(fd: RawFd, buf: &[u8]) -> Result<usize> { +pub fn write<Fd: AsFd>(fd: Fd, buf: &[u8]) -> Result<usize> { let res = unsafe { - libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) + libc::write( + fd.as_fd().as_raw_fd(), + buf.as_ptr().cast(), + buf.len() as size_t, + ) }; Errno::result(res).map(|r| r as usize) @@ -1143,11 +1134,9 @@ pub enum Whence { /// equal to offset that contains some data. If offset points to /// some data, then the file offset is set to offset. #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", + freebsdlike, + solarish, target_os = "linux", - target_os = "solaris" ))] SeekData = libc::SEEK_DATA, /// Specify an offset relative to the next hole in the file greater than @@ -1156,11 +1145,9 @@ pub enum Whence { /// then the file offset should be adjusted to the end of the file (i.e., there /// is an implicit hole at the end of any file). #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", + freebsdlike, + solarish, target_os = "linux", - target_os = "solaris" ))] SeekHole = libc::SEEK_HOLE, } @@ -1174,7 +1161,11 @@ pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result<off_t> { Errno::result(res).map(|r| r as off_t) } -#[cfg(any(target_os = "linux", target_os = "android"))] +/// Move the read/write file offset. +/// +/// Unlike [`lseek`], it takes a 64-bit argument even on platforms where [`libc::off_t`] is +/// 32 bits. +#[cfg(linux_android)] pub fn lseek64( fd: RawFd, offset: libc::off64_t, @@ -1189,14 +1180,15 @@ pub fn lseek64( /// Create an interprocess channel. /// /// See also [pipe(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html) -pub fn pipe() -> std::result::Result<(RawFd, RawFd), Error> { - let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); +pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error> { + let mut fds = mem::MaybeUninit::<[OwnedFd; 2]>::uninit(); - let res = unsafe { libc::pipe(fds.as_mut_ptr() as *mut c_int) }; + let res = unsafe { libc::pipe(fds.as_mut_ptr().cast()) }; Error::result(res)?; - unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) } + let [read, write] = unsafe { fds.assume_init() }; + Ok((read, write)) } feature! { @@ -1219,26 +1211,24 @@ feature! { /// /// See also [pipe(2)](https://man7.org/linux/man-pages/man2/pipe.2.html) #[cfg(any( - target_os = "android", - target_os = "dragonfly", + linux_android, + freebsdlike, + solarish, target_os = "emscripten", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", + target_os = "hurd", target_os = "redox", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" + netbsdlike, ))] -pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { - let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit(); +pub fn pipe2(flags: OFlag) -> Result<(OwnedFd, OwnedFd)> { + let mut fds = mem::MaybeUninit::<[OwnedFd; 2]>::uninit(); let res = - unsafe { libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits()) }; + unsafe { libc::pipe2(fds.as_mut_ptr().cast(), flags.bits()) }; Errno::result(res)?; - unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) } + let [read, write] = unsafe { fds.assume_init() }; + Ok((read, write)) } /// Truncate a file to a specified length @@ -1261,6 +1251,7 @@ pub fn ftruncate<Fd: AsFd>(fd: Fd, len: off_t) -> Result<()> { Errno::result(unsafe { libc::ftruncate(fd.as_fd().as_raw_fd(), len) }).map(drop) } +/// Determines if the file descriptor refers to a valid terminal type device. pub fn isatty(fd: RawFd) -> Result<bool> { unsafe { // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so @@ -1276,11 +1267,18 @@ pub fn isatty(fd: RawFd) -> Result<bool> { } } -/// Flags for `linkat` function. -#[derive(Clone, Copy, Debug)] -pub enum LinkatFlags { - SymlinkFollow, - NoSymlinkFollow, +#[allow(missing_docs)] +#[cfg(not(target_os = "redox"))] +pub type LinkatFlags = AtFlags; +#[allow(missing_docs)] +#[cfg(not(target_os = "redox"))] +impl LinkatFlags { + #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")] + #[allow(non_upper_case_globals)] + pub const SymlinkFollow: LinkatFlags = LinkatFlags::AT_SYMLINK_FOLLOW; + #[deprecated(since = "0.28.0", note = "The variant is deprecated, please use `AtFlags` instead")] + #[allow(non_upper_case_globals)] + pub const NoSymlinkFollow: LinkatFlags = LinkatFlags::empty(); } /// Link one file to another file @@ -1288,7 +1286,7 @@ pub enum LinkatFlags { /// Creates a new link (directory entry) at `newpath` for the existing file at `oldpath`. In the /// case of a relative `oldpath`, the path is interpreted relative to the directory associated /// with file descriptor `olddirfd` instead of the current working directory and similiarly for -/// `newpath` and file descriptor `newdirfd`. In case `flag` is LinkatFlags::SymlinkFollow and +/// `newpath` and file descriptor `newdirfd`. In case `flag` is `AtFlags::AT_SYMLINK_FOLLOW` and /// `oldpath` names a symoblic link, a new link for the target of the symbolic link is created. /// If either `olddirfd` or `newdirfd` is `None`, `AT_FDCWD` is used respectively where `oldpath` /// and/or `newpath` is then interpreted relative to the current working directory of the calling @@ -1302,13 +1300,8 @@ pub fn linkat<P: ?Sized + NixPath>( oldpath: &P, newdirfd: Option<RawFd>, newpath: &P, - flag: LinkatFlags, + flag: AtFlags, ) -> Result<()> { - let atflag = match flag { - LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW, - LinkatFlags::NoSymlinkFollow => AtFlags::empty(), - }; - let res = oldpath.with_nix_path(|oldcstr| { newpath.with_nix_path(|newcstr| unsafe { libc::linkat( @@ -1316,7 +1309,7 @@ pub fn linkat<P: ?Sized + NixPath>( oldcstr.as_ptr(), at_rawfd(newdirfd), newcstr.as_ptr(), - atflag.bits() as libc::c_int, + flag.bits(), ) }) })??; @@ -1335,7 +1328,9 @@ pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> { /// Flags for `unlinkat` function. #[derive(Clone, Copy, Debug)] pub enum UnlinkatFlags { + /// Remove the directory entry as a directory, not a normal file RemoveDir, + /// Remove the directory entry as a normal file, not a directory NoRemoveDir, } @@ -1369,6 +1364,7 @@ pub fn unlinkat<P: ?Sized + NixPath>( Errno::result(res).map(drop) } +/// Change a process's root directory #[inline] #[cfg(not(target_os = "fuchsia"))] pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> { @@ -1381,13 +1377,7 @@ pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> { /// Commit filesystem caches to disk /// /// See also [sync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html) -#[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd" -))] +#[cfg(any(freebsdlike, linux_android, netbsdlike))] pub fn sync() { unsafe { libc::sync() }; } @@ -1396,7 +1386,7 @@ pub fn sync() { /// descriptor `fd` to disk /// /// See also [syncfs(2)](https://man7.org/linux/man-pages/man2/sync.2.html) -#[cfg(target_os = "linux")] +#[cfg(linux_android)] pub fn syncfs(fd: RawFd) -> Result<()> { let res = unsafe { libc::syncfs(fd) }; @@ -1418,15 +1408,12 @@ pub fn fsync(fd: RawFd) -> Result<()> { /// See also /// [fdatasync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html) #[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "emscripten", + linux_android, + solarish, + netbsdlike, target_os = "freebsd", + target_os = "emscripten", target_os = "fuchsia", - target_os = "netbsd", - target_os = "openbsd", - target_os = "illumos", - target_os = "solaris" ))] #[inline] pub fn fdatasync(fd: RawFd) -> Result<()> { @@ -1527,7 +1514,7 @@ feature! { /// ID of the caller. /// /// See also [setfsuid(2)](https://man7.org/linux/man-pages/man2/setfsuid.2.html) -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] pub fn setfsuid(uid: Uid) -> Uid { let prev_fsuid = unsafe { libc::setfsuid(uid.into()) }; Uid::from_raw(prev_fsuid as uid_t) @@ -1538,7 +1525,7 @@ pub fn setfsuid(uid: Uid) -> Uid { /// ID of the caller. /// /// See also [setfsgid(2)](https://man7.org/linux/man-pages/man2/setfsgid.2.html) -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(linux_android)] pub fn setfsgid(gid: Gid) -> Gid { let prev_fsgid = unsafe { libc::setfsgid(gid.into()) }; Gid::from_raw(prev_fsgid as gid_t) @@ -1555,14 +1542,14 @@ feature! { /// **Note:** This function is not available for Apple platforms. On those /// platforms, checking group membership should be achieved via communication /// with the `opendirectoryd` service. -#[cfg(not(any(target_os = "ios", target_os = "macos")))] +#[cfg(not(apple_targets))] pub fn getgroups() -> Result<Vec<Gid>> { // First get the maximum number of groups. The value returned // shall always be greater than or equal to one and less than or // equal to the value of {NGROUPS_MAX} + 1. let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) { Ok(Some(n)) => (n + 1) as usize, - Ok(None) | Err(_) => <usize>::max_value(), + Ok(None) | Err(_) => usize::MAX, }; // Next, get the number of groups so we can size our Vec @@ -1588,7 +1575,7 @@ pub fn getgroups() -> Result<Vec<Gid>> { let ngroups = unsafe { libc::getgroups( groups.capacity() as c_int, - groups.as_mut_ptr() as *mut gid_t, + groups.as_mut_ptr().cast(), ) }; @@ -1640,22 +1627,15 @@ pub fn getgroups() -> Result<Vec<Gid>> { /// # try_main().unwrap(); /// ``` #[cfg(not(any( - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "redox", target_os = "haiku" )))] pub fn setgroups(groups: &[Gid]) -> Result<()> { cfg_if! { - if #[cfg(any(target_os = "aix", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris"))] { + if #[cfg(any(bsd, + solarish, + target_os = "aix"))] { type setgroups_ngroups_t = c_int; } else { type setgroups_ngroups_t = size_t; @@ -1667,7 +1647,7 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> { let res = unsafe { libc::setgroups( groups.len() as setgroups_ngroups_t, - groups.as_ptr() as *const gid_t, + groups.as_ptr().cast(), ) }; @@ -1696,20 +1676,19 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> { /// will only ever return the complete list or else an error. #[cfg(not(any( target_os = "aix", - target_os = "illumos", - target_os = "ios", - target_os = "macos", + solarish, + apple_targets, target_os = "redox" )))] pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) { Ok(Some(n)) => n as c_int, - Ok(None) | Err(_) => <c_int>::max_value(), + Ok(None) | Err(_) => c_int::MAX, }; use std::cmp::min; let mut groups = Vec::<Gid>::with_capacity(min(ngroups_max, 8) as usize); cfg_if! { - if #[cfg(any(target_os = "ios", target_os = "macos"))] { + if #[cfg(apple_targets)] { type getgrouplist_group_t = c_int; } else { type getgrouplist_group_t = gid_t; @@ -1722,7 +1701,7 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { libc::getgrouplist( user.as_ptr(), gid as getgrouplist_group_t, - groups.as_mut_ptr() as *mut getgrouplist_group_t, + groups.as_mut_ptr().cast(), &mut ngroups, ) }; @@ -1781,14 +1760,13 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> { /// # try_main().unwrap(); /// ``` #[cfg(not(any( - target_os = "ios", - target_os = "macos", + apple_targets, target_os = "redox", target_os = "haiku" )))] pub fn initgroups(user: &CStr, group: Gid) -> Result<()> { cfg_if! { - if #[cfg(any(target_os = "ios", target_os = "macos"))] { + if #[cfg(apple_targets)] { type initgroups_group_t = c_int; } else { type initgroups_group_t = gid_t; @@ -1915,6 +1893,7 @@ pub fn sleep(seconds: c_uint) -> c_uint { feature! { #![feature = "acct"] +/// Process accounting #[cfg(not(any(target_os = "redox", target_os = "haiku")))] pub mod acct { use crate::errno::Errno; @@ -1970,7 +1949,7 @@ feature! { pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> { let mut path = template.with_nix_path(|path| path.to_bytes_with_nul().to_owned())?; - let p = path.as_mut_ptr() as *mut _; + let p = path.as_mut_ptr().cast(); let fd = unsafe { libc::mkstemp(p) }; let last = path.pop(); // drop the trailing nul debug_assert!(last == Some(b'\0')); @@ -1983,6 +1962,38 @@ pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> { feature! { #![all(feature = "fs", feature = "feature")] +/// Creates a directory which persists even after process termination +/// +/// * `template`: a path whose rightmost characters contain some number of X, e.g. `/tmp/tmpdir_XXXXXX` +/// * returns: filename +/// +/// Err is returned either if no temporary filename could be created or the template had insufficient X +/// +/// See also [mkstemp(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdtemp.html) +/// +/// ``` +/// use nix::unistd; +/// +/// match unistd::mkdtemp("/tmp/tempdir_XXXXXX") { +/// Ok(_path) => { +/// // do something with directory +/// } +/// Err(e) => panic!("mkdtemp failed: {}", e) +/// }; +/// ``` +pub fn mkdtemp<P: ?Sized + NixPath>(template: &P) -> Result<PathBuf> { + let mut path = template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})?; + let p = path.as_mut_ptr() as *mut _; + let p = unsafe { libc::mkdtemp(p) }; + if p.is_null() { + return Err(Errno::last()); + } + let last = path.pop(); // drop the trailing nul + debug_assert!(last == Some(b'\0')); + let pathname = OsString::from_vec(path); + Ok(PathBuf::from(pathname)) +} + /// Variable names for `pathconf` /// /// Nix uses the same naming convention for these variables as the @@ -2004,16 +2015,13 @@ feature! { #[non_exhaustive] pub enum PathconfVar { #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", + freebsdlike, + netbsdlike, target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", target_os = "redox" ))] /// Minimum number of bits needed to represent, as a signed integer value, /// the maximum size of a regular file allowed in the specified directory. - #[cfg_attr(docsrs, doc(cfg(all())))] FILESIZEBITS = libc::_PC_FILESIZEBITS, /// Maximum number of links to a single file. LINK_MAX = libc::_PC_LINK_MAX, @@ -2035,86 +2043,62 @@ pub enum PathconfVar { /// a pipe. PIPE_BUF = libc::_PC_PIPE_BUF, #[cfg(any( - target_os = "android", + linux_android, + solarish, + netbsdlike, target_os = "dragonfly", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", target_os = "redox", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Symbolic links can be created. POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", + linux_android, + freebsdlike, target_os = "openbsd", target_os = "redox" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Minimum number of bytes of storage actually allocated for any portion of /// a file. POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", + freebsdlike, + linux_android, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Recommended increment for file transfer sizes between the /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values. POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", + linux_android, + freebsdlike, target_os = "openbsd", target_os = "redox" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Maximum recommended file transfer size. POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", + linux_android, + freebsdlike, target_os = "openbsd", target_os = "redox" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Minimum recommended file transfer size. POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", + linux_android, + freebsdlike, target_os = "openbsd", target_os = "redox" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Recommended file transfer buffer alignment. POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", + linux_android, + freebsdlike, + solarish, + netbsdlike, target_os = "redox", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Maximum number of bytes in a symbolic link. SYMLINK_MAX = libc::_PC_SYMLINK_MAX, /// The use of `chown` and `fchown` is restricted to a process with @@ -2128,50 +2112,36 @@ pub enum PathconfVar { /// disable terminal special character handling. _POSIX_VDISABLE = libc::_PC_VDISABLE, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", + linux_android, + freebsdlike, + solarish, target_os = "openbsd", target_os = "redox", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Asynchronous input or output operations may be performed for the /// associated file. _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", + linux_android, + freebsdlike, + solarish, target_os = "openbsd", target_os = "redox", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Prioritized input or output operations may be performed for the /// associated file. _POSIX_PRIO_IO = libc::_PC_PRIO_IO, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", + linux_android, + freebsdlike, + solarish, + netbsdlike, target_os = "redox", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Synchronized input or output operations may be performed for the /// associated file. _POSIX_SYNC_IO = libc::_PC_SYNC_IO, #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The resolution in nanoseconds for all file timestamps. _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION, } @@ -2192,13 +2162,13 @@ pub enum PathconfVar { /// - `Ok(None)`: the variable has no limit (for limit variables) or is /// unsupported (for option variables) /// - `Err(x)`: an error occurred -pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>> { +pub fn fpathconf<F: AsFd>(fd: F, var: PathconfVar) -> Result<Option<c_long>> { let raw = unsafe { Errno::clear(); - libc::fpathconf(fd, var as c_int) + libc::fpathconf(fd.as_fd().as_raw_fd(), var as c_int) }; if raw == -1 { - if errno::errno() == 0 { + if Errno::last_raw() == 0 { Ok(None) } else { Err(Errno::last()) @@ -2238,7 +2208,7 @@ pub fn pathconf<P: ?Sized + NixPath>( libc::pathconf(cstr.as_ptr(), var as c_int) })?; if raw == -1 { - if errno::errno() == 0 { + if Errno::last_raw() == 0 { Ok(None) } else { Err(Errno::last()) @@ -2275,23 +2245,17 @@ pub enum SysconfVar { /// Maximum number of I/O operations in a single list I/O call supported by /// the implementation. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] AIO_LISTIO_MAX = libc::_SC_AIO_LISTIO_MAX, /// Maximum number of outstanding asynchronous I/O operations supported by /// the implementation. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] AIO_MAX = libc::_SC_AIO_MAX, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The maximum amount by which a process can decrease its asynchronous I/O /// priority level from its own scheduling priority. AIO_PRIO_DELTA_MAX = libc::_SC_AIO_PRIO_DELTA_MAX, @@ -2299,68 +2263,47 @@ pub enum SysconfVar { ARG_MAX = libc::_SC_ARG_MAX, /// Maximum number of functions that may be registered with `atexit`. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] ATEXIT_MAX = libc::_SC_ATEXIT_MAX, /// Maximum obase values allowed by the bc utility. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] BC_BASE_MAX = libc::_SC_BC_BASE_MAX, /// Maximum number of elements permitted in an array by the bc utility. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] BC_DIM_MAX = libc::_SC_BC_DIM_MAX, /// Maximum scale value allowed by the bc utility. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] BC_SCALE_MAX = libc::_SC_BC_SCALE_MAX, /// Maximum length of a string constant accepted by the bc utility. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] BC_STRING_MAX = libc::_SC_BC_STRING_MAX, /// Maximum number of simultaneous processes per real user ID. CHILD_MAX = libc::_SC_CHILD_MAX, - // The number of clock ticks per second. + /// The frequency of the statistics clock in ticks per second. CLK_TCK = libc::_SC_CLK_TCK, /// Maximum number of weights that can be assigned to an entry of the /// LC_COLLATE order keyword in the locale definition file #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] COLL_WEIGHTS_MAX = libc::_SC_COLL_WEIGHTS_MAX, /// Maximum number of timer expiration overruns. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] DELAYTIMER_MAX = libc::_SC_DELAYTIMER_MAX, /// Maximum number of expressions that can be nested within parentheses by /// the expr utility. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, solarish, target_os = "linux"))] /// Maximum length of a host name (not including the terminating null) as /// returned from the `gethostname` function HOST_NAME_MAX = libc::_SC_HOST_NAME_MAX, /// Maximum number of iovec structures that one process has available for /// use with `readv` or `writev`. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] IOV_MAX = libc::_SC_IOV_MAX, /// Unless otherwise noted, the maximum length, in bytes, of a utility's /// input line (either standard input or another file), when the utility is /// described as processing text files. The length includes room for the /// trailing newline. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] LINE_MAX = libc::_SC_LINE_MAX, /// Maximum length of a login name. #[cfg(not(target_os = "haiku"))] @@ -2369,308 +2312,176 @@ pub enum SysconfVar { NGROUPS_MAX = libc::_SC_NGROUPS_MAX, /// Initial size of `getgrgid_r` and `getgrnam_r` data buffers #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX, /// Initial size of `getpwuid_r` and `getpwnam_r` data buffers #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX, /// The maximum number of open message queue descriptors a process may hold. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX, /// The maximum number of message priorities supported by the implementation. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX, /// A value one greater than the maximum value that the system may assign to /// a newly-created file descriptor. OPEN_MAX = libc::_SC_OPEN_MAX, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Advisory Information option. _POSIX_ADVISORY_INFO = libc::_SC_ADVISORY_INFO, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, solarish, target_os = "linux"))] /// The implementation supports barriers. _POSIX_BARRIERS = libc::_SC_BARRIERS, /// The implementation supports asynchronous input and output. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, solarish, target_os = "linux"))] /// The implementation supports clock selection. _POSIX_CLOCK_SELECTION = libc::_SC_CLOCK_SELECTION, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, solarish, target_os = "linux"))] /// The implementation supports the Process CPU-Time Clocks option. _POSIX_CPUTIME = libc::_SC_CPUTIME, /// The implementation supports the File Synchronization option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_FSYNC = libc::_SC_FSYNC, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", + freebsdlike, + apple_targets, + solarish, target_os = "linux", - target_os = "macos", target_os = "openbsd", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the IPv6 option. _POSIX_IPV6 = libc::_SC_IPV6, /// The implementation supports job control. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL, /// The implementation supports memory mapped Files. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES, /// The implementation supports the Process Memory Locking option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MEMLOCK = libc::_SC_MEMLOCK, /// The implementation supports the Range Memory Locking option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE, /// The implementation supports memory protection. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION, /// The implementation supports the Message Passing option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING, /// The implementation supports the Monotonic Clock option. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + solarish, + apple_targets, target_os = "openbsd", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Prioritized Input and Output option. _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO, /// The implementation supports the Process Scheduling option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", + freebsdlike, + solarish, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Raw Sockets option. _POSIX_RAW_SOCKETS = libc::_SC_RAW_SOCKETS, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", + bsd, + solarish, target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports read-write locks. _POSIX_READER_WRITER_LOCKS = libc::_SC_READER_WRITER_LOCKS, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports realtime signals. _POSIX_REALTIME_SIGNALS = libc::_SC_REALTIME_SIGNALS, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "ios", + bsd, + solarish, target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Regular Expression Handling option. _POSIX_REGEXP = libc::_SC_REGEXP, /// Each process has a saved set-user-ID and a saved set-group-ID. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SAVED_IDS = libc::_SC_SAVED_IDS, /// The implementation supports semaphores. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES, /// The implementation supports the Shared Memory Objects option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux",))] /// The implementation supports the POSIX shell. _POSIX_SHELL = libc::_SC_SHELL, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux",))] /// The implementation supports the Spawn option. _POSIX_SPAWN = libc::_SC_SPAWN, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux",))] /// The implementation supports spin locks. _POSIX_SPIN_LOCKS = libc::_SC_SPIN_LOCKS, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Process Sporadic Server option. _POSIX_SPORADIC_SERVER = libc::_SC_SPORADIC_SERVER, + /// The number of replenishment operations that can be simultaneously pending for a particular + /// sporadic server scheduler. #[cfg(any( - target_os = "ios", + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX, /// The implementation supports the Synchronized Input and Output option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO, /// The implementation supports the Thread Stack Address Attribute option. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_ATTR_STACKADDR = libc::_SC_THREAD_ATTR_STACKADDR, /// The implementation supports the Thread Stack Size Attribute option. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE, #[cfg(any( - target_os = "ios", + apple_targets, target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" + netbsdlike, ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Thread CPU-Time Clocks option. _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME, /// The implementation supports the Non-Robust Mutex Priority Inheritance /// option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT, /// The implementation supports the Non-Robust Mutex Priority Protection option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT, /// The implementation supports the Thread Execution Scheduling option. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation supports the Thread Process-Shared Synchronization /// option. _POSIX_THREAD_PROCESS_SHARED = libc::_SC_THREAD_PROCESS_SHARED, @@ -2679,7 +2490,6 @@ pub enum SysconfVar { target_os = "linux", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Robust Mutex Priority Inheritance option. _POSIX_THREAD_ROBUST_PRIO_INHERIT = libc::_SC_THREAD_ROBUST_PRIO_INHERIT, #[cfg(any( @@ -2687,484 +2497,319 @@ pub enum SysconfVar { target_os = "linux", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Robust Mutex Priority Protection option. _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT, /// The implementation supports thread-safe functions. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Thread Sporadic Server option. _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER, /// The implementation supports threads. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_THREADS = libc::_SC_THREADS, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports timeouts. _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS, /// The implementation supports timers. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TIMERS = libc::_SC_TIMERS, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Trace option. _POSIX_TRACE = libc::_SC_TRACE, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Trace Event Filter option. _POSIX_TRACE_EVENT_FILTER = libc::_SC_TRACE_EVENT_FILTER, + /// Maximum size of a trace event name in characters. #[cfg(any( - target_os = "ios", + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_EVENT_NAME_MAX = libc::_SC_TRACE_EVENT_NAME_MAX, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Trace Inherit option. _POSIX_TRACE_INHERIT = libc::_SC_TRACE_INHERIT, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Trace Log option. _POSIX_TRACE_LOG = libc::_SC_TRACE_LOG, + /// The length in bytes of a trace generation version string or a trace stream name. #[cfg(any( - target_os = "ios", + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_NAME_MAX = libc::_SC_TRACE_NAME_MAX, + /// Maximum number of times `posix_trace_create` may be called from the same or different + /// processes. #[cfg(any( - target_os = "ios", + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_SYS_MAX = libc::_SC_TRACE_SYS_MAX, + /// Maximum number of user trace event type identifiers for a single process. #[cfg(any( - target_os = "ios", + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX_TRACE_USER_EVENT_MAX = libc::_SC_TRACE_USER_EVENT_MAX, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Typed Memory Objects option. _POSIX_TYPED_MEMORY_OBJECTS = libc::_SC_TYPED_MEMORY_OBJECTS, /// Integer value indicating version of this standard (C-language binding) /// to which the implementation conforms. For implementations conforming to /// POSIX.1-2008, the value shall be 200809L. _POSIX_VERSION = libc::_SC_VERSION, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation provides a C-language compilation environment with /// 32-bit `int`, `long`, `pointer`, and `off_t` types. _POSIX_V6_ILP32_OFF32 = libc::_SC_V6_ILP32_OFF32, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation provides a C-language compilation environment with /// 32-bit `int`, `long`, and pointer types and an `off_t` type using at /// least 64 bits. _POSIX_V6_ILP32_OFFBIG = libc::_SC_V6_ILP32_OFFBIG, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation provides a C-language compilation environment with /// 32-bit `int` and 64-bit `long`, `pointer`, and `off_t` types. _POSIX_V6_LP64_OFF64 = libc::_SC_V6_LP64_OFF64, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation provides a C-language compilation environment with an /// `int` type using at least 32 bits and `long`, pointer, and `off_t` types /// using at least 64 bits. _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG, /// The implementation supports the C-Language Binding option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_C_BIND = libc::_SC_2_C_BIND, /// The implementation supports the C-Language Development Utilities option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_C_DEV = libc::_SC_2_C_DEV, /// The implementation supports the Terminal Characteristics option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM, /// The implementation supports the FORTRAN Development Utilities option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV, /// The implementation supports the FORTRAN Runtime Utilities option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN, /// The implementation supports the creation of locales by the localedef /// utility. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation supports the Batch Environment Services and Utilities /// option. _POSIX2_PBS = libc::_SC_2_PBS, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation supports the Batch Accounting option. _POSIX2_PBS_ACCOUNTING = libc::_SC_2_PBS_ACCOUNTING, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation supports the Batch Checkpoint/Restart option. _POSIX2_PBS_CHECKPOINT = libc::_SC_2_PBS_CHECKPOINT, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation supports the Locate Batch Job Request option. _POSIX2_PBS_LOCATE = libc::_SC_2_PBS_LOCATE, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation supports the Batch Job Message Request option. _POSIX2_PBS_MESSAGE = libc::_SC_2_PBS_MESSAGE, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + #[cfg(any(bsd, target_os = "linux"))] /// The implementation supports the Track Batch Job Request option. _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK, /// The implementation supports the Software Development Utilities option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_SW_DEV = libc::_SC_2_SW_DEV, /// The implementation supports the User Portability Utilities option. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_UPE = libc::_SC_2_UPE, /// Integer value indicating version of the Shell and Utilities volume of /// POSIX.1 to which the implementation conforms. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _POSIX2_VERSION = libc::_SC_2_VERSION, /// The size of a system page in bytes. /// /// POSIX also defines an alias named `PAGESIZE`, but Rust does not allow two /// enum constants to have the same value, so nix omits `PAGESIZE`. PAGE_SIZE = libc::_SC_PAGE_SIZE, + /// Maximum number of attempts made to destroy a thread's thread-specific data values on thread + /// exit. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS, + /// Maximum number of data keys that can be created by a process. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX, + /// Minimum size in bytes of thread stack storage. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN, + /// Maximum number of threads that can be created per process. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX, + /// The maximum number of repeated occurrences of a regular expression permitted when using + /// interval notation. #[cfg(not(target_os = "haiku"))] RE_DUP_MAX = libc::_SC_RE_DUP_MAX, + /// Maximum number of realtime signals reserved for application use. #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] RTSIG_MAX = libc::_SC_RTSIG_MAX, + /// Maximum number of semaphores that a process may have. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX, + /// The maximum value a semaphore may have. #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] SEM_VALUE_MAX = libc::_SC_SEM_VALUE_MAX, + /// Maximum number of queued signals that a process may send and have pending at the + /// receiver(s) at any time. #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] SIGQUEUE_MAX = libc::_SC_SIGQUEUE_MAX, + /// The minimum maximum number of streams that a process may have open at any one time. STREAM_MAX = libc::_SC_STREAM_MAX, - #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + /// Maximum number of symbolic links that can be reliably traversed in the resolution of a + /// pathname in the absence of a loop. + #[cfg(any(bsd, target_os = "linux"))] SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX, + /// Maximum number of timers per process supported. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(all())))] TIMER_MAX = libc::_SC_TIMER_MAX, + /// Maximum length of terminal device name. TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX, + /// The minimum maximum number of types supported for the name of a timezone. TZNAME_MAX = libc::_SC_TZNAME_MAX, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the X/Open Encryption Option Group. _XOPEN_CRYPT = libc::_SC_XOPEN_CRYPT, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the Issue 4, Version 2 Enhanced /// Internationalization Option Group. _XOPEN_ENH_I18N = libc::_SC_XOPEN_ENH_I18N, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] + /// The implementation supports the XOpen Legacy Option group. + /// + /// See Also <https://pubs.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap02.html> _XOPEN_LEGACY = libc::_SC_XOPEN_LEGACY, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the X/Open Realtime Option Group. _XOPEN_REALTIME = libc::_SC_XOPEN_REALTIME, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the X/Open Realtime Threads Option Group. _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS, /// The implementation supports the Issue 4, Version 2 Shared Memory Option /// Group. #[cfg(not(any(target_os = "redox", target_os = "haiku")))] - #[cfg_attr(docsrs, doc(cfg(all())))] _XOPEN_SHM = libc::_SC_XOPEN_SHM, #[cfg(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", + freebsdlike, + apple_targets, target_os = "linux", - target_os = "macos", target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the XSI STREAMS Option Group. _XOPEN_STREAMS = libc::_SC_XOPEN_STREAMS, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// The implementation supports the XSI option _XOPEN_UNIX = libc::_SC_XOPEN_UNIX, #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", + linux_android, + freebsdlike, + apple_targets, target_os = "openbsd" ))] - #[cfg_attr(docsrs, doc(cfg(all())))] /// Integer value indicating version of the X/Open Portability Guide to /// which the implementation conforms. _XOPEN_VERSION = libc::_SC_XOPEN_VERSION, /// The number of pages of physical memory. Note that it is possible for /// the product of this value to overflow. - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] _PHYS_PAGES = libc::_SC_PHYS_PAGES, /// The number of currently available pages of physical memory. - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] _AVPHYS_PAGES = libc::_SC_AVPHYS_PAGES, /// The number of processors configured. - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] _NPROCESSORS_CONF = libc::_SC_NPROCESSORS_CONF, /// The number of processors currently online (available). - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(linux_android)] _NPROCESSORS_ONLN = libc::_SC_NPROCESSORS_ONLN, } @@ -3190,7 +2835,7 @@ pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> { libc::sysconf(var as c_int) }; if raw == -1 { - if errno::errno() == 0 { + if Errno::last_raw() == 0 { Ok(None) } else { Err(Errno::last()) @@ -3201,12 +2846,15 @@ pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> { } } -#[cfg(any(target_os = "android", target_os = "linux"))] +#[cfg(linux_android)] #[cfg(feature = "fs")] mod pivot_root { use crate::errno::Errno; use crate::{NixPath, Result}; + /// Change the root file system. + /// + /// See Also [`pivot_root`](https://man7.org/linux/man-pages/man2/pivot_root.2.html) pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( new_root: &P1, put_old: &P2, @@ -3225,13 +2873,7 @@ mod pivot_root { } } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] +#[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))] mod setres { feature! { #![feature = "user"] @@ -3276,13 +2918,7 @@ mod setres { } } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd" -))] +#[cfg(any(linux_android, freebsdlike, target_os = "openbsd"))] mod getres { feature! { #![feature = "user"] @@ -3294,16 +2930,22 @@ mod getres { /// Real, effective and saved user IDs. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct ResUid { + /// Real UID pub real: Uid, + /// Effective UID pub effective: Uid, + /// Saved UID pub saved: Uid, } /// Real, effective and saved group IDs. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct ResGid { + /// Real GID pub real: Gid, + /// Effective GID pub effective: Gid, + /// Saved GID pub saved: Gid, } @@ -3318,9 +2960,9 @@ mod getres { /// #[inline] pub fn getresuid() -> Result<ResUid> { - let mut ruid = libc::uid_t::max_value(); - let mut euid = libc::uid_t::max_value(); - let mut suid = libc::uid_t::max_value(); + let mut ruid = libc::uid_t::MAX; + let mut euid = libc::uid_t::MAX; + let mut suid = libc::uid_t::MAX; let res = unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) }; Errno::result(res).map(|_| ResUid { @@ -3341,9 +2983,9 @@ mod getres { /// #[inline] pub fn getresgid() -> Result<ResGid> { - let mut rgid = libc::gid_t::max_value(); - let mut egid = libc::gid_t::max_value(); - let mut sgid = libc::gid_t::max_value(); + let mut rgid = libc::gid_t::MAX; + let mut egid = libc::gid_t::MAX; + let mut sgid = libc::gid_t::MAX; let res = unsafe { libc::getresgid(&mut rgid, &mut egid, &mut sgid) }; Errno::result(res).map(|_| ResGid { @@ -3355,6 +2997,62 @@ mod getres { } } +#[cfg(feature = "process")] +#[cfg(target_os = "freebsd")] +libc_bitflags! { + /// Flags for [`rfork`] + /// + /// subset of flags supported by FreeBSD 12.x and onwards + /// with a safe outcome, thus as `RFMEM` can possibly lead to undefined behavior, + /// it is not in the list. And `rfork_thread` is deprecated. + pub struct RforkFlags: libc::c_int { + /// creates a new process. + RFPROC; + /// the child process will detach from the parent. + /// however, no status will be emitted at child's exit. + RFNOWAIT; + /// the file descriptor's table will be copied + RFFDG; + /// a new file descriptor's table will be created + RFCFDG; + /// force sharing the sigacts structure between + /// the child and the parent. + RFSIGSHARE; + /// enables kernel thread support. + RFTHREAD; + /// sets a status to emit at child's exit. + RFTSIGZMB; + /// linux's behavior compatibility setting. + /// emits SIGUSR1 as opposed to SIGCHLD upon child's exit. + RFLINUXTHPN; + } +} + +feature! { +#![feature = "process"] +#[cfg(target_os = "freebsd")] +/// Like [`fork`], `rfork` can be used to have a tigher control about which +/// resources child and parent process will be sharing, file descriptors, +/// address spaces and child exit's behavior. +/// +/// # Safety +/// +/// The same restrictions apply as for [`fork`]. +/// +/// # See Also +/// +/// * [rfork(2)](https://man.freebsd.org/cgi/man.cgi?query=rfork) +pub unsafe fn rfork(flags: RforkFlags) -> Result<ForkResult> { + use ForkResult::*; + let res = unsafe { libc::rfork(flags.bits()) }; + + Errno::result(res).map(|res| match res { + 0 => Child, + res => Parent { child: Pid(res) }, + }) +} +} + #[cfg(feature = "fs")] libc_bitflags! { /// Options for access() @@ -3419,9 +3117,8 @@ pub fn faccessat<P: ?Sized + NixPath>( /// * [FreeBSD man page](https://www.freebsd.org/cgi/man.cgi?query=eaccess&sektion=2&n=1) /// * [Linux man page](https://man7.org/linux/man-pages/man3/euidaccess.3.html) #[cfg(any( + freebsdlike, all(target_os = "linux", not(target_env = "uclibc")), - target_os = "freebsd", - target_os = "dragonfly" ))] pub fn eaccess<P: ?Sized + NixPath>(path: &P, mode: AccessFlags) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { @@ -3460,39 +3157,33 @@ pub struct User { pub shell: PathBuf, /// Login class #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub class: CString, /// Last password change #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub change: libc::time_t, /// Expiration time of account #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] - #[cfg_attr(docsrs, doc(cfg(all())))] pub expire: libc::time_t, } @@ -3539,34 +3230,31 @@ impl From<&libc::passwd> for User { uid: Uid::from_raw(pw.pw_uid), gid: Gid::from_raw(pw.pw_gid), #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] class: CString::new(CStr::from_ptr(pw.pw_class).to_bytes()) .unwrap(), #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] change: pw.pw_change, #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] expire: pw.pw_expire, } @@ -3602,40 +3290,37 @@ impl From<User> for libc::passwd { pw_uid: u.uid.0, pw_gid: u.gid.0, #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] pw_class: u.class.into_raw(), #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] pw_change: u.change, #[cfg(not(any( + linux_android, + solarish, target_os = "aix", - target_os = "android", target_os = "fuchsia", target_os = "haiku", - target_os = "illumos", - target_os = "linux", - target_os = "solaris" + target_os = "hurd", )))] pw_expire: u.expire, - #[cfg(target_os = "illumos")] + #[cfg(solarish)] pw_age: CString::new("").unwrap().into_raw(), - #[cfg(target_os = "illumos")] + #[cfg(solarish)] pw_comment: CString::new("").unwrap().into_raw(), - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + #[cfg(freebsdlike)] pw_fields: 0, } } @@ -3680,7 +3365,7 @@ impl User { } else { // SAFETY: `f` guarantees that `pwd` is initialized if `res` // is not null. - let pwd = pwd.assume_init(); + let pwd = unsafe { pwd.assume_init() }; return Ok(Some(User::from(&pwd))); } } else if Errno::last() == Errno::ERANGE { @@ -3790,18 +3475,17 @@ impl Group { let mut ret = Vec::new(); for i in 0.. { - let u = mem.offset(i); - if (*u).is_null() { + let u = unsafe { mem.offset(i).read_unaligned() }; + if u.is_null() { break; } else { - let s = CStr::from_ptr(*u).to_string_lossy().into_owned(); + let s = unsafe {CStr::from_ptr(u).to_string_lossy().into_owned()}; ret.push(s); } } ret } - /// # Safety /// /// If `f` writes to its `*mut *mut libc::group` parameter, then it must @@ -3839,7 +3523,7 @@ impl Group { } else { // SAFETY: `f` guarantees that `grp` is initialized if `res` // is not null. - let grp = grp.assume_init(); + let grp = unsafe { grp.assume_init() }; return Ok(Some(Group::from(&grp))); } } else if Errno::last() == Errno::ERANGE { @@ -3913,19 +3597,22 @@ feature! { /// Get the name of the terminal device that is open on file descriptor fd /// (see [`ttyname(3)`](https://man7.org/linux/man-pages/man3/ttyname.3.html)). #[cfg(not(target_os = "fuchsia"))] -pub fn ttyname(fd: RawFd) -> Result<PathBuf> { +pub fn ttyname<F: AsFd>(fd: F) -> Result<PathBuf> { + #[cfg(not(target_os = "hurd"))] const PATH_MAX: usize = libc::PATH_MAX as usize; + #[cfg(target_os = "hurd")] + const PATH_MAX: usize = 1024; // Hurd does not define a hard limit, so try a guess first let mut buf = vec![0_u8; PATH_MAX]; - let c_buf = buf.as_mut_ptr() as *mut libc::c_char; + let c_buf = buf.as_mut_ptr().cast(); - let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) }; + let ret = unsafe { libc::ttyname_r(fd.as_fd().as_raw_fd(), c_buf, buf.len()) }; if ret != 0 { - return Err(Errno::from_i32(ret)); + return Err(Errno::from_raw(ret)); } - let nul = buf.iter().position(|c| *c == b'\0').unwrap(); - buf.truncate(nul); - Ok(OsString::from_vec(buf).into()) + CStr::from_bytes_until_nul(&buf[..]) + .map(|s| OsStr::from_bytes(s.to_bytes()).into()) + .map_err(|_| Errno::EINVAL) } } @@ -3935,19 +3622,12 @@ feature! { /// Get the effective user ID and group ID associated with a Unix domain socket. /// /// See also [getpeereid(3)](https://www.freebsd.org/cgi/man.cgi?query=getpeereid) -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "dragonfly", -))] -pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> { +#[cfg(bsd)] +pub fn getpeereid<F: AsFd>(fd: F) -> Result<(Uid, Gid)> { let mut uid = 1; let mut gid = 1; - let ret = unsafe { libc::getpeereid(fd, &mut uid, &mut gid) }; + let ret = unsafe { libc::getpeereid(fd.as_fd().as_raw_fd(), &mut uid, &mut gid) }; Errno::result(ret).map(|_| (Uid(uid), Gid(gid))) } @@ -3959,14 +3639,7 @@ feature! { /// Set the file flags. /// /// See also [chflags(2)](https://www.freebsd.org/cgi/man.cgi?query=chflags&sektion=2) -#[cfg(any( - target_os = "openbsd", - target_os = "netbsd", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "macos", - target_os = "ios" -))] +#[cfg(bsd)] pub fn chflags<P: ?Sized + NixPath>(path: &P, flags: FileFlag) -> Result<()> { let res = path.with_nix_path(|cstr| unsafe { libc::chflags(cstr.as_ptr(), flags.bits()) |