From e1def7b4f3508777743d666b198e92bae7272bd0 Mon Sep 17 00:00:00 2001 From: Keith Koskie Date: Tue, 31 May 2022 23:20:03 -0400 Subject: [PATCH 1/2] Document the sys::wait module Noteworthy secondary changes included as a result of the primary documentation: * Additions to unistd::Pid to support waitpid calling conventions * Change the waitpid function signature (backward compatible) * Application of rustfmt to unistd.rs and sys::wait.rs Continued from work by * Marcin Mielniczuk * Michael Aaron Murphy Closes #654 and #651 --- CHANGELOG.md | 4 + src/sys/wait.rs | 268 ++++++++++++++++++++++++++++++++++++++---------- src/unistd.rs | 64 ++++++++++++ 3 files changed, 284 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f40e4089f..896ed663bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). - Added `aio_writev` and `aio_readv`. (#[1713](https://github.com/nix-rust/nix/pull/1713)) +- Added `Pid::as_wait_pgrp` for use with `waitpid` + (#[1732](https://github.com/nix-rust/nix/pull/1732)) - impl `From` for `Uid` and `From` for `Gid` (#[1727](https://github.com/nix-rust/nix/pull/1727)) @@ -28,6 +30,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). * Changes the type of the `priority` arguments to `i32`. * Changes the return type of `aio_return` to `usize`. (#[1713](https://github.com/nix-rust/nix/pull/1713)) +- `waitpid` now accepts any `Into>` instead of `Option` + (#[1732](https://github.com/nix-rust/nix/pull/1732)) ### Fixed diff --git a/src/sys/wait.rs b/src/sys/wait.rs index 5fb2075fd9..627a29d939 100644 --- a/src/sys/wait.rs +++ b/src/sys/wait.rs @@ -1,4 +1,78 @@ -//! Wait for a process to change status +//! This module contains the [`wait`] and [`waitpid`] functions. +//! +//! These are used to wait on and obtain status information from child +//! processes, which provide more granular control over child management than +//! the primitives provided by Rust's standard library, and are critical in the +//! creation of shells and managing jobs on *nix platforms. +//! +//! # Manual Pages +//! +//! - [`waitpid(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitpid.html) +//! - [`wait(2)`](http://pubs.opengroup.org/onlinepubs/007908799/xsh/wait.html) +//! - [`waitid(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitid.html) +//! +//! # Examples +//! +//! The following is an adaptation of the example program in the +//! [waitpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitpid.html) +//! documentation. +//! +//! ```no_run +//! use nix::unistd::{fork,ForkResult}; +//! use nix::unistd::Pid; +//! +//! let cpid = unsafe { fork() }.unwrap(); +//! match cpid { +//! ForkResult::Child => child_process(), +//! ForkResult::Parent{ child } => parent_process(child), +//! } +//! +//! fn child_process() { +//! use nix::unistd::{getpid,pause}; +//! use std::{write,io::{stdout,Write}}; +//! +//! let cpid = getpid(); +//! writeln!(stdout(), "Child PID is {}. Send it signals. E.g.:", cpid); +//! writeln!(stdout(), " kill -s SIGSTOP {}", cpid); +//! nix::unistd::pause(); +//! unsafe { libc::_exit(0) }; +//! } +//! +//! fn parent_process(cpid: Pid) { +//! use nix::sys::wait::{WaitPidFlag,WaitStatus,waitpid}; +//! loop { +//! match waitpid(cpid, WaitPidFlag::WUNTRACED | WaitPidFlag::WCONTINUED) { +//! Err(err) => panic!("waitpid failed: {}", err.desc()), +//! Ok(status) => { +//! match status { +//! WaitStatus::Exited(pid, code) => { +//! println!("pid {}, exited, status={}", pid, code); +//! break; +//! }, +//! +//! WaitStatus::Signaled(pid, signal, core) => { +//! let comment = if core { " (core dumped)"} else { "" }; +//! println!("pid {} killed by signal {}{}", pid, signal, comment); +//! break; +//! }, +//! +//! WaitStatus::Stopped(pid, signal) => +//! println!("pid {} stopped by signal {}", pid, signal), +//! +//! WaitStatus::Continued(pid) => +//! println!("pid {} continued", pid), +//! +//! WaitStatus::StillAlive => +//! println!("child pid {} is still alive", cpid), +//! +//! // Additional statuses are platform-specific +//! _ => panic!("Unexpected WaitStatus {:?}", status), +//! } +//! }, +//! } +//! } +//! } +//! ``` use crate::errno::Errno; use crate::sys::signal::Signal; use crate::unistd::Pid; @@ -15,7 +89,8 @@ use std::os::unix::io::RawFd; libc_bitflags!( /// Controls the behavior of [`waitpid`]. pub struct WaitPidFlag: c_int { - /// Do not block when there are no processes wishing to report status. + /// Do not block if the status is not immediately available for one + /// of the child processes specified by pid. WNOHANG; /// Report the status of selected processes which are stopped due to a /// [`SIGTTIN`](crate::sys::signal::Signal::SIGTTIN), @@ -38,7 +113,7 @@ libc_bitflags!( /// job control stop by receiving a /// [`SIGCONT`](crate::sys::signal::Signal::SIGCONT) signal. WCONTINUED; - /// An alias for WUNTRACED. + /// An alias for [`WUNTRACED`](Self::WUNTRACED). #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "haiku", @@ -49,7 +124,9 @@ libc_bitflags!( target_os = "netbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] WSTOPPED; - /// Don't reap, just poll status. + /// Don't wait, just poll status. Leaves the child in a waitable + /// state; a later wait call can be used to again retrieve the + /// child status information. #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "haiku", @@ -64,74 +141,106 @@ libc_bitflags!( #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] __WNOTHREAD; - /// Wait on all children, regardless of type + /// Wait for all children, regardless of type (clone or non-clone) #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] __WALL; - /// Wait for "clone" children only. + /// Wait for "clone" children only. If omitted then wait for + /// "non-clone" children only. (A "clone" child is one which delivers + /// no signal, or a signal other than [`SIGCHLD`] to its parent upon + /// termination.) This option is ignored if [`__WALL`] is also + /// specified. + /// + /// [`SIGCHLD`]: crate::sys::signal::Signal::SIGCHLD + /// [`__WALL`]: Self::__WALL #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))] #[cfg_attr(docsrs, doc(cfg(all())))] __WCLONE; } ); -/// Possible return values from `wait()` or `waitpid()`. +/// Possible return values from [`wait`] or [`waitpid`]. /// -/// Each status (other than `StillAlive`) describes a state transition -/// in a child process `Pid`, such as the process exiting or stopping, +/// Each status (other than [`StillAlive`](WaitStatus::StillAlive)) +/// describes a state transition in a child process +/// [`Pid`](crate::unistd::Pid), such as the process exiting or stopping, /// plus additional data about the transition if any. /// -/// Note that there are two Linux-specific enum variants, `PtraceEvent` -/// and `PtraceSyscall`. Portable code should avoid exhaustively -/// matching on `WaitStatus`. +/// Note that there are two Linux-specific enum variants, +/// [`PtraceEvent`](WaitStatus) and [`PtraceSyscall`](WaitStatus). +/// Portable code should avoid exhaustively matching on [`WaitStatus`]. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum WaitStatus { /// The process exited normally (as with `exit()` or returning from /// `main`) with the given exit code. This case matches the C macro - /// `WIFEXITED(status)`; the second field is `WEXITSTATUS(status)`. + /// [`WIFEXITED(status)`]; the second field is [`WEXITSTATUS(status)`]. + /// + /// [`WIFEXITED(status)`]: libc::WIFEXITED + /// [`WEXITSTATUS(status)`]: libc::WEXITSTATUS Exited(Pid, i32), /// The process was killed by the given signal. The third field /// indicates whether the signal generated a core dump. This case - /// matches the C macro `WIFSIGNALED(status)`; the last two fields - /// correspond to `WTERMSIG(status)` and `WCOREDUMP(status)`. + /// matches the C macro [`WIFSIGNALED(status)`]; the last two + /// fields correspond to [`WTERMSIG(status)`] and + /// [`WCOREDUMP(status)`]. + /// + /// [`WIFSIGNALED(status)`]: libc::WIFSIGNALED + /// [`WTERMSIG(status)`]: libc::WTERMSIG + /// [`WCOREDUMP(status)`]: libc::WCOREDUMP Signaled(Pid, Signal, bool), /// The process is alive, but was stopped by the given signal. This - /// is only reported if `WaitPidFlag::WUNTRACED` was passed. This - /// case matches the C macro `WIFSTOPPED(status)`; the second field - /// is `WSTOPSIG(status)`. + /// is only reported if [`WUNTRACED`] was passed. This case matches + /// the C macro [`WIFSTOPPED(status)`]; the second field is + /// [`WSTOPSIG(status)`]. + /// + /// [`WUNTRACED`]: self::WaitPidFlag::WUNTRACED + /// [`WIFSTOPPED(status)`]: libc::WIFSTOPPED + /// [`WSTOPSIG(status)`]: libc::WSTOPSIG Stopped(Pid, Signal), - /// The traced process was stopped by a `PTRACE_EVENT_*` event. See - /// [`nix::sys::ptrace`] and [`ptrace`(2)] for more information. All - /// currently-defined events use `SIGTRAP` as the signal; the third - /// field is the `PTRACE_EVENT_*` value of the event. + /// The traced process was stopped by a [`ptrace`] event. All + /// currently defined events use [`SIGTRAP`] as the signal; the third + /// field is the [`Event`] value. /// - /// [`nix::sys::ptrace`]: ../ptrace/index.html - /// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html + /// See [`ptrace(2)`] for more information. + /// + /// [`ptrace`]: crate::sys::ptrace + /// [`Event`]: crate::sys::ptrace::Event + /// [`SIGTRAP`]: crate::sys::signal::Signal::SIGTRAP + /// [`ptrace(2)`]: https://man7.org/linux/man-pages/man2/ptrace.2.html #[cfg(any(target_os = "linux", target_os = "android"))] #[cfg_attr(docsrs, doc(cfg(all())))] PtraceEvent(Pid, Signal, c_int), /// The traced process was stopped by execution of a system call, - /// and `PTRACE_O_TRACESYSGOOD` is in effect. See [`ptrace`(2)] for - /// more information. + /// and [`PTRACE_O_TRACESYSGOOD`] is in effect. + /// + /// See [`ptrace(2)`] for more information. /// - /// [`ptrace`(2)]: https://man7.org/linux/man-pages/man2/ptrace.2.html + /// [`PTRACE_O_TRACESYSGOOD`]: crate::sys::ptrace::Options::PTRACE_O_TRACESYSGOOD + /// [`ptrace(2)`]: https://man7.org/linux/man-pages/man2/ptrace.2.html #[cfg(any(target_os = "linux", target_os = "android"))] #[cfg_attr(docsrs, doc(cfg(all())))] PtraceSyscall(Pid), /// The process was previously stopped but has resumed execution - /// after receiving a `SIGCONT` signal. This is only reported if - /// `WaitPidFlag::WCONTINUED` was passed. This case matches the C - /// macro `WIFCONTINUED(status)`. + /// after receiving a [`SIGCONT`] signal. This is only reported if + /// [`WCONTINUED`] was passed. This case matches the C + /// macro [`WIFCONTINUED(status)`]. + /// + /// [`SIGCONT`]: crate::sys::signal::Signal::SIGCONT + /// [`WCONTINUED`]: self::WaitPidFlag::WCONTINUED + /// [`WIFCONTINUED(status)`]: libc::WIFCONTINUED Continued(Pid), /// There are currently no state changes to report in any awaited - /// child process. This is only returned if `WaitPidFlag::WNOHANG` - /// was used (otherwise `wait()` or `waitpid()` would block until + /// child process. This is only returned if [`WNOHANG`] + /// was used (otherwise [`wait`] or [`waitpid`] would block until /// there was something to report). + /// + /// [`WNOHANG`]: self::WaitPidFlag::WNOHANG StillAlive, } impl WaitStatus { - /// Extracts the PID from the WaitStatus unless it equals StillAlive. + /// Extracts the PID from the [`WaitStatus`] unless it's + /// [`StillAlive`](self::WaitStatus::StillAlive). pub fn pid(&self) -> Option { use self::WaitStatus::*; match *self { @@ -190,16 +299,16 @@ fn continued(status: i32) -> bool { } impl WaitStatus { - /// Convert a raw `wstatus` as returned by `waitpid`/`wait` into a `WaitStatus` + /// Convert a `wstatus` obtained from [`libc::waitpid`] into a + /// [`WaitStatus`]: /// /// # Errors /// - /// Returns an `Error` corresponding to `EINVAL` for invalid status values. + /// - [`EINVAL`](crate::errno::Errno::EINVAL): The supplied options were + /// invalid. /// /// # Examples /// - /// Convert a `wstatus` obtained from `libc::waitpid` into a `WaitStatus`: - /// /// ``` /// use nix::sys::wait::WaitStatus; /// use nix::sys::signal::Signal; @@ -239,17 +348,24 @@ impl WaitStatus { }) } - /// Convert a `siginfo_t` as returned by `waitid` to a `WaitStatus` + /// Convert a [`siginfo_t`] value obtained from [`libc::waitid`] to a + /// [`WaitStatus`] /// /// # Errors /// - /// Returns an `Error` corresponding to `EINVAL` for invalid values. + /// - [`EINVAL`](crate::errno::Errno::EINVAL): The supplied options were + /// invalid. /// /// # Safety /// - /// siginfo_t is actually a union, not all fields may be initialized. - /// The functions si_pid() and si_status() must be valid to call on - /// the passed siginfo_t. + /// Because [`siginfo_t`] is implemented as a union, not all fields may + /// be initialized. The functions [`si_pid()`] and [`si_status()`] must be + /// valid to call on the passed reference. + /// + /// [`siginfo_t`]: libc::siginfo_t + /// [`si_pid()`]: libc::unix::linux_like::linux::gnu::siginfo_t + /// [`si_status()`]: libc::unix::linux_like::linux::gnu::siginfo_t + /// [`libc::waitid`]: libc::unix::linux_like::waitid #[cfg(any( target_os = "android", target_os = "freebsd", @@ -295,15 +411,45 @@ impl WaitStatus { } } -/// Wait for a process to change status +/// Waits for and events from one or more child processes. +/// +/// # Usage Notes +/// +/// The value of `pid` changes the behavior of [`waitpid`] /// -/// See also [waitpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitpid.html) -pub fn waitpid>>(pid: P, options: Option) -> Result { +/// - To wait on a specific child PID, pass it as an argument directly. +/// - To wait on any child process, pass [`None`] or +/// [`ANY_CHILD`](crate::unistd::ANY_CHILD). +/// - To wait on any child within a specific process group ID, pass +/// `some_pid.`[`as_wait_pgrp()`](crate::unistd::Pid::as_wait_pgrp). +/// - To wait on any child whose process group matches the current process pass +/// [`ANY_PGRP_CHILD`](crate::unistd::ANY_PGRP_CHILD). +/// +/// # Errors +/// +/// - [`ECHILD`](crate::errno::Errno::ECHILD): The process does not exist or is +/// not a child of the current process.This may also happen if a child +/// process has the [`SIGCHLD`](crate::sys::signal::Signal::SIGCHLD) signal +/// masked or set to [`SigIgn`](crate::sys::signal::SigHandler::SigIgn). +/// - [`EINTR`](crate::errno::Errno::EINTR): +/// [`WNOHANG`](self::WaitPidFlag::WNOHANG) was not set and either +/// an unblocked signal or a [`SIGCHLD`](crate::sys::signal::Signal::SIGCHLD) +/// was caught. +/// - [`EINVAL`](crate::errno::Errno::EINVAL): The supplied options were +/// invalid. +/// +/// # See also +/// +/// [`waitpid(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitpid.html) +pub fn waitpid(pid: P, options: O) -> Result + where + P: Into>, + O: Into> +{ use self::WaitStatus::*; + let mut status = 0; - let mut status: i32 = 0; - - let option_bits = match options { + let option_bits = match options.into() { Some(bits) => bits.bits(), None => 0, }; @@ -322,14 +468,27 @@ pub fn waitpid>>(pid: P, options: Option) -> Re } } -/// Wait for any child process to change status or a signal is received. +/// Waits for and returns events from any child of the current process. +/// +/// While waiting on the child, this function will return on events that +/// indicate that the status of that child has changed. It is directly +/// equivalent to [`waitpid(None, None)`](self::waitpid). /// -/// See also [wait(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html) +/// # Errors +/// +/// - [`ECHILD`](crate::errno::Errno::ECHILD): The process does not exist or is +/// not a child of the current process.This may also happen if a child +/// process has the [`SIGCHLD`](crate::sys::signal::Signal::SIGCHLD) signal +/// masked or set to [`SigIgn`](crate::sys::signal::SigHandler::SigIgn). +/// +/// # See also +/// +/// [wait(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html) pub fn wait() -> Result { waitpid(None, None) } -/// The ID argument for `waitid` +/// The ID argument for [`waitid`] #[cfg(any( target_os = "android", target_os = "freebsd", @@ -353,7 +512,12 @@ pub enum Id { /// Wait for a process to change status /// -/// See also [waitid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitid.html) +/// This is the glibc and POSIX interface for [`waitpid`]which has +/// different semantics for expressing process group IDs. +/// +/// # See also +/// +/// [waitid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitid.html) #[cfg(any( target_os = "android", target_os = "freebsd", diff --git a/src/unistd.rs b/src/unistd.rs index 2a8389ef7e..d04be791a0 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -159,6 +159,14 @@ feature! { #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct Pid(pid_t); +/// A helper constant which causes `waitpid` to return for any +/// child PID with the same process group as the current process +pub const ANY_PGRP_CHILD: Pid = Pid(0); + +/// A helper constant which causes `waitpid` +/// to wait on any child process +pub const ANY_CHILD: Pid = Pid(-1); + impl Pid { /// Creates `Pid` from raw `pid_t`. pub const fn from_raw(pid: pid_t) -> Self { @@ -179,6 +187,62 @@ impl Pid { pub const fn as_raw(self) -> pid_t { self.0 } + + /// Convert a Pid to its process group representation for use with + /// [`waitpid`] + /// + /// [`waitpid`] accepts process group ids (PGIDs) as well as single PIDs. + /// Because both types are natively represented as positive, signed + /// [`pid_t`], [`waitpid`] distinguishes between the two by having PGIDs + /// passed negated (twos compliment). + /// + /// # Notes + /// + /// - In contexts where PGIDs do not intersect with PIDs, (e.g., the return + /// value of [`getpgrp`]) they are still represented by positive values. + /// - `Pid` is [`Copy`], so unless the return value is bound to the same + /// variable, inversion is unnecessary. + /// - This function only converts in one direction. All calls after first + /// have no effect. + /// - This function is only useful in the rare cases when the given process + /// group is not the same as that of the process calling [`waitpid`]. + /// Otherwise, it's preferrable to use the [`ANY_PGRP_CHILD`] which will + /// always use the current process' PGID. + /// - In debug mode, panics if the raw PID is `i32::MIN` + /// (See [`abs`](i32::abs)) + /// + /// [`pid_t`]: libc::pid_t + /// [`waitpid`]: crate::sys::wait::waitpid + /// + /// # Examples + /// + /// ``` + /// use nix::unistd::Pid; + /// + /// let pid = Pid::from_raw(42); + /// + /// // Calls after the first do nothing + /// assert_ne!(pid, pid.as_wait_pgrp()); + /// assert_eq!(pid.as_wait_pgrp(), pid.as_wait_pgrp().as_wait_pgrp()); + /// + /// // Inversion is generally unnecessary because Pid is Copy + /// assert_eq!(pid, Pid::from_raw(42)); + /// ``` + /// + /// ```no_run + /// use nix::unistd::{ANY_PGRP_CHILD, getpgrp}; + /// use nix::sys::wait::waitpid; + /// + /// // Unnecessary: + /// let my_pgrp = getpgrp(); + /// let _ = waitpid(my_pgrp.as_wait_pgrp(), None); + /// + /// // Equivalent and preferred: + /// let _ = waitpid(ANY_PGRP_CHILD, None); + /// ``` + pub const fn as_wait_pgrp(self) -> Pid { + Pid(-self.0.abs()) + } } impl From for pid_t { From d01d59372943265950fea0d39be0a304f77d4c76 Mon Sep 17 00:00:00 2001 From: Keith Koskie Date: Tue, 7 Jun 2022 23:57:08 -0400 Subject: [PATCH 2/2] rustfmt unistd.rs --- src/unistd.rs | 77 +++++++++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index d04be791a0..9efd51d898 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -1,28 +1,30 @@ //! Safe wrappers around functions found in libc "unistd.h" header -#[cfg(not(target_os = "redox"))] -use cfg_if::cfg_if; use crate::errno::{self, Errno}; -use crate::{Error, Result, NixPath}; #[cfg(not(target_os = "redox"))] #[cfg(feature = "fs")] -use crate::fcntl::{AtFlags, at_rawfd}; -use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t, - uid_t, gid_t, mode_t, PATH_MAX}; +use crate::fcntl::{at_rawfd, AtFlags}; #[cfg(feature = "fs")] -use crate::fcntl::{FdFlag, OFlag, fcntl, FcntlArg::F_SETFD}; -use std::{fmt, mem, ptr}; +use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag}; +#[cfg(feature = "fs")] +use crate::sys::stat::Mode; +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, +}; use std::convert::Infallible; use std::ffi::{CStr, OsString}; #[cfg(not(target_os = "redox"))] use std::ffi::{CString, OsStr}; -use std::os::unix::ffi::OsStringExt; #[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::path::PathBuf; -#[cfg(feature = "fs")] -use crate::sys::stat::Mode; +use std::{fmt, mem, ptr}; feature! { #![feature = "fs"] @@ -30,18 +32,22 @@ feature! { pub use self::pivot_root::*; } -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + 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( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" +))] pub use self::getres::*; feature! { @@ -373,6 +379,7 @@ pub fn setpgid(pid: Pid, pgid: Pid) -> Result<()> { let res = unsafe { libc::setpgid(pid.into(), pgid.into()) }; Errno::result(res).map(drop) } + #[inline] pub fn getpgid(pid: Option) -> Result { let res = unsafe { libc::getpgid(pid.unwrap_or(Pid(0)).into()) }; @@ -672,7 +679,7 @@ fn reserve_double_buffer_size(buf: &mut Vec, limit: usize) -> Result<()> { use std::cmp::min; if buf.capacity() >= limit { - return Err(Errno::ERANGE) + return Err(Errno::ERANGE); } let capacity = min(buf.capacity() * 2, limit); @@ -2776,11 +2783,13 @@ mod pivot_root { } } -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" +))] mod setres { feature! { #![feature = "user"] @@ -2823,11 +2832,13 @@ mod setres { } } -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "linux", - target_os = "openbsd"))] +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "openbsd" +))] mod getres { feature! { #![feature = "user"] @@ -2893,7 +2904,7 @@ mod getres { } #[cfg(feature = "fs")] -libc_bitflags!{ +libc_bitflags! { /// Options for access() #[cfg_attr(docsrs, doc(cfg(feature = "fs")))] pub struct AccessFlags : c_int {