summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert O'Callahan <robert@ocallahan.org>2017-08-21 15:07:37 +1200
committerRobert O'Callahan <robert@ocallahan.org>2017-12-05 10:14:23 +1300
commit996bc6b76a4830dfb0a1f28ee62f5d8b17febbac (patch)
tree2c758055e2b4a6aae70b5c9de9db5cc206bebeb6
parent3871586a9bcff84eea6dd05f229fbe6ddb3f2bdd (diff)
downloadnix-996bc6b76a4830dfb0a1f28ee62f5d8b17febbac.zip
Expose `from_raw` on `WaitStatus` and make it return a `Result`
-rw-r--r--CHANGELOG.md3
-rw-r--r--src/sys/wait.rs85
-rw-r--r--test/sys/test_wait.rs9
3 files changed, 64 insertions, 33 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3e3994c8..06d2b79d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -45,6 +45,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
([#785](https://github.com/nix-rust/nix/pull/785))
- Added `nix::unistd::execveat` on Linux and Android.
([#800](https://github.com/nix-rust/nix/pull/800))
+- Added the `from_raw()` method to `WaitStatus` for converting raw status values
+ to `WaitStatus` independent of syscalls.
+ ([#741](https://github.com/nix-rust/nix/pull/741))
### Changed
- Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692))
diff --git a/src/sys/wait.rs b/src/sys/wait.rs
index 019b751f..4c36cee5 100644
--- a/src/sys/wait.rs
+++ b/src/sys/wait.rs
@@ -129,8 +129,8 @@ fn signaled(status: i32) -> bool {
unsafe { libc::WIFSIGNALED(status) }
}
-fn term_signal(status: i32) -> Signal {
- Signal::from_c_int(unsafe { libc::WTERMSIG(status) }).unwrap()
+fn term_signal(status: i32) -> Result<Signal> {
+ Signal::from_c_int(unsafe { libc::WTERMSIG(status) })
}
fn dumped_core(status: i32) -> bool {
@@ -141,8 +141,8 @@ fn stopped(status: i32) -> bool {
unsafe { libc::WIFSTOPPED(status) }
}
-fn stop_signal(status: i32) -> Signal {
- Signal::from_c_int(unsafe { libc::WSTOPSIG(status) }).unwrap()
+fn stop_signal(status: i32) -> Result<Signal> {
+ Signal::from_c_int(unsafe { libc::WSTOPSIG(status) })
}
fn syscall_stop(status: i32) -> bool {
@@ -161,34 +161,53 @@ fn continued(status: i32) -> bool {
unsafe { libc::WIFCONTINUED(status) }
}
-fn decode(pid: Pid, status: i32) -> WaitStatus {
- if exited(status) {
- WaitStatus::Exited(pid, exit_status(status))
- } else if signaled(status) {
- WaitStatus::Signaled(pid, term_signal(status), dumped_core(status))
- } else if stopped(status) {
- cfg_if! {
- if #[cfg(any(target_os = "linux", target_os = "android"))] {
- fn decode_stopped(pid: Pid, status: i32) -> WaitStatus {
- let status_additional = stop_additional(status);
- if syscall_stop(status) {
- WaitStatus::PtraceSyscall(pid)
- } else if status_additional == 0 {
- WaitStatus::Stopped(pid, stop_signal(status))
- } else {
- WaitStatus::PtraceEvent(pid, stop_signal(status), stop_additional(status))
+impl WaitStatus {
+ /// Convert a raw `wstatus` as returned by `waitpid`/`wait` into a `WaitStatus`
+ ///
+ /// # Errors
+ ///
+ /// Returns an `Error` corresponding to `EINVAL` for invalid status values.
+ ///
+ /// # Examples
+ ///
+ /// Convert a `wstatus` obtained from `libc::waitpid` into a `WaitStatus`:
+ ///
+ /// ```
+ /// use nix::sys::wait::WaitStatus;
+ /// use nix::sys::signal::Signal;
+ /// let pid = nix::unistd::Pid::from_raw(1);
+ /// let status = WaitStatus::from_raw(pid, 0x0002);
+ /// assert_eq!(status, Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)));
+ /// ```
+ pub fn from_raw(pid: Pid, status: i32) -> Result<WaitStatus> {
+ Ok(if exited(status) {
+ WaitStatus::Exited(pid, exit_status(status))
+ } else if signaled(status) {
+ WaitStatus::Signaled(pid, try!(term_signal(status)), dumped_core(status))
+ } else if stopped(status) {
+ cfg_if! {
+ if #[cfg(any(target_os = "linux", target_os = "android"))] {
+ fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> {
+ let status_additional = stop_additional(status);
+ Ok(if syscall_stop(status) {
+ WaitStatus::PtraceSyscall(pid)
+ } else if status_additional == 0 {
+ WaitStatus::Stopped(pid, try!(stop_signal(status)))
+ } else {
+ WaitStatus::PtraceEvent(pid, try!(stop_signal(status)), stop_additional(status))
+ })
+ }
+ } else {
+ fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> {
+ Ok(WaitStatus::Stopped(pid, try!(stop_signal(status))))
}
- }
- } else {
- fn decode_stopped(pid: Pid, status: i32) -> WaitStatus {
- WaitStatus::Stopped(pid, stop_signal(status))
}
}
- }
- decode_stopped(pid, status)
- } else {
- assert!(continued(status));
- WaitStatus::Continued(pid)
+ return decode_stopped(pid, status);
+ } else {
+ assert!(continued(status));
+ WaitStatus::Continued(pid)
+ })
}
}
@@ -210,10 +229,10 @@ pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Re
)
};
- Ok(match try!(Errno::result(res)) {
- 0 => StillAlive,
- res => decode(Pid::from_raw(res), status),
- })
+ match try!(Errno::result(res)) {
+ 0 => Ok(StillAlive),
+ res => WaitStatus::from_raw(Pid::from_raw(res), status),
+ }
}
pub fn wait() -> Result<WaitStatus> {
diff --git a/test/sys/test_wait.rs b/test/sys/test_wait.rs
index 44a111a3..02f32734 100644
--- a/test/sys/test_wait.rs
+++ b/test/sys/test_wait.rs
@@ -1,3 +1,4 @@
+use nix::Error;
use nix::unistd::*;
use nix::unistd::ForkResult::*;
use nix::sys::signal::*;
@@ -38,6 +39,14 @@ fn test_wait_exit() {
}
#[test]
+fn test_waitstatus_from_raw() {
+ let pid = Pid::from_raw(1);
+ assert_eq!(WaitStatus::from_raw(pid, 0x0002), Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)));
+ assert_eq!(WaitStatus::from_raw(pid, 0x0200), Ok(WaitStatus::Exited(pid, 2)));
+ assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Error::invalid_argument()));
+}
+
+#[test]
fn test_waitstatus_pid() {
let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");