summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml92
-rw-r--r--CHANGELOG.md132
-rw-r--r--CONTRIBUTING.md7
-rw-r--r--CONVENTIONS.md5
-rw-r--r--Cargo.toml6
-rw-r--r--README.md40
-rw-r--r--RELEASE_PROCEDURE.md41
-rw-r--r--ci/run-travis.sh1
-rwxr-xr-xci/run.sh2
-rw-r--r--src/fcntl.rs4
-rw-r--r--src/lib.rs4
-rw-r--r--src/mqueue.rs178
-rw-r--r--src/poll.rs92
-rw-r--r--src/sched.rs226
-rw-r--r--src/sys/event.rs2
-rw-r--r--src/sys/eventfd.rs26
-rw-r--r--src/sys/mman.rs2
-rw-r--r--src/sys/mod.rs3
-rw-r--r--src/sys/reboot.rs43
-rw-r--r--src/sys/select.rs1
-rw-r--r--src/sys/signal.rs254
-rw-r--r--src/sys/socket/consts.rs3
-rw-r--r--src/sys/socket/ffi.rs14
-rw-r--r--src/sys/socket/mod.rs32
-rw-r--r--src/sys/socket/sockopt.rs62
-rw-r--r--src/sys/wait.rs61
-rw-r--r--src/ucontext.rs12
-rw-r--r--src/unistd.rs181
-rw-r--r--test/test_mount.rs6
-rw-r--r--test/test_mq.rs8
-rw-r--r--test/test_poll.rs10
-rw-r--r--test/test_signalfd.rs3
-rw-r--r--test/test_unistd.rs116
33 files changed, 1087 insertions, 582 deletions
diff --git a/.travis.yml b/.travis.yml
index 700e7fdf..cf8a20cb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,35 +1,42 @@
+#
+# Operating Environment
+#
language: rust
sudo: false
dist: trusty
services:
- docker
+addons:
+ apt:
+ packages:
+ - gcc-multilib
+ - libcurl4-openssl-dev
+ - libelf-dev
+ - libdw-dev
+ - binutils-dev
rust:
- - 1.1.0 # Oldest supported version
- - 1.2.0
- - 1.3.0
- - 1.4.0
- - 1.5.0
- - 1.6.0
+ - 1.2.0 # Oldest supported version
+ - 1.7.0
+ - 1.8.0
- stable
- beta
- nightly
-script:
- - bash ci/run-travis.sh
-
+#
+# Environment Variables and Build Matrix
+#
env:
- - ARCH=x86_64
- - ARCH=i686
+ global:
+ - PATH=$HOME/.local/bin:$PATH
+ - TRAVIS_CARGO_NIGHTLY_FEATURE=""
+ matrix:
+ - ARCH=x86_64
+ - ARCH=i686
-os:
+os: # OSX included in build matrix explicitly
- linux
-addons:
- apt:
- packages:
- - gcc-multilib
-
# Failures on nightly shouldn't fail the overall build.
matrix:
fast_finish: true
@@ -43,10 +50,10 @@ matrix:
rust: stable
- os: osx
env: ARCH=x86_64
- rust: 1.1.0
+ rust: 1.2.0
- os: osx
env: ARCH=i686
- rust: 1.1.0
+ rust: 1.2.0
# Docker builds for other targets
- os: linux
env: TARGET=aarch64-unknown-linux-gnu DOCKER_IMAGE=posborne/rust-cross:arm
@@ -61,7 +68,7 @@ matrix:
rust: 1.7.0
sudo: true
- os: linux
- env: TARGET=mipsel-unknwon-linux-gnu DOCKER_IMAGE=posborne/rust-cross:mips
+ env: TARGET=mipsel-unknown-linux-gnu DOCKER_IMAGE=posborne/rust-cross:mips
rust: 1.7.0
sudo: true
- os: linux
@@ -71,25 +78,30 @@ matrix:
allow_failures:
- rust: nightly
- env: TARGET=mips-unknown-linux-gnu DOCKER_IMAGE=posborne/rust-cross:mips
- - env: TARGET=mipsel-unknwon-linux-gnu DOCKER_IMAGE=posborne/rust-cross:mips
+ - env: TARGET=mipsel-unknown-linux-gnu DOCKER_IMAGE=posborne/rust-cross:mips
- env: TARGET=arm-linux-androideabi DOCKER_IMAGE=posborne/rust-cross:android
-# Deploy documentation to S3 for specific branches. At some
-# point, it would be nice to also support building docs for
-# a specific tag
-deploy:
- provider: s3
- access_key_id: AKIAIGFX36YKEFRZJAXA
- secret_access_key:
- secure: Q10KEdtBoYxaGXtt23L00J0obv9fpVWtao8YKFEroZMOmvu8Sq2+9aTNGEQRp2OojOxuu+DjZInJlUDFhq6trmV3kpZH2BF7cNRxiZQpQ2FEmlr6ZpYN38GhcIUKdxXqVwXiASJi6j+vz6QdpaOGCs5lQC3VhM5sn49MFXNUrFU=
- bucket: rustdoc
- endpoint: "rustdoc.s3-website-us-east-1.amazonaws.com"
- skip_cleanup: true
- local-dir: target/doc
- upload-dir: nix/${TRAVIS_BRANCH}/${TRAVIS_OS_NAME}
- acl: public_read
- on:
- condition: "\"$TRAVIS_RUST_VERSION/$ARCH\" == \"1.1.0/x86_64\""
- repo: carllerche/nix-rust
- branch:
- - master
+
+#
+# Build/Test/Deploy Steps
+#
+before_script:
+ - pip install 'travis-cargo<0.2' --user
+
+script:
+ - bash ci/run-travis.sh
+ - |
+ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
+ travis-cargo --only stable doc
+ fi
+
+after_success:
+ - |
+ if [ "$TRAVIS_OS_NAME" = "linux" ] && \
+ [ "$TRAVIS_RUST_VERSION" = "stable" ] && \
+ [ "$ARCH" = "x86_64" ]; then
+ # Upload docs for stable (on master) to gh-pages
+ travis-cargo --only stable doc-upload
+ # Measure code coverage using kcov and upload to coveralls.io
+ travis-cargo coveralls --no-sudo --verify
+ fi
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 00000000..4238ed74
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,132 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+This project adheres to [Semantic Versioning](http://semver.org/).
+
+## [Unreleased]
+
+## [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))
+- Added `WUNTRACED` to `WaitPidFlag` in `::nix::sys::wait` for non-_linux_
+ targets.
+ ([#379](https://github.com/nix-rust/nix/pull/379))
+- 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
+- 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`.
+ ([#0](https://github.com/nix-rust/nix/pull/0))
+- 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.
+ ([#0](https://github.com/nix-rust/nix/pull/0))
+- 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.
+ ([#0](https://github.com/nix-rust/nix/pull/0))
+
+### 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 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))
+- 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))
+
+## [0.6.0] 2016-06-10
+
+### Added
+- Added `gettid` in `::nix::unistd` for _linux_ and _android_.
+ ([#293](https://github.com/nix-rust/nix/pull/293))
+- Some _mips_ support in `::nix::sched` and `::nix::sys::syscall`.
+ ([#301](https://github.com/nix-rust/nix/pull/301))
+- Added `SIGNALFD_SIGINFO_SIZE` in `::nix::sys::signalfd`.
+ ([#309](https://github.com/nix-rust/nix/pull/309))
+- Added new module `::nix::ucontext` with struct `UContext`. Currently for
+ _linux_ only.
+ ([#311](https://github.com/nix-rust/nix/pull/311))
+- Added `EPOLLEXCLUSIVE` to `EpollEventKind` in `::nix::sys::epoll`.
+ ([#330](https://github.com/nix-rust/nix/pull/330))
+- Added `pause` to `::nix::unistd`.
+ ([#336](https://github.com/nix-rust/nix/pull/336))
+- Added `sleep` to `::nix::unistd`.
+ ([#351](https://github.com/nix-rust/nix/pull/351))
+- Added `S_IFDIR`, `S_IFLNK`, `S_IFMT` to `SFlag` in `::nix::sys::stat`.
+ ([#359](https://github.com/nix-rust/nix/pull/359))
+- Added `clear` and `extend` functions to `SigSet`'s implementation in
+ `::nix::sys::signal`.
+ ([#347](https://github.com/nix-rust/nix/pull/347))
+- `sockaddr_storage_to_addr` in `::nix::sys::socket` now supports `sockaddr_nl`
+ on _linux_ and _android_.
+ ([#366](https://github.com/nix-rust/nix/pull/366))
+- Added support for `SO_ORIGINAL_DST` in `::nix::sys::socket` on _linux_.
+ ([#367](https://github.com/nix-rust/nix/pull/367))
+- Added `SIGINFO` in `::nix::sys::signal` for the _macos_ target as well as
+ `SIGPWR` and `SIGSTKFLT` in `::nix::sys::signal` for non-_macos_ targets.
+ ([#361](https://github.com/nix-rust/nix/pull/361))
+
+### Changed
+- Changed the structure `IoVec` in `::nix::sys::uio`.
+ ([#304](https://github.com/nix-rust/nix/pull/304))
+- Replaced `CREATE_NEW_FD` by `SIGNALFD_NEW` in `::nix::sys::signalfd`.
+ ([#309](https://github.com/nix-rust/nix/pull/309))
+- Renamed `SaFlag` to `SaFlags` and `SigFlag` to `SigFlags` in
+ `::nix::sys::signal`.
+ ([#314](https://github.com/nix-rust/nix/pull/314))
+- Renamed `Fork` to `ForkResult` and changed its fields in `::nix::unistd`.
+ ([#332](https://github.com/nix-rust/nix/pull/332))
+- Added the `signal` parameter to `clone`'s signature in `::nix::sched`.
+ ([#344](https://github.com/nix-rust/nix/pull/344))
+- `execv`, `execve`, and `execvp` now return `Result<Void>` instead of
+ `Result<()>` in `::nix::unistd`.
+ ([#357](https://github.com/nix-rust/nix/pull/357))
+
+### Fixed
+- Improved the conversion from `std::net::SocketAddr` to `InetAddr` in
+ `::nix::sys::socket::addr`.
+ ([#335](https://github.com/nix-rust/nix/pull/335))
+
+## [0.5.0] 2016-03-01
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 35a85ec3..9158bf1b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -60,8 +60,13 @@ pull' model described there.
Please make pull requests against the `master` branch.
-[pr-docs]: https://help.github.com/articles/using-pull-requests/
+If you change the API by way of adding, removing or changing something or if
+you fix a bug, please add an appropriate note to the [change log][cl]. We
+follow the conventions of [Keep A CHANGELOG][kacl].
+[cl]: https://github.com/nix-rust/nix/blob/master/CHANGELOG.md
+[kacl]: https://github.com/olivierlacan/keep-a-changelog/tree/18adb5f5be7a898d046f6a4acb93e39dcf40c4ad
+[pr-docs]: https://help.github.com/articles/using-pull-requests/
## Testing
diff --git a/CONVENTIONS.md b/CONVENTIONS.md
index b3a68d16..8abec905 100644
--- a/CONVENTIONS.md
+++ b/CONVENTIONS.md
@@ -9,6 +9,11 @@ conventions we try to follow have been documented here. If you find an instance
of either, feel free to remedy the flaw by opening a pull request with
appropriate changes or additions.
+## Change Log
+
+We follow the conventions laid out in [Keep A CHANGELOG][kacl].
+
+[kacl]: https://github.com/olivierlacan/keep-a-changelog/tree/18adb5f5be7a898d046f6a4acb93e39dcf40c4ad
## libc constants, functions and structs
diff --git a/Cargo.toml b/Cargo.toml
index bb1c8157..9302181c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,7 +2,7 @@
name = "nix"
description = "Rust friendly bindings to *nix APIs"
-version = "0.5.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"
@@ -23,7 +23,7 @@ preadv_pwritev = []
signalfd = []
[dependencies]
-libc = "0.2.8"
+libc = { git = "https://github.com/rust-lang/libc" }
bitflags = "0.4"
cfg-if = "0.1.0"
void = "1.0.2"
@@ -36,7 +36,7 @@ semver = "0.1.20" # Old version for compatibility with rustc_version.
rand = "0.3.8"
tempdir = "0.3"
tempfile = "2"
-nix-test = { path = "nix-test" }
+nix-test = { path = "nix-test", version = "0.0.1" }
[[test]]
name = "test"
diff --git a/README.md b/README.md
index d10bc0ee..20753af7 100644
--- a/README.md
+++ b/README.md
@@ -1,18 +1,32 @@
# Rust bindings to *nix APIs
-Rust friendly bindings to various *nix platform APIs (Linux, Darwin,
+[![Build Status](https://travis-ci.org/nix-rust/nix.svg?branch=master)](https://travis-ci.org/nix-rust/nix)
+[![crates.io](http://meritbadge.herokuapp.com/nix)](https://crates.io/crates/nix)
+
+[Documentation](https://nix-rust.github.io/nix/nix/index.html)
+
+Nix seeks to provide friendly bindings to various *nix platform APIs (Linux, Darwin,
...). The goal is to not provide a 100% unified interface, but to unify
what can be while still providing platform specific APIs.
-[![Build Status](https://travis-ci.org/nix-rust/nix.svg?branch=master)](https://travis-ci.org/nix-rust/nix)
-[![crates.io](http://meritbadge.herokuapp.com/nix)](https://crates.io/crates/nix)
+For many system APIs, Nix provides a safe alternative to the unsafe APIs
+exposed by the [libc crate](https://github.com/rust-lang/libc). This is done by
+wrapping the libc functionality with types/abstractions that enforce legal/safe
+usage.
-## Documentation
-API documentation generated by rustdoc:
+As an example of what Nix provides, examine the differences between what is
+exposed by libc and nix for the
+[gethostname](http://man7.org/linux/man-pages/man2/gethostname.2.html) system
+call:
-- Linux: [master](http://rustdoc.s3-website-us-east-1.amazonaws.com/nix/master/linux/nix/)
-- OS X: [master](http://rustdoc.s3-website-us-east-1.amazonaws.com/nix/master/osx/nix/)
+```rust,ignore
+// libc api (unsafe, requires handling return code/errno)
+pub unsafe extern fn gethostname(name: *mut c_char, len: size_t) -> c_int;
+
+// nix api (returns a nix::Result)
+pub fn gethostname(name: &mut [u8]) -> Result<()>;
+```
## Usage
@@ -20,15 +34,19 @@ To use `nix`, first add this to your `Cargo.toml`:
```toml
[dependencies]
-nix = "0.5.0"
+nix = "0.7.0"
```
Then, add this to your crate root:
-```rust
+```rust,ignore
extern crate nix;
```
-
## Contributing
-See [CONTRIBUTING](CONTRIBUTING.md).
+Contributions are very welcome. Please See [CONTRIBUTING](CONTRIBUTING.md) for
+additional details.
+
+## License
+
+Nix is licensed under the MIT license. See [LICENSE](LICENSE) for more details.
diff --git a/RELEASE_PROCEDURE.md b/RELEASE_PROCEDURE.md
new file mode 100644
index 00000000..14496f23
--- /dev/null
+++ b/RELEASE_PROCEDURE.md
@@ -0,0 +1,41 @@
+This document lists the steps that lead to a successful release of the Nix
+library.
+
+# Before Release
+
+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.
+
+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/ci/run-travis.sh b/ci/run-travis.sh
index 3b4ee138..5be6372e 100644
--- a/ci/run-travis.sh
+++ b/ci/run-travis.sh
@@ -33,7 +33,6 @@ fi
if [ "$DOCKER_IMAGE" = "" ]; then
export RUST_TEST_THREADS=1
curl -sSL "https://raw.githubusercontent.com/carllerche/travis-rust-matrix/master/test" | bash
- cargo doc --no-deps
else
export RUST_VERSION=${TRAVIS_RUST_VERSION}
export RUST_TARGET=${TARGET}
diff --git a/ci/run.sh b/ci/run.sh
index 2a94980f..770f5aa7 100755
--- a/ci/run.sh
+++ b/ci/run.sh
@@ -6,7 +6,7 @@
set -e
# This should only be run in a docker container, so verify that
-if [ ! -f /.dockerinit ]; then
+if [ ! $(pidof $0) = "1" ]; then
echo "run.sh should only be executed in a docker container"
echo "and that does not appear to be the case. Maybe you meant"
echo "to execute the tests via run-all.sh or run-docker.sh."
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 e746c6b2..8dbf9fe0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -8,7 +8,7 @@
// latest bitflags triggers a rustc bug with cross-crate macro expansions causing dead_code
// warnings even though the macro expands into something with allow(dead_code)
#![allow(dead_code)]
-#![deny(warnings)]
+#![cfg_attr(test, deny(warnings))]
#[macro_use]
extern crate bitflags;
@@ -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/event.rs b/src/sys/event.rs
index 8b112689..0e94475e 100644
--- a/src/sys/event.rs
+++ b/src/sys/event.rs
@@ -355,7 +355,7 @@ pub fn ev_set(ev: &mut KEvent,
filter: EventFilter,
flags: EventFlag,
fflags: FilterFlag,
- udata: i64) {
+ udata: isize) {
ev.ident = ident as uintptr_t;
ev.filter = filter;
diff --git a/src/sys/eventfd.rs b/src/sys/eventfd.rs
index cd740341..e6e410ec 100644
--- a/src/sys/eventfd.rs
+++ b/src/sys/eventfd.rs
@@ -2,26 +2,16 @@ use libc;
use std::os::unix::io::RawFd;
use {Errno, Result};
-bitflags!(
- flags EventFdFlag: libc::c_int {
- const EFD_CLOEXEC = 0o2000000, // Since Linux 2.6.27
- const EFD_NONBLOCK = 0o0004000, // Since Linux 2.6.27
- const EFD_SEMAPHORE = 0o0000001, // Since Linux 2.6.30
- }
-);
-
-mod ffi {
- use libc;
-
- extern {
- pub fn eventfd(initval: libc::c_uint, flags: libc::c_int) -> libc::c_int;
+libc_bitflags! {
+ flags EfdFlags: libc::c_int {
+ const EFD_CLOEXEC, // Since Linux 2.6.27
+ const EFD_NONBLOCK, // Since Linux 2.6.27
+ const EFD_SEMAPHORE, // Since Linux 2.6.30
}
}
-pub fn eventfd(initval: usize, flags: EventFdFlag) -> Result<RawFd> {
- unsafe {
- let res = ffi::eventfd(initval as libc::c_uint, flags.bits());
+pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<RawFd> {
+ let res = unsafe { libc::eventfd(initval, flags.bits()) };
- Errno::result(res).map(|r| r as RawFd)
- }
+ Errno::result(res).map(|r| r as RawFd)
}
diff --git a/src/sys/mman.rs b/src/sys/mman.rs
index 5bc1c82d..a1bf6134 100644
--- a/src/sys/mman.rs
+++ b/src/sys/mman.rs
@@ -131,7 +131,7 @@ mod consts {
const MAP_RENAME = libc::MAP_RENAME,
const MAP_NORESERVE = libc::MAP_NORESERVE,
const MAP_HASSEMAPHORE = libc::MAP_HASSEMAPHORE,
- #[cfg(not(target_os = "openbsd"))]
+ #[cfg(not(any(target_os = "openbsd", target_os = "netbsd")))]
const MAP_STACK = libc::MAP_STACK,
#[cfg(target_os = "netbsd")]
const MAP_WIRED = libc::MAP_WIRED,
diff --git a/src/sys/mod.rs b/src/sys/mod.rs
index 82934164..793bc70e 100644
--- a/src/sys/mod.rs
+++ b/src/sys/mod.rs
@@ -31,6 +31,9 @@ pub mod stat;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod syscall;
+#[cfg(any(target_os = "linux"))]
+pub mod reboot;
+
#[cfg(not(target_os = "ios"))]
pub mod termios;
diff --git a/src/sys/reboot.rs b/src/sys/reboot.rs
new file mode 100644
index 00000000..94f30f62
--- /dev/null
+++ b/src/sys/reboot.rs
@@ -0,0 +1,43 @@
+//! Reboot/shutdown or enable/disable Ctrl-Alt-Delete.
+
+use {Errno, Error, Result};
+use libc;
+use void::Void;
+use std::mem::drop;
+
+/// How exactly should the system be rebooted.
+///
+/// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for
+/// enabling/disabling Ctrl-Alt-Delete.
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum RebootMode {
+ RB_HALT_SYSTEM = libc::RB_HALT_SYSTEM,
+ RB_KEXEC = libc::RB_KEXEC,
+ RB_POWER_OFF = libc::RB_POWER_OFF,
+ RB_AUTOBOOT = libc::RB_AUTOBOOT,
+ // we do not support Restart2,
+ RB_SW_SUSPEND = libc::RB_SW_SUSPEND,
+}
+
+pub fn reboot(how: RebootMode) -> Result<Void> {
+ unsafe {
+ libc::reboot(how as libc::c_int)
+ };
+ Err(Error::Sys(Errno::last()))
+}
+
+/// Enable or disable the reboot keystroke (Ctrl-Alt-Delete).
+///
+/// Corresponds to calling `reboot(RB_ENABLE_CAD)` or `reboot(RB_DISABLE_CAD)` in C.
+pub fn set_cad_enabled(enable: bool) -> Result<()> {
+ let cmd = if enable {
+ libc::RB_ENABLE_CAD
+ } else {
+ libc::RB_DISABLE_CAD
+ };
+ let res = unsafe {
+ libc::reboot(cmd)
+ };
+ Errno::result(res).map(drop)
+}
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 753c1562..18827332 100644
--- a/src/sys/signal.rs
+++ b/src/sys/signal.rs
@@ -2,48 +2,166 @@
// See http://rust-lang.org/COPYRIGHT.
use libc;
-use {Errno, Result};
+use {Errno, Error, Result};
use std::mem;
use std::ptr;
-pub use libc::{
+// Currently there is only one definition of c_int in libc, as well as only one
+// type for signal constants.
+// We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately
+// this is not (yet) possible.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[repr(i32)]
+pub enum Signal {
+ SIGHUP = libc::SIGHUP,
+ SIGINT = libc::SIGINT,
+ SIGQUIT = libc::SIGQUIT,
+ SIGILL = libc::SIGILL,
+ SIGTRAP = libc::SIGTRAP,
+ SIGABRT = libc::SIGABRT,
+ SIGBUS = libc::SIGBUS,
+ SIGFPE = libc::SIGFPE,
+ SIGKILL = libc::SIGKILL,
+ SIGUSR1 = libc::SIGUSR1,
+ SIGSEGV = libc::SIGSEGV,
+ SIGUSR2 = libc::SIGUSR2,
+ SIGPIPE = libc::SIGPIPE,
+ SIGALRM = libc::SIGALRM,
+ SIGTERM = libc::SIGTERM,
+ #[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
+ SIGSTKFLT = libc::SIGSTKFLT,
+ SIGCHLD = libc::SIGCHLD,
+ SIGCONT = libc::SIGCONT,
+ SIGSTOP = libc::SIGSTOP,
+ SIGTSTP = libc::SIGTSTP,
+ SIGTTIN = libc::SIGTTIN,
+ SIGTTOU = libc::SIGTTOU,
+ SIGURG = libc::SIGURG,
+ SIGXCPU = libc::SIGXCPU,
+ SIGXFSZ = libc::SIGXFSZ,
+ SIGVTALRM = libc::SIGVTALRM,
+ SIGPROF = libc::SIGPROF,
+ SIGWINCH = libc::SIGWINCH,
+ SIGIO = libc::SIGIO,
+ #[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
+ SIGPWR = libc::SIGPWR,
+ SIGSYS = libc::SIGSYS,
+ #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "emscripten")))]
+ SIGEMT = libc::SIGEMT,
+ #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "emscripten")))]
+ SIGINFO = libc::SIGINFO,
+}
+
+pub use self::Signal::*;
+
+#[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
+const SIGNALS: [Signal; 31] = [
SIGHUP,
SIGINT,
SIGQUIT,
SIGILL,
+ SIGTRAP,
SIGABRT,
+ SIGBUS,
SIGFPE,
SIGKILL,
+ SIGUSR1,
SIGSEGV,
+ SIGUSR2,
SIGPIPE,
SIGALRM,
SIGTERM,
- SIGTRAP,
- SIGIOT,
- SIGBUS,
- SIGSYS,
- SIGURG,
+ SIGSTKFLT,
+ SIGCHLD,
+ SIGCONT,
SIGSTOP,
SIGTSTP,
- SIGCONT,
- SIGCHLD,
SIGTTIN,
SIGTTOU,
- SIGIO,
+ 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,
+ SIGINT,
+ SIGQUIT,
+ SIGILL,
+ SIGTRAP,
+ SIGABRT,
+ SIGBUS,
+ SIGFPE,
+ SIGKILL,
SIGUSR1,
+ SIGSEGV,
SIGUSR2,
-};
-
-// This doesn't always exist, but when it does, it's 7
-pub const SIGEMT: libc::c_int = 7;
+ SIGPIPE,
+ SIGALRM,
+ SIGTERM,
+ SIGCHLD,
+ SIGCONT,
+ SIGSTOP,
+ SIGTSTP,
+ SIGTTIN,
+ SIGTTOU,
+ SIGURG,
+ SIGXCPU,
+ SIGXFSZ,
+ SIGVTALRM,
+ SIGPROF,
+ SIGWINCH,
+ SIGIO,
+ SIGSYS,
+ SIGEMT,
+ SIGINFO];
pub const NSIG: libc::c_int = 32;
+pub struct SignalIterator {
+ next: usize,
+}
+
+impl Iterator for SignalIterator {
+ type Item = Signal;
+
+ fn next(&mut self) -> Option<Signal> {
+ if self.next < SIGNALS.len() {
+ let next_signal = SIGNALS[self.next];
+ self.next += 1;
+ Some(next_signal)
+ } else {
+ None
+ }
+ }
+}
+
+impl Signal {
+ pub fn iterator() -> SignalIterator {
+ SignalIterator{next: 0}
+ }
+
+ // We do not implement the From trait, because it is supposed to be infallible.
+ // With Rust RFC 1542 comes the appropriate trait TryFrom. Once it is
+ // implemented, we'll replace this function.
+ #[inline]
+ pub fn from_c_int(signum: libc::c_int) -> Result<Signal> {
+ match 0 < signum && signum < NSIG {
+ true => Ok(unsafe { mem::transmute(signum) }),
+ false => Err(Error::invalid_argument()),
+ }
+ }
+}
+
+pub const SIGIOT : Signal = SIGABRT;
+pub const SIGPOLL : Signal = SIGIO;
+pub const SIGUNUSED : Signal = SIGSYS;
+
bitflags!{
flags SaFlags: libc::c_int {
const SA_NOCLDSTOP = libc::SA_NOCLDSTOP,
@@ -69,7 +187,6 @@ pub struct SigSet {
sigset: libc::sigset_t
}
-pub type SigNum = libc::c_int;
impl SigSet {
pub fn all() -> SigSet {
@@ -86,40 +203,33 @@ impl SigSet {
SigSet { sigset: sigset }
}
- pub fn add(&mut self, signum: SigNum) -> Result<()> {
- let res = unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signum) };
-
- Errno::result(res).map(drop)
+ pub fn add(&mut self, signal: Signal) {
+ unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
}
- pub fn clear(&mut self) -> Result<()> {
- let res = unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
-
- Errno::result(res).map(drop)
+ pub fn clear(&mut self) {
+ unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
}
- pub fn remove(&mut self, signum: SigNum) -> Result<()> {
- let res = unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signum) };
-
- Errno::result(res).map(drop)
+ pub fn remove(&mut self, signal: Signal) {
+ unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
}
- pub fn extend(&mut self, other: &SigSet) -> Result<()> {
- for i in 1..NSIG {
- if try!(other.contains(i)) {
- try!(self.add(i));
- }
+ pub fn contains(&self, signal: Signal) -> bool {
+ let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
+
+ match res {
+ 1 => true,
+ 0 => false,
+ _ => unreachable!("unexpected value from sigismember"),
}
- Ok(())
}
- pub fn contains(&self, signum: SigNum) -> Result<bool> {
- let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signum) };
-
- match try!(Errno::result(res)) {
- 1 => Ok(true),
- 0 => Ok(false),
- _ => unreachable!("unexpected value from sigismember"),
+ pub fn extend(&mut self, other: &SigSet) {
+ for signal in Signal::iterator() {
+ if other.contains(signal) {
+ self.add(signal);
+ }
}
}
@@ -154,11 +264,11 @@ impl SigSet {
/// Suspends execution of the calling thread until one of the signals in the
/// signal mask becomes pending, and returns the accepted signal.
- pub fn wait(&self) -> Result<SigNum> {
- let mut signum: SigNum = unsafe { mem::uninitialized() };
+ pub fn wait(&self) -> Result<Signal> {
+ let mut signum: libc::c_int = unsafe { mem::uninitialized() };
let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, &mut signum) };
- Errno::result(res).map(|_| signum)
+ Errno::result(res).map(|_| Signal::from_c_int(signum).unwrap())
}
}
@@ -174,8 +284,8 @@ impl AsRef<libc::sigset_t> for SigSet {
pub enum SigHandler {
SigDfl,
SigIgn,
- Handler(extern fn(SigNum)),
- SigAction(extern fn(SigNum, *mut libc::siginfo_t, *mut libc::c_void))
+ Handler(extern fn(libc::c_int)),
+ SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
}
pub struct SigAction {
@@ -203,11 +313,11 @@ impl SigAction {
}
}
-pub unsafe fn sigaction(signum: SigNum, sigaction: &SigAction) -> Result<SigAction> {
+pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
let mut oldact = mem::uninitialized::<libc::sigaction>();
let res =
- libc::sigaction(signum, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction);
+ libc::sigaction(signal as libc::c_int, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction);
Errno::result(res).map(|_| SigAction { sigaction: oldact })
}
@@ -246,14 +356,14 @@ pub fn pthread_sigmask(how: SigFlags,
Errno::result(res).map(drop)
}
-pub fn kill(pid: libc::pid_t, signum: SigNum) -> Result<()> {
- let res = unsafe { libc::kill(pid, signum) };
+pub fn kill(pid: libc::pid_t, signal: Signal) -> Result<()> {
+ let res = unsafe { libc::kill(pid, signal as libc::c_int) };
Errno::result(res).map(drop)
}
-pub fn raise(signum: SigNum) -> Result<()> {
- let res = unsafe { libc::raise(signum) };
+pub fn raise(signal: Signal) -> Result<()> {
+ let res = unsafe { libc::raise(signal as libc::c_int) };
Errno::result(res).map(drop)
}
@@ -265,42 +375,42 @@ mod tests {
#[test]
fn test_contains() {
let mut mask = SigSet::empty();
- mask.add(SIGUSR1).unwrap();
+ mask.add(SIGUSR1);
- assert_eq!(mask.contains(SIGUSR1), Ok(true));
- assert_eq!(mask.contains(SIGUSR2), Ok(false));
+ assert!(mask.contains(SIGUSR1));
+ assert!(!mask.contains(SIGUSR2));
let all = SigSet::all();
- assert_eq!(all.contains(SIGUSR1), Ok(true));
- assert_eq!(all.contains(SIGUSR2), Ok(true));
+ assert!(all.contains(SIGUSR1));
+ assert!(all.contains(SIGUSR2));
}
#[test]
fn test_clear() {
let mut set = SigSet::all();
- set.clear().unwrap();
- for i in 1..NSIG {
- assert_eq!(set.contains(i), Ok(false));
+ set.clear();
+ for signal in Signal::iterator() {
+ assert!(!set.contains(signal));
}
}
#[test]
fn test_extend() {
let mut one_signal = SigSet::empty();
- one_signal.add(SIGUSR1).unwrap();
+ one_signal.add(SIGUSR1);
let mut two_signals = SigSet::empty();
- two_signals.add(SIGUSR2).unwrap();
- two_signals.extend(&one_signal).unwrap();
+ two_signals.add(SIGUSR2);
+ two_signals.extend(&one_signal);
- assert_eq!(two_signals.contains(SIGUSR1), Ok(true));
- assert_eq!(two_signals.contains(SIGUSR2), Ok(true));
+ assert!(two_signals.contains(SIGUSR1));
+ assert!(two_signals.contains(SIGUSR2));
}
#[test]
fn test_thread_signal_block() {
let mut mask = SigSet::empty();
- mask.add(SIGUSR1).unwrap();
+ mask.add(SIGUSR1);
assert!(mask.thread_block().is_ok());
}
@@ -308,18 +418,18 @@ mod tests {
#[test]
fn test_thread_signal_swap() {
let mut mask = SigSet::empty();
- mask.add(SIGUSR1).unwrap();
+ mask.add(SIGUSR1);
mask.thread_block().unwrap();
- assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1).unwrap());
+ assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
let mask2 = SigSet::empty();
- mask.add(SIGUSR2).unwrap();
+ mask.add(SIGUSR2);
let oldmask = mask2.thread_swap_mask(SIG_SETMASK).unwrap();
- assert!(oldmask.contains(SIGUSR1).unwrap());
- assert!(!oldmask.contains(SIGUSR2).unwrap());
+ assert!(oldmask.contains(SIGUSR1));
+ assert!(!oldmask.contains(SIGUSR2));
}
// TODO(#251): Re-enable after figuring out flakiness.
@@ -327,8 +437,8 @@ mod tests {
#[test]
fn test_sigwait() {
let mut mask = SigSet::empty();
- mask.add(SIGUSR1).unwrap();
- mask.add(SIGUSR2).unwrap();
+ mask.add(SIGUSR1);
+ mask.add(SIGUSR2);
mask.thread_block().unwrap();
raise(SIGUSR1).unwrap();
diff --git a/src/sys/socket/consts.rs b/src/sys/socket/consts.rs
index ddd8f6a9..63eaf28a 100644
--- a/src/sys/socket/consts.rs
+++ b/src/sys/socket/consts.rs
@@ -59,6 +59,8 @@ mod os {
pub const SO_TIMESTAMP: c_int = 29;
pub const SO_TYPE: c_int = 3;
pub const SO_BUSY_POLL: c_int = 46;
+ #[cfg(target_os = "linux")]
+ pub const SO_ORIGINAL_DST: c_int = 80;
// Socket options for TCP sockets
pub const TCP_NODELAY: c_int = 1;
@@ -96,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/sys/socket/ffi.rs b/src/sys/socket/ffi.rs
index 1cbf766c..55a47eb6 100644
--- a/src/sys/socket/ffi.rs
+++ b/src/sys/socket/ffi.rs
@@ -4,8 +4,11 @@
pub use libc::{socket, listen, bind, accept, connect, setsockopt, sendto, recvfrom, getsockname, getpeername, recv, send};
use libc::{c_int, c_void, socklen_t, size_t, ssize_t};
-use sys::uio::IoVec;
+#[cfg(target_os = "macos")]
+use libc::c_uint;
+
+use sys::uio::IoVec;
#[cfg(target_os = "linux")]
pub type type_of_cmsg_len = size_t;
@@ -13,6 +16,13 @@ pub type type_of_cmsg_len = size_t;
#[cfg(not(target_os = "linux"))]
pub type type_of_cmsg_len = socklen_t;
+// OSX always aligns struct cmsghdr as if it were a 32-bit OS
+#[cfg(target_os = "macos")]
+pub type type_of_cmsg_data = c_uint;
+
+#[cfg(not(target_os = "macos"))]
+pub type type_of_cmsg_data = size_t;
+
// Private because we don't expose any external functions that operate
// directly on this type; we just use it internally at FFI boundaries.
// Note that in some cases we store pointers in *const fields that the
@@ -37,7 +47,7 @@ pub struct cmsghdr {
pub cmsg_len: type_of_cmsg_len,
pub cmsg_level: c_int,
pub cmsg_type: c_int,
- pub cmsg_data: [type_of_cmsg_len; 0]
+ pub cmsg_data: [type_of_cmsg_data; 0]
}
extern {
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
index c96a5c8d..69f26aa0 100644
--- a/src/sys/socket/mod.rs
+++ b/src/sys/socket/mod.rs
@@ -94,7 +94,7 @@ unsafe fn copy_bytes<'a, 'b, T: ?Sized>(src: &T, dst: &'a mut &'b mut [u8]) {
}
-use self::ffi::{cmsghdr, msghdr, type_of_cmsg_len};
+use self::ffi::{cmsghdr, msghdr, type_of_cmsg_len, type_of_cmsg_data};
/// A structure used to make room in a cmsghdr passed to recvmsg. The
/// size and alignment match that of a cmsghdr followed by a T, but the
@@ -169,8 +169,7 @@ impl<'a> Iterator for CmsgIterator<'a> {
(SOL_SOCKET, SCM_RIGHTS) => unsafe {
Some(ControlMessage::ScmRights(
slice::from_raw_parts(
- &cmsg.cmsg_data as *const _ as *const _,
- len / mem::size_of::<RawFd>())))
+ &cmsg.cmsg_data as *const _ as *const _, 1)))
},
(_, _) => unsafe {
Some(ControlMessage::Unknown(UnknownCmsg(
@@ -201,12 +200,8 @@ pub enum ControlMessage<'a> {
pub struct UnknownCmsg<'a>(&'a cmsghdr, &'a [u8]);
fn cmsg_align(len: usize) -> usize {
- let round_to = mem::size_of::<type_of_cmsg_len>();
- if len % round_to == 0 {
- len
- } else {
- len + round_to - (len % round_to)
- }
+ let align_bytes = mem::size_of::<type_of_cmsg_data>() - 1;
+ (len + align_bytes) & !align_bytes
}
impl<'a> ControlMessage<'a> {
@@ -217,7 +212,7 @@ impl<'a> ControlMessage<'a> {
/// The value of CMSG_LEN on this message.
fn len(&self) -> usize {
- mem::size_of::<cmsghdr>() + match *self {
+ cmsg_align(mem::size_of::<cmsghdr>()) + match *self {
ControlMessage::ScmRights(fds) => {
mem::size_of_val(fds)
},
@@ -240,7 +235,11 @@ impl<'a> ControlMessage<'a> {
cmsg_data: [],
};
copy_bytes(&cmsg, buf);
- copy_bytes(fds, buf);
+
+ let padlen = cmsg_align(mem::size_of_val(&cmsg)) -
+ mem::size_of_val(&cmsg);
+ let buf2 = &mut &mut buf[padlen..];
+ copy_bytes(fds, buf2);
},
ControlMessage::Unknown(UnknownCmsg(orig_cmsg, bytes)) => {
copy_bytes(orig_cmsg, buf);
@@ -267,10 +266,10 @@ pub fn sendmsg<'a>(fd: RawFd, iov: &[IoVec<&'a [u8]>], cmsgs: &[ControlMessage<'
// multiple of size_t. Note also that the resulting vector claims
// to have length == capacity, so it's presently uninitialized.
let mut cmsg_buffer = unsafe {
- let mut vec = Vec::<size_t>::with_capacity(capacity / mem::size_of::<size_t>());
+ let mut vec = Vec::<u8>::with_capacity(len);
let ptr = vec.as_mut_ptr();
mem::forget(vec);
- Vec::<u8>::from_raw_parts(ptr as *mut _, capacity, capacity)
+ Vec::<u8>::from_raw_parts(ptr as *mut _, len, len)
};
{
let mut ptr = &mut cmsg_buffer[..];
@@ -290,7 +289,7 @@ pub fn sendmsg<'a>(fd: RawFd, iov: &[IoVec<&'a [u8]>], cmsgs: &[ControlMessage<'
msg_iov: iov.as_ptr(),
msg_iovlen: iov.len() as size_t,
msg_control: cmsg_buffer.as_ptr() as *const c_void,
- msg_controllen: len as size_t,
+ msg_controllen: capacity as size_t,
msg_flags: 0,
};
let ret = unsafe { ffi::sendmsg(fd, &mhdr, flags.bits()) };
@@ -630,6 +629,11 @@ pub unsafe fn sockaddr_storage_to_addr(
consts::AF_UNIX => {
Ok(SockAddr::Unix(UnixAddr(*(addr as *const _ as *const sockaddr_un), len)))
}
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ consts::AF_NETLINK => {
+ use libc::sockaddr_nl;
+ Ok(SockAddr::Netlink(NetlinkAddr(*(addr as *const _ as *const sockaddr_nl))))
+ }
af => panic!("unexpected address family {}", af),
}
}
diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs
index 17de2d27..bf17347c 100644
--- a/src/sys/socket/sockopt.rs
+++ b/src/sys/socket/sockopt.rs
@@ -2,6 +2,8 @@ use super::{ffi, consts, GetSockOpt, SetSockOpt};
use {Errno, Result};
use sys::time::TimeVal;
use libc::{c_int, uint8_t, c_void, socklen_t};
+#[cfg(target_os = "linux")]
+use libc::sockaddr_in;
use std::mem;
use std::os::unix::io::RawFd;
@@ -47,10 +49,6 @@ macro_rules! getsockopt_impl {
// Helper to generate the sockopt accessors
macro_rules! sockopt_impl {
- (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
- sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>);
- };
-
(GetOnly, $name:ident, $level:path, $flag:path, bool) => {
sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool);
};
@@ -63,17 +61,6 @@ macro_rules! sockopt_impl {
sockopt_impl!(GetOnly, $name, $level, $flag, usize, GetUsize);
};
- (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
- #[derive(Copy, Clone, Debug)]
- pub struct $name;
-
- getsockopt_impl!($name, $level, $flag, $ty, $getter);
- };
-
- (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
- sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>);
- };
-
(SetOnly, $name:ident, $level:path, $flag:path, bool) => {
sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool);
};
@@ -86,31 +73,50 @@ macro_rules! sockopt_impl {
sockopt_impl!(SetOnly, $name, $level, $flag, usize, SetUsize);
};
- (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
- #[derive(Copy, Clone, Debug)]
- pub struct $name;
+ (Both, $name:ident, $level:path, $flag:path, bool) => {
+ sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool);
+ };
- setsockopt_impl!($name, $level, $flag, $ty, $setter);
+ (Both, $name:ident, $level:path, $flag:path, u8) => {
+ sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8);
};
- (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
+ (Both, $name:ident, $level:path, $flag:path, usize) => {
+ sockopt_impl!(Both, $name, $level, $flag, usize, GetUsize, SetUsize);
+ };
+
+ /*
+ * Matchers with generic getter types must be placed at the end, so
+ * they'll only match _after_ specialized matchers fail
+ */
+ (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
+ sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>);
+ };
+
+ (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
#[derive(Copy, Clone, Debug)]
pub struct $name;
- setsockopt_impl!($name, $level, $flag, $ty, $setter);
getsockopt_impl!($name, $level, $flag, $ty, $getter);
};
- (Both, $name:ident, $level:path, $flag:path, bool) => {
- sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool);
+ (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
+ sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>);
};
- (Both, $name:ident, $level:path, $flag:path, u8) => {
- sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8);
+ (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
+ #[derive(Copy, Clone, Debug)]
+ pub struct $name;
+
+ setsockopt_impl!($name, $level, $flag, $ty, $setter);
};
- (Both, $name:ident, $level:path, $flag:path, usize) => {
- sockopt_impl!(Both, $name, $level, $flag, usize, GetUsize, SetUsize);
+ (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
+ #[derive(Copy, Clone, Debug)]
+ pub struct $name;
+
+ setsockopt_impl!($name, $level, $flag, $ty, $setter);
+ getsockopt_impl!($name, $level, $flag, $ty, $getter);
};
(Both, $name:ident, $level:path, $flag:path, $ty:ty) => {
@@ -168,6 +174,8 @@ sockopt_impl!(GetOnly, SockType, consts::SOL_SOCKET, consts::SO_TYPE, super::Soc
target_os = "linux",
target_os = "nacl"))]
sockopt_impl!(GetOnly, AcceptConn, consts::SOL_SOCKET, consts::SO_ACCEPTCONN, bool);
+#[cfg(target_os = "linux")]
+sockopt_impl!(GetOnly, OriginalDst, consts::SOL_IP, consts::SO_ORIGINAL_DST, sockaddr_in);
/*
*
diff --git a/src/sys/wait.rs b/src/sys/wait.rs
index 3d9b3a50..259efb70 100644
--- a/src/sys/wait.rs
+++ b/src/sys/wait.rs
@@ -1,7 +1,7 @@
-use libc::{pid_t, c_int};
+use libc::{self, pid_t, c_int};
use {Errno, Result};
-use sys::signal;
+use sys::signal::Signal;
mod ffi {
use libc::{pid_t, c_int};
@@ -15,7 +15,8 @@ mod ffi {
target_os = "android")))]
bitflags!(
flags WaitPidFlag: c_int {
- const WNOHANG = 0x00000001,
+ const WNOHANG = libc::WNOHANG,
+ const WUNTRACED = libc::WUNTRACED,
}
);
@@ -23,14 +24,14 @@ bitflags!(
target_os = "android"))]
bitflags!(
flags WaitPidFlag: c_int {
- const WNOHANG = 0x00000001,
- const WUNTRACED = 0x00000002,
- const WEXITED = 0x00000004,
- const WCONTINUED = 0x00000008,
- const WNOWAIT = 0x01000000, // Don't reap, just poll status.
- const __WNOTHREAD = 0x20000000, // Don't wait on children of other threads in this group
- const __WALL = 0x40000000, // Wait on all children, regardless of type
- // const __WCLONE = 0x80000000,
+ const WNOHANG = libc::WNOHANG,
+ const WUNTRACED = libc::WUNTRACED,
+ const WEXITED = libc::WEXITED,
+ const WCONTINUED = libc::WCONTINUED,
+ const WNOWAIT = libc::WNOWAIT, // Don't reap, just poll status.
+ const __WNOTHREAD = libc::__WNOTHREAD, // Don't wait on children of other threads in this group
+ const __WALL = libc::__WALL, // Wait on all children, regardless of type
+ const __WCLONE = libc::__WCLONE,
}
);
@@ -41,8 +42,8 @@ const WSTOPPED: WaitPidFlag = WUNTRACED;
#[derive(Eq, PartialEq, Clone, Copy, Debug)]
pub enum WaitStatus {
Exited(pid_t, i8),
- Signaled(pid_t, signal::SigNum, bool),
- Stopped(pid_t, signal::SigNum),
+ Signaled(pid_t, Signal, bool),
+ Stopped(pid_t, Signal),
Continued(pid_t),
StillAlive
}
@@ -50,7 +51,7 @@ pub enum WaitStatus {
#[cfg(any(target_os = "linux",
target_os = "android"))]
mod status {
- use sys::signal;
+ use sys::signal::Signal;
pub fn exited(status: i32) -> bool {
(status & 0x7F) == 0
@@ -64,8 +65,8 @@ mod status {
((((status & 0x7f) + 1) as i8) >> 1) > 0
}
- pub fn term_signal(status: i32) -> signal::SigNum {
- (status & 0x7f) as signal::SigNum
+ pub fn term_signal(status: i32) -> Signal {
+ Signal::from_c_int(status & 0x7f).unwrap()
}
pub fn dumped_core(status: i32) -> bool {
@@ -76,8 +77,8 @@ mod status {
(status & 0xff) == 0x7f
}
- pub fn stop_signal(status: i32) -> signal::SigNum {
- ((status & 0xFF00) >> 8) as signal::SigNum
+ pub fn stop_signal(status: i32) -> Signal {
+ Signal::from_c_int((status & 0xFF00) >> 8).unwrap()
}
pub fn continued(status: i32) -> bool {
@@ -88,7 +89,7 @@ mod status {
#[cfg(any(target_os = "macos",
target_os = "ios"))]
mod status {
- use sys::signal;
+ use sys::signal::{Signal,SIGCONT};
const WCOREFLAG: i32 = 0x80;
const WSTOPPED: i32 = 0x7f;
@@ -101,16 +102,16 @@ mod status {
((status >> 8) & 0xFF) as i8
}
- pub fn stop_signal(status: i32) -> signal::SigNum {
- (status >> 8) as signal::SigNum
+ pub fn stop_signal(status: i32) -> Signal {
+ Signal::from_c_int(status >> 8).unwrap()
}
pub fn continued(status: i32) -> bool {
- wstatus(status) == WSTOPPED && stop_signal(status) == 0x13
+ wstatus(status) == WSTOPPED && stop_signal(status) == SIGCONT
}
pub fn stopped(status: i32) -> bool {
- wstatus(status) == WSTOPPED && stop_signal(status) != 0x13
+ wstatus(status) == WSTOPPED && stop_signal(status) != SIGCONT
}
pub fn exited(status: i32) -> bool {
@@ -121,8 +122,8 @@ mod status {
wstatus(status) != WSTOPPED && wstatus(status) != 0
}
- pub fn term_signal(status: i32) -> signal::SigNum {
- wstatus(status) as signal::SigNum
+ pub fn term_signal(status: i32) -> Signal {
+ Signal::from_c_int(wstatus(status)).unwrap()
}
pub fn dumped_core(status: i32) -> bool {
@@ -135,7 +136,7 @@ mod status {
target_os = "dragonfly",
target_os = "netbsd"))]
mod status {
- use sys::signal;
+ use sys::signal::Signal;
const WCOREFLAG: i32 = 0x80;
const WSTOPPED: i32 = 0x7f;
@@ -148,16 +149,16 @@ mod status {
wstatus(status) == WSTOPPED
}
- pub fn stop_signal(status: i32) -> signal::SigNum {
- (status >> 8) as signal::SigNum
+ pub fn stop_signal(status: i32) -> Signal {
+ Signal::from_c_int(status >> 8).unwrap()
}
pub fn signaled(status: i32) -> bool {
wstatus(status) != WSTOPPED && wstatus(status) != 0 && status != 0x13
}
- pub fn term_signal(status: i32) -> signal::SigNum {
- wstatus(status) as signal::SigNum
+ pub fn term_signal(status: i32) -> Signal {
+ Signal::from_c_int(wstatus(status)).unwrap()
}
pub fn exited(status: i32) -> bool {
diff --git a/src/ucontext.rs b/src/ucontext.rs
index f77b4815..6886dd41 100644
--- a/src/ucontext.rs
+++ b/src/ucontext.rs
@@ -1,6 +1,8 @@
use libc;
+#[cfg(not(target_env = "musl"))]
use {Errno, Result};
use std::mem;
+use sys::signal::SigSet;
#[derive(Clone, Copy)]
pub struct UContext {
@@ -8,6 +10,7 @@ pub struct UContext {
}
impl UContext {
+ #[cfg(not(target_env = "musl"))]
pub fn get() -> Result<UContext> {
let mut context: libc::ucontext_t = unsafe { mem::uninitialized() };
let res = unsafe {
@@ -16,10 +19,19 @@ impl UContext {
Errno::result(res).map(|_| UContext { context: context })
}
+ #[cfg(not(target_env = "musl"))]
pub fn set(&self) -> Result<()> {
let res = unsafe {
libc::setcontext(&self.context as *const libc::ucontext_t)
};
Errno::result(res).map(drop)
}
+
+ pub fn sigmask_mut(&mut self) -> &mut SigSet {
+ unsafe { mem::transmute(&mut self.context.uc_sigmask) }
+ }
+
+ pub fn sigmask(&self) -> &SigSet {
+ unsafe { mem::transmute(&self.context.uc_sigmask) }
+ }
}
diff --git a/src/unistd.rs b/src/unistd.rs
index 8db44163..2eb218b3 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -3,13 +3,14 @@
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 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, OsStr};
-use std::os::unix::ffi::OsStrExt;
+use std::ffi::{CString, CStr, OsString, OsStr};
+use std::os::unix::ffi::{OsStringExt, OsStrExt};
use std::os::unix::io::RawFd;
-use std::path::{PathBuf, Path};
+use std::path::{PathBuf};
use void::Void;
+use sys::stat::Mode;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub use self::linux::*;
@@ -113,11 +114,109 @@ 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| {
- // We use `0 - 1` to get `-1 : {u,g}id_t` which is specified as the no-op value for chown(3).
- unsafe { libc::chown(cstr.as_ptr(), owner.unwrap_or(0 - 1), group.unwrap_or(0 - 1)) }
+ // According to the POSIX specification, -1 is used to indicate that
+ // owner and group, respectively, are not to be changed. Since uid_t and
+ // gid_t are unsigned types, we use wrapping_sub to get '-1'.
+ unsafe { libc::chown(cstr.as_ptr(),
+ owner.unwrap_or((0 as uid_t).wrapping_sub(1)),
+ group.unwrap_or((0 as gid_t).wrapping_sub(1))) }
}));
Errno::result(res).map(drop)
@@ -174,7 +273,10 @@ pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
pub fn sethostname(name: &[u8]) -> Result<()> {
// Handle some differences in type of the len arg across platforms.
cfg_if! {
- if #[cfg(any(target_os = "macos", target_os = "ios"))] {
+ if #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos", ))] {
type sethostname_len_t = c_int;
} else {
type sethostname_len_t = size_t;
@@ -212,6 +314,40 @@ pub fn write(fd: RawFd, buf: &[u8]) -> Result<usize> {
Errno::result(res).map(|r| r as usize)
}
+pub enum Whence {
+ SeekSet,
+ SeekCur,
+ SeekEnd,
+ SeekData,
+ SeekHole
+}
+
+impl Whence {
+ fn to_libc_type(&self) -> c_int {
+ match self {
+ &Whence::SeekSet => libc::SEEK_SET,
+ &Whence::SeekCur => libc::SEEK_CUR,
+ &Whence::SeekEnd => libc::SEEK_END,
+ &Whence::SeekData => 3,
+ &Whence::SeekHole => 4
+ }
+ }
+
+}
+
+pub fn lseek(fd: RawFd, offset: libc::off_t, whence: Whence) -> Result<libc::off_t> {
+ let res = unsafe { libc::lseek(fd, offset, whence.to_libc_type()) };
+
+ Errno::result(res).map(|r| r as libc::off_t)
+}
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result<libc::off64_t> {
+ let res = unsafe { libc::lseek64(fd, offset, whence.to_libc_type()) };
+
+ Errno::result(res).map(|r| r as libc::off64_t)
+}
+
pub fn pipe() -> Result<(RawFd, RawFd)> {
unsafe {
let mut fds: [c_int; 2] = mem::uninitialized();
@@ -290,7 +426,6 @@ pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> {
libc::unlink(cstr.as_ptr())
}
}));
-
Errno::result(res).map(drop)
}
@@ -376,19 +511,41 @@ 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 res = template.with_nix_path(|path| {
- let owned_path = path.to_owned();
- let path_ptr = owned_path.into_raw();
+ let mut path_copy = path.to_bytes_with_nul().to_owned();
+ let p: *mut i8 = path_copy.as_mut_ptr() as *mut i8;
unsafe {
- (libc::mkstemp(path_ptr), CString::from_raw(path_ptr))
+ (libc::mkstemp(p), OsStr::from_bytes(CStr::from_ptr(p).to_bytes()))
}
});
match res {
Ok((fd, pathname)) => {
try!(Errno::result(fd));
- Ok((fd, Path::new(OsStr::from_bytes(pathname.as_bytes())).to_owned()))
+ Ok((fd, PathBuf::from(pathname).to_owned()))
}
Err(e) => {
Err(e)
diff --git a/test/test_mount.rs b/test/test_mount.rs
index 74d2938c..7ddbce9f 100644
--- a/test/test_mount.rs
+++ b/test/test_mount.rs
@@ -15,7 +15,7 @@ mod test_mount {
use std::os::unix::fs::PermissionsExt;
use std::process::{self, Command};
- use libc::{self, EACCES, EROFS};
+ use libc::{EACCES, EROFS};
use nix::mount::{mount, umount, MsFlags, MS_BIND, MS_RDONLY, MS_NOEXEC};
use nix::sched::{unshare, CLONE_NEWNS, CLONE_NEWUSER};
@@ -179,8 +179,8 @@ exit 23";
let mut handle = stderr.lock();
writeln!(handle,
"unshare failed: {}. Are unprivileged user namespaces available?",
- e);
- writeln!(handle, "mount is not being tested");
+ e).unwrap();
+ writeln!(handle, "mount is not being tested").unwrap();
// Exit with success because not all systems support unprivileged user namespaces, and
// that's not what we're testing for.
process::exit(0);
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_signalfd.rs b/test/test_signalfd.rs
index 8bb62bb2..28a6decb 100644
--- a/test/test_signalfd.rs
+++ b/test/test_signalfd.rs
@@ -1,9 +1,10 @@
extern crate nix;
#[cfg(feature = "signalfd")]
-
use nix::sys::signalfd::SignalFd;
+#[cfg(feature = "signalfd")]
use nix::sys::signal;
+#[cfg(feature = "signalfd")]
use nix::unistd;
#[cfg(feature = "signalfd")]
diff --git a/test/test_unistd.rs b/test/test_unistd.rs
index 9b4bff2c..8b9e6e49 100644
--- a/test/test_unistd.rs
+++ b/test/test_unistd.rs
@@ -1,31 +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;
#[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")
}
}
@@ -33,15 +43,15 @@ 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")
}
}
@@ -123,6 +133,56 @@ 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();
+ tmp.write(CONTENTS).unwrap();
+
+ let offset: off_t = 5;
+ 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());
+
+ close(tmp.as_raw_fd()).unwrap();
+}
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+#[test]
+fn test_lseek64() {
+ const CONTENTS: &'static [u8] = b"abcdef123456";
+ let mut tmp = tempfile().unwrap();
+ tmp.write(CONTENTS).unwrap();
+
+ lseek64(tmp.as_raw_fd(), 5, Whence::SeekSet).unwrap();
+
+ let mut buf = String::new();
+ tmp.read_to_string(&mut buf).unwrap();
+ assert_eq!(b"f123456", buf.as_bytes());
+
+ close(tmp.as_raw_fd()).unwrap();
+}
+
execve_test_factory!(test_execve, execve, b"/bin/sh", b"/system/bin/sh");
#[cfg(any(target_os = "linux", target_os = "android"))]