summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlan Somers <asomers@gmail.com>2016-10-13 21:26:43 -0600
committerAlan Somers <asomers@gmail.com>2016-10-13 21:26:43 -0600
commit3ccb3130eb3a73bebc875e77bae562d7367c641c (patch)
treefeef93cbeb399db191eac7ba91e9214ae7650d08 /src
parentbe9c1ff4844ae3bcdf48180b6c1600ab539ca971 (diff)
parentbf00bf2db5401ca4deeabefac4388cf5cd75abb0 (diff)
downloadnix-3ccb3130eb3a73bebc875e77bae562d7367c641c.zip
Merge github.com:nix-rust/nix into evfilt
Diffstat (limited to 'src')
-rw-r--r--src/fcntl.rs4
-rw-r--r--src/lib.rs2
-rw-r--r--src/mqueue.rs178
-rw-r--r--src/poll.rs92
-rw-r--r--src/sched.rs226
-rw-r--r--src/sys/epoll.rs68
-rw-r--r--src/sys/select.rs1
-rw-r--r--src/sys/signal.rs36
-rw-r--r--src/sys/socket/addr.rs4
-rw-r--r--src/sys/socket/consts.rs1
-rw-r--r--src/unistd.rs174
11 files changed, 428 insertions, 358 deletions
diff --git a/src/fcntl.rs b/src/fcntl.rs
index 75e12549..1d9ba499 100644
--- a/src/fcntl.rs
+++ b/src/fcntl.rs
@@ -46,6 +46,8 @@ pub enum FcntlArg<'a> {
F_ADD_SEALS(SealFlag),
#[cfg(target_os = "linux")]
F_GET_SEALS,
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ F_FULLFSYNC,
// TODO: Rest of flags
}
@@ -69,6 +71,8 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> {
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 = "macos", target_os = "ios"))]
+ F_FULLFSYNC => libc::fcntl(fd, libc::F_FULLFSYNC),
#[cfg(any(target_os = "linux", target_os = "android"))]
_ => unimplemented!()
}
diff --git a/src/lib.rs b/src/lib.rs
index b983a9c2..8dbf9fe0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -40,7 +40,7 @@ pub mod fcntl;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod mount;
-#[cfg(any(target_os = "linux"))]
+#[cfg(target_os = "linux")]
pub mod mqueue;
#[cfg(any(target_os = "linux", target_os = "macos"))]
diff --git a/src/mqueue.rs b/src/mqueue.rs
index b8a2250e..9bf6e77e 100644
--- a/src/mqueue.rs
+++ b/src/mqueue.rs
@@ -4,114 +4,117 @@
use {Errno, Result};
-use libc::{c_int, c_long, c_char, size_t, mode_t};
+use libc::{self, c_char, c_long, mode_t, mqd_t, size_t};
use std::ffi::CString;
use sys::stat::Mode;
-use std::ptr;
-
-pub use self::consts::*;
-
-pub type MQd = c_int;
-
-#[cfg(target_os = "linux")]
-mod consts {
- use libc::c_int;
-
- bitflags!(
- flags MQ_OFlag: c_int {
- const O_RDONLY = 0o00000000,
- const O_WRONLY = 0o00000001,
- const O_RDWR = 0o00000002,
- const O_CREAT = 0o00000100,
- const O_EXCL = 0o00000200,
- const O_NONBLOCK = 0o00004000,
- const O_CLOEXEC = 0o02000000,
- }
- );
-
- bitflags!(
- flags FdFlag: c_int {
- const FD_CLOEXEC = 1
- }
- );
+use std::mem;
+
+libc_bitflags!{
+ flags MQ_OFlag: libc::c_int {
+ O_RDONLY,
+ O_WRONLY,
+ O_RDWR,
+ O_CREAT,
+ O_EXCL,
+ O_NONBLOCK,
+ O_CLOEXEC,
+ }
}
-mod ffi {
- use libc::{c_char, size_t, ssize_t, c_uint, c_int};
- use super::MQd;
- use super::MqAttr;
-
- #[allow(improper_ctypes)]
- extern "C" {
- pub fn mq_open(name: *const c_char, oflag: c_int, ...) -> MQd;
-
- pub fn mq_close (mqd: MQd) -> c_int;
-
- pub fn mq_unlink(name: *const c_char) -> c_int;
-
- pub fn mq_receive (mqd: MQd, msg_ptr: *const c_char, msg_len: size_t, msq_prio: *const c_uint) -> ssize_t;
-
- pub fn mq_send (mqd: MQd, msg_ptr: *const c_char, msg_len: size_t, msq_prio: c_uint) -> c_int;
-
- pub fn mq_getattr(mqd: MQd, attr: *mut MqAttr) -> c_int;
-
- pub fn mq_setattr(mqd: MQd, newattr: *const MqAttr, oldattr: *mut MqAttr) -> c_int;
+libc_bitflags!{
+ flags FdFlag: libc::c_int {
+ FD_CLOEXEC,
}
}
#[repr(C)]
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[derive(Clone, Copy)]
pub struct MqAttr {
- pub mq_flags: c_long,
- pub mq_maxmsg: c_long,
- pub mq_msgsize: c_long,
- pub mq_curmsgs: c_long,
- pad: [c_long; 4]
+ mq_attr: libc::mq_attr,
}
-impl MqAttr {
- pub fn new(mq_flags: c_long, mq_maxmsg: c_long, mq_msgsize: c_long, mq_curmsgs: c_long) -> MqAttr {
- MqAttr { mq_flags: mq_flags, mq_maxmsg: mq_maxmsg, mq_msgsize: mq_msgsize, mq_curmsgs: mq_curmsgs, pad: [0; 4] }
- }
+impl PartialEq<MqAttr> for MqAttr {
+ fn eq(&self, other: &MqAttr) -> bool {
+ let self_attr = self.mq_attr;
+ let other_attr = other.mq_attr;
+ self_attr.mq_flags == other_attr.mq_flags && self_attr.mq_maxmsg == other_attr.mq_maxmsg &&
+ self_attr.mq_msgsize == other_attr.mq_msgsize &&
+ self_attr.mq_curmsgs == other_attr.mq_curmsgs
+ }
}
+impl MqAttr {
+ pub fn new(mq_flags: c_long,
+ mq_maxmsg: c_long,
+ mq_msgsize: c_long,
+ mq_curmsgs: c_long)
+ -> MqAttr {
+ let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
+ attr.mq_flags = mq_flags;
+ attr.mq_maxmsg = mq_maxmsg;
+ attr.mq_msgsize = mq_msgsize;
+ attr.mq_curmsgs = mq_curmsgs;
+ MqAttr { mq_attr: attr }
+ }
-pub fn mq_open(name: &CString, oflag: MQ_OFlag, mode: Mode, attr: Option<&MqAttr>) -> Result<MQd> {
- let attr_p = attr.map(|attr| attr as *const MqAttr).unwrap_or(ptr::null());
- let res = unsafe { ffi::mq_open(name.as_ptr(), oflag.bits(), mode.bits() as mode_t, attr_p) };
+ pub fn flags(&self) -> c_long {
+ self.mq_attr.mq_flags
+ }
+}
+
+pub fn mq_open(name: &CString,
+ oflag: MQ_OFlag,
+ mode: Mode,
+ attr: Option<&MqAttr>)
+ -> Result<mqd_t> {
+ let res = match attr {
+ Some(mq_attr) => unsafe {
+ libc::mq_open(name.as_ptr(),
+ oflag.bits(),
+ mode.bits() as mode_t,
+ &mq_attr.mq_attr as *const libc::mq_attr)
+ },
+ None => unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) },
+ };
Errno::result(res)
}
pub fn mq_unlink(name: &CString) -> Result<()> {
- let res = unsafe { ffi::mq_unlink(name.as_ptr()) };
+ let res = unsafe { libc::mq_unlink(name.as_ptr()) };
Errno::result(res).map(drop)
}
-pub fn mq_close(mqdes: MQd) -> Result<()> {
- let res = unsafe { ffi::mq_close(mqdes) };
+pub fn mq_close(mqdes: mqd_t) -> Result<()> {
+ let res = unsafe { libc::mq_close(mqdes) };
Errno::result(res).map(drop)
}
-
-pub fn mq_receive(mqdes: MQd, message: &mut [u8], msq_prio: u32) -> Result<usize> {
+pub fn mq_receive(mqdes: mqd_t, message: &mut [u8], msg_prio: &mut u32) -> Result<usize> {
let len = message.len() as size_t;
- let res = unsafe { ffi::mq_receive(mqdes, message.as_mut_ptr() as *mut c_char, len, &msq_prio) };
-
+ let res = unsafe {
+ libc::mq_receive(mqdes,
+ message.as_mut_ptr() as *mut c_char,
+ len,
+ msg_prio as *mut u32)
+ };
Errno::result(res).map(|r| r as usize)
}
-pub fn mq_send(mqdes: MQd, message: &[u8], msq_prio: u32) -> Result<()> {
- let res = unsafe { ffi::mq_send(mqdes, message.as_ptr() as *const c_char, message.len(), msq_prio) };
-
+pub fn mq_send(mqdes: mqd_t, message: &[u8], msq_prio: u32) -> Result<()> {
+ let res = unsafe {
+ libc::mq_send(mqdes,
+ message.as_ptr() as *const c_char,
+ message.len(),
+ msq_prio)
+ };
Errno::result(res).map(drop)
}
-pub fn mq_getattr(mqd: MQd) -> Result<MqAttr> {
- let mut attr = MqAttr::new(0, 0, 0, 0);
- let res = unsafe { ffi::mq_getattr(mqd, &mut attr) };
- try!(Errno::result(res));
- Ok(attr)
+pub fn mq_getattr(mqd: mqd_t) -> Result<MqAttr> {
+ let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
+ let res = unsafe { libc::mq_getattr(mqd, &mut attr) };
+ Errno::result(res).map(|_| MqAttr { mq_attr: attr })
}
/// Set the attributes of the message queue. Only `O_NONBLOCK` can be set, everything else will be ignored
@@ -119,27 +122,32 @@ pub fn mq_getattr(mqd: MQd) -> Result<MqAttr> {
/// It is recommend to use the `mq_set_nonblock()` and `mq_remove_nonblock()` convenience functions as they are easier to use
///
/// [Further reading](http://man7.org/linux/man-pages/man3/mq_setattr.3.html)
-pub fn mq_setattr(mqd: MQd, newattr: &MqAttr) -> Result<MqAttr> {
- let mut attr = MqAttr::new(0, 0, 0, 0);
- let res = unsafe { ffi::mq_setattr(mqd, newattr as *const MqAttr, &mut attr) };
- try!(Errno::result(res));
- Ok(attr)
+pub fn mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result<MqAttr> {
+ let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
+ let res = unsafe { libc::mq_setattr(mqd, &newattr.mq_attr as *const libc::mq_attr, &mut attr) };
+ Errno::result(res).map(|_| MqAttr { mq_attr: attr })
}
/// Convenience function.
/// Sets the `O_NONBLOCK` attribute for a given message queue descriptor
/// Returns the old attributes
-pub fn mq_set_nonblock(mqd: MQd) -> Result<(MqAttr)> {
+pub fn mq_set_nonblock(mqd: mqd_t) -> Result<(MqAttr)> {
let oldattr = try!(mq_getattr(mqd));
- let newattr = MqAttr::new(O_NONBLOCK.bits() as c_long, oldattr.mq_maxmsg, oldattr.mq_msgsize, oldattr.mq_curmsgs);
+ let newattr = MqAttr::new(O_NONBLOCK.bits() as c_long,
+ oldattr.mq_attr.mq_maxmsg,
+ oldattr.mq_attr.mq_msgsize,
+ oldattr.mq_attr.mq_curmsgs);
mq_setattr(mqd, &newattr)
}
/// Convenience function.
/// Removes `O_NONBLOCK` attribute for a given message queue descriptor
/// Returns the old attributes
-pub fn mq_remove_nonblock(mqd: MQd) -> Result<(MqAttr)> {
+pub fn mq_remove_nonblock(mqd: mqd_t) -> Result<(MqAttr)> {
let oldattr = try!(mq_getattr(mqd));
- let newattr = MqAttr::new(0, oldattr.mq_maxmsg, oldattr.mq_msgsize, oldattr.mq_curmsgs);
+ let newattr = MqAttr::new(0,
+ oldattr.mq_attr.mq_maxmsg,
+ oldattr.mq_attr.mq_msgsize,
+ oldattr.mq_attr.mq_curmsgs);
mq_setattr(mqd, &newattr)
}
diff --git a/src/poll.rs b/src/poll.rs
index 88ca9825..6ba9f5e4 100644
--- a/src/poll.rs
+++ b/src/poll.rs
@@ -1,74 +1,48 @@
-use libc::c_int;
+use libc;
use {Errno, Result};
-pub use self::ffi::PollFd;
-pub use self::ffi::consts::*;
-
-mod ffi {
- use libc::c_int;
- pub use self::consts::*;
-
- #[derive(Clone, Copy, Debug)]
- #[repr(C)]
- pub struct PollFd {
- pub fd: c_int,
- pub events: EventFlags,
- pub revents: EventFlags
- }
-
- #[cfg(target_os = "linux")]
- pub mod consts {
- use libc::{c_short, c_ulong};
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct PollFd {
+ pollfd: libc::pollfd,
+}
- bitflags! {
- flags EventFlags: c_short {
- const POLLIN = 0x001,
- const POLLPRI = 0x002,
- const POLLOUT = 0x004,
- const POLLRDNORM = 0x040,
- const POLLWRNORM = 0x100,
- const POLLRDBAND = 0x080,
- const POLLWRBAND = 0x200,
- const POLLERR = 0x008,
- const POLLHUP = 0x010,
- const POLLNVAL = 0x020,
- }
+impl PollFd {
+ pub fn new(fd: libc::c_int, events: EventFlags, revents: EventFlags) -> PollFd {
+ PollFd {
+ pollfd: libc::pollfd {
+ fd: fd,
+ events: events.bits(),
+ revents: revents.bits(),
+ },
}
-
- pub type nfds_t = c_ulong;
}
- #[cfg(target_os = "macos")]
- pub mod consts {
- use libc::{c_short, c_uint};
-
- bitflags! {
- flags EventFlags: c_short {
- const POLLIN = 0x0001,
- const POLLPRI = 0x0002,
- const POLLOUT = 0x0004,
- const POLLRDNORM = 0x0040,
- const POLLWRNORM = 0x0004,
- const POLLRDBAND = 0x0080,
- const POLLWRBAND = 0x0100,
- const POLLERR = 0x0008,
- const POLLHUP = 0x0010,
- const POLLNVAL = 0x0020,
- }
- }
-
- pub type nfds_t = c_uint;
+ pub fn revents(&self) -> Option<EventFlags> {
+ EventFlags::from_bits(self.pollfd.revents)
}
+}
- #[allow(improper_ctypes)]
- extern {
- pub fn poll(fds: *mut PollFd, nfds: nfds_t, timeout: c_int) -> c_int;
+libc_bitflags! {
+ flags EventFlags: libc::c_short {
+ POLLIN,
+ POLLPRI,
+ POLLOUT,
+ POLLRDNORM,
+ POLLWRNORM,
+ POLLRDBAND,
+ POLLWRBAND,
+ POLLERR,
+ POLLHUP,
+ POLLNVAL,
}
}
-pub fn poll(fds: &mut [PollFd], timeout: c_int) -> Result<c_int> {
+pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> {
let res = unsafe {
- ffi::poll(fds.as_mut_ptr(), fds.len() as ffi::nfds_t, timeout)
+ libc::poll(fds.as_mut_ptr() as *mut libc::pollfd,
+ fds.len() as libc::nfds_t,
+ timeout)
};
Errno::result(res)
diff --git a/src/sched.rs b/src/sched.rs
index 934ce13f..91a7c42a 100644
--- a/src/sched.rs
+++ b/src/sched.rs
@@ -1,204 +1,110 @@
use std::mem;
use std::os::unix::io::RawFd;
use std::option::Option;
-use libc::{self, c_int, c_void, c_ulong, pid_t};
-use {Errno, Result};
+use libc::{self, c_int, c_void, pid_t};
+use {Errno, Error, Result};
// For some functions taking with a parameter of type CloneFlags,
// only a subset of these flags have an effect.
-bitflags!{
- flags CloneFlags: c_int {
- const CLONE_VM = libc::CLONE_VM,
- const CLONE_FS = libc::CLONE_FS,
- const CLONE_FILES = libc::CLONE_FILES,
- const CLONE_SIGHAND = libc::CLONE_SIGHAND,
- const CLONE_PTRACE = libc::CLONE_PTRACE,
- const CLONE_VFORK = libc::CLONE_VFORK,
- const CLONE_PARENT = libc::CLONE_PARENT,
- const CLONE_THREAD = libc::CLONE_THREAD,
- const CLONE_NEWNS = libc::CLONE_NEWNS,
- const CLONE_SYSVSEM = libc::CLONE_SYSVSEM,
- const CLONE_SETTLS = libc::CLONE_SETTLS,
- const CLONE_PARENT_SETTID = libc::CLONE_PARENT_SETTID,
- const CLONE_CHILD_CLEARTID = libc::CLONE_CHILD_CLEARTID,
- const CLONE_DETACHED = libc::CLONE_DETACHED,
- const CLONE_UNTRACED = libc::CLONE_UNTRACED,
- const CLONE_CHILD_SETTID = libc::CLONE_CHILD_SETTID,
- // TODO: Once, we use a version containing
- // https://github.com/rust-lang-nursery/libc/pull/147
- // get rid of the casts.
- const CLONE_NEWUTS = libc::CLONE_NEWUTS as c_int,
- const CLONE_NEWIPC = libc::CLONE_NEWIPC as c_int,
- const CLONE_NEWUSER = libc::CLONE_NEWUSER as c_int,
- const CLONE_NEWPID = libc::CLONE_NEWPID as c_int,
- const CLONE_NEWNET = libc::CLONE_NEWNET as c_int,
- const CLONE_IO = libc::CLONE_IO as c_int,
- }
-}
-
-// Support a maximum CPU set of 1024 nodes
-#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
-mod cpuset_attribs {
- use super::CpuMask;
- pub const CPU_SETSIZE: usize = 1024;
- pub const CPU_MASK_BITS: usize = 64;
-
- #[inline]
- pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
- cur | (1u64 << bit)
- }
-
- #[inline]
- pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
- cur & !(1u64 << bit)
- }
-}
-
-#[cfg(all(target_arch = "x86", target_os = "linux"))]
-mod cpuset_attribs {
- use super::CpuMask;
- pub const CPU_SETSIZE: usize = 1024;
- pub const CPU_MASK_BITS: usize = 32;
-
- #[inline]
- pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
- cur | (1u32 << bit)
- }
-
- #[inline]
- pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
- cur & !(1u32 << bit)
- }
-}
-
-#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
-mod cpuset_attribs {
- use super::CpuMask;
- pub const CPU_SETSIZE: usize = 1024;
- pub const CPU_MASK_BITS: usize = 64;
-
- #[inline]
- pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
- cur | (1u64 << bit)
- }
-
- #[inline]
- pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
- cur & !(1u64 << bit)
- }
-}
-
-#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "android"))]
-mod cpuset_attribs {
- use super::CpuMask;
- // bionic only supports up to 32 independent CPUs, instead of 1024.
- pub const CPU_SETSIZE: usize = 32;
- pub const CPU_MASK_BITS: usize = 32;
-
- #[inline]
- pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
- cur | (1u32 << bit)
- }
-
- #[inline]
- pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
- cur & !(1u32 << bit)
- }
-}
-
-#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "linux"))]
-mod cpuset_attribs {
- use super::CpuMask;
- pub const CPU_SETSIZE: usize = 1024;
- pub const CPU_MASK_BITS: usize = 32;
-
- #[inline]
- pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
- cur | (1u32 << bit)
- }
-
- #[inline]
- pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
- cur & !(1u32 << bit)
+libc_bitflags!{
+ flags CloneFlags: libc::c_int {
+ CLONE_VM,
+ CLONE_FS,
+ CLONE_FILES,
+ CLONE_SIGHAND,
+ CLONE_PTRACE,
+ CLONE_VFORK,
+ CLONE_PARENT,
+ CLONE_THREAD,
+ CLONE_NEWNS,
+ CLONE_SYSVSEM,
+ CLONE_SETTLS,
+ CLONE_PARENT_SETTID,
+ CLONE_CHILD_CLEARTID,
+ CLONE_DETACHED,
+ CLONE_UNTRACED,
+ CLONE_CHILD_SETTID,
+ CLONE_NEWUTS,
+ CLONE_NEWIPC,
+ CLONE_NEWUSER,
+ CLONE_NEWPID,
+ CLONE_NEWNET,
+ CLONE_IO,
}
}
pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;
-// A single CPU mask word
-pub type CpuMask = c_ulong;
-
-// Structure representing the CPU set to apply
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CpuSet {
- cpu_mask: [CpuMask; cpuset_attribs::CPU_SETSIZE/cpuset_attribs::CPU_MASK_BITS]
+ cpu_set: libc::cpu_set_t,
}
impl CpuSet {
pub fn new() -> CpuSet {
- CpuSet {
- cpu_mask: unsafe { mem::zeroed() }
- }
+ CpuSet { cpu_set: unsafe { mem::zeroed() } }
}
- pub fn set(&mut self, field: usize) {
- let word = field / cpuset_attribs::CPU_MASK_BITS;
- let bit = field % cpuset_attribs::CPU_MASK_BITS;
-
- self.cpu_mask[word] = cpuset_attribs::set_cpu_mask_flag(self.cpu_mask[word], bit);
+ pub fn is_set(&self, field: usize) -> Result<bool> {
+ if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
+ Err(Error::Sys(Errno::EINVAL))
+ } else {
+ Ok(unsafe { libc::CPU_ISSET(field, &self.cpu_set) })
+ }
}
- pub fn unset(&mut self, field: usize) {
- let word = field / cpuset_attribs::CPU_MASK_BITS;
- let bit = field % cpuset_attribs::CPU_MASK_BITS;
+ pub fn set(&mut self, field: usize) -> Result<()> {
+ if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
+ Err(Error::Sys(Errno::EINVAL))
+ } else {
+ Ok(unsafe { libc::CPU_SET(field, &mut self.cpu_set) })
+ }
+ }
- self.cpu_mask[word] = cpuset_attribs::clear_cpu_mask_flag(self.cpu_mask[word], bit);
+ pub fn unset(&mut self, field: usize) -> Result<()> {
+ if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
+ Err(Error::Sys(Errno::EINVAL))
+ } else {
+ Ok(unsafe { libc::CPU_CLR(field, &mut self.cpu_set) })
+ }
}
}
mod ffi {
- use libc::{c_void, c_int, pid_t, size_t};
- use super::CpuSet;
+ use libc::{c_void, c_int};
- pub type CloneCb = extern "C" fn (data: *const super::CloneCb) -> 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 {
+ 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;
-
- // disassociate parts of the process execution context
- // doc: http://man7.org/linux/man-pages/man2/unshare.2.html
- pub fn unshare(flags: c_int) -> c_int;
-
- // reassociate thread with a namespace
- // doc: http://man7.org/linux/man-pages/man2/setns.2.html
- pub fn setns(fd: c_int, nstype: c_int) -> c_int;
-
- // Set the current CPU set that a task is allowed to run on
- pub fn sched_setaffinity(__pid: pid_t, __cpusetsize: size_t, __cpuset: *const CpuSet) -> c_int;
+ 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: isize, cpuset: &CpuSet) -> Result<()> {
- use libc::{pid_t, size_t};
-
let res = unsafe {
- ffi::sched_setaffinity(pid as pid_t, mem::size_of::<CpuSet>() as size_t, mem::transmute(cpuset))
+ libc::sched_setaffinity(pid as libc::pid_t,
+ mem::size_of::<CpuSet>() as libc::size_t,
+ mem::transmute(cpuset))
};
Errno::result(res).map(drop)
}
-pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags, signal: Option<c_int>) -> Result<pid_t> {
+pub fn clone(mut cb: CloneCb,
+ stack: &mut [u8],
+ flags: CloneFlags,
+ signal: Option<c_int>)
+ -> Result<pid_t> {
extern "C" fn callback(data: *mut CloneCb) -> c_int {
let cb: &mut CloneCb = unsafe { &mut *data };
(*cb)() as c_int
@@ -217,13 +123,13 @@ pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags, signal: Optio
}
pub fn unshare(flags: CloneFlags) -> Result<()> {
- let res = unsafe { ffi::unshare(flags.bits()) };
+ let res = unsafe { libc::unshare(flags.bits()) };
Errno::result(res).map(drop)
}
pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
- let res = unsafe { ffi::setns(fd, nstype.bits()) };
+ let res = unsafe { libc::setns(fd, nstype.bits()) };
Errno::result(res).map(drop)
}
diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs
index 2090a0df..9774318f 100644
--- a/src/sys/epoll.rs
+++ b/src/sys/epoll.rs
@@ -1,21 +1,10 @@
use {Errno, Result};
-use libc::c_int;
+use libc::{self, c_int};
use std::os::unix::io::RawFd;
-mod ffi {
- use libc::{c_int};
- use super::EpollEvent;
-
- extern {
- pub fn epoll_create(size: c_int) -> c_int;
- pub fn epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: *const EpollEvent) -> c_int;
- pub fn epoll_wait(epfd: c_int, events: *mut EpollEvent, max_events: c_int, timeout: c_int) -> c_int;
- }
-}
-
bitflags!(
#[repr(C)]
- flags EpollEventKind: u32 {
+ flags EpollFlags: u32 {
const EPOLLIN = 0x001,
const EPOLLPRI = 0x002,
const EPOLLOUT = 0x004,
@@ -42,46 +31,49 @@ pub enum EpollOp {
EpollCtlMod = 3
}
-#[cfg(not(target_arch = "x86_64"))]
-#[derive(Clone, Copy)]
-#[repr(C)]
-pub struct EpollEvent {
- pub events: EpollEventKind,
- pub data: u64
+libc_bitflags!{
+ flags EpollCreateFlags: c_int {
+ EPOLL_CLOEXEC,
+ }
}
-#[cfg(target_arch = "x86_64")]
#[derive(Clone, Copy)]
-#[repr(C, packed)]
+#[repr(C)]
pub struct EpollEvent {
- pub events: EpollEventKind,
- pub data: u64
+ event: libc::epoll_event,
}
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-#[test]
-fn test_epoll_event_size() {
- use std::mem::size_of;
- assert_eq!(size_of::<EpollEvent>(), 12);
-}
+impl EpollEvent {
+ pub fn new(events: EpollFlags, data: u64) -> EpollEvent {
+ EpollEvent { event: libc::epoll_event { events: events.bits(), u64: data } }
+ }
+
+ pub fn events(&self) -> EpollFlags {
+ EpollFlags::from_bits(self.event.events).unwrap()
+ }
-#[cfg(target_arch = "arm")]
-#[test]
-fn test_epoll_event_size() {
- use std::mem::size_of;
- assert_eq!(size_of::<EpollEvent>(), 16);
+ pub fn data(&self) -> u64 {
+ self.event.u64
+ }
}
#[inline]
pub fn epoll_create() -> Result<RawFd> {
- let res = unsafe { ffi::epoll_create(1024) };
+ let res = unsafe { libc::epoll_create(1024) };
+
+ Errno::result(res)
+}
+
+#[inline]
+pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
+ let res = unsafe { libc::epoll_create1(flags.bits()) };
Errno::result(res)
}
#[inline]
-pub fn epoll_ctl(epfd: RawFd, op: EpollOp, fd: RawFd, event: &EpollEvent) -> Result<()> {
- let res = unsafe { ffi::epoll_ctl(epfd, op as c_int, fd, event as *const EpollEvent) };
+pub fn epoll_ctl(epfd: RawFd, op: EpollOp, fd: RawFd, event: &mut EpollEvent) -> Result<()> {
+ let res = unsafe { libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event) };
Errno::result(res).map(drop)
}
@@ -89,7 +81,7 @@ pub fn epoll_ctl(epfd: RawFd, op: EpollOp, fd: RawFd, event: &EpollEvent) -> Res
#[inline]
pub fn epoll_wait(epfd: RawFd, events: &mut [EpollEvent], timeout_ms: isize) -> Result<usize> {
let res = unsafe {
- ffi::epoll_wait(epfd, events.as_mut_ptr(), events.len() as c_int, timeout_ms as c_int)
+ libc::epoll_wait(epfd, events.as_mut_ptr() as *mut libc::epoll_event, events.len() as c_int, timeout_ms as c_int)
};
Errno::result(res).map(|r| r as usize)
diff --git a/src/sys/select.rs b/src/sys/select.rs
index 1b47d759..28b664aa 100644
--- a/src/sys/select.rs
+++ b/src/sys/select.rs
@@ -8,6 +8,7 @@ pub const FD_SETSIZE: RawFd = 1024;
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[repr(C)]
+#[derive(Clone)]
pub struct FdSet {
bits: [i32; FD_SETSIZE as usize / 32]
}
diff --git a/src/sys/signal.rs b/src/sys/signal.rs
index 18827332..bdc25b47 100644
--- a/src/sys/signal.rs
+++ b/src/sys/signal.rs
@@ -28,7 +28,7 @@ pub enum Signal {
SIGPIPE = libc::SIGPIPE,
SIGALRM = libc::SIGALRM,
SIGTERM = libc::SIGTERM,
- #[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
+ #[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(target_arch = "mips")))]
SIGSTKFLT = libc::SIGSTKFLT,
SIGCHLD = libc::SIGCHLD,
SIGCONT = libc::SIGCONT,
@@ -54,7 +54,7 @@ pub enum Signal {
pub use self::Signal::*;
-#[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
+#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(target_arch = "mips")))]
const SIGNALS: [Signal; 31] = [
SIGHUP,
SIGINT,
@@ -87,6 +87,38 @@ const SIGNALS: [Signal; 31] = [
SIGIO,
SIGPWR,
SIGSYS];
+#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), target_arch = "mips"))]
+const SIGNALS: [Signal; 30] = [
+ SIGHUP,
+ SIGINT,
+ SIGQUIT,
+ SIGILL,
+ SIGTRAP,
+ SIGABRT,
+ SIGBUS,
+ SIGFPE,
+ SIGKILL,
+ SIGUSR1,
+ SIGSEGV,
+ SIGUSR2,
+ SIGPIPE,
+ SIGALRM,
+ SIGTERM,
+ SIGCHLD,
+ SIGCONT,
+ SIGSTOP,
+ SIGTSTP,
+ SIGTTIN,
+ SIGTTOU,
+ SIGURG,
+ SIGXCPU,
+ SIGXFSZ,
+ SIGVTALRM,
+ SIGPROF,
+ SIGWINCH,
+ SIGIO,
+ SIGPWR,
+ SIGSYS];
#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "emscripten")))]
const SIGNALS: [Signal; 31] = [
SIGHUP,
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs
index 22970d8b..e3c1401c 100644
--- a/src/sys/socket/addr.rs
+++ b/src/sys/socket/addr.rs
@@ -391,7 +391,7 @@ impl UnixAddr {
.. mem::zeroed()
};
- if path.len() > ret.sun_path.len() {
+ if path.len() + 1 > ret.sun_path.len() {
return Err(Error::Sys(Errno::ENAMETOOLONG));
}
@@ -401,7 +401,7 @@ impl UnixAddr {
ret.sun_path.as_mut_ptr().offset(1) as *mut u8,
path.len());
- Ok(UnixAddr(ret, path.len()))
+ Ok(UnixAddr(ret, path.len() + 1))
}
}
diff --git a/src/sys/socket/consts.rs b/src/sys/socket/consts.rs
index aeeea5c3..63eaf28a 100644
--- a/src/sys/socket/consts.rs
+++ b/src/sys/socket/consts.rs
@@ -98,6 +98,7 @@ mod os {
const MSG_DONTWAIT = 0x0040,
const MSG_EOR = 0x0080,
const MSG_ERRQUEUE = 0x2000,
+ const MSG_CMSG_CLOEXEC = 0x40000000,
}
}
diff --git a/src/unistd.rs b/src/unistd.rs
index d4da60da..2c4a92c3 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -1,13 +1,16 @@
//! Standard symbolic constants and types
//!
use {Errno, Error, Result, NixPath};
-use fcntl::{fcntl, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC};
-use fcntl::FcntlArg::{F_SETFD, F_SETFL};
-use libc::{self, c_char, c_void, c_int, c_uint, size_t, pid_t, off_t, uid_t, gid_t};
+use fcntl::{fcntl, OFlag, O_CLOEXEC, FD_CLOEXEC};
+use fcntl::FcntlArg::F_SETFD;
+use libc::{self, c_char, c_void, c_int, c_uint, size_t, pid_t, off_t, uid_t, gid_t, mode_t};
use std::mem;
-use std::ffi::CString;
+use std::ffi::{CString, CStr, OsString};
+use std::os::unix::ffi::{OsStringExt};
use std::os::unix::io::RawFd;
+use std::path::{PathBuf};
use void::Void;
+use sys::stat::Mode;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub use self::linux::*;
@@ -111,6 +114,100 @@ pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> {
Errno::result(res).map(drop)
}
+/// Creates new directory `path` with access rights `mode`.
+///
+/// # Errors
+///
+/// There are several situations where mkdir might fail:
+///
+/// - current user has insufficient rights in the parent directory
+/// - the path already exists
+/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X)
+///
+/// For a full list consult
+/// [man mkdir(2)](http://man7.org/linux/man-pages/man2/mkdir.2.html#ERRORS)
+///
+/// # Example
+///
+/// ```rust
+/// extern crate tempdir;
+/// extern crate nix;
+///
+/// use nix::unistd;
+/// use nix::sys::stat;
+/// use tempdir::TempDir;
+///
+/// fn main() {
+/// let mut tmp_dir = TempDir::new("test_mkdir").unwrap().into_path();
+/// tmp_dir.push("new_dir");
+///
+/// // create new directory and give read, write and execute rights to the owner
+/// match unistd::mkdir(&tmp_dir, stat::S_IRWXU) {
+/// Ok(_) => println!("created {:?}", tmp_dir),
+/// Err(err) => println!("Error creating directory: {}", err),
+/// }
+/// }
+/// ```
+#[inline]
+pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
+ let res = try!(path.with_nix_path(|cstr| {
+ unsafe { libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t) }
+ }));
+
+ Errno::result(res).map(drop)
+}
+
+/// Returns the current directory as a PathBuf
+///
+/// Err is returned if the current user doesn't have the permission to read or search a component
+/// of the current path.
+///
+/// # Example
+///
+/// ```rust
+/// extern crate nix;
+///
+/// use nix::unistd;
+///
+/// fn main() {
+/// // assume that we are allowed to get current directory
+/// let dir = unistd::getcwd().unwrap();
+/// println!("The current directory is {:?}", dir);
+/// }
+/// ```
+#[inline]
+pub fn getcwd() -> Result<PathBuf> {
+ let mut buf = Vec::with_capacity(512);
+ loop {
+ unsafe {
+ let ptr = buf.as_mut_ptr() as *mut libc::c_char;
+
+ // The buffer must be large enough to store the absolute pathname plus
+ // a terminating null byte, or else null is returned.
+ // To safely handle this we start with a reasonable size (512 bytes)
+ // and double the buffer size upon every error
+ if !libc::getcwd(ptr, buf.capacity()).is_null() {
+ let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len();
+ buf.set_len(len);
+ buf.shrink_to_fit();
+ return Ok(PathBuf::from(OsString::from_vec(buf)));
+ } else {
+ let error = Errno::last();
+ // ERANGE means buffer was too small to store directory name
+ if error != Errno::ERANGE {
+ return Err(Error::Sys(error));
+ }
+ }
+
+ // Trigger the internal buffer resizing logic of `Vec` by requiring
+ // more space than the current capacity.
+ let cap = buf.capacity();
+ buf.set_len(cap);
+ buf.reserve(1);
+ }
+ }
+}
+
#[inline]
pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<uid_t>, group: Option<gid_t>) -> Result<()> {
let res = try!(path.with_nix_path(|cstr| {
@@ -263,21 +360,42 @@ pub fn pipe() -> Result<(RawFd, RawFd)> {
}
}
+// libc only defines `pipe2` in `libc::notbsd`.
+#[cfg(any(target_os = "linux",
+ target_os = "android",
+ target_os = "emscripten"))]
pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
- unsafe {
- let mut fds: [c_int; 2] = mem::uninitialized();
+ let mut fds: [c_int; 2] = unsafe { mem::uninitialized() };
- let res = libc::pipe(fds.as_mut_ptr());
+ let res = unsafe { libc::pipe2(fds.as_mut_ptr(), flags.bits()) };
- try!(Errno::result(res));
+ try!(Errno::result(res));
- try!(pipe2_setflags(fds[0], fds[1], flags));
+ Ok((fds[0], fds[1]))
+}
- Ok((fds[0], fds[1]))
- }
+#[cfg(not(any(target_os = "linux",
+ target_os = "android",
+ target_os = "emscripten")))]
+pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
+ let mut fds: [c_int; 2] = unsafe { mem::uninitialized() };
+
+ let res = unsafe { libc::pipe(fds.as_mut_ptr()) };
+
+ try!(Errno::result(res));
+
+ try!(pipe2_setflags(fds[0], fds[1], flags));
+
+ Ok((fds[0], fds[1]))
}
+#[cfg(not(any(target_os = "linux",
+ target_os = "android",
+ target_os = "emscripten")))]
fn pipe2_setflags(fd1: RawFd, fd2: RawFd, flags: OFlag) -> Result<()> {
+ use fcntl::O_NONBLOCK;
+ use fcntl::FcntlArg::F_SETFL;
+
let mut res = Ok(0);
if flags.contains(O_CLOEXEC) {
@@ -414,6 +532,40 @@ pub fn sleep(seconds: libc::c_uint) -> c_uint {
unsafe { libc::sleep(seconds) }
}
+/// 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
+/// * returns: tuple of file descriptor and filename
+///
+/// Err is returned either if no temporary filename could be created or the template doesn't
+/// end with XXXXXX
+///
+/// # Example
+///
+/// ```rust
+/// use nix::unistd;
+///
+/// let fd = match unistd::mkstemp("/tmp/tempfile_XXXXXX") {
+/// Ok((fd, path)) => {
+/// unistd::unlink(path.as_path()).unwrap(); // flag file to be deleted at app termination
+/// fd
+/// }
+/// Err(e) => panic!("mkstemp failed: {}", e)
+/// };
+/// // do something with fd
+/// ```
+#[inline]
+pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> {
+ let mut path = try!(template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()}));
+ let p = path.as_mut_ptr() as *mut _;
+ let fd = unsafe { libc::mkstemp(p) };
+ let last = path.pop(); // drop the trailing nul
+ debug_assert!(last == Some(b'\0'));
+ let pathname = OsString::from_vec(path);
+ try!(Errno::result(fd));
+ Ok((fd, PathBuf::from(pathname)))
+}
+
#[cfg(any(target_os = "linux", target_os = "android"))]
mod linux {
use sys::syscall::{syscall, SYSPIVOTROOT};