summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fcntl.rs9
-rw-r--r--src/lib.rs17
-rw-r--r--src/sys/aio.rs4
-rw-r--r--src/sys/ioctl/linux.rs2
-rw-r--r--src/sys/ioctl/mod.rs15
-rw-r--r--src/sys/mod.rs8
-rw-r--r--src/sys/ptrace/bsd.rs170
-rw-r--r--src/sys/ptrace/linux.rs (renamed from src/sys/ptrace.rs)50
-rw-r--r--src/sys/ptrace/mod.rs22
-rw-r--r--src/sys/signal.rs10
-rw-r--r--src/sys/signalfd.rs2
-rw-r--r--src/sys/socket/addr.rs3
-rw-r--r--src/sys/socket/mod.rs14
-rw-r--r--src/sys/stat.rs50
-rw-r--r--src/sys/termios.rs45
-rw-r--r--src/sys/time.rs3
-rw-r--r--src/unistd.rs153
17 files changed, 496 insertions, 81 deletions
diff --git a/src/fcntl.rs b/src/fcntl.rs
index 58de3b31..5942506b 100644
--- a/src/fcntl.rs
+++ b/src/fcntl.rs
@@ -2,6 +2,7 @@ use {Error, Result, NixPath};
use errno::Errno;
use libc::{self, c_int, c_uint, c_char, size_t, ssize_t};
use sys::stat::Mode;
+use std::os::raw;
use std::os::unix::io::RawFd;
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
@@ -182,6 +183,14 @@ pub fn readlinkat<'a, P: ?Sized + NixPath>(dirfd: RawFd, path: &P, buffer: &'a m
wrap_readlink_result(buffer, res)
}
+/// Computes the raw fd consumed by a function of the form `*at`.
+pub(crate) fn at_rawfd(fd: Option<RawFd>) -> raw::c_int {
+ match fd {
+ None => libc::AT_FDCWD,
+ Some(fd) => fd,
+ }
+}
+
#[cfg(any(target_os = "android", target_os = "linux"))]
libc_bitflags!(
/// Additional flags for file sealing, which allows for limiting operations on a file.
diff --git a/src/lib.rs b/src/lib.rs
index 48426594..ae3cc734 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -110,6 +110,23 @@ pub enum Error {
}
impl Error {
+ /// Convert this `Error` to an [`Errno`](enum.Errno.html).
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use nix::Error;
+ /// # use nix::errno::Errno;
+ /// let e = Error::from(Errno::EPERM);
+ /// assert_eq!(Some(Errno::EPERM), e.as_errno());
+ /// ```
+ pub fn as_errno(&self) -> Option<Errno> {
+ if let &Error::Sys(ref e) = self {
+ Some(*e)
+ } else {
+ None
+ }
+ }
/// Create a nix Error from a given errno
pub fn from_errno(errno: Errno) -> Error {
diff --git a/src/sys/aio.rs b/src/sys/aio.rs
index 3d539821..c54c2e31 100644
--- a/src/sys/aio.rs
+++ b/src/sys/aio.rs
@@ -1138,7 +1138,7 @@ impl<'a> LioCb<'a> {
let p = self.list.as_ptr();
Errno::result(unsafe {
libc::lio_listio(mode as i32, p, self.list.len() as i32, sigevp)
- }).map(|_| ())
+ }).map(drop)
}
/// Resubmits any incomplete operations with [`lio_listio`].
@@ -1229,7 +1229,7 @@ impl<'a> LioCb<'a> {
let p = self.list.as_ptr();
Errno::result(unsafe {
libc::lio_listio(mode as i32, p, self.list.len() as i32, sigevp)
- }).map(|_| ())
+ }).map(drop)
}
/// Collect final status for an individual `AioCb` submitted as part of an
diff --git a/src/sys/ioctl/linux.rs b/src/sys/ioctl/linux.rs
index 17c8cff9..750a1c98 100644
--- a/src/sys/ioctl/linux.rs
+++ b/src/sys/ioctl/linux.rs
@@ -14,7 +14,7 @@ pub const NRBITS: ioctl_num_type = 8;
#[doc(hidden)]
pub const TYPEBITS: ioctl_num_type = 8;
-#[cfg(any(target_arch = "mips", target_arch = "mips64", target_arch = "powerpc", target_arch = "powerpc64"))]
+#[cfg(any(target_arch = "mips", target_arch = "mips64", target_arch = "powerpc", target_arch = "powerpc64", target_arch = "sparc64"))]
mod consts {
#[doc(hidden)]
pub const NONE: u8 = 1;
diff --git a/src/sys/ioctl/mod.rs b/src/sys/ioctl/mod.rs
index e00e5934..35d508b1 100644
--- a/src/sys/ioctl/mod.rs
+++ b/src/sys/ioctl/mod.rs
@@ -221,7 +221,6 @@
//!
//! # fn main() {}
//! ```
-//!
#[cfg(any(target_os = "android", target_os = "linux"))]
#[macro_use]
mod linux;
@@ -502,9 +501,13 @@ cfg_if!{
/// The generated function has the following signature:
///
/// ```rust,ignore
- /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: libc::c_int) -> Result<libc::c_int>
+ /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result<libc::c_int>
/// ```
///
+ /// `nix::sys::ioctl::ioctl_param_type` depends on the OS:
+ /// * BSD - `libc::c_int`
+ /// * Linux - `libc::c_ulong`
+ ///
/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
///
/// # Example
@@ -537,9 +540,13 @@ cfg_if!{
/// The generated function has the following signature:
///
/// ```rust,ignore
- /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: libc::c_int) -> Result<libc::c_int>
+ /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result<libc::c_int>
/// ```
///
+ /// `nix::sys::ioctl::ioctl_param_type` depends on the OS:
+ /// * BSD - `libc::c_int`
+ /// * Linux - `libc::c_ulong`
+ ///
/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
///
/// # Example
@@ -655,7 +662,7 @@ macro_rules! ioctl_readwrite {
///
/// The generated function has the following signature:
///
-/// ```rust,ignorerust,ignore
+/// ```rust,ignore
/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
/// ```
///
diff --git a/src/sys/mod.rs b/src/sys/mod.rs
index e6c7880c..72d59649 100644
--- a/src/sys/mod.rs
+++ b/src/sys/mod.rs
@@ -38,7 +38,13 @@ pub mod mman;
pub mod pthread;
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
pub mod ptrace;
#[cfg(target_os = "linux")]
diff --git a/src/sys/ptrace/bsd.rs b/src/sys/ptrace/bsd.rs
new file mode 100644
index 00000000..7797d106
--- /dev/null
+++ b/src/sys/ptrace/bsd.rs
@@ -0,0 +1,170 @@
+use errno::Errno;
+use libc::{self, c_int};
+use std::ptr;
+use sys::signal::Signal;
+use unistd::Pid;
+use Result;
+
+pub type RequestType = c_int;
+
+cfg_if! {
+ if #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "openbsd"))] {
+ #[doc(hidden)]
+ pub type AddressType = *mut ::libc::c_char;
+ } else {
+ #[doc(hidden)]
+ pub type AddressType = *mut ::libc::c_void;
+ }
+}
+
+libc_enum! {
+ #[repr(i32)]
+ /// Ptrace Request enum defining the action to be taken.
+ pub enum Request {
+ PT_TRACE_ME,
+ PT_READ_I,
+ PT_READ_D,
+ #[cfg(target_os = "macos")]
+ PT_READ_U,
+ PT_WRITE_I,
+ PT_WRITE_D,
+ #[cfg(target_os = "macos")]
+ PT_WRITE_U,
+ PT_CONTINUE,
+ PT_KILL,
+ #[cfg(any(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos"),
+ all(target_os = "openbsd", target_arch = "x86_64"),
+ all(target_os = "netbsd", any(target_arch = "x86_64",
+ target_arch = "powerpc"))))]
+ PT_STEP,
+ PT_ATTACH,
+ PT_DETACH,
+ #[cfg(target_os = "macos")]
+ PT_SIGEXC,
+ #[cfg(target_os = "macos")]
+ PT_THUPDATE,
+ #[cfg(target_os = "macos")]
+ PT_ATTACHEXC
+ }
+}
+
+unsafe fn ptrace_other(
+ request: Request,
+ pid: Pid,
+ addr: AddressType,
+ data: c_int,
+) -> Result<c_int> {
+ Errno::result(libc::ptrace(
+ request as RequestType,
+ libc::pid_t::from(pid),
+ addr,
+ data,
+ )).map(|_| 0)
+}
+
+/// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)`
+///
+/// Indicates that this process is to be traced by its parent.
+/// This is the only ptrace request to be issued by the tracee.
+pub fn traceme() -> Result<()> {
+ unsafe { ptrace_other(Request::PT_TRACE_ME, Pid::from_raw(0), ptr::null_mut(), 0).map(drop) }
+}
+
+/// Attach to a running process, as with `ptrace(PT_ATTACH, ...)`
+///
+/// Attaches to the process specified in pid, making it a tracee of the calling process.
+pub fn attach(pid: Pid) -> Result<()> {
+ unsafe { ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(drop) }
+}
+
+/// Detaches the current running process, as with `ptrace(PT_DETACH, ...)`
+///
+/// Detaches from the process specified in pid allowing it to run freely
+pub fn detach(pid: Pid) -> Result<()> {
+ unsafe { ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), 0).map(drop) }
+}
+
+/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
+///
+/// Continues the execution of the process with PID `pid`, optionally
+/// delivering a signal specified by `sig`.
+pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
+ let data = match sig.into() {
+ Some(s) => s as c_int,
+ None => 0,
+ };
+ unsafe {
+ // Ignore the useless return value
+ ptrace_other(Request::PT_CONTINUE, pid, 1 as AddressType, data).map(drop)
+ }
+}
+
+/// Issues a kill request as with `ptrace(PT_KILL, ...)`
+///
+/// This request is equivalent to `ptrace(PT_CONTINUE, ..., SIGKILL);`
+pub fn kill(pid: Pid) -> Result<()> {
+ unsafe {
+ ptrace_other(Request::PT_KILL, pid, 0 as AddressType, 0).map(drop)
+ }
+}
+
+/// Move the stopped tracee process forward by a single step as with
+/// `ptrace(PT_STEP, ...)`
+///
+/// Advances the execution of the process with PID `pid` by a single step optionally delivering a
+/// signal specified by `sig`.
+///
+/// # Example
+/// ```rust
+/// extern crate nix;
+/// use nix::sys::ptrace::step;
+/// use nix::unistd::Pid;
+/// use nix::sys::signal::Signal;
+/// use nix::sys::wait::*;
+/// fn main() {
+/// // If a process changes state to the stopped state because of a SIGUSR1
+/// // signal, this will step the process forward and forward the user
+/// // signal to the stopped process
+/// match waitpid(Pid::from_raw(-1), None) {
+/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => {
+/// let _ = step(pid, Signal::SIGUSR1);
+/// }
+/// _ => {},
+/// }
+/// }
+/// ```
+#[cfg(
+ any(
+ any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"),
+ all(target_os = "openbsd", target_arch = "x86_64"),
+ all(target_os = "netbsd",
+ any(target_arch = "x86_64", target_arch = "powerpc")
+ )
+ )
+)]
+pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
+ let data = match sig.into() {
+ Some(s) => s as c_int,
+ None => 0,
+ };
+ unsafe { ptrace_other(Request::PT_STEP, pid, ptr::null_mut(), data).map(drop) }
+}
+
+/// Reads a word from a processes memory at the given address
+pub fn read(pid: Pid, addr: AddressType) -> Result<c_int> {
+ unsafe {
+ // Traditionally there was a difference between reading data or
+ // instruction memory but not in modern systems.
+ ptrace_other(Request::PT_READ_D, pid, addr, 0)
+ }
+}
+
+/// Writes a word into the processes memory at the given address
+pub fn write(pid: Pid, addr: AddressType, data: c_int) -> Result<()> {
+ unsafe { ptrace_other(Request::PT_WRITE_D, pid, addr, data).map(drop) }
+}
diff --git a/src/sys/ptrace.rs b/src/sys/ptrace/linux.rs
index 4bb7e06f..f10c6d83 100644
--- a/src/sys/ptrace.rs
+++ b/src/sys/ptrace/linux.rs
@@ -7,9 +7,10 @@ use libc::{self, c_void, c_long, siginfo_t};
use ::unistd::Pid;
use sys::signal::Signal;
+pub type AddressType = *mut ::libc::c_void;
cfg_if! {
- if #[cfg(any(all(target_os = "linux", arch = "s390x"),
+ if #[cfg(any(all(target_os = "linux", target_arch = "s390x"),
all(target_os = "linux", target_env = "gnu")))] {
#[doc(hidden)]
pub type RequestType = ::libc::c_uint;
@@ -170,16 +171,17 @@ libc_bitflags! {
since="0.10.0",
note="usages of `ptrace()` should be replaced with the specialized helper functions instead"
)]
-pub unsafe fn ptrace(request: Request, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
+pub unsafe fn ptrace(request: Request, pid: Pid, addr: AddressType, 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),
+ PTRACE_PEEKTEXT | PTRACE_PEEKDATA | PTRACE_GETSIGINFO |
+ PTRACE_GETEVENTMSG | PTRACE_SETSIGINFO | PTRACE_SETOPTIONS |
+ PTRACE_POKETEXT | PTRACE_POKEDATA | PTRACE_KILL => Err(Error::UnsupportedOperation),
_ => ptrace_other(request, pid, addr, data)
}
}
-fn ptrace_peek(request: Request, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
+fn ptrace_peek(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
let ret = unsafe {
Errno::clear();
libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)
@@ -207,7 +209,7 @@ fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> {
Ok(data)
}
-unsafe fn ptrace_other(request: Request, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
+unsafe fn ptrace_other(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
Errno::result(libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)).map(|_| 0)
}
@@ -221,7 +223,7 @@ pub fn setoptions(pid: Pid, options: Options) -> Result<()> {
ptr::null_mut::<c_void>(),
options.bits() as *mut c_void)
};
- Errno::result(res).map(|_| ())
+ Errno::result(res).map(drop)
}
/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)`
@@ -260,7 +262,7 @@ pub fn traceme() -> Result<()> {
Pid::from_raw(0),
ptr::null_mut(),
ptr::null_mut(),
- ).map(|_| ()) // ignore the useless return value
+ ).map(drop) // ignore the useless return value
}
}
@@ -274,7 +276,7 @@ pub fn syscall(pid: Pid) -> Result<()> {
pid,
ptr::null_mut(),
ptr::null_mut(),
- ).map(|_| ()) // ignore the useless return value
+ ).map(drop) // ignore the useless return value
}
}
@@ -288,7 +290,7 @@ pub fn attach(pid: Pid) -> Result<()> {
pid,
ptr::null_mut(),
ptr::null_mut(),
- ).map(|_| ()) // ignore the useless return value
+ ).map(drop) // ignore the useless return value
}
}
@@ -302,7 +304,7 @@ pub fn detach(pid: Pid) -> Result<()> {
pid,
ptr::null_mut(),
ptr::null_mut()
- ).map(|_| ())
+ ).map(drop)
}
}
@@ -316,7 +318,16 @@ pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
None => ptr::null_mut(),
};
unsafe {
- ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(|_| ()) // ignore the useless return value
+ ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(drop) // ignore the useless return value
+ }
+}
+
+/// Issues a kill request as with `ptrace(PTRACE_KILL, ...)`
+///
+/// This request is equivalent to `ptrace(PTRACE_CONT, ..., SIGKILL);`
+pub fn kill(pid: Pid) -> Result<()> {
+ unsafe {
+ ptrace_other(Request::PTRACE_KILL, pid, ptr::null_mut(), ptr::null_mut()).map(drop)
}
}
@@ -351,6 +362,19 @@ pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
None => ptr::null_mut(),
};
unsafe {
- ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data).map(|_| ())
+ ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data).map(drop)
+ }
+}
+
+
+/// Reads a word from a processes memory at the given address
+pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> {
+ ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut())
+}
+
+/// Writes a word into the processes memory at the given address
+pub fn write(pid: Pid, addr: AddressType, data: *mut c_void) -> Result<()> {
+ unsafe {
+ ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop)
}
}
diff --git a/src/sys/ptrace/mod.rs b/src/sys/ptrace/mod.rs
new file mode 100644
index 00000000..782c3040
--- /dev/null
+++ b/src/sys/ptrace/mod.rs
@@ -0,0 +1,22 @@
+///! Provides helpers for making ptrace system calls
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+mod linux;
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub use self::linux::*;
+
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+mod bsd;
+
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+pub use self::bsd::*;
diff --git a/src/sys/signal.rs b/src/sys/signal.rs
index c2dd856c..c9826d72 100644
--- a/src/sys/signal.rs
+++ b/src/sys/signal.rs
@@ -39,7 +39,7 @@ libc_enum!{
SIGALRM,
SIGTERM,
#[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
- not(any(target_arch = "mips", target_arch = "mips64"))))]
+ not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
SIGSTKFLT,
SIGCHLD,
SIGCONT,
@@ -84,7 +84,7 @@ impl FromStr for Signal {
"SIGALRM" => Signal::SIGALRM,
"SIGTERM" => Signal::SIGTERM,
#[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
- not(any(target_arch = "mips", target_arch = "mips64"))))]
+ not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
"SIGSTKFLT" => Signal::SIGSTKFLT,
"SIGCHLD" => Signal::SIGCHLD,
"SIGCONT" => Signal::SIGCONT,
@@ -130,7 +130,7 @@ impl AsRef<str> for Signal {
Signal::SIGALRM => "SIGALRM",
Signal::SIGTERM => "SIGTERM",
#[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
- not(any(target_arch = "mips", target_arch = "mips64"))))]
+ not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
Signal::SIGSTKFLT => "SIGSTKFLT",
Signal::SIGCHLD => "SIGCHLD",
Signal::SIGCONT => "SIGCONT",
@@ -164,7 +164,7 @@ impl fmt::Display for Signal {
pub use self::Signal::*;
-#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(any(target_arch = "mips", target_arch = "mips64"))))]
+#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
const SIGNALS: [Signal; 31] = [
SIGHUP,
SIGINT,
@@ -197,7 +197,7 @@ const SIGNALS: [Signal; 31] = [
SIGIO,
SIGPWR,
SIGSYS];
-#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), any(target_arch = "mips", target_arch = "mips64")))]
+#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")))]
const SIGNALS: [Signal; 30] = [
SIGHUP,
SIGINT,
diff --git a/src/sys/signalfd.rs b/src/sys/signalfd.rs
index 52027d36..65c09ea4 100644
--- a/src/sys/signalfd.rs
+++ b/src/sys/signalfd.rs
@@ -94,7 +94,7 @@ impl SignalFd {
}
pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> {
- signalfd(self.0, mask, SfdFlags::empty()).map(|_| ())
+ signalfd(self.0, mask, SfdFlags::empty()).map(drop)
}
pub fn read_signal(&mut self) -> Result<Option<siginfo>> {
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs
index 93014f1c..ebd32c1f 100644
--- a/src/sys/socket/addr.rs
+++ b/src/sys/socket/addr.rs
@@ -209,6 +209,9 @@ pub enum AddressFamily {
target_os = "netbsd",
target_os = "openbsd"))]
Natm = libc::AF_NATM,
+ /// Unspecified address family, (see [`getaddrinfo(3)`](http://man7.org/linux/man-pages/man3/getaddrinfo.3.html))
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Unspec = libc::AF_UNSPEC,
}
impl AddressFamily {
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
index 4ee1acee..85acaf4c 100644
--- a/src/sys/socket/mod.rs
+++ b/src/sys/socket/mod.rs
@@ -976,6 +976,20 @@ pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> {
/// Sets the value for the requested socket option
///
/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html)
+///
+/// # Examples
+///
+/// ```
+/// use nix::sys::socket::setsockopt;
+/// use nix::sys::socket::sockopt::KeepAlive;
+/// use std::net::TcpListener;
+/// use std::os::unix::io::AsRawFd;
+///
+/// let listener = TcpListener::bind("0.0.0.0:0").unwrap();
+/// let fd = listener.as_raw_fd();
+/// let res = setsockopt(fd, KeepAlive, &true);
+/// assert!(res.is_ok());
+/// ```
pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()> {
opt.set(fd, val)
}
diff --git a/src/sys/stat.rs b/src/sys/stat.rs
index b810c167..f3a2e7e3 100644
--- a/src/sys/stat.rs
+++ b/src/sys/stat.rs
@@ -1,12 +1,11 @@
-pub use libc::dev_t;
+pub use libc::{dev_t, mode_t};
pub use libc::stat as FileStat;
use {Result, NixPath};
use errno::Errno;
-use fcntl::AtFlags;
-use libc::{self, mode_t};
+use fcntl::{AtFlags, at_rawfd};
+use libc;
use std::mem;
-use std::os::raw;
use std::os::unix::io::RawFd;
use sys::time::{TimeSpec, TimeVal};
@@ -132,16 +131,7 @@ pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> R
pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> {
let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) };
- Errno::result(res).map(|_| ())
-}
-
-/// Computes the raw fd consumed by a function of the form `*at`.
-#[inline]
-fn actual_atfd(fd: Option<RawFd>) -> raw::c_int {
- match fd {
- None => libc::AT_FDCWD,
- Some(fd) => fd,
- }
+ Errno::result(res).map(drop)
}
/// Flags for `fchmodat` function.
@@ -180,14 +170,14 @@ pub fn fchmodat<P: ?Sized + NixPath>(
};
let res = path.with_nix_path(|cstr| unsafe {
libc::fchmodat(
- actual_atfd(dirfd),
+ at_rawfd(dirfd),
cstr.as_ptr(),
mode.bits() as mode_t,
atflag.bits() as libc::c_int,
)
})?;
- Errno::result(res).map(|_| ())
+ Errno::result(res).map(drop)
}
/// Change the access and modification times of a file.
@@ -206,7 +196,27 @@ pub fn utimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -
libc::utimes(cstr.as_ptr(), &times[0])
})?;
- Errno::result(res).map(|_| ())
+ Errno::result(res).map(drop)
+}
+
+/// Change the access and modification times of a file without following symlinks.
+///
+/// `lutimes(path, times)` is identical to
+/// `utimensat(None, path, times, UtimensatFlags::NoFollowSymlink)`. The former
+/// is a deprecated API so prefer using the latter if the platforms you care
+/// about support it.
+///
+/// # References
+///
+/// [lutimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html).
+#[cfg(not(target_os = "android"))]
+pub fn lutimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
+ let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
+ let res = path.with_nix_path(|cstr| unsafe {
+ libc::lutimes(cstr.as_ptr(), &times[0])
+ })?;
+
+ Errno::result(res).map(drop)
}
/// Change the access and modification times of the file specified by a file descriptor.
@@ -219,7 +229,7 @@ pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> {
let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
let res = unsafe { libc::futimens(fd, &times[0]) };
- Errno::result(res).map(|_| ())
+ Errno::result(res).map(drop)
}
/// Flags for `utimensat` function.
@@ -260,12 +270,12 @@ pub fn utimensat<P: ?Sized + NixPath>(
let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
let res = path.with_nix_path(|cstr| unsafe {
libc::utimensat(
- actual_atfd(dirfd),
+ at_rawfd(dirfd),
cstr.as_ptr(),
&times[0],
atflag.bits() as libc::c_int,
)
})?;
- Errno::result(res).map(|_| ())
+ Errno::result(res).map(drop)
}
diff --git a/src/sys/termios.rs b/src/sys/termios.rs
index 11cacd7c..8a99c1ab 100644
--- a/src/sys/termios.rs
+++ b/src/sys/termios.rs
@@ -366,13 +366,13 @@ libc_enum!{
B1500000,
#[cfg(any(target_os = "android", target_os = "linux"))]
B2000000,
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
B2500000,
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
B3000000,
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
B3500000,
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
B4000000,
}
}
@@ -383,8 +383,9 @@ impl From<libc::speed_t> for BaudRate {
use libc::{B0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, B4800,
B9600, B19200, B38400, B57600, B115200, B230400};
#[cfg(any(target_os = "android", target_os = "linux"))]
- use libc::{B500000, B576000, B1000000, B1152000, B1500000, B2000000, B2500000, B3000000,
- B3500000, B4000000};
+ use libc::{B500000, B576000, B1000000, B1152000, B1500000, B2000000};
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+ use libc::{B2500000, B3000000, B3500000, B4000000};
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "macos",
@@ -463,13 +464,13 @@ impl From<libc::speed_t> for BaudRate {
B1500000 => BaudRate::B1500000,
#[cfg(any(target_os = "android", target_os = "linux"))]
B2000000 => BaudRate::B2000000,
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
B2500000 => BaudRate::B2500000,
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
B3000000 => BaudRate::B3000000,
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
B3500000 => BaudRate::B3500000,
- #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
B4000000 => BaudRate::B4000000,
b => unreachable!("Invalid baud constant: {}", b),
}
@@ -558,6 +559,7 @@ libc_enum! {
VINTR,
VKILL,
VLNEXT,
+ #[cfg(not(all(target_os = "linux", target_arch = "sparc64")))]
VMIN,
VQUIT,
VREPRINT,
@@ -574,6 +576,7 @@ libc_enum! {
VSWTC,
#[cfg(target_os = "haiku")]
VSWTCH,
+ #[cfg(not(all(target_os = "linux", target_arch = "sparc64")))]
VTIME,
VWERASE,
#[cfg(target_os = "dragonfly")]
@@ -929,7 +932,7 @@ cfg_if!{
let inner_termios = unsafe { termios.get_libc_termios_mut() };
let res = unsafe { libc::cfsetispeed(inner_termios, baud.into() as libc::speed_t) };
termios.update_wrapper();
- Errno::result(res).map(|_| ())
+ Errno::result(res).map(drop)
}
/// Set output baud rate (see
@@ -940,7 +943,7 @@ cfg_if!{
let inner_termios = unsafe { termios.get_libc_termios_mut() };
let res = unsafe { libc::cfsetospeed(inner_termios, baud.into() as libc::speed_t) };
termios.update_wrapper();
- Errno::result(res).map(|_| ())
+ Errno::result(res).map(drop)
}
/// Set both the input and output baud rates (see
@@ -952,7 +955,7 @@ cfg_if!{
let inner_termios = unsafe { termios.get_libc_termios_mut() };
let res = unsafe { libc::cfsetspeed(inner_termios, baud.into() as libc::speed_t) };
termios.update_wrapper();
- Errno::result(res).map(|_| ())
+ Errno::result(res).map(drop)
}
} else {
/// Get input baud rate (see
@@ -981,7 +984,7 @@ cfg_if!{
let inner_termios = unsafe { termios.get_libc_termios_mut() };
let res = unsafe { libc::cfsetispeed(inner_termios, baud as libc::speed_t) };
termios.update_wrapper();
- Errno::result(res).map(|_| ())
+ Errno::result(res).map(drop)
}
/// Set output baud rate (see
@@ -992,7 +995,7 @@ cfg_if!{
let inner_termios = unsafe { termios.get_libc_termios_mut() };
let res = unsafe { libc::cfsetospeed(inner_termios, baud as libc::speed_t) };
termios.update_wrapper();
- Errno::result(res).map(|_| ())
+ Errno::result(res).map(drop)
}
/// Set both the input and output baud rates (see
@@ -1004,7 +1007,7 @@ cfg_if!{
let inner_termios = unsafe { termios.get_libc_termios_mut() };
let res = unsafe { libc::cfsetspeed(inner_termios, baud as libc::speed_t) };
termios.update_wrapper();
- Errno::result(res).map(|_| ())
+ Errno::result(res).map(drop)
}
}
}
@@ -1060,13 +1063,13 @@ pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
/// *any* of the parameters were successfully set, not only if all were set successfully.
pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> {
let inner_termios = termios.get_libc_termios();
- Errno::result(unsafe { libc::tcsetattr(fd, actions as c_int, &*inner_termios) }).map(|_| ())
+ Errno::result(unsafe { libc::tcsetattr(fd, actions as c_int, &*inner_termios) }).map(drop)
}
/// Block until all output data is written (see
/// [tcdrain(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)).
pub fn tcdrain(fd: RawFd) -> Result<()> {
- Errno::result(unsafe { libc::tcdrain(fd) }).map(|_| ())
+ Errno::result(unsafe { libc::tcdrain(fd) }).map(drop)
}
/// Suspend or resume the transmission or reception of data (see
@@ -1075,7 +1078,7 @@ pub fn tcdrain(fd: RawFd) -> Result<()> {
/// `tcflow()` suspends of resumes the transmission or reception of data for the given port
/// depending on the value of `action`.
pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> {
- Errno::result(unsafe { libc::tcflow(fd, action as c_int) }).map(|_| ())
+ Errno::result(unsafe { libc::tcflow(fd, action as c_int) }).map(drop)
}
/// Discard data in the output or input queue (see
@@ -1084,7 +1087,7 @@ pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> {
/// `tcflush()` will discard data for a terminal port in the input queue, output queue, or both
/// depending on the value of `action`.
pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> {
- Errno::result(unsafe { libc::tcflush(fd, action as c_int) }).map(|_| ())
+ Errno::result(unsafe { libc::tcflush(fd, action as c_int) }).map(drop)
}
/// Send a break for a specific duration (see
@@ -1093,7 +1096,7 @@ pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> {
/// When using asynchronous data transmission `tcsendbreak()` will transmit a continuous stream
/// of zero-valued bits for an implementation-defined duration.
pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> {
- Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(|_| ())
+ Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop)
}
/// Get the session controlled by the given terminal (see
diff --git a/src/sys/time.rs b/src/sys/time.rs
index 51286a06..e300cfe7 100644
--- a/src/sys/time.rs
+++ b/src/sys/time.rs
@@ -1,5 +1,6 @@
use std::{cmp, fmt, ops};
-use libc::{c_long, time_t, suseconds_t, timespec, timeval};
+use libc::{c_long, timespec, timeval};
+pub use libc::{time_t, suseconds_t};
pub trait TimeValLike: Sized {
#[inline]
diff --git a/src/unistd.rs b/src/unistd.rs
index 1f357c41..07f1e6fd 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -2,7 +2,7 @@
use errno::{self, Errno};
use {Error, Result, NixPath};
-use fcntl::{fcntl, FdFlag, OFlag};
+use fcntl::{AtFlags, at_rawfd, fcntl, FdFlag, OFlag};
use fcntl::FcntlArg::F_SETFD;
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};
@@ -557,6 +557,16 @@ pub fn getcwd() -> Result<PathBuf> {
}
}
+/// Computes the raw UID and GID values to pass to a `*chown` call.
+fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc::gid_t) {
+ // According to the POSIX specification, -1 is used to indicate that owner and group
+ // are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap
+ // around to get -1.
+ let uid = owner.map(Into::into).unwrap_or((0 as uid_t).wrapping_sub(1));
+ let gid = group.map(Into::into).unwrap_or((0 as gid_t).wrapping_sub(1));
+ (uid, gid)
+}
+
/// Change the ownership of the file at `path` to be owned by the specified
/// `owner` (user) and `group` (see
/// [chown(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html)).
@@ -567,17 +577,62 @@ pub fn getcwd() -> Result<PathBuf> {
#[inline]
pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
let res = try!(path.with_nix_path(|cstr| {
- // According to the POSIX specification, -1 is used to indicate that
- // owner and group, respectively, are not to be changed. Since uid_t and
- // gid_t are unsigned types, we use wrapping_sub to get '-1'.
- unsafe { libc::chown(cstr.as_ptr(),
- owner.map(Into::into).unwrap_or((0 as uid_t).wrapping_sub(1)),
- group.map(Into::into).unwrap_or((0 as gid_t).wrapping_sub(1))) }
+ let (uid, gid) = chown_raw_ids(owner, group);
+ unsafe { libc::chown(cstr.as_ptr(), uid, gid) }
}));
Errno::result(res).map(drop)
}
+/// Flags for `fchownat` function.
+#[derive(Clone, Copy, Debug)]
+pub enum FchownatFlags {
+ FollowSymlink,
+ NoFollowSymlink,
+}
+
+/// Change the ownership of the file at `path` to be owned by the specified
+/// `owner` (user) and `group`.
+///
+/// The owner/group for the provided path name will not be modified if `None` is
+/// provided for that argument. Ownership change will be attempted for the path
+/// only if `Some` owner/group is provided.
+///
+/// The file to be changed is determined relative to the directory associated
+/// 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,
+/// then the mode of the symbolic link is changed.
+///
+/// `fchownat(None, path, mode, FchownatFlags::NoFollowSymlink)` is identical to
+/// a call `libc::lchown(path, mode)`. That's why `lchmod` is unimplemented in
+/// the `nix` crate.
+///
+/// # References
+///
+/// [fchownat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html).
+pub fn fchownat<P: ?Sized + NixPath>(
+ dirfd: Option<RawFd>,
+ path: &P,
+ owner: Option<Uid>,
+ group: Option<Gid>,
+ flag: FchownatFlags,
+) -> 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(at_rawfd(dirfd), cstr.as_ptr(), uid, gid,
+ atflag.bits() as libc::c_int)
+ })?;
+
+ Errno::result(res).map(drop)
+}
+
fn to_exec_array(args: &[CString]) -> Vec<*const c_char> {
let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
args_p.push(ptr::null());
@@ -646,6 +701,27 @@ pub fn execvp(filename: &CString, args: &[CString]) -> Result<Void> {
Err(Error::Sys(Errno::last()))
}
+/// Replace the current process image with a new one and replicate shell `PATH`
+/// searching behavior (see
+/// [`execvpe(3)`](http://man7.org/linux/man-pages/man3/exec.3.html)).
+///
+/// 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"))]
+pub fn execvpe(filename: &CString, args: &[CString], env: &[CString]) -> Result<Void> {
+ let args_p = to_exec_array(args);
+ let env_p = to_exec_array(env);
+
+ unsafe {
+ libc::execvpe(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
+ };
+
+ Err(Error::Sys(Errno::last()))
+}
+
/// Replace the current process image with a new one (see
/// [fexecve(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html)).
///
@@ -989,6 +1065,20 @@ fn pipe2_setflags(fd1: RawFd, fd2: RawFd, flags: OFlag) -> Result<()> {
/// Truncate a file to a specified length
///
/// See also
+/// [truncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html)
+pub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> {
+ let res = try!(path.with_nix_path(|cstr| {
+ unsafe {
+ libc::truncate(cstr.as_ptr(), len)
+ }
+ }));
+
+ Errno::result(res).map(drop)
+}
+
+/// Truncate a file to a specified length
+///
+/// See also
/// [ftruncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html)
pub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> {
Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop)
@@ -1032,6 +1122,20 @@ pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> {
Errno::result(res).map(drop)
}
+/// Commit filesystem caches to disk
+///
+/// See also [sync(2)](http://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"
+))]
+pub fn sync() -> () {
+ unsafe { libc::sync() };
+}
+
/// Synchronize changes to a file
///
/// See also [fsync(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html)
@@ -1214,7 +1318,7 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> {
libc::setgroups(groups.len() as setgroups_ngroups_t, groups.as_ptr() as *const gid_t)
};
- Errno::result(res).map(|_| ())
+ Errno::result(res).map(drop)
}
/// Calculate the supplementary group access list.
@@ -1340,7 +1444,7 @@ pub fn initgroups(user: &CStr, group: Gid) -> Result<()> {
let gid: gid_t = group.into();
let res = unsafe { libc::initgroups(user.as_ptr(), gid as initgroups_group_t) };
- Errno::result(res).map(|_| ())
+ Errno::result(res).map(drop)
}
/// Suspend the thread until a signal is received.
@@ -1439,6 +1543,31 @@ pub fn sleep(seconds: c_uint) -> c_uint {
unsafe { libc::sleep(seconds) }
}
+pub mod acct {
+ use libc;
+ use {Result, NixPath};
+ use errno::Errno;
+ use std::ptr;
+
+ /// Enable process accounting
+ ///
+ /// See also [acct(2)](https://linux.die.net/man/2/acct)
+ pub fn enable<P: ?Sized + NixPath>(filename: &P) -> Result<()> {
+ let res = try!(filename.with_nix_path(|cstr| {
+ unsafe { libc::acct(cstr.as_ptr()) }
+ }));
+
+ Errno::result(res).map(drop)
+ }
+
+ /// Disable process accounting
+ pub fn disable() -> Result<()> {
+ let res = unsafe { libc::acct(ptr::null()) };
+
+ Errno::result(res).map(drop)
+ }
+}
+
/// Creates a regular file which persists even after process termination
///
/// * `template`: a path whose 6 rightmost characters must be X, e.g. `/tmp/tmpfile_XXXXXX`
@@ -2138,9 +2267,9 @@ mod setres {
/// Sets the real, effective, and saved gid.
/// ([see setresuid(2)](http://man7.org/linux/man-pages/man2/setresuid.2.html))
///
- /// * `rgid`: real user id
- /// * `egid`: effective user id
- /// * `sgid`: saved user id
+ /// * `rgid`: real group id
+ /// * `egid`: effective group id
+ /// * `sgid`: saved group id
/// * returns: Ok or libc error code.
///
/// Err is returned if the user doesn't have permission to set this GID.