diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/fcntl.rs | 4 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | src/mqueue.rs | 178 | ||||
-rw-r--r-- | src/poll.rs | 92 | ||||
-rw-r--r-- | src/sched.rs | 226 | ||||
-rw-r--r-- | src/sys/epoll.rs | 68 | ||||
-rw-r--r-- | src/sys/select.rs | 1 | ||||
-rw-r--r-- | src/sys/signal.rs | 36 | ||||
-rw-r--r-- | src/sys/socket/addr.rs | 4 | ||||
-rw-r--r-- | src/sys/socket/consts.rs | 1 | ||||
-rw-r--r-- | src/unistd.rs | 174 |
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!() } @@ -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}; |