summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md74
-rw-r--r--Cargo.toml2
-rw-r--r--README.md2
-rw-r--r--RELEASE_PROCEDURE.md29
-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
-rw-r--r--test/test_mq.rs8
-rw-r--r--test/test_poll.rs10
-rw-r--r--test/test_unistd.rs110
18 files changed, 608 insertions, 413 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4cf6b1c8..56d4828f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,8 +9,42 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Added complete definitions for all kqueue-related constants on all supported
OSes
([#415](https://github.com/nix-rust/nix/pull/415))
+- Added function `epoll_create1` and bitflags `EpollCreateFlags` in
+ `::nix::sys::epoll` in order to support `::libc::epoll_create1`.
+ ([#410](https://github.com/nix-rust/nix/pull/410))
+
+### Changed
+- Changed `KEvent` to an opaque structure that may only be modified by its
+ constructor and the `ev_set` method.
+ ([#415](https://github.com/nix-rust/nix/pull/415))
+- `pipe2` now calls `libc::pipe2` where available. Previously it was emulated
+ using `pipe`, which meant that setting `O_CLOEXEC` was not atomic.
+ ([#427](https://github.com/nix-rust/nix/pull/427))
+- Renamed `EpollEventKind` to `EpollFlags` in `::nix::sys::epoll` in order for
+ it to conform with our conventions.
+ ([#410](https://github.com/nix-rust/nix/pull/410))
+- `EpollEvent` in `::nix::sys::epoll` is now an opaque proxy for
+ `::libc::epoll_event`. The formerly public field `events` is now be read-only
+ accessible with the new method `events()` of `EpollEvent`. Instances of
+ `EpollEvent` can be constructed using the new method `new()` of EpollEvent.
+ ([#410](https://github.com/nix-rust/nix/pull/410))
+
+### Fixed
+- Fixed using kqueue with `EVFILT_USER` on FreeBSD
+ ([#415](https://github.com/nix-rust/nix/pull/415))
+- Fixed the build on FreeBSD, and fixed the getsockopt, sendmsg, and recvmsg
+ functions on that same OS.
+ ([#397](https://github.com/nix-rust/nix/pull/397))
+- Fixed an off-by-one bug in `UnixAddr::new_abstract` in `::nix::sys::socket`.
+ ([#429](https://github.com/nix-rust/nix/pull/429))
+
+## [0.7.0] 2016-09-09
+
+### Added
- Added `lseek` and `lseek64` in `::nix::unistd`
([#377](https://github.com/nix-rust/nix/pull/377))
+- Added `mkdir` and `getcwd` in `::nix::unistd`
+ ([#416](https://github.com/nix-rust/nix/pull/416))
- Added accessors `sigmask_mut` and `sigmask` to `UContext` in
`::nix::ucontext`.
([#370](https://github.com/nix-rust/nix/pull/370))
@@ -20,24 +54,54 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Added new module `::nix::sys::reboot` with enumeration `RebootMode` and
functions `reboot` and `set_cad_enabled`. Currently for _linux_ only.
([#386](https://github.com/nix-rust/nix/pull/386))
+- `FdSet` in `::nix::sys::select` now also implements `Clone`.
+ ([#405](https://github.com/nix-rust/nix/pull/405))
+- Added `F_FULLFSYNC` to `FcntlArg` in `::nix::fcntl` for _apple_ targets.
+ ([#407](https://github.com/nix-rust/nix/pull/407))
+- Added `CpuSet::unset` in `::nix::sched`.
+ ([#402](https://github.com/nix-rust/nix/pull/402))
+- Added constructor method `new()` to `PollFd` in `::nix::poll`, in order to
+ allow creation of objects, after removing public access to members.
+ ([#399](https://github.com/nix-rust/nix/pull/399))
+- Added method `revents()` to `PollFd` in `::nix::poll`, in order to provide
+ read access to formerly public member `revents`.
+ ([#399](https://github.com/nix-rust/nix/pull/399))
+- Added `MSG_CMSG_CLOEXEC` to `MsgFlags` in `::nix::sys::socket` for _linux_ only.
+ ([#422](https://github.com/nix-rust/nix/pull/422))
### Changed
-- Changed `KEvent` to an opaque structure that may only be modified by its
- constructor and the `ev_set` method.
- ([#415](https://github.com/nix-rust/nix/pull/415))
- Replaced the reexported integer constants for signals by the enumeration
`Signal` in `::nix::sys::signal`.
([#362](https://github.com/nix-rust/nix/pull/362))
- Renamed `EventFdFlag` to `EfdFlags` in `::nix::sys::eventfd`.
([#383](https://github.com/nix-rust/nix/pull/383))
+- Changed the result types of `CpuSet::is_set` and `CpuSet::set` in
+ `::nix::sched` to `Result<bool>` and `Result<()>`, respectively. They now
+ return `EINVAL`, if an invalid argument for the `field` parameter is passed.
+ ([#402](https://github.com/nix-rust/nix/pull/402))
+- `MqAttr` in `::nix::mqueue` is now an opaque proxy for `::libc::mq_attr`,
+ which has the same structure as the old `MqAttr`. The field `mq_flags` of
+ `::libc::mq_attr` is readable using the new method `flags()` of `MqAttr`.
+ `MqAttr` also no longer implements `Debug`.
+ ([#392](https://github.com/nix-rust/nix/pull/392))
+- The parameter `msq_prio` of `mq_receive` with type `u32` in `::nix::mqueue`
+ was replaced by a parameter named `msg_prio` with type `&mut u32`, so that
+ the message priority can be obtained by the caller.
+ ([#392](https://github.com/nix-rust/nix/pull/392))
+- The type alias `MQd` in `::nix::queue` was replaced by the type alias
+ `libc::mqd_t`, both of which are aliases for the same type.
+ ([#392](https://github.com/nix-rust/nix/pull/392))
### Removed
- Type alias `SigNum` from `::nix::sys::signal`.
([#362](https://github.com/nix-rust/nix/pull/362))
+- Type alias `CpuMask` from `::nix::shed`.
+ ([#402](https://github.com/nix-rust/nix/pull/402))
+- Removed public fields from `PollFd` in `::nix::poll`. (See also added method
+ `revents()`.
+ ([#399](https://github.com/nix-rust/nix/pull/399))
### Fixed
-- Fixed using kqueue with `EVFILT_USER` on FreeBSD
- ([#415](https://github.com/nix-rust/nix/pull/415))
- Fixed the build problem for NetBSD (Note, that we currently do not support
it, so it might already be broken again).
([#389](https://github.com/nix-rust/nix/pull/389))
diff --git a/Cargo.toml b/Cargo.toml
index 86027b2c..9302181c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,7 +2,7 @@
name = "nix"
description = "Rust friendly bindings to *nix APIs"
-version = "0.6.1-pre"
+version = "0.7.1-pre"
authors = ["Carl Lerche <me@carllerche.com>"]
homepage = "https://github.com/nix-rust/nix"
repository = "https://github.com/nix-rust/nix"
diff --git a/README.md b/README.md
index d9d1dbfb..20753af7 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@ To use `nix`, first add this to your `Cargo.toml`:
```toml
[dependencies]
-nix = "0.6.0"
+nix = "0.7.0"
```
Then, add this to your crate root:
diff --git a/RELEASE_PROCEDURE.md b/RELEASE_PROCEDURE.md
index 2613ce5a..14496f23 100644
--- a/RELEASE_PROCEDURE.md
+++ b/RELEASE_PROCEDURE.md
@@ -3,16 +3,39 @@ library.
# Before Release
-The release is prepared by a commit with the following changes.
+Based on changes since the last release, pick a new version number
+following semver conventions. For nix, a change that drops support for
+some Rust versions counts as a breaking change, and requires a major bump.
-- In CHANGELOG.md, rename the Unreleased section to the new version followed by
- the date of the release.
+The release is prepared as follows:
+
+- Ask for a new libc version if, necessary. It usually is.
+- Make a commit with a message like "Release v0.8.3" with the following
+ changes:
+ - In `CHANGELOG.md`, rename the Unreleased section to the new version
+ followed by the date of the release.
+ - In `Cargo.toml`, update the version to the new version.
+ - In `Cargo.toml`, change the libc dependency to the latest version.
+ - In `README.md`, update the version in the Usage section to the new
+ version.
+- Make a pull request.
+- Once the PR is merged, tag the merge commit, e.g. `git tag v0.8.3
+ $MERGE_COMMIT_SHA1`.
+- Push the tag, e.g. `git push origin v0.8.3`.
# Create Release
+- Checkout the tag.
+- Publish to crates.io with `cargo publish`.
+
# After Release
After the release a commit with the following changes is added to the master
branch.
- Add a new Unreleased section header to CHANGELOG.md.
+- In `Cargo.toml`, update the version to the next `-dev` version, e.g.
+ `v0.8.4-dev`.
+- In `Cargo.tml`, revert the libc dependency to its git master branch.
+- Commit with a message like "Bump to v0.8.4-dev"
+- Make a pull request.
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};
diff --git a/test/test_mq.rs b/test/test_mq.rs
index 94431a04..fd050d47 100644
--- a/test/test_mq.rs
+++ b/test/test_mq.rs
@@ -33,7 +33,9 @@ fn test_mq_send_and_receive() {
let mq_name_in_child = &CString::new(b"/a_nix_test_queue".as_ref()).unwrap();
let mqd_in_child = mq_open(mq_name_in_child, O_CREAT | O_RDONLY, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, Some(&attr)).unwrap();
let mut buf = [0u8; 32];
- mq_receive(mqd_in_child, &mut buf, 1).unwrap();
+ let mut prio = 0u32;
+ mq_receive(mqd_in_child, &mut buf, &mut prio).unwrap();
+ assert!(prio == 1);
write(writer, &buf).unwrap(); // pipe result to parent process. Otherwise cargo does not report test failures correctly
mq_close(mqd_in_child).unwrap();
}
@@ -99,10 +101,10 @@ fn test_mq_set_nonblocking() {
let mqd = mq_open(mq_name, O_CREAT | O_WRONLY, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, Some(&initial_attr)).unwrap();
mq_set_nonblock(mqd).unwrap();
let new_attr = mq_getattr(mqd);
- assert!(new_attr.unwrap().mq_flags == O_NONBLOCK.bits() as c_long);
+ assert!(new_attr.unwrap().flags() == O_NONBLOCK.bits() as c_long);
mq_remove_nonblock(mqd).unwrap();
let new_attr = mq_getattr(mqd);
- assert!(new_attr.unwrap().mq_flags == 0);
+ assert!(new_attr.unwrap().flags() == 0);
mq_close(mqd).unwrap();
}
diff --git a/test/test_poll.rs b/test/test_poll.rs
index 54fd4029..13a95d2c 100644
--- a/test/test_poll.rs
+++ b/test/test_poll.rs
@@ -4,19 +4,15 @@ use nix::unistd::{write, pipe};
#[test]
fn test_poll() {
let (r, w) = pipe().unwrap();
- let mut fds = [PollFd {
- fd: r,
- events: POLLIN,
- revents: EventFlags::empty()
- }];
+ let mut fds = [PollFd::new(r, POLLIN, EventFlags::empty())];
let nfds = poll(&mut fds, 100).unwrap();
assert_eq!(nfds, 0);
- assert!(!fds[0].revents.contains(POLLIN));
+ assert!(!fds[0].revents().unwrap().contains(POLLIN));
write(w, b".").unwrap();
let nfds = poll(&mut fds, 100).unwrap();
assert_eq!(nfds, 1);
- assert!(fds[0].revents.contains(POLLIN));
+ assert!(fds[0].revents().unwrap().contains(POLLIN));
}
diff --git a/test/test_unistd.rs b/test/test_unistd.rs
index 188bfbeb..856693f6 100644
--- a/test/test_unistd.rs
+++ b/test/test_unistd.rs
@@ -1,38 +1,41 @@
+extern crate tempdir;
+
use nix::unistd::*;
use nix::unistd::ForkResult::*;
use nix::sys::wait::*;
+use nix::sys::stat;
+use std::iter;
use std::ffi::CString;
-
use std::io::{Write, Read};
+use std::os::unix::prelude::*;
+use std::env::current_dir;
use tempfile::tempfile;
+use tempdir::TempDir;
use libc::off_t;
-use std::os::unix::prelude::*;
-
-
#[test]
fn test_fork_and_waitpid() {
let pid = fork();
match pid {
- Ok(Child) => {} // ignore child here
- Ok(Parent { child }) => {
- // assert that child was created and pid > 0
- assert!(child > 0);
- let wait_status = waitpid(child, None);
- match wait_status {
- // assert that waitpid returned correct status and the pid is the one of the child
- Ok(WaitStatus::Exited(pid_t, _)) => assert!(pid_t == child),
-
- // panic, must never happen
- Ok(_) => panic!("Child still alive, should never happen"),
-
- // panic, waitpid should never fail
- Err(_) => panic!("Error: waitpid Failed")
- }
-
- },
- // panic, fork should never fail unless there is a serious problem with the OS
- Err(_) => panic!("Error: Fork Failed")
+ Ok(Child) => {} // ignore child here
+ Ok(Parent { child }) => {
+ // assert that child was created and pid > 0
+ assert!(child > 0);
+ let wait_status = waitpid(child, None);
+ match wait_status {
+ // assert that waitpid returned correct status and the pid is the one of the child
+ Ok(WaitStatus::Exited(pid_t, _)) => assert!(pid_t == child),
+
+ // panic, must never happen
+ Ok(_) => panic!("Child still alive, should never happen"),
+
+ // panic, waitpid should never fail
+ Err(_) => panic!("Error: waitpid Failed")
+ }
+
+ },
+ // panic, fork should never fail unless there is a serious problem with the OS
+ Err(_) => panic!("Error: Fork Failed")
}
}
@@ -40,18 +43,37 @@ fn test_fork_and_waitpid() {
fn test_wait() {
let pid = fork();
match pid {
- Ok(Child) => {} // ignore child here
- Ok(Parent { child }) => {
- let wait_status = wait();
-
- // just assert that (any) one child returns with WaitStatus::Exited
- assert_eq!(wait_status, Ok(WaitStatus::Exited(child, 0)));
- },
- // panic, fork should never fail unless there is a serious problem with the OS
- Err(_) => panic!("Error: Fork Failed")
+ Ok(Child) => {} // ignore child here
+ Ok(Parent { child }) => {
+ let wait_status = wait();
+
+ // just assert that (any) one child returns with WaitStatus::Exited
+ assert_eq!(wait_status, Ok(WaitStatus::Exited(child, 0)));
+ },
+ // panic, fork should never fail unless there is a serious problem with the OS
+ Err(_) => panic!("Error: Fork Failed")
}
}
+#[test]
+fn test_mkstemp() {
+ let result = mkstemp("/tmp/nix_tempfile.XXXXXX");
+ match result {
+ Ok((fd, path)) => {
+ close(fd).unwrap();
+ unlink(path.as_path()).unwrap();
+ },
+ Err(e) => panic!("mkstemp failed: {}", e)
+ }
+
+ let result = mkstemp("/tmp/");
+ match result {
+ Ok(_) => {
+ panic!("mkstemp succeeded even though it should fail (provided a directory)");
+ },
+ Err(_) => {}
+ }
+}
#[test]
fn test_getpid() {
@@ -120,6 +142,24 @@ macro_rules! execve_test_factory(
);
#[test]
+fn test_getcwd() {
+ let mut tmp_dir = TempDir::new("test_getcwd").unwrap().into_path();
+ assert!(chdir(tmp_dir.as_path()).is_ok());
+ assert_eq!(getcwd().unwrap(), current_dir().unwrap());
+
+ // make path 500 chars longer so that buffer doubling in getcwd kicks in.
+ // Note: One path cannot be longer than 255 bytes (NAME_MAX)
+ // whole path cannot be longer than PATH_MAX (usually 4096 on linux, 1024 on macos)
+ for _ in 0..5 {
+ let newdir = iter::repeat("a").take(100).collect::<String>();
+ tmp_dir.push(newdir);
+ assert!(mkdir(tmp_dir.as_path(), stat::S_IRWXU).is_ok());
+ }
+ assert!(chdir(tmp_dir.as_path()).is_ok());
+ assert_eq!(getcwd().unwrap(), current_dir().unwrap());
+}
+
+#[test]
fn test_lseek() {
const CONTENTS: &'static [u8] = b"abcdef123456";
let mut tmp = tempfile().unwrap();
@@ -129,10 +169,10 @@ fn test_lseek() {
lseek(tmp.as_raw_fd(), offset, Whence::SeekSet).unwrap();
let mut buf = String::new();
- tmp.read_to_string(&mut buf).unwrap();
- assert_eq!(b"f123456", buf.as_bytes());
+ tmp.read_to_string(&mut buf).unwrap();
+ assert_eq!(b"f123456", buf.as_bytes());
- close(tmp.as_raw_fd()).unwrap();
+ close(tmp.as_raw_fd()).unwrap();
}
#[cfg(any(target_os = "linux", target_os = "android"))]