diff --git a/CHANGELOG.md b/CHANGELOG.md index 9535b1fd53..9b97155d7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#556](https://github.com/nix-rust/nix/pull/556) - Added `nix::ptr::openpty` ([#456](https://github.com/nix-rust/nix/pull/456)) +- Added `nix::ptrace::{ptrace_get_data, ptrace_getsiginfo, ptrace_setsiginfo + and nix::Error::UnsupportedOperation}` + ([#614](https://github.com/nix-rust/nix/pull/614)) ### Changed - Marked `sys::mman::{ mmap, munmap, madvise, munlock, msync }` as unsafe. @@ -29,6 +32,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Changed type signature of `sys::select::FdSet::contains` to make `self` immutable ([#564](https://github.com/nix-rust/nix/pull/564)) +### Removed +- Removed io::Error from nix::Error and conversion from nix::Error to Errno + ([#614](https://github.com/nix-rust/nix/pull/614)) + ### Fixed - Fixed multiple issues compiling under different archetectures and OSes. Now compiles on Linux/MIPS ([#538](https://github.com/nix-rust/nix/pull/538)), diff --git a/src/lib.rs b/src/lib.rs index 42f2333457..f0cdb581ee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,7 +75,6 @@ use std::{ptr, result}; use std::ffi::{CStr, OsStr}; use std::path::{Path, PathBuf}; use std::os::unix::ffi::OsStrExt; -use std::io; use std::fmt; use std::error; use libc::PATH_MAX; @@ -97,6 +96,9 @@ pub enum Error { /// The operation involved a conversion to Rust's native String type, which failed because the /// string did not contain all valid UTF-8. InvalidUtf8, + /// The operation is not supported by Nix, in this instance either use the libc bindings or + /// consult the module documentation to see if there is a more appropriate interface available. + UnsupportedOperation, } impl Error { @@ -116,14 +118,6 @@ impl Error { Error::Sys(errno::EINVAL) } - /// Get the errno associated with this error - pub fn errno(&self) -> errno::Errno { - match *self { - Error::InvalidPath => errno::Errno::EINVAL, - Error::InvalidUtf8 => errno::Errno::UnknownErrno, - Error::Sys(errno) => errno, - } - } } impl From for Error { @@ -139,6 +133,7 @@ impl error::Error for Error { match self { &Error::InvalidPath => "Invalid path", &Error::InvalidUtf8 => "Invalid UTF-8 string", + &Error::UnsupportedOperation => "Unsupported Operation", &Error::Sys(ref errno) => errno.desc(), } } @@ -149,21 +144,12 @@ impl fmt::Display for Error { match self { &Error::InvalidPath => write!(f, "Invalid path"), &Error::InvalidUtf8 => write!(f, "Invalid UTF-8 string"), + &Error::UnsupportedOperation => write!(f, "Unsupported Operation"), &Error::Sys(errno) => write!(f, "{:?}: {}", errno, errno.desc()), } } } -impl From for io::Error { - fn from(err: Error) -> Self { - match err { - Error::InvalidPath => io::Error::new(io::ErrorKind::InvalidInput, err), - Error::InvalidUtf8 => io::Error::new(io::ErrorKind::Other, err), - Error::Sys(errno) => io::Error::from_raw_os_error(errno as i32), - } - } -} - pub trait NixPath { fn len(&self) -> usize; diff --git a/src/sys/ptrace.rs b/src/sys/ptrace.rs index edbc973478..bf6ee8bb82 100644 --- a/src/sys/ptrace.rs +++ b/src/sys/ptrace.rs @@ -1,5 +1,6 @@ +use std::{mem, ptr}; use {Errno, Error, Result}; -use libc::{pid_t, c_void, c_long}; +use libc::{pid_t, c_void, c_long, siginfo_t}; #[cfg(all(target_os = "linux", any(target_arch = "x86", @@ -71,11 +72,14 @@ mod ffi { } } +/// Performs a ptrace request. If the request in question is provided by a specialised function +/// this function will return an unsupported operation error. pub fn ptrace(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> Result { use self::ptrace::*; match request { PTRACE_PEEKTEXT | PTRACE_PEEKDATA | PTRACE_PEEKUSER => ptrace_peek(request, pid, addr, data), + PTRACE_GETSIGINFO | PTRACE_GETEVENTMSG | PTRACE_SETSIGINFO | PTRACE_SETOPTIONS => Err(Error::UnsupportedOperation), _ => ptrace_other(request, pid, addr, data) } } @@ -91,6 +95,20 @@ fn ptrace_peek(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, da } } +/// Function for ptrace requests that return values from the data field. +/// Some ptrace get requests populate structs or larger elements than c_long +/// and therefore use the data field to return values. This function handles these +/// requests. +fn ptrace_get_data(request: ptrace::PtraceRequest, pid: pid_t) -> Result { + // Creates an uninitialized pointer to store result in + let data: Box = Box::new(unsafe { mem::uninitialized() }); + let data: *mut c_void = unsafe { mem::transmute(data) }; + ptrace(request, pid, ptr::null_mut(), data)?; + // Convert back into the original data format and return unboxed value + let data: Box = unsafe { mem::transmute(data) }; + Ok(*data) +} + fn ptrace_other(request: ptrace::PtraceRequest, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> Result { Errno::result(unsafe { ffi::ptrace(request, pid, addr, data) }).map(|_| 0) } @@ -102,3 +120,28 @@ pub fn ptrace_setoptions(pid: pid_t, options: ptrace::PtraceOptions) -> Result<( ptrace(PTRACE_SETOPTIONS, pid, ptr::null_mut(), options as *mut c_void).map(drop) } + +/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)` +pub fn ptrace_getevent(pid: pid_t) -> Result { + use self::ptrace::*; + ptrace_get_data::(PTRACE_GETEVENTMSG, pid) +} + +/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)` +pub fn ptrace_getsiginfo(pid: pid_t) -> Result { + use self::ptrace::*; + ptrace_get_data::(PTRACE_GETSIGINFO, pid) +} + +/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)` +pub fn ptrace_setsiginfo(pid: pid_t, sig: &siginfo_t) -> Result<()> { + use self::ptrace::*; + let ret = unsafe{ + Errno::clear(); + ffi::ptrace(PTRACE_SETSIGINFO, pid, ptr::null_mut(), sig as *const _ as *const c_void) + }; + match Errno::result(ret) { + Ok(_) => Ok(()), + Err(e) => Err(e), + } +}