diff options
-rw-r--r-- | CHANGELOG.md | 9 | ||||
-rw-r--r-- | src/fcntl.rs | 301 | ||||
-rw-r--r-- | src/macros.rs | 17 | ||||
-rw-r--r-- | src/sched.rs | 23 | ||||
-rw-r--r-- | src/sys/memfd.rs | 5 | ||||
-rw-r--r-- | src/sys/mod.rs | 3 | ||||
-rw-r--r-- | src/sys/ptrace.rs | 235 | ||||
-rw-r--r-- | src/sys/syscall.rs | 91 | ||||
-rw-r--r-- | src/unistd.rs | 8 | ||||
-rw-r--r-- | test/sys/test_ptrace.rs | 3 | ||||
-rw-r--r-- | test/sys/test_termios.rs | 2 | ||||
-rw-r--r-- | test/sys/test_wait.rs | 4 |
12 files changed, 364 insertions, 337 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 148f0c6d..36b528ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#739](https://github.com/nix-rust/nix/pull/739)) - Expose `signalfd` module on Android as well. ([#739](https://github.com/nix-rust/nix/pull/739)) +- Added nix::sys::ptrace::detach. + ([#749](https://github.com/nix-rust/nix/pull/749)) ### Changed - Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692)) @@ -47,11 +49,18 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#731](https://github.com/nix-rust/nix/pull/731)) - Marked `pty::ptsname` function as `unsafe` ([#744](https://github.com/nix-rust/nix/pull/744)) +- Moved constants ptrace request, event and options to enums and updated ptrace functions and argument types accordingly. + ([#749](https://github.com/nix-rust/nix/pull/749)) # Fixed - Fix compilation and tests for OpenBSD targets ([#688](https://github.com/nix-rust/nix/pull/688)) +# Removed +- The syscall module has been removed. This only exposed enough functionality for + `memfd_create()` and `pivot_root()`, which are still exposed as separate functions. + ([#747](https://github.com/nix-rust/nix/pull/747)) + ## [0.9.0] 2017-07-23 ### Added diff --git a/src/fcntl.rs b/src/fcntl.rs index e42c923e..003c316c 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -5,31 +5,138 @@ use std::os::unix::io::RawFd; use std::ffi::OsStr; use std::os::unix::ffi::OsStrExt; -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(any(target_os = "android", target_os = "linux"))] use sys::uio::IoVec; // For vmsplice -pub use self::consts::*; - -// TODO: The remainder of the ffi module should be removed afer work on -// https://github.com/rust-lang/libc/issues/235 is resolved. -#[allow(dead_code)] -mod ffi { - use libc::c_int; - - pub const F_ADD_SEALS: c_int = 1033; - pub const F_GET_SEALS: c_int = 1034; -} - libc_bitflags!{ pub struct AtFlags: c_int { AT_SYMLINK_NOFOLLOW; - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(any(target_os = "android", target_os = "linux"))] AT_NO_AUTOMOUNT; - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(any(target_os = "android", target_os = "linux"))] AT_EMPTY_PATH; } } +libc_bitflags!( + /// Configuration options for opened files. + pub struct OFlag: c_int { + /// Mask for the access mode of the file. + O_ACCMODE; + /// Use alternate I/O semantics. + #[cfg(target_os = "netbsd")] + O_ALT_IO; + /// Open the file in append-only mode. + O_APPEND; + /// Generate a signal when input or output becomes possible. + O_ASYNC; + /// Closes the file descriptor once an `execve` call is made. + /// + /// Also sets the file offset to the beginning of the file. + O_CLOEXEC; + /// Create the file if it does not exist. + O_CREAT; + /// Try to minimize cache effects of the I/O for this file. + #[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd"))] + O_DIRECT; + /// If the specified path isn't a directory, fail. + O_DIRECTORY; + /// Implicitly follow each `write()` with an `fdatasync()`. + #[cfg(any(target_os = "android", + target_os = "dragonfly", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + O_DSYNC; + /// Error out if a file was not created. + O_EXCL; + /// Open for execute only. + #[cfg(target_os = "freebsd")] + O_EXEC; + /// Open with an exclusive file lock. + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + O_EXLOCK; + /// Same as `O_SYNC`. + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + all(target_os = "linux", not(target_env = "musl")), + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + O_FSYNC; + /// Allow files whose sizes can't be represented in an `off_t` to be opened. + #[cfg(any(target_os = "android", target_os = "linux"))] + O_LARGEFILE; + /// Do not update the file last access time during `read(2)`s. + #[cfg(any(target_os = "android", target_os = "linux"))] + O_NOATIME; + /// Don't attach the device as the process' controlling terminal. + O_NOCTTY; + /// Same as `O_NONBLOCK`. + O_NDELAY; + /// `open()` will fail if the given path is a symbolic link. + O_NOFOLLOW; + /// When possible, open the file in nonblocking mode. + O_NONBLOCK; + /// Don't deliver `SIGPIPE`. + #[cfg(target_os = "netbsd")] + O_NOSIGPIPE; + /// Obtain a file descriptor for low-level access. + /// + /// The file itself is not opened and other file operations will fail. + #[cfg(any(target_os = "android", target_os = "linux"))] + O_PATH; + /// Only allow reading. + /// + /// This should not be combined with `O_WRONLY` or `O_RDWR`. + O_RDONLY; + /// Allow both reading and writing. + /// + /// This should not be combined with `O_WRONLY` or `O_RDWR`. + O_RDWR; + /// Similar to `O_DSYNC` but applies to `read`s instead. + #[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "openbsd"))] + O_RSYNC; + /// Skip search permission checks. + #[cfg(target_os = "netbsd")] + O_SEARCH; + /// Open with a shared file lock. + #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] + O_SHLOCK; + /// Implicitly follow each `write()` with an `fsync()`. + O_SYNC; + /// Create an unnamed temporary file. + #[cfg(any(target_os = "android", target_os = "linux"))] + O_TMPFILE; + /// Truncate an existing regular file to 0 length if it allows writing. + O_TRUNC; + /// Restore default TTY attributes. + #[cfg(target_os = "freebsd")] + O_TTY_INIT; + /// Only allow writing. + /// + /// This should not be combined with `O_RDONLY` or `O_RDWR`. + O_WRONLY; + } +); + pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> { let fd = try!(path.with_nix_path(|cstr| { unsafe { libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) } @@ -76,6 +183,29 @@ pub fn readlinkat<'a, P: ?Sized + NixPath>(dirfd: RawFd, path: &P, buffer: &'a m wrap_readlink_result(buffer, res) } +#[cfg(any(target_os = "android", target_os = "linux"))] +libc_bitflags!( + /// Additional flags for file sealing, which allows for limiting operations on a file. + pub struct SealFlag: c_int { + /// Prevents further calls to `fcntl()` with `F_ADD_SEALS`. + F_SEAL_SEAL; + /// The file cannot be reduced in size. + F_SEAL_SHRINK; + /// The size of the file cannot be increased. + F_SEAL_GROW; + /// The file contents cannot be modified. + F_SEAL_WRITE; + } +); + +libc_bitflags!( + /// Additional configuration flags for `fcntl`'s `F_SETFD`. + pub struct FdFlag: c_int { + /// The file descriptor will automatically be closed during a successful `execve(2)`. + FD_CLOEXEC; + } +); + pub enum FcntlArg<'a> { F_DUPFD(RawFd), F_DUPFD_CLOEXEC(RawFd), @@ -92,9 +222,9 @@ pub enum FcntlArg<'a> { F_OFD_SETLKW(&'a libc::flock), #[cfg(any(target_os = "linux", target_os = "android"))] F_OFD_GETLK(&'a mut libc::flock), - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "android", target_os = "linux"))] F_ADD_SEALS(SealFlag), - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "android", target_os = "linux"))] F_GET_SEALS, #[cfg(any(target_os = "macos", target_os = "ios"))] F_FULLFSYNC, @@ -120,10 +250,10 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> { F_SETLK(flock) => libc::fcntl(fd, libc::F_SETLK, flock), F_SETLKW(flock) => libc::fcntl(fd, libc::F_SETLKW, flock), F_GETLK(flock) => libc::fcntl(fd, libc::F_GETLK, flock), - #[cfg(target_os = "linux")] - F_ADD_SEALS(flag) => libc::fcntl(fd, ffi::F_ADD_SEALS, flag.bits()), - #[cfg(target_os = "linux")] - F_GET_SEALS => libc::fcntl(fd, ffi::F_GET_SEALS), + #[cfg(any(target_os = "android", target_os = "linux"))] + F_ADD_SEALS(flag) => libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()), + #[cfg(any(target_os = "android", target_os = "linux"))] + F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS), #[cfg(any(target_os = "macos", target_os = "ios"))] F_FULLFSYNC => libc::fcntl(fd, libc::F_FULLFSYNC), #[cfg(any(target_os = "linux", target_os = "android"))] @@ -164,6 +294,27 @@ pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> { Errno::result(res).map(drop) } +#[cfg(any(target_os = "android", target_os = "linux"))] +libc_bitflags! { + /// Additional flags to `splice` and friends. + pub struct SpliceFFlags: c_uint { + /// Request that pages be moved instead of copied. + /// + /// Not applicable to `vmsplice`. + SPLICE_F_MOVE; + /// Do not block on I/O. + SPLICE_F_NONBLOCK; + /// Hint that more data will be coming in a subsequent splice. + /// + /// Not applicable to `vmsplice`. + SPLICE_F_MORE; + /// Gift the user pages to the kernel. + /// + /// Not applicable to `splice`. + SPLICE_F_GIFT; + } +} + #[cfg(any(target_os = "linux", target_os = "android"))] pub fn splice(fd_in: RawFd, off_in: Option<&mut libc::loff_t>, fd_out: RawFd, off_out: Option<&mut libc::loff_t>, @@ -190,111 +341,3 @@ pub fn vmsplice(fd: RawFd, iov: &[IoVec<&[u8]>], flags: SpliceFFlags) -> Result< Errno::result(ret).map(|r| r as usize) } -#[cfg(any(target_os = "linux", target_os = "android"))] -mod consts { - use libc::{self, c_int, c_uint}; - - libc_bitflags! { - pub struct SpliceFFlags: c_uint { - SPLICE_F_MOVE; - SPLICE_F_NONBLOCK; - SPLICE_F_MORE; - SPLICE_F_GIFT; - } - } - - bitflags!( - pub struct OFlag: c_int { - const O_ACCMODE = libc::O_ACCMODE; - const O_RDONLY = libc::O_RDONLY; - const O_WRONLY = libc::O_WRONLY; - const O_RDWR = libc::O_RDWR; - const O_CREAT = libc::O_CREAT; - const O_EXCL = libc::O_EXCL; - const O_NOCTTY = libc::O_NOCTTY; - const O_TRUNC = libc::O_TRUNC; - const O_APPEND = libc::O_APPEND; - const O_NONBLOCK = libc::O_NONBLOCK; - const O_DSYNC = libc::O_DSYNC; - const O_DIRECT = libc::O_DIRECT; - const O_LARGEFILE = 0o00100000; - const O_DIRECTORY = libc::O_DIRECTORY; - const O_NOFOLLOW = libc::O_NOFOLLOW; - const O_NOATIME = 0o01000000; - const O_CLOEXEC = libc::O_CLOEXEC; - const O_SYNC = libc::O_SYNC; - const O_PATH = 0o10000000; - const O_TMPFILE = libc::O_TMPFILE; - const O_NDELAY = libc::O_NDELAY; - } - ); - - libc_bitflags!( - pub struct FdFlag: c_int { - FD_CLOEXEC; - } - ); - - bitflags!( - pub struct SealFlag: c_int { - const F_SEAL_SEAL = 1; - const F_SEAL_SHRINK = 2; - const F_SEAL_GROW = 4; - const F_SEAL_WRITE = 8; - } - ); - -} - -#[cfg(any(target_os = "netbsd", target_os = "dragonfly", target_os = "openbsd", - target_os = "freebsd", target_os = "macos", target_os = "ios"))] -mod consts { - use libc::{self,c_int}; - - libc_bitflags!( - pub struct OFlag: c_int { - O_ACCMODE; - O_RDONLY; - O_WRONLY; - O_RDWR; - O_NONBLOCK; - O_APPEND; - O_SHLOCK; - O_EXLOCK; - O_ASYNC; - O_SYNC; - O_NOFOLLOW; - O_CREAT; - O_TRUNC; - O_EXCL; - O_NOCTTY; - O_DIRECTORY; - O_CLOEXEC; - O_FSYNC; - O_NDELAY; - #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "macos", - target_os = "ios"))] - O_DSYNC; - #[cfg(any(target_os = "netbsd", target_os = "dragonfly", target_os = "freebsd"))] - O_DIRECT; - #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] - O_RSYNC; - #[cfg(target_os = "freebsd")] - O_EXEC; - #[cfg(target_os = "freebsd")] - O_TTY_INIT; - #[cfg(target_os = "netbsd")] - O_ALT_IO; - #[cfg(target_os = "netbsd")] - O_NOSIGPIPE; - #[cfg(target_os = "netbsd")] - O_SEARCH; - } - ); - - libc_bitflags!( - pub struct FdFlag: c_int { - FD_CLOEXEC; - } - ); -} diff --git a/src/macros.rs b/src/macros.rs index 7a0eb07c..39bc466d 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -379,6 +379,23 @@ macro_rules! libc_enum { } }; + // Munch an ident and cast it to the given type; covers terminating comma. + (@accumulate_entries + $prefix:tt, + [$($entries:tt)*]; + $entry:ident as $ty:ty, $($tail:tt)* + ) => { + libc_enum! { + @accumulate_entries + $prefix, + [ + $($entries)* + $entry = libc::$entry as $ty, + ]; + $($tail)* + } + }; + // (non-pub) Entry rule. ( $(#[$attr:meta])* diff --git a/src/sched.rs b/src/sched.rs index 943b432b..74c23072 100644 --- a/src/sched.rs +++ b/src/sched.rs @@ -73,25 +73,6 @@ impl CpuSet { } } -mod ffi { - use libc::{c_void, c_int}; - - pub type CloneCb = extern "C" fn(data: *const super::CloneCb) -> c_int; - - // We cannot give a proper #[repr(C)] to super::CloneCb - #[allow(improper_ctypes)] - extern "C" { - // create a child process - // doc: http://man7.org/linux/man-pages/man2/clone.2.html - pub fn clone(cb: *const CloneCb, - child_stack: *mut c_void, - flags: c_int, - arg: *mut super::CloneCb, - ...) - -> c_int; - } -} - pub fn sched_setaffinity(pid: Pid, cpuset: &CpuSet) -> Result<()> { let res = unsafe { libc::sched_setaffinity(pid.into(), @@ -116,10 +97,10 @@ pub fn clone(mut cb: CloneCb, let combined = flags.bits() | signal.unwrap_or(0); let ptr = stack.as_mut_ptr().offset(stack.len() as isize); let ptr_aligned = ptr.offset((ptr as usize % 16) as isize * -1); - ffi::clone(mem::transmute(callback as extern "C" fn(*mut Box<::std::ops::FnMut() -> isize>) -> i32), + libc::clone(mem::transmute(callback as extern "C" fn(*mut Box<::std::ops::FnMut() -> isize>) -> i32), ptr_aligned as *mut c_void, combined, - &mut cb) + &mut cb as *mut _ as *mut c_void) }; Errno::result(res).map(Pid::from_raw) diff --git a/src/sys/memfd.rs b/src/sys/memfd.rs index b9812943..056e9e43 100644 --- a/src/sys/memfd.rs +++ b/src/sys/memfd.rs @@ -11,8 +11,9 @@ bitflags!( ); pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<RawFd> { - use sys::syscall::{syscall, MEMFD_CREATE}; - let res = unsafe { syscall(MEMFD_CREATE, name.as_ptr(), flags.bits()) }; + let res = unsafe { + libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags.bits()) + }; Errno::result(res).map(|r| r as RawFd) } diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 16a0ee3d..c99fe2db 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -31,9 +31,6 @@ pub mod socket; pub mod stat; -#[cfg(any(target_os = "linux", target_os = "android"))] -pub mod syscall; - #[cfg(any(target_os = "linux"))] pub mod reboot; diff --git a/src/sys/ptrace.rs b/src/sys/ptrace.rs index 5f0391d4..64b523c3 100644 --- a/src/sys/ptrace.rs +++ b/src/sys/ptrace.rs @@ -6,68 +6,117 @@ use libc::{self, c_void, c_long, siginfo_t}; use ::unistd::Pid; use sys::signal::Signal; -pub mod ptrace { - use libc::c_int; - - cfg_if! { - if #[cfg(any(all(target_os = "linux", arch = "s390x"), - all(target_os = "linux", target_env = "gnu")))] { - pub type PtraceRequest = ::libc::c_uint; - } else { - pub type PtraceRequest = c_int; - } + +cfg_if! { + if #[cfg(any(all(target_os = "linux", arch = "s390x"), + all(target_os = "linux", target_env = "gnu")))] { + #[doc(hidden)] + pub type RequestType = ::libc::c_uint; + } else { + #[doc(hidden)] + pub type RequestType = ::libc::c_int; + } +} + +libc_enum!{ + #[cfg_attr(not(any(target_env = "musl", target_os = "android")), repr(u32))] + #[cfg_attr(any(target_env = "musl", target_os = "android"), repr(i32))] + /// Ptrace Request enum defining the action to be taken. + pub enum Request { + PTRACE_TRACEME, + PTRACE_PEEKTEXT, + PTRACE_PEEKDATA, + PTRACE_PEEKUSER, + PTRACE_POKETEXT, + PTRACE_POKEDATA, + PTRACE_POKEUSER, + PTRACE_CONT, + PTRACE_KILL, + PTRACE_SINGLESTEP, + #[cfg(all(any(target_env = "musl", target_arch ="x86_64", target_arch = "s390x"), not(target_os = "android")))] + PTRACE_GETREGS, + #[cfg(all(any(target_env = "musl", target_arch ="x86_64", target_arch = "s390x"), not(target_os = "android")))] + PTRACE_SETREGS, + #[cfg(all(any(target_env = "musl", target_arch ="x86_64", target_arch = "s390x"), not(target_os = "android")))] + PTRACE_GETFPREGS, + #[cfg(all(any(target_env = "musl", target_arch ="x86_64", target_arch = "s390x"), not(target_os = "android")))] + PTRACE_SETFPREGS, + PTRACE_ATTACH, + PTRACE_DETACH, + #[cfg(all(any(target_env = "musl", target_arch ="x86_64"), not(target_os = "android")))] + PTRACE_GETFPXREGS, + #[cfg(all(any(target_env = "musl", target_arch ="x86_64"), not(target_os = "android")))] + PTRACE_SETFPXREGS, + PTRACE_SYSCALL, + PTRACE_SETOPTIONS, + PTRACE_GETEVENTMSG, + PTRACE_GETSIGINFO, + PTRACE_SETSIGINFO, + #[cfg(all(any(target_env = "musl", target_arch ="x86_64", target_arch = "s390x"), not(target_os = "android")))] + PTRACE_GETREGSET, + #[cfg(all(any(target_env = "musl", target_arch ="x86_64", target_arch = "s390x"), not(target_os = "android")))] + PTRACE_SETREGSET, + #[cfg(not(any(target_os = "android", target_arch = "mips", target_arch = "mips64")))] + PTRACE_SEIZE, + #[cfg(not(any(target_os = "android", target_arch = "mips", target_arch = "mips64")))] + PTRACE_INTERRUPT, + #[cfg(not(any(target_os = "android", target_arch = "mips", target_arch = "mips64")))] + PTRACE_LISTEN, + #[cfg(not(any(target_os = "android", target_arch = "mips", target_arch = "mips64")))] + PTRACE_PEEKSIGINFO, + } +} + +libc_enum!{ + #[repr(i32)] + /// Using the ptrace options the tracer can configure the tracee to stop + /// at certain events. This enum is used to define those events as defined + /// in `man ptrace`. + pub enum Event { + /// Event that stops before a return from fork or clone. + PTRACE_EVENT_FORK, + /// Event that stops before a return from vfork or clone. + PTRACE_EVENT_VFORK, + /// Event that stops before a return from clone. + PTRACE_EVENT_CLONE, + /// Event that stops before a return from execve. + PTRACE_EVENT_EXEC, + /// Event for a return from vfork. + PTRACE_EVENT_VFORK_DONE, + /// Event for a stop before an exit. Unlike the waitpid Exit status program. + /// registers can still be examined + PTRACE_EVENT_EXIT, + /// STop triggered by a seccomp rule on a tracee. + PTRACE_EVENT_SECCOMP, + // PTRACE_EVENT_STOP not provided by libc because it's defined in glibc 2.26 } +} - pub const PTRACE_TRACEME: PtraceRequest = 0; - pub const PTRACE_PEEKTEXT: PtraceRequest = 1; - pub const PTRACE_PEEKDATA: PtraceRequest = 2; - pub const PTRACE_PEEKUSER: PtraceRequest = 3; - pub const PTRACE_POKETEXT: PtraceRequest = 4; - pub const PTRACE_POKEDATA: PtraceRequest = 5; - pub const PTRACE_POKEUSER: PtraceRequest = 6; - pub const PTRACE_CONT: PtraceRequest = 7; - pub const PTRACE_KILL: PtraceRequest = 8; - pub const PTRACE_SINGLESTEP: PtraceRequest = 9; - pub const PTRACE_GETREGS: PtraceRequest = 12; - pub const PTRACE_SETREGS: PtraceRequest = 13; - pub const PTRACE_GETFPREGS: PtraceRequest = 14; - pub const PTRACE_SETFPREGS: PtraceRequest = 15; - pub const PTRACE_ATTACH: PtraceRequest = 16; - pub const PTRACE_DETACH: PtraceRequest = 17; - pub const PTRACE_GETFPXREGS: PtraceRequest = 18; - pub const PTRACE_SETFPXREGS: PtraceRequest = 19; - pub const PTRACE_SYSCALL: PtraceRequest = 24; - pub const PTRACE_SETOPTIONS: PtraceRequest = 0x4200; - pub const PTRACE_GETEVENTMSG: PtraceRequest = 0x4201; - pub const PTRACE_GETSIGINFO: PtraceRequest = 0x4202; - pub const PTRACE_SETSIGINFO: PtraceRequest = 0x4203; - pub const PTRACE_GETREGSET: PtraceRequest = 0x4204; - pub const PTRACE_SETREGSET: PtraceRequest = 0x4205; - pub const PTRACE_SEIZE: PtraceRequest = 0x4206; - pub const PTRACE_INTERRUPT: PtraceRequest = 0x4207; - pub const PTRACE_LISTEN: PtraceRequest = 0x4208; - pub const PTRACE_PEEKSIGINFO: PtraceRequest = 0x4209; - - pub type PtraceEvent = c_int; - - pub const PTRACE_EVENT_FORK: PtraceEvent = 1; - pub const PTRACE_EVENT_VFORK: PtraceEvent = 2; - pub const PTRACE_EVENT_CLONE: PtraceEvent = 3; - pub const PTRACE_EVENT_EXEC: PtraceEvent = 4; - pub const PTRACE_EVENT_VFORK_DONE: PtraceEvent = 5; - pub const PTRACE_EVENT_EXIT: PtraceEvent = 6; - pub const PTRACE_EVENT_SECCOMP: PtraceEvent = 6; - pub const PTRACE_EVENT_STOP: PtraceEvent = 128; - - pub type PtraceOptions = c_int; - pub const PTRACE_O_TRACESYSGOOD: PtraceOptions = 1; - pub const PTRACE_O_TRACEFORK: PtraceOptions = (1 << PTRACE_EVENT_FORK); - pub const PTRACE_O_TRACEVFORK: PtraceOptions = (1 << PTRACE_EVENT_VFORK); - pub const PTRACE_O_TRACECLONE: PtraceOptions = (1 << PTRACE_EVENT_CLONE); - pub const PTRACE_O_TRACEEXEC: PtraceOptions = (1 << PTRACE_EVENT_EXEC); - pub const PTRACE_O_TRACEVFORKDONE: PtraceOptions = (1 << PTRACE_EVENT_VFORK_DONE); - pub const PTRACE_O_TRACEEXIT: PtraceOptions = (1 << PTRACE_EVENT_EXIT); - pub const PTRACE_O_TRACESECCOMP: PtraceOptions = (1 << PTRACE_EVENT_SECCOMP); +libc_bitflags! { + /// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request. + /// See `man ptrace` for more details. + pub struct Options: libc::c_int { + /// When delivering system call traps set a bit to allow tracer to + /// distinguish between normal stops or syscall stops. May not work on + /// all systems. + PTRACE_O_TRACESYSGOOD; + /// Stop tracee at next fork and start tracing the forked process. + PTRACE_O_TRACEFORK; + /// Stop tracee at next vfork call and trace the vforked process. + PTRACE_O_TRACEVFORK; + /// Stop tracee at next clone call and trace the cloned process. + PTRACE_O_TRACECLONE; + /// Stop tracee at next execve call. + PTRACE_O_TRACEEXEC; + /// Stop tracee at vfork completion. + PTRACE_O_TRACEVFORKDONE; + /// Stop tracee at next exit call. Stops before exit commences allowing + /// tracer to see location of exit and register states. + PTRACE_O_TRACEEXIT; + /// Stop tracee when a SECCOMP_RET_TRACE rule is triggered. See `man seccomp` for more + /// details. + PTRACE_O_TRACESECCOMP; + } } /// Performs a ptrace request. If the request in question is provided by a specialised function @@ -76,9 +125,8 @@ pub mod ptrace { since="0.10.0", note="usages of `ptrace()` should be replaced with the specialized helper functions instead" )] -pub unsafe fn ptrace(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> { - use self::ptrace::*; - +pub unsafe fn ptrace(request: Request, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> { + use self::Request::*; 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), @@ -86,10 +134,10 @@ pub unsafe fn ptrace(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void } } -fn ptrace_peek(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> { +fn ptrace_peek(request: Request, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> { let ret = unsafe { Errno::clear(); - libc::ptrace(request, libc::pid_t::from(pid), addr, data) + libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data) }; match Errno::result(ret) { Ok(..) | Err(Error::Sys(Errno::UnknownErrno)) => Ok(ret), @@ -101,45 +149,54 @@ fn ptrace_peek(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data /// 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<T>(request: ptrace::PtraceRequest, pid: Pid) -> Result<T> { +fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> { // Creates an uninitialized pointer to store result in let data: T = unsafe { mem::uninitialized() }; - let res = unsafe { libc::ptrace(request, libc::pid_t::from(pid), ptr::null_mut::<T>(), &data as *const _ as *const c_void) }; + let res = unsafe { + libc::ptrace(request as RequestType, + libc::pid_t::from(pid), + ptr::null_mut::<T>(), + &data as *const _ as *const c_void) + }; Errno::result(res)?; Ok(data) } -unsafe fn ptrace_other(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> { - Errno::result(libc::ptrace(request, libc::pid_t::from(pid), addr, data)).map(|_| 0) +unsafe fn ptrace_other(request: Request, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> { + Errno::result(libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)).map(|_| 0) } /// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`. -pub fn setoptions(pid: Pid, options: ptrace::PtraceOptions) -> Result<()> { - use self::ptrace::*; +pub fn setoptions(pid: Pid, options: Options) -> Result<()> { use std::ptr; - let res = unsafe { libc::ptrace(PTRACE_SETOPTIONS, libc::pid_t::from(pid), ptr::null_mut::<libc::c_void>(), options as *mut c_void) }; + let res = unsafe { + libc::ptrace(Request::PTRACE_SETOPTIONS as RequestType, + libc::pid_t::from(pid), + ptr::null_mut::<libc::c_void>(), + options.bits() as *mut c_void) + }; Errno::result(res).map(|_| ()) } /// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)` pub fn getevent(pid: Pid) -> Result<c_long> { - use self::ptrace::*; - ptrace_get_data::<c_long>(PTRACE_GETEVENTMSG, pid) + ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid) } /// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)` pub fn getsiginfo(pid: Pid) -> Result<siginfo_t> { - use self::ptrace::*; - ptrace_get_data::<siginfo_t>(PTRACE_GETSIGINFO, pid) + ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid) } /// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)` pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> { - use self::ptrace::*; let ret = unsafe{ Errno::clear(); - libc::ptrace(PTRACE_SETSIGINFO, libc::pid_t::from(pid), ptr::null_mut::<libc::c_void>(), sig as *const _ as *const c_void) + libc::ptrace(Request::PTRACE_SETSIGINFO as RequestType, + libc::pid_t::from(pid), + ptr::null_mut::<libc::c_void>(), + sig as *const _ as *const c_void) }; match Errno::result(ret) { Ok(_) => Ok(()), @@ -154,7 +211,7 @@ pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> { pub fn traceme() -> Result<()> { unsafe { ptrace_other( - ptrace::PTRACE_TRACEME, + Request::PTRACE_TRACEME, Pid::from_raw(0), ptr::null_mut(), ptr::null_mut(), @@ -168,7 +225,7 @@ pub fn traceme() -> Result<()> { pub fn syscall(pid: Pid) -> Result<()> { unsafe { ptrace_other( - ptrace::PTRACE_SYSCALL, + Request::PTRACE_SYSCALL, pid, ptr::null_mut(), ptr::null_mut(), @@ -182,7 +239,7 @@ pub fn syscall(pid: Pid) -> Result<()> { pub fn attach(pid: Pid) -> Result<()> { unsafe { ptrace_other( - ptrace::PTRACE_ATTACH, + Request::PTRACE_ATTACH, pid, ptr::null_mut(), ptr::null_mut(), @@ -190,6 +247,20 @@ pub fn attach(pid: Pid) -> Result<()> { } } +/// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)` +/// +/// Detaches from the process specified in pid allowing it to run freely +pub fn detach(pid: Pid) -> Result<()> { + unsafe { + ptrace_other( + Request::PTRACE_DETACH, + pid, + ptr::null_mut(), + ptr::null_mut() + ).map(|_| ()) + } +} + /// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)` /// /// Continues the execution of the process with PID `pid`, optionally @@ -200,7 +271,7 @@ pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { None => ptr::null_mut(), }; unsafe { - ptrace_other(ptrace::PTRACE_CONT, pid, ptr::null_mut(), data).map(|_| ()) // ignore the useless return value + ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(|_| ()) // ignore the useless return value } } diff --git a/src/sys/syscall.rs b/src/sys/syscall.rs deleted file mode 100644 index 50866ca7..00000000 --- a/src/sys/syscall.rs +++ /dev/null @@ -1,91 +0,0 @@ -//! Indirect system call -//! -use libc::c_int; - -pub use self::arch::*; - -#[cfg(target_arch = "x86_64")] -mod arch { - use libc::c_long; - - pub type Syscall = c_long; - - pub static SYSPIVOTROOT: Syscall = 155; - pub static MEMFD_CREATE: Syscall = 319; -} - -#[cfg(target_arch = "x86")] -mod arch { - use libc::c_long; - - pub type Syscall = c_long; - - pub static SYSPIVOTROOT: Syscall = 217; - pub static MEMFD_CREATE: Syscall = 356; -} - -#[cfg(target_arch = "aarch64")] -mod arch { - use libc::c_long; - - pub type Syscall = c_long; - - pub static SYSPIVOTROOT: Syscall = 41; - pub static MEMFD_CREATE: Syscall = 279; -} - -#[cfg(target_arch = "arm")] -mod arch { - use libc::c_long; - - pub type Syscall = c_long; - - pub static SYSPIVOTROOT: Syscall = 218; - pub static MEMFD_CREATE: Syscall = 385; -} - -// Rust on mips uses the N32 ABI -#[cfg(target_arch = "mips")] -mod arch { - use libc::c_long; - - pub type Syscall = c_long; - - pub static SYSPIVOTROOT: Syscall = 216; - pub static MEMFD_CREATE: Syscall = 354; -} - -// Rust on mips64 uses the N64 ABI -#[cfg(target_arch = "mips64")] -mod arch { - use libc::c_long; - - pub type Syscall = c_long; - - pub static SYSPIVOTROOT: Syscall = 151; - pub static MEMFD_CREATE: Syscall = 314; -} - -#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] -mod arch { - use libc::c_long; - - pub type Syscall = c_long; - - pub static SYSPIVOTROOT: Syscall = 203; - pub static MEMFD_CREATE: Syscall = 360; -} - -#[cfg(target_arch = "s390x")] -mod arch { - use libc::c_long; - - pub type Syscall = c_long; - - pub static SYSPIVOTROOT: Syscall = 217; - pub static MEMFD_CREATE: Syscall = 350; -} - -extern { - pub fn syscall(num: Syscall, ...) -> c_int; -} diff --git a/src/unistd.rs b/src/unistd.rs index af38cf2d..fad51272 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -16,7 +16,7 @@ use sys::stat::Mode; use std::fmt; #[cfg(any(target_os = "android", target_os = "linux"))] -pub use self::linux::*; +pub use self::pivot_root::*; #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux", target_os = "openbsd"))] @@ -1647,8 +1647,8 @@ pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> { } #[cfg(any(target_os = "android", target_os = "linux"))] -mod linux { - use sys::syscall::{syscall, SYSPIVOTROOT}; +mod pivot_root { + use libc; use {Errno, Result, NixPath}; pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( @@ -1656,7 +1656,7 @@ mod linux { let res = try!(try!(new_root.with_nix_path(|new_root| { put_old.with_nix_path(|put_old| { unsafe { - syscall(SYSPIVOTROOT, new_root.as_ptr(), put_old.as_ptr()) + libc::syscall(libc::SYS_pivot_root, new_root.as_ptr(), put_old.as_ptr()) } }) }))); diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs index 16b24110..20cde1aa 100644 --- a/test/sys/test_ptrace.rs +++ b/test/sys/test_ptrace.rs @@ -16,8 +16,7 @@ fn test_ptrace() { // Just make sure ptrace_setoptions can be called at all, for now. #[test] fn test_ptrace_setoptions() { - use nix::sys::ptrace::ptrace::PTRACE_O_TRACESYSGOOD; - let err = ptrace::setoptions(getpid(), PTRACE_O_TRACESYSGOOD).unwrap_err(); + let err = ptrace::setoptions(getpid(), ptrace::PTRACE_O_TRACESYSGOOD).unwrap_err(); assert!(err != Error::UnsupportedOperation); } diff --git a/test/sys/test_termios.rs b/test/sys/test_termios.rs index 2455a4e5..6640c3af 100644 --- a/test/sys/test_termios.rs +++ b/test/sys/test_termios.rs @@ -116,7 +116,7 @@ fn test_local_flags() { // Set the master is in nonblocking mode or reading will never return. let flags = fcntl::fcntl(pty.master, fcntl::F_GETFL).unwrap(); - let new_flags = fcntl::OFlag::from_bits(flags).unwrap() | fcntl::O_NONBLOCK; + let new_flags = fcntl::OFlag::from_bits_truncate(flags) | fcntl::O_NONBLOCK; fcntl::fcntl(pty.master, fcntl::F_SETFL(new_flags)).unwrap(); // Write into the master diff --git a/test/sys/test_wait.rs b/test/sys/test_wait.rs index 0193e262..0fcaa19c 100644 --- a/test/sys/test_wait.rs +++ b/test/sys/test_wait.rs @@ -55,7 +55,7 @@ fn test_waitstatus_pid() { #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] mod ptrace { use nix::sys::ptrace; - use nix::sys::ptrace::ptrace::*; + use nix::sys::ptrace::*; use nix::sys::signal::*; use nix::sys::wait::*; use nix::unistd::*; @@ -81,7 +81,7 @@ mod ptrace { assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); // Then get the ptrace event for the process exiting assert!(ptrace::cont(child, None).is_ok()); - assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceEvent(child, SIGTRAP, PTRACE_EVENT_EXIT))); + assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceEvent(child, SIGTRAP, Event::PTRACE_EVENT_EXIT as i32))); // Finally get the normal wait() result, now that the process has exited assert!(ptrace::cont(child, None).is_ok()); assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0))); |