aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Galenson <jgalenson@google.com>2021-08-17 21:09:42 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-08-17 21:09:42 +0000
commit1dc99aca939fc87b42e711ead2185a70df0441a1 (patch)
treefc4e4c5fce5873e157076a945055babb79b88d61
parentfef73fda591b8826ae639760855b678f567774fe (diff)
parent981b40ad24a6d181cf843903a983f37305526484 (diff)
downloadnix-1dc99aca939fc87b42e711ead2185a70df0441a1.tar.gz
Upgrade rust/crates/nix to 0.22.0 am: 981b40ad24
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/nix/+/1790951 Change-Id: I0b831c18e290a0aadcc68341daa0cc5fa7216521
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp2
-rw-r--r--CHANGELOG.md35
-rw-r--r--Cargo.toml4
-rw-r--r--Cargo.toml.orig4
-rw-r--r--METADATA8
-rw-r--r--README.md2
-rw-r--r--src/dir.rs2
-rw-r--r--src/env.rs20
-rw-r--r--src/errno.rs134
-rw-r--r--src/fcntl.rs41
-rw-r--r--src/lib.rs95
-rw-r--r--src/mount/bsd.rs425
-rw-r--r--src/mount/linux.rs (renamed from src/mount.rs)0
-rw-r--r--src/mount/mod.rs20
-rw-r--r--src/net/if_.rs144
-rw-r--r--src/pty.rs35
-rw-r--r--src/sched.rs14
-rw-r--r--src/sys/aio.rs24
-rw-r--r--src/sys/epoll.rs5
-rw-r--r--src/sys/mman.rs4
-rw-r--r--src/sys/ptrace/linux.rs4
-rw-r--r--src/sys/reboot.rs2
-rw-r--r--src/sys/signal.rs10
-rw-r--r--src/sys/signalfd.rs4
-rw-r--r--src/sys/socket/addr.rs6
-rw-r--r--src/sys/socket/mod.rs42
-rw-r--r--src/sys/socket/sockopt.rs6
-rw-r--r--src/sys/termios.rs2
-rw-r--r--src/sys/timerfd.rs6
-rw-r--r--src/sys/uio.rs10
-rw-r--r--src/time.rs2
-rw-r--r--src/unistd.rs45
-rw-r--r--test/common/mod.rs14
-rw-r--r--test/sys/test_aio.rs6
-rw-r--r--test/sys/test_aio_drop.rs1
-rw-r--r--test/sys/test_epoll.rs4
-rw-r--r--test/sys/test_inotify.rs4
-rw-r--r--test/sys/test_ioctl.rs32
-rw-r--r--test/sys/test_lio_listio_resubmit.rs9
-rw-r--r--test/sys/test_ptrace.rs19
-rw-r--r--test/sys/test_signal.rs4
-rw-r--r--test/sys/test_socket.rs95
-rw-r--r--test/sys/test_termios.rs8
-rw-r--r--test/sys/test_wait.rs4
-rw-r--r--test/test.rs2
-rw-r--r--test/test_dir.rs2
-rw-r--r--test/test_fcntl.rs161
-rw-r--r--test/test_kmod/mod.rs6
-rw-r--r--test/test_mq.rs17
-rw-r--r--test/test_nmount.rs51
-rw-r--r--test/test_poll.rs3
-rw-r--r--test/test_ptymaster_drop.rs4
-rw-r--r--test/test_stat.rs4
-rw-r--r--test/test_unistd.rs22
55 files changed, 1317 insertions, 314 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 4893485..3433190 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
{
"git": {
- "sha1": "db2af196c9c279f8bb4856c5eff1e2b658fcf2ff"
+ "sha1": "5dd14c39b88fb6eb25ad670435d1a79ba294b21e"
}
}
diff --git a/Android.bp b/Android.bp
index 487e081..1fe2da1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -44,5 +44,5 @@ rust_library {
// autocfg-1.0.1
// bitflags-1.2.1 "default"
// cfg-if-1.0.0
-// libc-0.2.97 "default,extra_traits,std"
+// libc-0.2.98 "default,extra_traits,std"
// memoffset-0.6.4 "default"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 91364a6..21cb4b8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,34 @@ This project adheres to [Semantic Versioning](https://semver.org/).
### Fixed
### Removed
+## [0.22.0] - 9 July 2021
+### Added
+- Added `if_nameindex` (#[1445](https://github.com/nix-rust/nix/pull/1445))
+- Added `nmount` for FreeBSD.
+ (#[1453](https://github.com/nix-rust/nix/pull/1453))
+- Added `IpFreebind` socket option (sockopt) on Linux, Fuchsia and Android.
+ (#[1456](https://github.com/nix-rust/nix/pull/1456))
+- Added `TcpUserTimeout` socket option (sockopt) on Linux and Fuchsia.
+ (#[1457](https://github.com/nix-rust/nix/pull/1457))
+- Added `renameat2` for Linux
+ (#[1458](https://github.com/nix-rust/nix/pull/1458))
+- Added `RxqOvfl` support on Linux, Fuchsia and Android.
+ (#[1455](https://github.com/nix-rust/nix/pull/1455))
+
+### Changed
+- `ptsname_r` now returns a lossily-converted string in the event of bad UTF,
+ just like `ptsname`.
+ ([#1446](https://github.com/nix-rust/nix/pull/1446))
+- Nix's error type is now a simple wrapper around the platform's Errno. This
+ means it is now `Into<std::io::Error>`. It's also `Clone`, `Copy`, `Eq`, and
+ has a small fixed size. It also requires less typing. For example, the old
+ enum variant `nix::Error::Sys(nix::errno::Errno::EINVAL)` is now simply
+ `nix::Error::EINVAL`.
+ ([#1446](https://github.com/nix-rust/nix/pull/1446))
+
+### Fixed
+### Removed
+
## [0.21.0] - 31 May 2021
### Added
- Added `getresuid` and `getresgid`
@@ -38,12 +66,17 @@ This project adheres to [Semantic Versioning](https://semver.org/).
(#[1440](https://github.com/nix-rust/nix/pull/1440))
- Minimum supported Rust version is now 1.41.0.
([#1440](https://github.com/nix-rust/nix/pull/1440))
+- Errno aliases are now associated consts on `Errno`, instead of consts in the
+ `errno` module.
+ (#[1452](https://github.com/nix-rust/nix/pull/1452))
### Fixed
- Allow `sockaddr_ll` size, as reported by the Linux kernel, to be smaller then it's definition
(#[1395](https://github.com/nix-rust/nix/pull/1395))
- Fix spurious errors using `sendmmsg` with multiple cmsgs
(#[1414](https://github.com/nix-rust/nix/pull/1414))
+- Added `Errno::EOPNOTSUPP` to FreeBSD, where it was missing.
+ (#[1452](https://github.com/nix-rust/nix/pull/1452))
### Removed
@@ -55,6 +88,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
longer be needed now that async/await are available. `AioCb`s now work
exclusively with borrowed buffers, not owned ones.
(#[1440](https://github.com/nix-rust/nix/pull/1440))
+- Removed some Errno values from platforms where they aren't actually defined.
+ (#[1452](https://github.com/nix-rust/nix/pull/1452))
## [0.20.0] - 20 February 2021
### Added
diff --git a/Cargo.toml b/Cargo.toml
index ae10774..a111b80 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "nix"
-version = "0.21.0"
+version = "0.22.0"
authors = ["The nix-rust Project Developers"]
exclude = ["/.gitignore", "/.cirrus.yml", "/ci/*", "/Cross.toml", "/RELEASE_PROCEDURE.md", "/bors.toml"]
description = "Rust friendly bindings to *nix APIs"
@@ -54,7 +54,7 @@ version = "1.1"
version = "1.0"
[dependencies.libc]
-version = "0.2.95"
+version = "0.2.98"
features = ["extra_traits"]
[dev-dependencies.assert-impl]
version = "0.1"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 843c5c1..c5cdd08 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -2,7 +2,7 @@
name = "nix"
description = "Rust friendly bindings to *nix APIs"
edition = "2018"
-version = "0.21.0"
+version = "0.22.0"
authors = ["The nix-rust Project Developers"]
repository = "https://github.com/nix-rust/nix"
license = "MIT"
@@ -32,7 +32,7 @@ targets = [
]
[dependencies]
-libc = { version = "0.2.95", features = [ "extra_traits" ] }
+libc = { version = "0.2.98", features = [ "extra_traits" ] }
bitflags = "1.1"
cfg-if = "1.0"
diff --git a/METADATA b/METADATA
index 0b954fe..bb088b2 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/nix/nix-0.21.0.crate"
+ value: "https://static.crates.io/crates/nix/nix-0.22.0.crate"
}
- version: "0.21.0"
+ version: "0.22.0"
license_type: NOTICE
last_upgrade_date {
year: 2021
- month: 6
- day: 21
+ month: 8
+ day: 9
}
}
diff --git a/README.md b/README.md
index 816f233..895ef1e 100644
--- a/README.md
+++ b/README.md
@@ -93,7 +93,7 @@ To use `nix`, add this to your `Cargo.toml`:
```toml
[dependencies]
-nix = "0.21.0"
+nix = "0.22.0"
```
## Contributing
diff --git a/src/dir.rs b/src/dir.rs
index 7c35d70..65ed2e9 100644
--- a/src/dir.rs
+++ b/src/dir.rs
@@ -84,7 +84,7 @@ impl AsRawFd for Dir {
impl Drop for Dir {
fn drop(&mut self) {
let e = Errno::result(unsafe { libc::closedir(self.0.as_ptr()) });
- if !std::thread::panicking() && e == Err(Error::Sys(Errno::EBADF)) {
+ if !std::thread::panicking() && e == Err(Error::from(Errno::EBADF)) {
panic!("Closing an invalid file descriptor!");
};
}
diff --git a/src/env.rs b/src/env.rs
index f144dfe..613b0cd 100644
--- a/src/env.rs
+++ b/src/env.rs
@@ -1,12 +1,24 @@
use cfg_if::cfg_if;
-use crate::{Error, Result};
+use std::fmt;
+
+/// Indicates that [`clearenv`] failed for some unknown reason
+#[derive(Clone, Copy, Debug)]
+pub struct ClearEnvError;
+
+impl fmt::Display for ClearEnvError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "clearenv failed")
+ }
+}
+
+impl std::error::Error for ClearEnvError {}
/// Clear the environment of all name-value pairs.
///
/// On platforms where libc provides `clearenv()`, it will be used. libc's
/// `clearenv()` is documented to return an error code but not set errno; if the
/// return value indicates a failure, this function will return
-/// `Error::UnsupportedOperation`.
+/// [`ClearEnvError`].
///
/// On platforms where libc does not provide `clearenv()`, a fallback
/// implementation will be used that iterates over all environment variables and
@@ -25,7 +37,7 @@ use crate::{Error, Result};
/// `environ` is currently held. The latter is not an issue if the only other
/// environment access in the program is via `std::env`, but the requirement on
/// thread safety must still be upheld.
-pub unsafe fn clearenv() -> Result<()> {
+pub unsafe fn clearenv() -> std::result::Result<(), ClearEnvError> {
let ret;
cfg_if! {
if #[cfg(any(target_os = "fuchsia",
@@ -48,6 +60,6 @@ pub unsafe fn clearenv() -> Result<()> {
if ret == 0 {
Ok(())
} else {
- Err(Error::UnsupportedOperation)
+ Err(ClearEnvError)
}
}
diff --git a/src/errno.rs b/src/errno.rs
index 9275feb..00e2014 100644
--- a/src/errno.rs
+++ b/src/errno.rs
@@ -1,5 +1,6 @@
use cfg_if::cfg_if;
use libc::{c_int, c_void};
+use std::convert::TryFrom;
use std::{fmt, io, error};
use crate::{Error, Result};
@@ -48,6 +49,42 @@ pub fn errno() -> i32 {
}
impl Errno {
+ /// Convert this `Error` to an [`Errno`](enum.Errno.html).
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use nix::Error;
+ /// # use nix::errno::Errno;
+ /// let e = Error::from(Errno::EPERM);
+ /// assert_eq!(Some(Errno::EPERM), e.as_errno());
+ /// ```
+ #[deprecated(
+ since = "0.22.0",
+ note = "It's a no-op now; just delete it."
+ )]
+ pub fn as_errno(self) -> Option<Self> {
+ Some(self)
+ }
+
+ /// Create a nix Error from a given errno
+ #[deprecated(
+ since = "0.22.0",
+ note = "It's a no-op now; just delete it."
+ )]
+ pub fn from_errno(errno: Errno) -> Error {
+ Error::from(errno)
+ }
+
+ /// Create a new invalid argument error (`EINVAL`)
+ #[deprecated(
+ since = "0.22.0",
+ note = "Use Errno::EINVAL instead"
+ )]
+ pub fn invalid_argument() -> Error {
+ Errno::EINVAL
+ }
+
pub fn last() -> Self {
last()
}
@@ -68,11 +105,26 @@ impl Errno {
/// should not be used when `-1` is not the errno sentinel value.
pub fn result<S: ErrnoSentinel + PartialEq<S>>(value: S) -> Result<S> {
if value == S::sentinel() {
- Err(Error::Sys(Self::last()))
+ Err(Self::last())
} else {
Ok(value)
}
}
+
+ /// Backwards compatibility hack for Nix <= 0.21.0 users
+ ///
+ /// In older versions of Nix, `Error::Sys` was an enum variant. Now it's a
+ /// function, which is compatible with most of the former use cases of the
+ /// enum variant. But you should use `Error(Errno::...)` instead.
+ #[deprecated(
+ since = "0.22.0",
+ note = "Use Errno::... instead"
+ )]
+ #[allow(non_snake_case)]
+ #[inline]
+ pub fn Sys(errno: Errno) -> Error {
+ errno
+ }
}
/// The sentinel value indicates that a function failed and more detailed
@@ -115,6 +167,16 @@ impl From<Errno> for io::Error {
}
}
+impl TryFrom<io::Error> for Errno {
+ type Error = io::Error;
+
+ fn try_from(ioerror: io::Error) -> std::result::Result<Self, io::Error> {
+ ioerror.raw_os_error()
+ .map(Errno::from_i32)
+ .ok_or(ioerror)
+ }
+}
+
fn last() -> Errno {
Errno::from_i32(errno())
}
@@ -843,9 +905,11 @@ mod consts {
EHWPOISON = libc::EHWPOISON,
}
- pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
- pub const EDEADLOCK: Errno = Errno::EDEADLK;
- pub const ENOTSUP: Errno = Errno::EOPNOTSUPP;
+ impl Errno {
+ pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
+ pub const EDEADLOCK: Errno = Errno::EDEADLK;
+ pub const ENOTSUP: Errno = Errno::EOPNOTSUPP;
+ }
pub fn from_i32(e: i32) -> Errno {
use self::Errno::*;
@@ -1103,11 +1167,11 @@ mod consts {
EQFULL = libc::EQFULL,
}
- pub const ELAST: Errno = Errno::EQFULL;
- pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
- pub const EDEADLOCK: Errno = Errno::EDEADLK;
-
- pub const EL2NSYNC: Errno = Errno::UnknownErrno;
+ impl Errno {
+ pub const ELAST: Errno = Errno::EQFULL;
+ pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
+ pub const EDEADLOCK: Errno = Errno::EDEADLK;
+ }
pub fn from_i32(e: i32) -> Errno {
use self::Errno::*;
@@ -1328,11 +1392,12 @@ mod consts {
EOWNERDEAD = libc::EOWNERDEAD,
}
- pub const ELAST: Errno = Errno::EOWNERDEAD;
- pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
- pub const EDEADLOCK: Errno = Errno::EDEADLK;
-
- pub const EL2NSYNC: Errno = Errno::UnknownErrno;
+ impl Errno {
+ pub const ELAST: Errno = Errno::EOWNERDEAD;
+ pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
+ pub const EDEADLOCK: Errno = Errno::EDEADLK;
+ pub const EOPNOTSUPP: Errno = Errno::ENOTSUP;
+ }
pub fn from_i32(e: i32) -> Errno {
use self::Errno::*;
@@ -1542,12 +1607,12 @@ mod consts {
EASYNC = libc::EASYNC,
}
- pub const ELAST: Errno = Errno::EASYNC;
- pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
- pub const EDEADLOCK: Errno = Errno::EDEADLK;
- pub const EOPNOTSUPP: Errno = Errno::ENOTSUP;
-
- pub const EL2NSYNC: Errno = Errno::UnknownErrno;
+ impl Errno {
+ pub const ELAST: Errno = Errno::EASYNC;
+ pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
+ pub const EDEADLOCK: Errno = Errno::EDEADLK;
+ pub const EOPNOTSUPP: Errno = Errno::ENOTSUP;
+ }
pub fn from_i32(e: i32) -> Errno {
use self::Errno::*;
@@ -1756,10 +1821,10 @@ mod consts {
EPROTO = libc::EPROTO,
}
- pub const ELAST: Errno = Errno::ENOTSUP;
- pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
-
- pub const EL2NSYNC: Errno = Errno::UnknownErrno;
+ impl Errno {
+ pub const ELAST: Errno = Errno::ENOTSUP;
+ pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
+ }
pub fn from_i32(e: i32) -> Errno {
use self::Errno::*;
@@ -1969,10 +2034,10 @@ mod consts {
EPROTO = libc::EPROTO,
}
- pub const ELAST: Errno = Errno::ENOTSUP;
- pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
-
- pub const EL2NSYNC: Errno = Errno::UnknownErrno;
+ impl Errno {
+ pub const ELAST: Errno = Errno::ENOTSUP;
+ pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
+ }
pub fn from_i32(e: i32) -> Errno {
use self::Errno::*;
@@ -2172,10 +2237,9 @@ mod consts {
EPROTO = libc::EPROTO,
}
- pub const ELAST: Errno = Errno::UnknownErrno;
- pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
-
- pub const EL2NSYNC: Errno = Errno::UnknownErrno;
+ impl Errno {
+ pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
+ }
pub fn from_i32(e: i32) -> Errno {
use self::Errno::*;
@@ -2400,8 +2464,10 @@ mod consts {
ESTALE = libc::ESTALE,
}
- pub const ELAST: Errno = Errno::ESTALE;
- pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
+ impl Errno {
+ pub const ELAST: Errno = Errno::ESTALE;
+ pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
+ }
pub fn from_i32(e: i32) -> Errno {
use self::Errno::*;
diff --git a/src/fcntl.rs b/src/fcntl.rs
index ce30b7d..f8f1372 100644
--- a/src/fcntl.rs
+++ b/src/fcntl.rs
@@ -210,6 +210,43 @@ pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
Errno::result(res).map(drop)
}
+#[cfg(all(
+ target_os = "linux",
+ target_env = "gnu",
+))]
+libc_bitflags! {
+ pub struct RenameFlags: u32 {
+ RENAME_EXCHANGE;
+ RENAME_NOREPLACE;
+ RENAME_WHITEOUT;
+ }
+}
+
+#[cfg(all(
+ target_os = "linux",
+ target_env = "gnu",
+))]
+pub fn renameat2<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
+ old_dirfd: Option<RawFd>,
+ old_path: &P1,
+ new_dirfd: Option<RawFd>,
+ new_path: &P2,
+ flags: RenameFlags,
+) -> Result<()> {
+ let res = old_path.with_nix_path(|old_cstr| {
+ new_path.with_nix_path(|new_cstr| unsafe {
+ libc::renameat2(
+ at_rawfd(old_dirfd),
+ old_cstr.as_ptr(),
+ at_rawfd(new_dirfd),
+ new_cstr.as_ptr(),
+ flags.bits(),
+ )
+ })
+ })??;
+ Errno::result(res).map(drop)
+}
+
fn wrap_readlink_result(mut v: Vec<u8>, len: ssize_t) -> Result<OsString> {
unsafe { v.set_len(len as usize) }
v.shrink_to_fit();
@@ -288,7 +325,7 @@ fn inner_readlink<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P) -> Result
Some(next_size) => try_size = next_size,
// It's absurd that this would happen, but handle it sanely
// anyway.
- None => break Err(super::Error::Sys(Errno::ENAMETOOLONG)),
+ None => break Err(super::Error::from(Errno::ENAMETOOLONG)),
}
}
}
@@ -646,6 +683,6 @@ pub fn posix_fallocate(fd: RawFd, offset: libc::off_t, len: libc::off_t) -> Resu
match Errno::result(res) {
Err(err) => Err(err),
Ok(0) => Ok(()),
- Ok(errno) => Err(crate::Error::Sys(Errno::from_i32(errno))),
+ Ok(errno) => Err(crate::Error::from(Errno::from_i32(errno))),
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 899d3f8..3b534a5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -44,6 +44,7 @@ pub mod ifaddrs;
target_os = "linux"))]
pub mod kmod;
#[cfg(any(target_os = "android",
+ target_os = "freebsd",
target_os = "linux"))]
pub mod mount;
#[cfg(any(target_os = "dragonfly",
@@ -78,7 +79,7 @@ pub mod unistd;
use libc::{c_char, PATH_MAX};
-use std::{error, fmt, ptr, result};
+use std::{ptr, result};
use std::ffi::{CStr, OsStr};
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};
@@ -86,83 +87,19 @@ use std::path::{Path, PathBuf};
use errno::Errno;
/// Nix Result Type
-pub type Result<T> = result::Result<T, Error>;
+pub type Result<T> = result::Result<T, Errno>;
-/// Nix Error Type
+/// Nix's main error type.
///
-/// The nix error type provides a common way of dealing with
-/// various system system/libc calls that might fail. Each
-/// error has a corresponding errno (usually the one from the
-/// underlying OS) to which it can be mapped in addition to
-/// implementing other common traits.
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub enum Error {
- Sys(Errno),
- InvalidPath,
- /// The operation involved a conversion to Rust's native String type, which failed because the
- /// string did not contain all valid UTF-8.
- InvalidUtf8,
- /// The operation is not supported by Nix, in this instance either use the libc bindings or
- /// consult the module documentation to see if there is a more appropriate interface available.
- UnsupportedOperation,
-}
-
-impl Error {
- /// Convert this `Error` to an [`Errno`](enum.Errno.html).
- ///
- /// # Example
- ///
- /// ```
- /// # use nix::Error;
- /// # use nix::errno::Errno;
- /// let e = Error::from(Errno::EPERM);
- /// assert_eq!(Some(Errno::EPERM), e.as_errno());
- /// ```
- pub fn as_errno(self) -> Option<Errno> {
- if let Error::Sys(e) = self {
- Some(e)
- } else {
- None
- }
- }
-
- /// Create a nix Error from a given errno
- pub fn from_errno(errno: Errno) -> Error {
- Error::Sys(errno)
- }
-
- /// Get the current errno and convert it to a nix Error
- pub fn last() -> Error {
- Error::Sys(Errno::last())
- }
-
- /// Create a new invalid argument error (`EINVAL`)
- pub fn invalid_argument() -> Error {
- Error::Sys(Errno::EINVAL)
- }
-
-}
-
-impl From<Errno> for Error {
- fn from(errno: Errno) -> Error { Error::from_errno(errno) }
-}
-
-impl From<std::string::FromUtf8Error> for Error {
- fn from(_: std::string::FromUtf8Error) -> Error { Error::InvalidUtf8 }
-}
-
-impl error::Error for Error {}
-
-impl fmt::Display for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- Error::InvalidPath => write!(f, "Invalid path"),
- Error::InvalidUtf8 => write!(f, "Invalid UTF-8 string"),
- Error::UnsupportedOperation => write!(f, "Unsupported Operation"),
- Error::Sys(errno) => write!(f, "{:?}: {}", errno, errno.desc()),
- }
- }
-}
+/// It's a wrapper around Errno. As such, it's very interoperable with
+/// [`std::io::Error`], but it has the advantages of:
+/// * `Clone`
+/// * `Copy`
+/// * `Eq`
+/// * Small size
+/// * Represents all of the system's errnos, instead of just the most common
+/// ones.
+pub type Error = Errno;
pub trait NixPath {
fn is_empty(&self) -> bool;
@@ -216,7 +153,7 @@ impl NixPath for CStr {
where F: FnOnce(&CStr) -> T {
// Equivalence with the [u8] impl.
if self.len() >= PATH_MAX as usize {
- return Err(Error::InvalidPath);
+ return Err(Error::from(Errno::ENAMETOOLONG))
}
Ok(f(self))
@@ -237,11 +174,11 @@ impl NixPath for [u8] {
let mut buf = [0u8; PATH_MAX as usize];
if self.len() >= PATH_MAX as usize {
- return Err(Error::InvalidPath);
+ return Err(Error::from(Errno::ENAMETOOLONG))
}
match self.iter().position(|b| *b == 0) {
- Some(_) => Err(Error::InvalidPath),
+ Some(_) => Err(Error::from(Errno::EINVAL)),
None => {
unsafe {
// TODO: Replace with bytes::copy_memory. rust-lang/rust#24028
diff --git a/src/mount/bsd.rs b/src/mount/bsd.rs
new file mode 100644
index 0000000..0144908
--- /dev/null
+++ b/src/mount/bsd.rs
@@ -0,0 +1,425 @@
+use crate::{
+ Error,
+ Errno,
+ NixPath,
+ Result,
+ sys::uio::IoVec
+};
+use libc::{c_char, c_int, c_uint, c_void};
+use std::{
+ borrow::Cow,
+ ffi::{CString, CStr},
+ fmt,
+ io,
+ ptr
+};
+
+
+libc_bitflags!(
+ /// Used with [`Nmount::nmount`].
+ pub struct MntFlags: c_int {
+ /// ACL support enabled.
+ #[cfg(any(target_os = "netbsd", target_os = "freebsd"))]
+ MNT_ACLS;
+ /// All I/O to the file system should be done asynchronously.
+ MNT_ASYNC;
+ /// dir should instead be a file system ID encoded as “FSID:val0:val1”.
+ #[cfg(target_os = "freebsd")]
+ MNT_BYFSID;
+ /// Force a read-write mount even if the file system appears to be
+ /// unclean.
+ MNT_FORCE;
+ /// GEOM journal support enabled.
+ #[cfg(target_os = "freebsd")]
+ MNT_GJOURNAL;
+ /// MAC support for objects.
+ #[cfg(any(target_os = "macos", target_os = "freebsd"))]
+ MNT_MULTILABEL;
+ /// Disable read clustering.
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
+ MNT_NOCLUSTERR;
+ /// Disable write clustering.
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
+ MNT_NOCLUSTERW;
+ /// Enable NFS version 4 ACLs.
+ #[cfg(target_os = "freebsd")]
+ MNT_NFS4ACLS;
+ /// Do not update access times.
+ MNT_NOATIME;
+ /// Disallow program execution.
+ MNT_NOEXEC;
+ /// Do not honor setuid or setgid bits on files when executing them.
+ MNT_NOSUID;
+ /// Do not follow symlinks.
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
+ MNT_NOSYMFOLLOW;
+ /// Mount read-only.
+ MNT_RDONLY;
+ /// Causes the vfs subsystem to update its data structures pertaining to
+ /// the specified already mounted file system.
+ MNT_RELOAD;
+ /// Create a snapshot of the file system.
+ ///
+ /// See [mksnap_ffs(8)](https://www.freebsd.org/cgi/man.cgi?query=mksnap_ffs)
+ #[cfg(any(target_os = "macos", target_os = "freebsd"))]
+ MNT_SNAPSHOT;
+ /// Using soft updates.
+ #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+ MNT_SOFTDEP;
+ /// Directories with the SUID bit set chown new files to their own
+ /// owner.
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
+ MNT_SUIDDIR;
+ /// All I/O to the file system should be done synchronously.
+ MNT_SYNCHRONOUS;
+ /// Union with underlying fs.
+ #[cfg(any(
+ target_os = "macos",
+ target_os = "freebsd",
+ target_os = "netbsd"
+ ))]
+ MNT_UNION;
+ /// Indicates that the mount command is being applied to an already
+ /// mounted file system.
+ MNT_UPDATE;
+ /// Check vnode use counts.
+ #[cfg(target_os = "freebsd")]
+ MNT_NONBUSY;
+ }
+);
+
+
+/// The Error type of [`Nmount::nmount`].
+///
+/// It wraps an [`Errno`], but also may contain an additional message returned
+/// by `nmount(2)`.
+#[derive(Debug)]
+pub struct NmountError {
+ errno: Error,
+ errmsg: Option<String>
+}
+
+impl NmountError {
+ /// Returns the additional error string sometimes generated by `nmount(2)`.
+ pub fn errmsg(&self) -> Option<&str> {
+ self.errmsg.as_deref()
+ }
+
+ /// Returns the inner [`Error`]
+ pub fn error(&self) -> Error {
+ self.errno
+ }
+
+ fn new(error: Error, errmsg: Option<&CStr>) -> Self {
+ Self {
+ errno: error,
+ errmsg: errmsg.map(CStr::to_string_lossy).map(Cow::into_owned)
+ }
+ }
+}
+
+impl std::error::Error for NmountError {}
+
+impl fmt::Display for NmountError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if let Some(errmsg) = &self.errmsg {
+ write!(f, "{:?}: {}: {}", self.errno, errmsg, self.errno.desc())
+ } else {
+ write!(f, "{:?}: {}", self.errno, self.errno.desc())
+ }
+ }
+}
+
+impl From<NmountError> for io::Error {
+ fn from(err: NmountError) -> Self {
+ err.errno.into()
+ }
+}
+
+/// Result type of [`Nmount::nmount`].
+pub type NmountResult = std::result::Result<(), NmountError>;
+
+/// Mount a FreeBSD file system.
+///
+/// The `nmount(2)` system call works similarly to the `mount(8)` program; it
+/// takes its options as a series of name-value pairs. Most of the values are
+/// strings, as are all of the names. The `Nmount` structure builds up an
+/// argument list and then executes the syscall.
+///
+/// # Examples
+///
+/// To mount `target` onto `mountpoint` with `nullfs`:
+/// ```
+/// # use nix::unistd::Uid;
+/// # use ::sysctl::CtlValue;
+/// # if !Uid::current().is_root() && CtlValue::Int(0) == ::sysctl::value("vfs.usermount").unwrap() {
+/// # return;
+/// # };
+/// use nix::mount::{MntFlags, Nmount, unmount};
+/// use std::ffi::CString;
+/// use tempfile::tempdir;
+///
+/// let mountpoint = tempdir().unwrap();
+/// let target = tempdir().unwrap();
+///
+/// let fstype = CString::new("fstype").unwrap();
+/// let nullfs = CString::new("nullfs").unwrap();
+/// Nmount::new()
+/// .str_opt(&fstype, &nullfs)
+/// .str_opt_owned("fspath", mountpoint.path().to_str().unwrap())
+/// .str_opt_owned("target", target.path().to_str().unwrap())
+/// .nmount(MntFlags::empty()).unwrap();
+///
+/// unmount(mountpoint.path(), MntFlags::empty()).unwrap();
+/// ```
+///
+/// # See Also
+/// * [`nmount(2)`](https://www.freebsd.org/cgi/man.cgi?query=nmount)
+/// * [`nullfs(5)`](https://www.freebsd.org/cgi/man.cgi?query=nullfs)
+#[cfg(target_os = "freebsd")]
+#[derive(Debug, Default)]
+pub struct Nmount<'a>{
+ iov: Vec<IoVec<&'a [u8]>>,
+ is_owned: Vec<bool>,
+}
+
+#[cfg(target_os = "freebsd")]
+impl<'a> Nmount<'a> {
+ /// Add an opaque mount option.
+ ///
+ /// Some file systems take binary-valued mount options. They can be set
+ /// with this method.
+ ///
+ /// # Safety
+ ///
+ /// Unsafe because it will cause `Nmount::nmount` to dereference a raw
+ /// pointer. The user is responsible for ensuring that `val` is valid and
+ /// its lifetime outlives `self`! An easy way to do that is to give the
+ /// value a larger scope than `name`
+ ///
+ /// # Examples
+ /// ```
+ /// use libc::c_void;
+ /// use nix::mount::Nmount;
+ /// use std::ffi::CString;
+ /// use std::mem;
+ ///
+ /// // Note that flags outlives name
+ /// let mut flags: u32 = 0xdeadbeef;
+ /// let name = CString::new("flags").unwrap();
+ /// let p = &mut flags as *mut u32 as *mut c_void;
+ /// let len = mem::size_of_val(&flags);
+ /// let mut nmount = Nmount::new();
+ /// unsafe { nmount.mut_ptr_opt(&name, p, len) };
+ /// ```
+ pub unsafe fn mut_ptr_opt(
+ &mut self,
+ name: &'a CStr,
+ val: *mut c_void,
+ len: usize
+ ) -> &mut Self
+ {
+ self.iov.push(IoVec::from_slice(name.to_bytes_with_nul()));
+ self.is_owned.push(false);
+ self.iov.push(IoVec::from_raw_parts(val, len));
+ self.is_owned.push(false);
+ self
+ }
+
+ /// Add a mount option that does not take a value.
+ ///
+ /// # Examples
+ /// ```
+ /// use nix::mount::Nmount;
+ /// use std::ffi::CString;
+ ///
+ /// let read_only = CString::new("ro").unwrap();
+ /// Nmount::new()
+ /// .null_opt(&read_only);
+ /// ```
+ pub fn null_opt(&mut self, name: &'a CStr) -> &mut Self {
+ self.iov.push(IoVec::from_slice(name.to_bytes_with_nul()));
+ self.is_owned.push(false);
+ self.iov.push(IoVec::from_raw_parts(ptr::null_mut(), 0));
+ self.is_owned.push(false);
+ self
+ }
+
+ /// Add a mount option that does not take a value, but whose name must be
+ /// owned.
+ ///
+ ///
+ /// This has higher runtime cost than [`Nmount::null_opt`], but is useful
+ /// when the name's lifetime doesn't outlive the `Nmount`, or it's a
+ /// different string type than `CStr`.
+ ///
+ /// # Examples
+ /// ```
+ /// use nix::mount::Nmount;
+ ///
+ /// let read_only = "ro";
+ /// let mut nmount: Nmount<'static> = Nmount::new();
+ /// nmount.null_opt_owned(read_only);
+ /// ```
+ pub fn null_opt_owned<P: ?Sized + NixPath>(&mut self, name: &P) -> &mut Self
+ {
+ name.with_nix_path(|s| {
+ let len = s.to_bytes_with_nul().len();
+ self.iov.push(IoVec::from_raw_parts(
+ // Must free it later
+ s.to_owned().into_raw() as *mut c_void,
+ len
+ ));
+ self.is_owned.push(true);
+ }).unwrap();
+ self.iov.push(IoVec::from_raw_parts(ptr::null_mut(), 0));
+ self.is_owned.push(false);
+ self
+ }
+
+ /// Add a mount option as a [`CStr`].
+ ///
+ /// # Examples
+ /// ```
+ /// use nix::mount::Nmount;
+ /// use std::ffi::CString;
+ ///
+ /// let fstype = CString::new("fstype").unwrap();
+ /// let nullfs = CString::new("nullfs").unwrap();
+ /// Nmount::new()
+ /// .str_opt(&fstype, &nullfs);
+ /// ```
+ pub fn str_opt(
+ &mut self,
+ name: &'a CStr,
+ val: &'a CStr
+ ) -> &mut Self
+ {
+ self.iov.push(IoVec::from_slice(name.to_bytes_with_nul()));
+ self.is_owned.push(false);
+ self.iov.push(IoVec::from_slice(val.to_bytes_with_nul()));
+ self.is_owned.push(false);
+ self
+ }
+
+ /// Add a mount option as an owned string.
+ ///
+ /// This has higher runtime cost than [`Nmount::str_opt`], but is useful
+ /// when the value's lifetime doesn't outlive the `Nmount`, or it's a
+ /// different string type than `CStr`.
+ ///
+ /// # Examples
+ /// ```
+ /// use nix::mount::Nmount;
+ /// use std::path::Path;
+ ///
+ /// let mountpoint = Path::new("/mnt");
+ /// Nmount::new()
+ /// .str_opt_owned("fspath", mountpoint.to_str().unwrap());
+ /// ```
+ pub fn str_opt_owned<P1, P2>(&mut self, name: &P1, val: &P2) -> &mut Self
+ where P1: ?Sized + NixPath,
+ P2: ?Sized + NixPath
+ {
+ name.with_nix_path(|s| {
+ let len = s.to_bytes_with_nul().len();
+ self.iov.push(IoVec::from_raw_parts(
+ // Must free it later
+ s.to_owned().into_raw() as *mut c_void,
+ len
+ ));
+ self.is_owned.push(true);
+ }).unwrap();
+ val.with_nix_path(|s| {
+ let len = s.to_bytes_with_nul().len();
+ self.iov.push(IoVec::from_raw_parts(
+ // Must free it later
+ s.to_owned().into_raw() as *mut c_void,
+ len
+ ));
+ self.is_owned.push(true);
+ }).unwrap();
+ self
+ }
+
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Actually mount the file system.
+ pub fn nmount(&mut self, flags: MntFlags) -> NmountResult {
+ // nmount can return extra error information via a "errmsg" return
+ // argument.
+ const ERRMSG_NAME: &[u8] = b"errmsg\0";
+ let mut errmsg = vec![0u8; 255];
+ self.iov.push(IoVec::from_raw_parts(
+ ERRMSG_NAME.as_ptr() as *mut c_void,
+ ERRMSG_NAME.len()
+ ));
+ self.iov.push(IoVec::from_raw_parts(
+ errmsg.as_mut_ptr() as *mut c_void,
+ errmsg.len()
+ ));
+
+ let niov = self.iov.len() as c_uint;
+ let iovp = self.iov.as_mut_ptr() as *mut libc::iovec;
+ let res = unsafe {
+ libc::nmount(iovp, niov, flags.bits)
+ };
+ match Errno::result(res) {
+ Ok(_) => Ok(()),
+ Err(error) => {
+ let errmsg = match errmsg.iter().position(|&x| x == 0) {
+ None => None,
+ Some(0) => None,
+ Some(n) => {
+ let sl = &errmsg[0..n + 1];
+ Some(CStr::from_bytes_with_nul(sl).unwrap())
+ }
+ };
+ Err(NmountError::new(error.into(), errmsg))
+ }
+ }
+ }
+}
+
+#[cfg(target_os = "freebsd")]
+impl<'a> Drop for Nmount<'a> {
+ fn drop(&mut self) {
+ for (iov, is_owned) in self.iov.iter().zip(self.is_owned.iter()) {
+ if *is_owned {
+ // Free the owned string. Safe because we recorded ownership,
+ // and Nmount does not implement Clone.
+ unsafe {
+ CString::from_raw(iov.0.iov_base as *mut c_char);
+ }
+ }
+ }
+ }
+}
+
+/// Unmount the file system mounted at `mountpoint`.
+///
+/// Useful flags include
+/// * `MNT_FORCE` - Unmount even if still in use.
+/// * `MNT_BYFSID` - `mountpoint` is not a path, but a file system ID
+/// encoded as `FSID:val0:val1`, where `val0` and `val1`
+/// are the contents of the `fsid_t val[]` array in decimal.
+/// The file system that has the specified file system ID
+/// will be unmounted. See
+/// [`statfs`](crate::sys::statfs::statfs) to determine the
+/// `fsid`.
+pub fn unmount<P>(mountpoint: &P, flags: MntFlags) -> Result<()>
+ where P: ?Sized + NixPath
+{
+ let res = mountpoint.with_nix_path(|cstr| {
+ unsafe { libc::unmount(cstr.as_ptr(), flags.bits) }
+ })?;
+
+ Errno::result(res).map(drop)
+}
diff --git a/src/mount.rs b/src/mount/linux.rs
index edb8afb..edb8afb 100644
--- a/src/mount.rs
+++ b/src/mount/linux.rs
diff --git a/src/mount/mod.rs b/src/mount/mod.rs
new file mode 100644
index 0000000..8538bf3
--- /dev/null
+++ b/src/mount/mod.rs
@@ -0,0 +1,20 @@
+#[cfg(any(target_os = "android", target_os = "linux"))]
+mod linux;
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub use self::linux::*;
+
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+mod bsd;
+
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+pub use self::bsd::*;
diff --git a/src/net/if_.rs b/src/net/if_.rs
index 70349e5..bc00a43 100644
--- a/src/net/if_.rs
+++ b/src/net/if_.rs
@@ -3,8 +3,8 @@
//! Uses Linux and/or POSIX functions to resolve interface names like "eth0"
//! or "socan1" into device numbers.
+use crate::{Error, NixPath, Result};
use libc::c_uint;
-use crate::{Result, Error, NixPath};
/// Resolve an interface into a interface number.
pub fn if_nametoindex<P: ?Sized + NixPath>(name: &P) -> Result<c_uint> {
@@ -267,3 +267,145 @@ libc_bitflags!(
IFF_IPMP;
}
);
+
+#[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "fuchsia",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd",
+))]
+mod if_nameindex {
+ use super::*;
+
+ use std::ffi::CStr;
+ use std::fmt;
+ use std::marker::PhantomData;
+ use std::ptr::NonNull;
+
+ /// A network interface. Has a name like "eth0" or "wlp4s0" or "wlan0", as well as an index
+ /// (1, 2, 3, etc) that identifies it in the OS's networking stack.
+ #[allow(missing_copy_implementations)]
+ #[repr(transparent)]
+ pub struct Interface(libc::if_nameindex);
+
+ impl Interface {
+ /// Obtain the index of this interface.
+ pub fn index(&self) -> c_uint {
+ self.0.if_index
+ }
+
+ /// Obtain the name of this interface.
+ pub fn name(&self) -> &CStr {
+ unsafe { CStr::from_ptr(self.0.if_name) }
+ }
+ }
+
+ impl fmt::Debug for Interface {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Interface")
+ .field("index", &self.index())
+ .field("name", &self.name())
+ .finish()
+ }
+ }
+
+ /// A list of the network interfaces available on this system. Obtained from [`if_nameindex()`].
+ pub struct Interfaces {
+ ptr: NonNull<libc::if_nameindex>,
+ }
+
+ impl Interfaces {
+ /// Iterate over the interfaces in this list.
+ #[inline]
+ pub fn iter(&self) -> InterfacesIter<'_> {
+ self.into_iter()
+ }
+
+ /// Convert this to a slice of interfaces. Note that the underlying interfaces list is
+ /// null-terminated, so calling this calculates the length. If random access isn't needed,
+ /// [`Interfaces::iter()`] should be used instead.
+ pub fn to_slice(&self) -> &[Interface] {
+ let ifs = self.ptr.as_ptr() as *const Interface;
+ let len = self.iter().count();
+ unsafe { std::slice::from_raw_parts(ifs, len) }
+ }
+ }
+
+ impl Drop for Interfaces {
+ fn drop(&mut self) {
+ unsafe { libc::if_freenameindex(self.ptr.as_ptr()) };
+ }
+ }
+
+ impl fmt::Debug for Interfaces {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.to_slice().fmt(f)
+ }
+ }
+
+ impl<'a> IntoIterator for &'a Interfaces {
+ type IntoIter = InterfacesIter<'a>;
+ type Item = &'a Interface;
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ InterfacesIter {
+ ptr: self.ptr.as_ptr(),
+ _marker: PhantomData,
+ }
+ }
+ }
+
+ /// An iterator over the interfaces in an [`Interfaces`].
+ #[derive(Debug)]
+ pub struct InterfacesIter<'a> {
+ ptr: *const libc::if_nameindex,
+ _marker: PhantomData<&'a Interfaces>,
+ }
+
+ impl<'a> Iterator for InterfacesIter<'a> {
+ type Item = &'a Interface;
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ unsafe {
+ if (*self.ptr).if_index == 0 {
+ None
+ } else {
+ let ret = &*(self.ptr as *const Interface);
+ self.ptr = self.ptr.add(1);
+ Some(ret)
+ }
+ }
+ }
+ }
+
+ /// Retrieve a list of the network interfaces available on the local system.
+ ///
+ /// ```
+ /// let interfaces = nix::net::if_::if_nameindex().unwrap();
+ /// for iface in &interfaces {
+ /// println!("Interface #{} is called {}", iface.index(), iface.name().to_string_lossy());
+ /// }
+ /// ```
+ pub fn if_nameindex() -> Result<Interfaces> {
+ unsafe {
+ let ifs = libc::if_nameindex();
+ let ptr = NonNull::new(ifs).ok_or_else(Error::last)?;
+ Ok(Interfaces { ptr })
+ }
+ }
+}
+#[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "fuchsia",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd",
+))]
+pub use if_nameindex::*;
diff --git a/src/pty.rs b/src/pty.rs
index 07e0961..a8eb938 100644
--- a/src/pty.rs
+++ b/src/pty.rs
@@ -70,7 +70,7 @@ impl Drop for PtyMaster {
// condition, which can cause confusing errors for future I/O
// operations.
let e = unistd::close(self.0);
- if e == Err(Error::Sys(Errno::EBADF)) {
+ if e == Err(Errno::EBADF) {
panic!("Closing an invalid file descriptor!");
};
}
@@ -78,13 +78,13 @@ impl Drop for PtyMaster {
impl io::Read for PtyMaster {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- unistd::read(self.0, buf).map_err(|e| e.as_errno().unwrap().into())
+ unistd::read(self.0, buf).map_err(io::Error::from)
}
}
impl io::Write for PtyMaster {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- unistd::write(self.0, buf).map_err(|e| e.as_errno().unwrap().into())
+ unistd::write(self.0, buf).map_err(io::Error::from)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
@@ -99,7 +99,7 @@ impl io::Write for PtyMaster {
#[inline]
pub fn grantpt(fd: &PtyMaster) -> Result<()> {
if unsafe { libc::grantpt(fd.as_raw_fd()) } < 0 {
- return Err(Error::last());
+ return Err(Error::from(Errno::last()));
}
Ok(())
@@ -145,7 +145,7 @@ pub fn posix_openpt(flags: fcntl::OFlag) -> Result<PtyMaster> {
};
if fd < 0 {
- return Err(Error::last());
+ return Err(Error::from(Errno::last()));
}
Ok(PtyMaster(fd))
@@ -171,7 +171,7 @@ pub fn posix_openpt(flags: fcntl::OFlag) -> Result<PtyMaster> {
pub unsafe fn ptsname(fd: &PtyMaster) -> Result<String> {
let name_ptr = libc::ptsname(fd.as_raw_fd());
if name_ptr.is_null() {
- return Err(Error::last());
+ return Err(Error::from(Errno::last()));
}
let name = CStr::from_ptr(name_ptr);
@@ -190,18 +190,17 @@ pub unsafe fn ptsname(fd: &PtyMaster) -> Result<String> {
#[cfg(any(target_os = "android", target_os = "linux"))]
#[inline]
pub fn ptsname_r(fd: &PtyMaster) -> Result<String> {
- let mut name_buf = vec![0u8; 64];
- let name_buf_ptr = name_buf.as_mut_ptr() as *mut libc::c_char;
- if unsafe { libc::ptsname_r(fd.as_raw_fd(), name_buf_ptr, name_buf.capacity()) } != 0 {
- return Err(Error::last());
- }
-
- // Find the first null-character terminating this string. This is guaranteed to succeed if the
- // return value of `libc::ptsname_r` is 0.
- let null_index = name_buf.iter().position(|c| *c == b'\0').unwrap();
- name_buf.truncate(null_index);
+ let mut name_buf = Vec::<libc::c_char>::with_capacity(64);
+ let name_buf_ptr = name_buf.as_mut_ptr();
+ let cname = unsafe {
+ let cap = name_buf.capacity();
+ if libc::ptsname_r(fd.as_raw_fd(), name_buf_ptr, cap) != 0 {
+ return Err(Error::last());
+ }
+ CStr::from_ptr(name_buf.as_ptr())
+ };
- let name = String::from_utf8(name_buf)?;
+ let name = cname.to_string_lossy().into_owned();
Ok(name)
}
@@ -214,7 +213,7 @@ pub fn ptsname_r(fd: &PtyMaster) -> Result<String> {
#[inline]
pub fn unlockpt(fd: &PtyMaster) -> Result<()> {
if unsafe { libc::unlockpt(fd.as_raw_fd()) } < 0 {
- return Err(Error::last());
+ return Err(Error::from(Errno::last()));
}
Ok(())
diff --git a/src/sched.rs b/src/sched.rs
index 576eb4a..bf51bc1 100644
--- a/src/sched.rs
+++ b/src/sched.rs
@@ -68,7 +68,7 @@ mod sched_linux_like {
/// `field` is the CPU id to test
pub fn is_set(&self, field: usize) -> Result<bool> {
if field >= CpuSet::count() {
- Err(Error::Sys(Errno::EINVAL))
+ Err(Error::from(Errno::EINVAL))
} else {
Ok(unsafe { libc::CPU_ISSET(field, &self.cpu_set) })
}
@@ -78,7 +78,7 @@ mod sched_linux_like {
/// `field` is the CPU id to add
pub fn set(&mut self, field: usize) -> Result<()> {
if field >= CpuSet::count() {
- Err(Error::Sys(Errno::EINVAL))
+ Err(Error::from(Errno::EINVAL))
} else {
unsafe { libc::CPU_SET(field, &mut self.cpu_set); }
Ok(())
@@ -89,7 +89,7 @@ mod sched_linux_like {
/// `field` is the CPU id to remove
pub fn unset(&mut self, field: usize) -> Result<()> {
if field >= CpuSet::count() {
- Err(Error::Sys(Errno::EINVAL))
+ Err(Error::from(Errno::EINVAL))
} else {
unsafe { libc::CPU_CLR(field, &mut self.cpu_set);}
Ok(())
@@ -176,6 +176,14 @@ mod sched_linux_like {
Errno::result(res).and(Ok(cpuset))
}
+ /// `clone` create a child process
+ /// ([`clone(2)`](https://man7.org/linux/man-pages/man2/clone.2.html))
+ ///
+ /// `stack` is a reference to an array which will hold the stack of the new
+ /// process. Unlike when calling `clone(2)` from C, the provided stack
+ /// address need not be the highest address of the region. Nix will take
+ /// care of that requirement. The user only needs to provide a reference to
+ /// a normally allocated buffer.
pub fn clone(
mut cb: CloneCb,
stack: &mut [u8],
diff --git a/src/sys/aio.rs b/src/sys/aio.rs
index a03caa4..b63affb 100644
--- a/src/sys/aio.rs
+++ b/src/sys/aio.rs
@@ -379,7 +379,7 @@ impl<'a> AioCb<'a> {
}
}
- /// Like [`from_mut_slice`], but works on constant slices rather than
+ /// Like [`AioCb::from_mut_slice`], but works on constant slices rather than
/// mutable slices.
///
/// An `AioCb` created this way cannot be used with `read`, and its
@@ -508,7 +508,7 @@ impl<'a> AioCb<'a> {
libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled),
libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled),
libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone),
- -1 => Err(Error::last()),
+ -1 => Err(Error::from(Errno::last())),
_ => panic!("unknown aio_cancel return value")
}
}
@@ -519,8 +519,8 @@ impl<'a> AioCb<'a> {
};
match r {
0 => Ok(()),
- num if num > 0 => Err(Error::from_errno(Errno::from_i32(num))),
- -1 => Err(Error::last()),
+ num if num > 0 => Err(Error::from(Errno::from_i32(num))),
+ -1 => Err(Error::from(Errno::last())),
num => panic!("unknown aio_error return value {:?}", num)
}
}
@@ -735,7 +735,7 @@ pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> {
libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled),
libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled),
libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone),
- -1 => Err(Error::last()),
+ -1 => Err(Error::from(Errno::last())),
_ => panic!("unknown aio_cancel return value")
}
}
@@ -943,8 +943,8 @@ impl<'a> LioCb<'a> {
/// LioOpcode::LIO_WRITE
/// ).finish();
/// let mut err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone);
- /// while err == Err(Error::Sys(Errno::EIO)) ||
- /// err == Err(Error::Sys(Errno::EAGAIN)) {
+ /// while err == Err(Error::from(Errno::EIO)) ||
+ /// err == Err(Error::from(Errno::EAGAIN)) {
/// thread::sleep(time::Duration::from_millis(10));
/// err = liocb.listio_resubmit(LioMode::LIO_WAIT, SigevNotify::SigevNone);
/// }
@@ -983,13 +983,13 @@ impl<'a> LioCb<'a> {
// aiocb is complete; collect its status and don't resubmit
self.results[i] = Some(a.aio_return_unpinned());
},
- Err(Error::Sys(Errno::EAGAIN)) => {
+ Err(Errno::EAGAIN) => {
self.list.push(a as *mut AioCb<'a> as *mut libc::aiocb);
},
- Err(Error::Sys(Errno::EINPROGRESS)) => {
+ Err(Errno::EINPROGRESS) => {
// aiocb is was successfully queued; no need to do anything
},
- Err(Error::Sys(Errno::EINVAL)) => panic!(
+ Err(Errno::EINVAL) => panic!(
"AioCb was never submitted, or already finalized"),
_ => unreachable!()
}
@@ -1102,8 +1102,8 @@ impl<'a> LioCbBuilder<'a> {
///
/// Afterwards it will be possible to issue the operations with
/// [`LioCb::listio`]. Conversely, it will no longer be possible to add new
- /// operations with [`LioCb::emplace_slice`] or
- /// [`LioCb::emplace_mut_slice`].
+ /// operations with [`LioCbBuilder::emplace_slice`] or
+ /// [`LioCbBuilder::emplace_mut_slice`].
///
/// [`LioCb::listio`]: struct.LioCb.html#method.listio
/// [`LioCb::from_mut_slice`]: struct.LioCb.html#method.from_mut_slice
diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs
index 2437bbe..b73af13 100644
--- a/src/sys/epoll.rs
+++ b/src/sys/epoll.rs
@@ -1,10 +1,9 @@
-use crate::Result;
+use crate::{Error, Result};
use crate::errno::Errno;
use libc::{self, c_int};
use std::os::unix::io::RawFd;
use std::ptr;
use std::mem;
-use crate::Error;
libc_bitflags!(
pub struct EpollFlags: c_int {
@@ -86,7 +85,7 @@ pub fn epoll_ctl<'a, T>(epfd: RawFd, op: EpollOp, fd: RawFd, event: T) -> Result
{
let mut event: Option<&mut EpollEvent> = event.into();
if event.is_none() && op != EpollOp::EpollCtlDel {
- Err(Error::Sys(Errno::EINVAL))
+ Err(Error::from(Errno::EINVAL))
} else {
let res = unsafe {
if let Some(ref mut event) = event {
diff --git a/src/sys/mman.rs b/src/sys/mman.rs
index 34c7663..58edf08 100644
--- a/src/sys/mman.rs
+++ b/src/sys/mman.rs
@@ -320,7 +320,7 @@ pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: Ma
let ret = libc::mmap(addr, length, prot.bits(), flags.bits(), fd, offset);
if ret == libc::MAP_FAILED {
- Err(Error::Sys(Errno::last()))
+ Err(Error::from(Errno::last()))
} else {
Ok(ret)
}
@@ -344,7 +344,7 @@ pub unsafe fn mremap(
let ret = libc::mremap(addr, old_size, new_size, flags.bits(), new_address.unwrap_or(std::ptr::null_mut()));
if ret == libc::MAP_FAILED {
- Err(Error::Sys(Errno::last()))
+ Err(Error::from(Errno::last()))
} else {
Ok(ret)
}
diff --git a/src/sys/ptrace/linux.rs b/src/sys/ptrace/linux.rs
index 8d1dd16..4ac4393 100644
--- a/src/sys/ptrace/linux.rs
+++ b/src/sys/ptrace/linux.rs
@@ -2,7 +2,7 @@
use cfg_if::cfg_if;
use std::{mem, ptr};
-use crate::{Error, Result};
+use crate::Result;
use crate::errno::Errno;
use libc::{self, c_void, c_long, siginfo_t};
use crate::unistd::Pid;
@@ -180,7 +180,7 @@ fn ptrace_peek(request: Request, pid: Pid, addr: AddressType, data: *mut c_void)
libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)
};
match Errno::result(ret) {
- Ok(..) | Err(Error::Sys(Errno::UnknownErrno)) => Ok(ret),
+ Ok(..) | Err(Errno::UnknownErrno) => Ok(ret),
err @ Err(..) => err,
}
}
diff --git a/src/sys/reboot.rs b/src/sys/reboot.rs
index e319130..5b37682 100644
--- a/src/sys/reboot.rs
+++ b/src/sys/reboot.rs
@@ -26,7 +26,7 @@ pub fn reboot(how: RebootMode) -> Result<Infallible> {
unsafe {
libc::reboot(how as libc::c_int)
};
- Err(Error::Sys(Errno::last()))
+ Err(Error::from(Errno::last()))
}
/// Enable or disable the reboot keystroke (Ctrl-Alt-Delete).
diff --git a/src/sys/signal.rs b/src/sys/signal.rs
index bf3f762..273b352 100644
--- a/src/sys/signal.rs
+++ b/src/sys/signal.rs
@@ -121,7 +121,7 @@ impl FromStr for Signal {
target_os = "fuchsia", target_os = "linux",
target_os = "redox")))]
"SIGINFO" => Signal::SIGINFO,
- _ => return Err(Error::invalid_argument()),
+ _ => return Err(Error::from(Errno::EINVAL)),
})
}
}
@@ -368,7 +368,7 @@ impl TryFrom<libc::c_int> for Signal {
if 0 < signum && signum < NSIG {
Ok(unsafe { mem::transmute(signum) })
} else {
- Err(Error::invalid_argument())
+ Err(Error::from(Errno::EINVAL))
}
}
}
@@ -664,7 +664,7 @@ pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigActi
///
/// # Errors
///
-/// Returns [`Error::UnsupportedOperation`] if `handler` is
+/// Returns [`Error(Errno::EOPNOTSUPP)`] if `handler` is
/// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead.
///
/// `signal` also returns any error from `libc::signal`, such as when an attempt
@@ -681,7 +681,7 @@ pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler>
SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN),
SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t),
#[cfg(not(target_os = "redox"))]
- SigHandler::SigAction(_) => return Err(Error::UnsupportedOperation),
+ SigHandler::SigAction(_) => return Err(Error::from(Errno::ENOTSUP)),
};
Errno::result(res).map(|oldhandler| {
match oldhandler {
@@ -949,7 +949,7 @@ mod tests {
#[test]
fn test_from_str_invalid_value() {
- let errval = Err(Error::Sys(Errno::EINVAL));
+ let errval = Err(Error::from(Errno::EINVAL));
assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
assert_eq!("kill".parse::<Signal>(), errval);
assert_eq!("9".parse::<Signal>(), errval);
diff --git a/src/sys/signalfd.rs b/src/sys/signalfd.rs
index 1e162cf..49811a1 100644
--- a/src/sys/signalfd.rs
+++ b/src/sys/signalfd.rs
@@ -108,7 +108,7 @@ impl SignalFd {
match res {
Ok(SIGNALFD_SIGINFO_SIZE) => Ok(Some(unsafe { mem::transmute(buffer.assume_init()) })),
Ok(_) => unreachable!("partial read on signalfd"),
- Err(Error::Sys(Errno::EAGAIN)) => Ok(None),
+ Err(Errno::EAGAIN) => Ok(None),
Err(error) => Err(error)
}
}
@@ -117,7 +117,7 @@ impl SignalFd {
impl Drop for SignalFd {
fn drop(&mut self) {
let e = unistd::close(self.0);
- if !std::thread::panicking() && e == Err(Error::Sys(Errno::EBADF)) {
+ if !std::thread::panicking() && e == Err(Error::from(Errno::EBADF)) {
panic!("Closing an invalid file descriptor!");
};
}
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs
index 6a0bc9a..d486056 100644
--- a/src/sys/socket/addr.rs
+++ b/src/sys/socket/addr.rs
@@ -536,7 +536,7 @@ impl UnixAddr {
let bytes = cstr.to_bytes();
if bytes.len() > ret.sun_path.len() {
- return Err(Error::Sys(Errno::ENAMETOOLONG));
+ return Err(Error::from(Errno::ENAMETOOLONG));
}
ptr::copy_nonoverlapping(bytes.as_ptr(),
@@ -563,7 +563,7 @@ impl UnixAddr {
};
if path.len() + 1 > ret.sun_path.len() {
- return Err(Error::Sys(Errno::ENAMETOOLONG));
+ return Err(Error::from(Errno::ENAMETOOLONG));
}
// Abstract addresses are represented by sun_path[0] ==
@@ -1035,7 +1035,7 @@ pub mod sys_control {
pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> {
if name.len() > MAX_KCTL_NAME {
- return Err(Error::Sys(Errno::ENAMETOOLONG));
+ return Err(Error::from(Errno::ENAMETOOLONG));
}
let mut ctl_name = [0; MAX_KCTL_NAME];
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
index 6907046..da5573c 100644
--- a/src/sys/socket/mod.rs
+++ b/src/sys/socket/mod.rs
@@ -610,6 +610,17 @@ pub enum ControlMessageOwned {
#[cfg(target_os = "linux")]
UdpGroSegments(u16),
+ /// SO_RXQ_OVFL indicates that an unsigned 32 bit value
+ /// ancilliary msg (cmsg) should be attached to recieved
+ /// skbs indicating the number of packets dropped by the
+ /// socket between the last recieved packet and this
+ /// received packet.
+ ///
+ /// `RxqOvfl` socket option should be enabled on a socket
+ /// to allow receiving the drop counter.
+ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+ RxqOvfl(u32),
+
/// Catch-all variant for unimplemented cmsg types.
#[doc(hidden)]
Unknown(UnknownCmsg),
@@ -708,6 +719,11 @@ impl ControlMessageOwned {
let gso_size: u16 = ptr::read_unaligned(p as *const _);
ControlMessageOwned::UdpGroSegments(gso_size)
},
+ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+ (libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => {
+ let drop_counter = ptr::read_unaligned(p as *const u32);
+ ControlMessageOwned::RxqOvfl(drop_counter)
+ },
(_, _) => {
let sl = slice::from_raw_parts(p, len);
let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(sl));
@@ -826,6 +842,14 @@ pub enum ControlMessage<'a> {
target_os = "android",
target_os = "ios",))]
Ipv6PacketInfo(&'a libc::in6_pktinfo),
+
+ /// SO_RXQ_OVFL indicates that an unsigned 32 bit value
+ /// ancilliary msg (cmsg) should be attached to recieved
+ /// skbs indicating the number of packets dropped by the
+ /// socket between the last recieved packet and this
+ /// received packet.
+ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+ RxqOvfl(&'a u32),
}
// An opaque structure used to prevent cmsghdr from being a public type
@@ -916,6 +940,10 @@ impl<'a> ControlMessage<'a> {
target_os = "netbsd", target_os = "freebsd",
target_os = "android", target_os = "ios",))]
ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8,
+ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+ ControlMessage::RxqOvfl(drop_count) => {
+ drop_count as *const _ as *const u8
+ },
};
unsafe {
ptr::copy_nonoverlapping(
@@ -964,6 +992,10 @@ impl<'a> ControlMessage<'a> {
target_os = "netbsd", target_os = "freebsd",
target_os = "android", target_os = "ios",))]
ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info),
+ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+ ControlMessage::RxqOvfl(drop_count) => {
+ mem::size_of_val(drop_count)
+ },
}
}
@@ -988,6 +1020,8 @@ impl<'a> ControlMessage<'a> {
target_os = "netbsd", target_os = "freebsd",
target_os = "android", target_os = "ios",))]
ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6,
+ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+ ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET,
}
}
@@ -1023,6 +1057,10 @@ impl<'a> ControlMessage<'a> {
target_os = "netbsd", target_os = "freebsd",
target_os = "android", target_os = "ios",))]
ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO,
+ #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+ ControlMessage::RxqOvfl(_) => {
+ libc::SO_RXQ_OVFL
+ },
}
}
@@ -1572,7 +1610,7 @@ pub fn recvfrom(sockfd: RawFd, buf: &mut [u8])
&mut len as *mut socklen_t))? as usize;
match sockaddr_storage_to_addr(&addr, len as usize) {
- Err(Error::Sys(Errno::ENOTCONN)) => Ok((ret, None)),
+ Err(Errno::ENOTCONN) => Ok((ret, None)),
Ok(addr) => Ok((ret, Some(addr))),
Err(e) => Err(e)
}
@@ -1708,7 +1746,7 @@ pub fn sockaddr_storage_to_addr(
assert!(len <= mem::size_of::<sockaddr_un>());
if len < mem::size_of_val(&addr.ss_family) {
- return Err(Error::Sys(Errno::ENOTCONN));
+ return Err(Error::from(Errno::ENOTCONN));
}
match c_int::from(addr.ss_family) {
diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs
index fe17395..e2f2caf 100644
--- a/src/sys/socket/sockopt.rs
+++ b/src/sys/socket/sockopt.rs
@@ -238,6 +238,8 @@ cfg_if! {
}
sockopt_impl!(Both, IpMulticastTtl, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8);
sockopt_impl!(Both, IpMulticastLoop, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool);
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+sockopt_impl!(Both, IpFreebind, libc::IPPROTO_IP, libc::IP_FREEBIND, bool);
sockopt_impl!(Both, ReceiveTimeout, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal);
sockopt_impl!(Both, SendTimeout, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal);
sockopt_impl!(Both, Broadcast, libc::SOL_SOCKET, libc::SO_BROADCAST, bool);
@@ -259,6 +261,8 @@ sockopt_impl!(Both, TcpKeepIdle, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32);
sockopt_impl!(Both, TcpKeepCount, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32);
#[cfg(not(target_os = "openbsd"))]
sockopt_impl!(Both, TcpKeepInterval, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32);
+#[cfg(any(target_os = "fuchsia", target_os = "linux"))]
+sockopt_impl!(Both, TcpUserTimeout, libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT, u32);
sockopt_impl!(Both, RcvBuf, libc::SOL_SOCKET, libc::SO_RCVBUF, usize);
sockopt_impl!(Both, SndBuf, libc::SOL_SOCKET, libc::SO_SNDBUF, usize);
#[cfg(any(target_os = "android", target_os = "linux"))]
@@ -324,6 +328,8 @@ sockopt_impl!(Both, Ipv4RecvDstAddr, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, boo
sockopt_impl!(Both, UdpGsoSegment, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int);
#[cfg(target_os = "linux")]
sockopt_impl!(Both, UdpGroSegment, libc::IPPROTO_UDP, libc::UDP_GRO, bool);
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+sockopt_impl!(Both, RxqOvfl, libc::SOL_SOCKET, libc::SO_RXQ_OVFL, libc::c_int);
#[cfg(any(target_os = "android", target_os = "linux"))]
#[derive(Copy, Clone, Debug)]
diff --git a/src/sys/termios.rs b/src/sys/termios.rs
index 8c3c1cf..9abae9d 100644
--- a/src/sys/termios.rs
+++ b/src/sys/termios.rs
@@ -449,7 +449,7 @@ impl TryFrom<libc::speed_t> for BaudRate {
B3500000 => Ok(BaudRate::B3500000),
#[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
B4000000 => Ok(BaudRate::B4000000),
- _ => Err(Error::invalid_argument())
+ _ => Err(Error::from(Errno::EINVAL))
}
}
}
diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs
index e42fffd..44915be 100644
--- a/src/sys/timerfd.rs
+++ b/src/sys/timerfd.rs
@@ -30,7 +30,7 @@
//! ```
use crate::sys::time::TimeSpec;
use crate::unistd::read;
-use crate::{errno::Errno, Error, Result};
+use crate::{errno::Errno, Result};
use bitflags::bitflags;
use libc::c_int;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
@@ -259,7 +259,7 @@ impl TimerFd {
loop {
if let Err(e) = read(self.fd, &mut [0u8; 8]) {
match e {
- Error::Sys(Errno::EINTR) => continue,
+ Errno::EINTR => continue,
_ => return Err(e),
}
} else {
@@ -277,7 +277,7 @@ impl Drop for TimerFd {
let result = Errno::result(unsafe {
libc::close(self.fd)
});
- if let Err(Error::Sys(Errno::EBADF)) = result {
+ if let Err(Errno::EBADF) = result {
panic!("close of TimerFd encountered EBADF");
}
}
diff --git a/src/sys/uio.rs b/src/sys/uio.rs
index b8ae860..48a0efd 100644
--- a/src/sys/uio.rs
+++ b/src/sys/uio.rs
@@ -168,7 +168,7 @@ pub fn process_vm_readv(
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
-pub struct IoVec<T>(libc::iovec, PhantomData<T>);
+pub struct IoVec<T>(pub(crate) libc::iovec, PhantomData<T>);
impl<T> IoVec<T> {
#[inline]
@@ -184,6 +184,14 @@ impl<T> IoVec<T> {
}
impl<'a> IoVec<&'a [u8]> {
+ #[cfg(target_os = "freebsd")]
+ pub(crate) fn from_raw_parts(base: *mut c_void, len: usize) -> Self {
+ IoVec(libc::iovec {
+ iov_base: base,
+ iov_len: len
+ }, PhantomData)
+ }
+
pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> {
IoVec(libc::iovec {
iov_base: buf.as_ptr() as *mut c_void,
diff --git a/src/time.rs b/src/time.rs
index f7da654..45dd26e 100644
--- a/src/time.rs
+++ b/src/time.rs
@@ -255,6 +255,6 @@ pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> {
let res = unsafe { clk_id.assume_init() };
Ok(ClockId::from(res))
} else {
- Err(Error::Sys(Errno::from_i32(ret)))
+ Err(Error::from(Errno::from_i32(ret)))
}
}
diff --git a/src/unistd.rs b/src/unistd.rs
index d406efe..de3b049 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -393,7 +393,7 @@ pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
#[inline]
fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
if oldfd == newfd {
- return Err(Error::Sys(Errno::EINVAL));
+ return Err(Error::from(Errno::EINVAL));
}
let fd = dup2(oldfd, newfd)?;
@@ -567,7 +567,7 @@ fn reserve_double_buffer_size<T>(buf: &mut Vec<T>, limit: usize) -> Result<()> {
use std::cmp::min;
if buf.capacity() >= limit {
- return Err(Error::Sys(Errno::ERANGE))
+ return Err(Error::from(Errno::ERANGE))
}
let capacity = min(buf.capacity() * 2, limit);
@@ -610,7 +610,7 @@ pub fn getcwd() -> Result<PathBuf> {
let error = Errno::last();
// ERANGE means buffer was too small to store directory name
if error != Errno::ERANGE {
- return Err(Error::Sys(error));
+ return Err(Error::from(error));
}
}
@@ -734,7 +734,7 @@ pub fn execv<S: AsRef<CStr>>(path: &CStr, argv: &[S]) -> Result<Infallible> {
libc::execv(path.as_ptr(), args_p.as_ptr())
};
- Err(Error::Sys(Errno::last()))
+ Err(Error::from(Errno::last()))
}
@@ -759,7 +759,7 @@ pub fn execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(path: &CStr, args: &[SA], env: &
libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
};
- Err(Error::Sys(Errno::last()))
+ Err(Error::from(Errno::last()))
}
/// Replace the current process image with a new one and replicate shell `PATH`
@@ -779,7 +779,7 @@ pub fn execvp<S: AsRef<CStr>>(filename: &CStr, args: &[S]) -> Result<Infallible>
libc::execvp(filename.as_ptr(), args_p.as_ptr())
};
- Err(Error::Sys(Errno::last()))
+ Err(Error::from(Errno::last()))
}
/// Replace the current process image with a new one and replicate shell `PATH`
@@ -800,7 +800,7 @@ pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(filename: &CStr, args: &[SA], e
libc::execvpe(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
};
- Err(Error::Sys(Errno::last()))
+ Err(Error::from(Errno::last()))
}
/// Replace the current process image with a new one (see
@@ -828,7 +828,7 @@ pub fn fexecve<SA: AsRef<CStr> ,SE: AsRef<CStr>>(fd: RawFd, args: &[SA], env: &[
libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr())
};
- Err(Error::Sys(Errno::last()))
+ Err(Error::from(Errno::last()))
}
/// Execute program relative to a directory file descriptor (see
@@ -853,7 +853,7 @@ pub fn execveat<SA: AsRef<CStr>,SE: AsRef<CStr>>(dirfd: RawFd, pathname: &CStr,
args_p.as_ptr(), env_p.as_ptr(), flags);
};
- Err(Error::Sys(Errno::last()))
+ Err(Error::from(Errno::last()))
}
/// Daemonize this process by detaching from the controlling terminal (see
@@ -1056,13 +1056,13 @@ pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result<libc:
/// Create an interprocess channel.
///
/// See also [pipe(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html)
-pub fn pipe() -> Result<(RawFd, RawFd)> {
+pub fn pipe() -> std::result::Result<(RawFd, RawFd), Error> {
unsafe {
let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit();
let res = libc::pipe(fds.as_mut_ptr() as *mut c_int);
- Errno::result(res)?;
+ Error::result(res)?;
Ok((fds.assume_init()[0], fds.assume_init()[1]))
}
@@ -1133,7 +1133,7 @@ pub fn isatty(fd: RawFd) -> Result<bool> {
} else {
match Errno::last() {
Errno::ENOTTY => Ok(false),
- err => Err(Error::Sys(err)),
+ err => Err(Error::from(err)),
}
}
}
@@ -1432,11 +1432,11 @@ pub fn getgroups() -> Result<Vec<Gid>> {
unsafe { groups.set_len(s as usize) };
return Ok(groups);
},
- Err(Error::Sys(Errno::EINVAL)) => {
+ Err(Errno::EINVAL) => {
// EINVAL indicates that the buffer size was too
// small, resize it up to ngroups_max as limit.
reserve_double_buffer_size(&mut groups, ngroups_max)
- .or(Err(Error::Sys(Errno::EINVAL)))?;
+ .or(Err(Error::from(Errno::EINVAL)))?;
},
Err(e) => return Err(e)
}
@@ -1558,7 +1558,7 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
// groups as possible, but Linux manpages do not mention this
// behavior.
reserve_double_buffer_size(&mut groups, ngroups_max as usize)
- .map_err(|_| Error::invalid_argument())?;
+ .map_err(|_| Error::from(Errno::EINVAL))?;
}
}
}
@@ -1670,10 +1670,11 @@ pub mod alarm {
//! sigaction(Signal::SIGALRM, &sa);
//! }
//!
+ //! let start = Instant::now();
+ //!
//! // Set an alarm for 1 second from now.
//! alarm::set(1);
//!
- //! let start = Instant::now();
//! // Pause the process until the alarm signal is received.
//! let mut sigset = SigSet::empty();
//! sigset.add(Signal::SIGALRM);
@@ -1915,7 +1916,7 @@ pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>> {
if errno::errno() == 0 {
Ok(None)
} else {
- Err(Error::Sys(Errno::last()))
+ Err(Error::from(Errno::last()))
}
} else {
Ok(Some(raw))
@@ -1954,7 +1955,7 @@ pub fn pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Optio
if errno::errno() == 0 {
Ok(None)
} else {
- Err(Error::Sys(Errno::last()))
+ Err(Error::from(Errno::last()))
}
} else {
Ok(Some(raw))
@@ -2453,7 +2454,7 @@ pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> {
if errno::errno() == 0 {
Ok(None)
} else {
- Err(Error::Sys(Errno::last()))
+ Err(Error::from(Errno::last()))
}
} else {
Ok(Some(raw))
@@ -2720,7 +2721,7 @@ impl User {
// Trigger the internal buffer resizing logic.
reserve_double_buffer_size(&mut cbuf, buflimit)?;
} else {
- return Err(Error::Sys(Errno::last()));
+ return Err(Error::from(Errno::last()));
}
}
}
@@ -2841,7 +2842,7 @@ impl Group {
// Trigger the internal buffer resizing logic.
reserve_double_buffer_size(&mut cbuf, buflimit)?;
} else {
- return Err(Error::Sys(Errno::last()));
+ return Err(Error::from(Errno::last()));
}
}
}
@@ -2900,7 +2901,7 @@ pub fn ttyname(fd: RawFd) -> Result<PathBuf> {
let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) };
if ret != 0 {
- return Err(Error::Sys(Errno::from_i32(ret)));
+ return Err(Error::from(Errno::from_i32(ret)));
}
let nul = buf.iter().position(|c| *c == b'\0').unwrap();
diff --git a/test/common/mod.rs b/test/common/mod.rs
index 8a79d6a..cdc3258 100644
--- a/test/common/mod.rs
+++ b/test/common/mod.rs
@@ -31,6 +31,20 @@ cfg_if! {
}
}
+/// Skip the test if we don't have the ability to mount file systems.
+#[cfg(target_os = "freebsd")]
+#[macro_export] macro_rules! require_mount {
+ ($name:expr) => {
+ use ::sysctl::CtlValue;
+ use nix::unistd::Uid;
+
+ if !Uid::current().is_root() && CtlValue::Int(0) == ::sysctl::value("vfs.usermount").unwrap()
+ {
+ skip!("{} requires the ability to mount file systems. Skipping test.", $name);
+ }
+ }
+}
+
#[cfg(any(target_os = "linux", target_os= "android"))]
#[macro_export] macro_rules! skip_if_cirrus {
($reason:expr) => {
diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs
index 753f118..3208410 100644
--- a/test/sys/test_aio.rs
+++ b/test/sys/test_aio.rs
@@ -142,9 +142,7 @@ fn test_fsync_error() {
}
#[test]
-#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
-// On Travis, aio_suspend hits an assertion within glibc. This is either a bug
-// in Travis's version of glibc or Linux. Either way, we must skip the test.
+// On Cirrus on Linux, this test fails due to a glibc bug.
// https://github.com/nix-rust/nix/issues/1099
#[cfg_attr(target_os = "linux", ignore)]
// On Cirrus, aio_suspend is failing with EINVAL
@@ -179,7 +177,7 @@ fn test_aio_suspend() {
let cbbuf = [wcb.as_ref(), rcb.as_ref()];
let r = aio_suspend(&cbbuf[..], Some(timeout));
match r {
- Err(Error::Sys(Errno::EINTR)) => continue,
+ Err(Errno::EINTR) => continue,
Err(e) => panic!("aio_suspend returned {:?}", e),
Ok(_) => ()
};
diff --git a/test/sys/test_aio_drop.rs b/test/sys/test_aio_drop.rs
index 784ee3e..71a2183 100644
--- a/test/sys/test_aio_drop.rs
+++ b/test/sys/test_aio_drop.rs
@@ -9,7 +9,6 @@
target_os = "macos",
target_os = "freebsd",
target_os = "netbsd")))]
-#[cfg_attr(target_env = "gnu", ignore = "Occasionally fails in Travis; glibc bug suspected")]
fn test_drop() {
use nix::sys::aio::*;
use nix::sys::signal::*;
diff --git a/test/sys/test_epoll.rs b/test/sys/test_epoll.rs
index e0dc513..57bc484 100644
--- a/test/sys/test_epoll.rs
+++ b/test/sys/test_epoll.rs
@@ -8,11 +8,11 @@ pub fn test_epoll_errno() {
let efd = epoll_create1(EpollCreateFlags::empty()).unwrap();
let result = epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None);
assert!(result.is_err());
- assert_eq!(result.unwrap_err(), Error::Sys(Errno::ENOENT));
+ assert_eq!(result.unwrap_err(), Error::from(Errno::ENOENT));
let result = epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, None);
assert!(result.is_err());
- assert_eq!(result.unwrap_err(), Error::Sys(Errno::EINVAL));
+ assert_eq!(result.unwrap_err(), Error::from(Errno::EINVAL));
}
#[test]
diff --git a/test/sys/test_inotify.rs b/test/sys/test_inotify.rs
index a8ead46..121b726 100644
--- a/test/sys/test_inotify.rs
+++ b/test/sys/test_inotify.rs
@@ -14,7 +14,7 @@ pub fn test_inotify() {
instance.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS).unwrap();
let events = instance.read_events();
- assert_eq!(events.unwrap_err(), Error::Sys(Errno::EAGAIN));
+ assert_eq!(events.unwrap_err(), Error::from(Errno::EAGAIN));
File::create(tempdir.path().join("test")).unwrap();
@@ -31,7 +31,7 @@ pub fn test_inotify_multi_events() {
instance.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS).unwrap();
let events = instance.read_events();
- assert_eq!(events.unwrap_err(), Error::Sys(Errno::EAGAIN));
+ assert_eq!(events.unwrap_err(), Error::from(Errno::EAGAIN));
File::create(tempdir.path().join("test")).unwrap();
rename(tempdir.path().join("test"), tempdir.path().join("test2")).unwrap();
diff --git a/test/sys/test_ioctl.rs b/test/sys/test_ioctl.rs
index ddb8696..236d242 100644
--- a/test/sys/test_ioctl.rs
+++ b/test/sys/test_ioctl.rs
@@ -167,15 +167,14 @@ mod linux_ioctls {
use tempfile::tempfile;
use libc::{TCGETS, TCSBRK, TCSETS, TIOCNXCL, termios};
- use nix::Error::Sys;
- use nix::errno::Errno::{ENOTTY, ENOSYS};
+ use nix::errno::Errno;
ioctl_none_bad!(tiocnxcl, TIOCNXCL);
#[test]
fn test_ioctl_none_bad() {
let file = tempfile().unwrap();
let res = unsafe { tiocnxcl(file.as_raw_fd()) };
- assert_eq!(res, Err(Sys(ENOTTY)));
+ assert_eq!(res, Err(Errno::ENOTTY));
}
ioctl_read_bad!(tcgets, TCGETS, termios);
@@ -184,7 +183,7 @@ mod linux_ioctls {
let file = tempfile().unwrap();
let mut termios = unsafe { mem::zeroed() };
let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) };
- assert_eq!(res, Err(Sys(ENOTTY)));
+ assert_eq!(res, Err(Errno::ENOTTY));
}
ioctl_write_int_bad!(tcsbrk, TCSBRK);
@@ -192,7 +191,7 @@ mod linux_ioctls {
fn test_ioctl_write_int_bad() {
let file = tempfile().unwrap();
let res = unsafe { tcsbrk(file.as_raw_fd(), 0) };
- assert_eq!(res, Err(Sys(ENOTTY)));
+ assert_eq!(res, Err(Errno::ENOTTY));
}
ioctl_write_ptr_bad!(tcsets, TCSETS, termios);
@@ -201,7 +200,7 @@ mod linux_ioctls {
let file = tempfile().unwrap();
let termios: termios = unsafe { mem::zeroed() };
let res = unsafe { tcsets(file.as_raw_fd(), &termios) };
- assert_eq!(res, Err(Sys(ENOTTY)));
+ assert_eq!(res, Err(Errno::ENOTTY));
}
// FIXME: Find a suitable example for `ioctl_readwrite_bad`
@@ -212,7 +211,7 @@ mod linux_ioctls {
fn test_ioctl_none() {
let file = tempfile().unwrap();
let res = unsafe { log_status(file.as_raw_fd()) };
- assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
+ assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
}
#[repr(C)]
@@ -231,7 +230,7 @@ mod linux_ioctls {
let file = tempfile().unwrap();
let data: v4l2_audio = unsafe { mem::zeroed() };
let res = unsafe { s_audio(file.as_raw_fd(), &data) };
- assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
+ assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
}
// From linux/net/bluetooth/hci_sock.h
@@ -242,7 +241,7 @@ mod linux_ioctls {
fn test_ioctl_write_int() {
let file = tempfile().unwrap();
let res = unsafe { hcidevup(file.as_raw_fd(), 0) };
- assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
+ assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
}
// From linux/videodev2.h
@@ -252,7 +251,7 @@ mod linux_ioctls {
let file = tempfile().unwrap();
let mut data: v4l2_audio = unsafe { mem::zeroed() };
let res = unsafe { g_audio(file.as_raw_fd(), &mut data) };
- assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
+ assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
}
// From linux/videodev2.h
@@ -262,7 +261,7 @@ mod linux_ioctls {
let file = tempfile().unwrap();
let mut data: v4l2_audio = unsafe { mem::zeroed() };
let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) };
- assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
+ assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
}
// FIXME: Find a suitable example for `ioctl_read_buf`.
@@ -288,7 +287,7 @@ mod linux_ioctls {
let file = tempfile().unwrap();
let data: [spi_ioc_transfer; 4] = unsafe { mem::zeroed() };
let res = unsafe { spi_ioc_message(file.as_raw_fd(), &data[..]) };
- assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
+ assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
}
// FIXME: Find a suitable example for `ioctl_readwrite_buf`.
@@ -302,8 +301,7 @@ mod freebsd_ioctls {
use tempfile::tempfile;
use libc::termios;
- use nix::Error::Sys;
- use nix::errno::Errno::ENOTTY;
+ use nix::errno::Errno;
// From sys/sys/ttycom.h
const TTY_IOC_MAGIC: u8 = b't';
@@ -316,7 +314,7 @@ mod freebsd_ioctls {
fn test_ioctl_none() {
let file = tempfile().unwrap();
let res = unsafe { tiocnxcl(file.as_raw_fd()) };
- assert_eq!(res, Err(Sys(ENOTTY)));
+ assert_eq!(res, Err(Errno::ENOTTY));
}
ioctl_read!(tiocgeta, TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA, termios);
@@ -325,7 +323,7 @@ mod freebsd_ioctls {
let file = tempfile().unwrap();
let mut termios = unsafe { mem::zeroed() };
let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) };
- assert_eq!(res, Err(Sys(ENOTTY)));
+ assert_eq!(res, Err(Errno::ENOTTY));
}
ioctl_write_ptr!(tiocseta, TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA, termios);
@@ -334,6 +332,6 @@ mod freebsd_ioctls {
let file = tempfile().unwrap();
let termios: termios = unsafe { mem::zeroed() };
let res = unsafe { tiocseta(file.as_raw_fd(), &termios) };
- assert_eq!(res, Err(Sys(ENOTTY)));
+ assert_eq!(res, Err(Errno::ENOTTY));
}
}
diff --git a/test/sys/test_lio_listio_resubmit.rs b/test/sys/test_lio_listio_resubmit.rs
index 6b33aa4..c907789 100644
--- a/test/sys/test_lio_listio_resubmit.rs
+++ b/test/sys/test_lio_listio_resubmit.rs
@@ -4,7 +4,6 @@
// we must disable the test here rather than in Cargo.toml
#![cfg(target_os = "freebsd")]
-use nix::Error;
use nix::errno::*;
use nix::libc::off_t;
use nix::sys::aio::*;
@@ -25,7 +24,7 @@ fn finish_liocb(liocb: &mut LioCb) {
let e = liocb.error(j);
match e {
Ok(()) => break,
- Err(Error::Sys(Errno::EINPROGRESS)) =>
+ Err(Errno::EINPROGRESS) =>
thread::sleep(time::Duration::from_millis(10)),
Err(x) => panic!("aio_error({:?})", x)
}
@@ -82,9 +81,9 @@ fn test_lio_listio_resubmit() {
}
let mut liocb = builder.finish();
let mut err = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone);
- while err == Err(Error::Sys(Errno::EIO)) ||
- err == Err(Error::Sys(Errno::EAGAIN)) ||
- err == Err(Error::Sys(Errno::EINTR)) {
+ while err == Err(Errno::EIO) ||
+ err == Err(Errno::EAGAIN) ||
+ err == Err(Errno::EINTR) {
//
thread::sleep(time::Duration::from_millis(10));
resubmit_count += 1;
diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs
index b9793b3..985945d 100644
--- a/test/sys/test_ptrace.rs
+++ b/test/sys/test_ptrace.rs
@@ -1,4 +1,3 @@
-use nix::Error;
use nix::errno::Errno;
use nix::unistd::getpid;
use nix::sys::ptrace;
@@ -16,8 +15,8 @@ fn test_ptrace() {
// FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS
require_capability!(CAP_SYS_PTRACE);
let err = ptrace::attach(getpid()).unwrap_err();
- assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::EINVAL) ||
- err == Error::Sys(Errno::ENOSYS));
+ assert!(err == Errno::EPERM || err == Errno::EINVAL ||
+ err == Errno::ENOSYS);
}
// Just make sure ptrace_setoptions can be called at all, for now.
@@ -26,7 +25,7 @@ fn test_ptrace() {
fn test_ptrace_setoptions() {
require_capability!(CAP_SYS_PTRACE);
let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD).unwrap_err();
- assert!(err != Error::UnsupportedOperation);
+ assert!(err != Errno::EOPNOTSUPP);
}
// Just make sure ptrace_getevent can be called at all, for now.
@@ -35,7 +34,7 @@ fn test_ptrace_setoptions() {
fn test_ptrace_getevent() {
require_capability!(CAP_SYS_PTRACE);
let err = ptrace::getevent(getpid()).unwrap_err();
- assert!(err != Error::UnsupportedOperation);
+ assert!(err != Errno::EOPNOTSUPP);
}
// Just make sure ptrace_getsiginfo can be called at all, for now.
@@ -43,8 +42,8 @@ fn test_ptrace_getevent() {
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_getsiginfo() {
require_capability!(CAP_SYS_PTRACE);
- if let Err(Error::UnsupportedOperation) = ptrace::getsiginfo(getpid()) {
- panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!");
+ if let Err(Errno::EOPNOTSUPP) = ptrace::getsiginfo(getpid()) {
+ panic!("ptrace_getsiginfo returns Errno::EOPNOTSUPP!");
}
}
@@ -54,8 +53,8 @@ fn test_ptrace_getsiginfo() {
fn test_ptrace_setsiginfo() {
require_capability!(CAP_SYS_PTRACE);
let siginfo = unsafe { mem::zeroed() };
- if let Err(Error::UnsupportedOperation) = ptrace::setsiginfo(getpid(), &siginfo) {
- panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!");
+ if let Err(Errno::EOPNOTSUPP) = ptrace::setsiginfo(getpid(), &siginfo) {
+ panic!("ptrace_setsiginfo returns Errno::EOPNOTSUPP!");
}
}
@@ -79,7 +78,7 @@ fn test_ptrace_cont() {
// On valid platforms the ptrace call should return Errno::EPERM, this
// is already tested by `test_ptrace`.
let err = ptrace::attach(getpid()).unwrap_err();
- if err == Error::Sys(Errno::ENOSYS) {
+ if err == Errno::ENOSYS {
return;
}
diff --git a/test/sys/test_signal.rs b/test/sys/test_signal.rs
index c8c13e5..1b89af5 100644
--- a/test/sys/test_signal.rs
+++ b/test/sys/test_signal.rs
@@ -1,5 +1,5 @@
#[cfg(not(target_os = "redox"))]
-use nix::Error;
+use nix::errno::Errno;
use nix::sys::signal::*;
use nix::unistd::*;
use std::convert::TryFrom;
@@ -92,7 +92,7 @@ fn test_signal_sigaction() {
let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
let action_handler = SigHandler::SigAction(test_sigaction_action);
- assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Error::UnsupportedOperation);
+ assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Errno::ENOTSUP);
}
#[test]
diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs
index c22eaeb..5471afe 100644
--- a/test/sys/test_socket.rs
+++ b/test/sys/test_socket.rs
@@ -519,7 +519,6 @@ mod recvfrom {
// Test error handling of our recvmsg wrapper
#[test]
pub fn test_recvmsg_ebadf() {
- use nix::Error;
use nix::errno::Errno;
use nix::sys::socket::{MsgFlags, recvmsg};
use nix::sys::uio::IoVec;
@@ -528,7 +527,7 @@ pub fn test_recvmsg_ebadf() {
let iov = [IoVec::from_mut_slice(&mut buf[..])];
let fd = -1; // Bad file descriptor
let r = recvmsg(fd, &iov, None, MsgFlags::empty());
- assert_eq!(r.err().unwrap(), Error::Sys(Errno::EBADF));
+ assert_eq!(r.err().unwrap(), Errno::EBADF);
}
// Disable the test on emulated platforms due to a bug in QEMU versions <
@@ -818,7 +817,6 @@ pub fn test_sendmsg_ipv4packetinfo() {
target_os = "freebsd"))]
#[test]
pub fn test_sendmsg_ipv6packetinfo() {
- use nix::Error;
use nix::errno::Errno;
use nix::sys::uio::IoVec;
use nix::sys::socket::{socket, sendmsg, bind,
@@ -835,7 +833,7 @@ pub fn test_sendmsg_ipv6packetinfo() {
let inet_addr = InetAddr::from_std(&std_sa);
let sock_addr = SockAddr::new_inet(inet_addr);
- if let Err(Error::Sys(Errno::EADDRNOTAVAIL)) = bind(sock, &sock_addr) {
+ if let Err(Errno::EADDRNOTAVAIL) = bind(sock, &sock_addr) {
println!("IPv6 not available, skipping test.");
return;
}
@@ -1145,7 +1143,6 @@ pub fn test_unixdomain() {
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[test]
pub fn test_syscontrol() {
- use nix::Error;
use nix::errno::Errno;
use nix::sys::socket::{socket, SockAddr, SockType, SockFlag, SockProtocol};
@@ -1153,7 +1150,7 @@ pub fn test_syscontrol() {
SockFlag::empty(), SockProtocol::KextControl)
.expect("socket failed");
let _sockaddr = SockAddr::new_sys_control(fd, "com.apple.net.utun_control", 0).expect("resolving sys_control name failed");
- assert_eq!(SockAddr::new_sys_control(fd, "foo.bar.lol", 0).err(), Some(Error::Sys(Errno::ENOENT)));
+ assert_eq!(SockAddr::new_sys_control(fd, "foo.bar.lol", 0).err(), Some(Errno::ENOENT));
// requires root privileges
// connect(fd, &sockaddr).expect("connect failed");
@@ -1500,7 +1497,6 @@ pub fn test_recv_ipv6pktinfo() {
#[test]
pub fn test_vsock() {
use libc;
- use nix::Error;
use nix::errno::Errno;
use nix::sys::socket::{AddressFamily, socket, bind, connect, listen,
SockAddr, SockType, SockFlag};
@@ -1516,7 +1512,7 @@ pub fn test_vsock() {
// VMADDR_CID_HYPERVISOR is reserved, so we expect an EADDRNOTAVAIL error.
let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_HYPERVISOR, port);
assert_eq!(bind(s1, &sockaddr).err(),
- Some(Error::Sys(Errno::EADDRNOTAVAIL)));
+ Some(Errno::EADDRNOTAVAIL));
let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_ANY, port);
assert_eq!(bind(s1, &sockaddr), Ok(()));
@@ -1649,3 +1645,86 @@ fn test_recvmmsg_timestampns() {
// Close socket
nix::unistd::close(in_socket).unwrap();
}
+
+// Disable the test on emulated platforms because it fails in Cirrus-CI. Lack of QEMU
+// support is suspected.
+#[cfg_attr(not(any(target_arch = "x86_64")), ignore)]
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[test]
+fn test_recvmsg_rxq_ovfl() {
+ use nix::Error;
+ use nix::sys::socket::*;
+ use nix::sys::uio::IoVec;
+ use nix::sys::socket::sockopt::{RxqOvfl, RcvBuf};
+
+ let message = [0u8; 2048];
+ let bufsize = message.len() * 2;
+
+ let in_socket = socket(
+ AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None).unwrap();
+ let out_socket = socket(
+ AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None).unwrap();
+
+ let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0);
+ bind(in_socket, &SockAddr::new_inet(localhost)).unwrap();
+
+ let address = getsockname(in_socket).unwrap();
+ connect(out_socket, &address).unwrap();
+
+ // Set SO_RXQ_OVFL flag.
+ setsockopt(in_socket, RxqOvfl, &1).unwrap();
+
+ // Set the receiver buffer size to hold only 2 messages.
+ setsockopt(in_socket, RcvBuf, &bufsize).unwrap();
+
+ let mut drop_counter = 0;
+
+ for _ in 0..2 {
+ let iov = [IoVec::from_slice(&message)];
+ let flags = MsgFlags::empty();
+
+ // Send the 3 messages (the receiver buffer can only hold 2 messages)
+ // to create an overflow.
+ for _ in 0..3 {
+ let l = sendmsg(out_socket, &iov, &[], flags, Some(&address)).unwrap();
+ assert_eq!(message.len(), l);
+ }
+
+ // Receive the message and check the drop counter if any.
+ loop {
+ let mut buffer = vec![0u8; message.len()];
+ let mut cmsgspace = nix::cmsg_space!(u32);
+
+ let iov = [IoVec::from_mut_slice(&mut buffer)];
+
+ match recvmsg(
+ in_socket,
+ &iov,
+ Some(&mut cmsgspace),
+ MsgFlags::MSG_DONTWAIT) {
+ Ok(r) => {
+ drop_counter = match r.cmsgs().next() {
+ Some(ControlMessageOwned::RxqOvfl(drop_counter)) => drop_counter,
+ Some(_) => panic!("Unexpected control message"),
+ None => 0,
+ };
+ },
+ Err(Error::EAGAIN) => { break; },
+ _ => { panic!("unknown recvmsg() error"); },
+ }
+ }
+ }
+
+ // One packet lost.
+ assert_eq!(drop_counter, 1);
+
+ // Close sockets
+ nix::unistd::close(in_socket).unwrap();
+ nix::unistd::close(out_socket).unwrap();
+}
diff --git a/test/sys/test_termios.rs b/test/sys/test_termios.rs
index 00aeb2f..63d6a51 100644
--- a/test/sys/test_termios.rs
+++ b/test/sys/test_termios.rs
@@ -1,7 +1,7 @@
use std::os::unix::prelude::*;
use tempfile::tempfile;
-use nix::{Error, fcntl};
+use nix::fcntl;
use nix::errno::Errno;
use nix::pty::openpty;
use nix::sys::termios::{self, LocalFlags, OutputFlags, tcgetattr};
@@ -32,14 +32,14 @@ fn test_tcgetattr_pty() {
fn test_tcgetattr_enotty() {
let file = tempfile().unwrap();
assert_eq!(termios::tcgetattr(file.as_raw_fd()).err(),
- Some(Error::Sys(Errno::ENOTTY)));
+ Some(Errno::ENOTTY));
}
// Test tcgetattr on an invalid file descriptor
#[test]
fn test_tcgetattr_ebadf() {
assert_eq!(termios::tcgetattr(-1).err(),
- Some(Error::Sys(Errno::EBADF)));
+ Some(Errno::EBADF));
}
// Test modifying output flags
@@ -126,5 +126,5 @@ fn test_local_flags() {
let read = read(pty.master, &mut buf).unwrap_err();
close(pty.master).unwrap();
close(pty.slave).unwrap();
- assert_eq!(read, Error::Sys(Errno::EAGAIN));
+ assert_eq!(read, Errno::EAGAIN);
}
diff --git a/test/sys/test_wait.rs b/test/sys/test_wait.rs
index f68b8b0..2d26fb8 100644
--- a/test/sys/test_wait.rs
+++ b/test/sys/test_wait.rs
@@ -1,4 +1,4 @@
-use nix::Error;
+use nix::errno::Errno;
use nix::unistd::*;
use nix::unistd::ForkResult::*;
use nix::sys::signal::*;
@@ -41,7 +41,7 @@ fn test_waitstatus_from_raw() {
let pid = Pid::from_raw(1);
assert_eq!(WaitStatus::from_raw(pid, 0x0002), Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)));
assert_eq!(WaitStatus::from_raw(pid, 0x0200), Ok(WaitStatus::Exited(pid, 2)));
- assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Error::invalid_argument()));
+ assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Errno::EINVAL));
}
#[test]
diff --git a/test/test.rs b/test/test.rs
index 5a5330b..94f8e22 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -13,6 +13,8 @@ mod test_fcntl;
#[cfg(any(target_os = "android",
target_os = "linux"))]
mod test_kmod;
+#[cfg(target_os = "freebsd")]
+mod test_nmount;
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "fushsia",
diff --git a/test/test_dir.rs b/test/test_dir.rs
index 4d7f5f7..0dc7308 100644
--- a/test/test_dir.rs
+++ b/test/test_dir.rs
@@ -51,5 +51,5 @@ fn rewind() {
#[test]
fn ebadf() {
- assert_eq!(Dir::from_fd(-1).unwrap_err(), nix::Error::Sys(nix::errno::Errno::EBADF));
+ assert_eq!(Dir::from_fd(-1).unwrap_err(), nix::Error::EBADF);
}
diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs
index 48d4662..ae6756e 100644
--- a/test/test_fcntl.rs
+++ b/test/test_fcntl.rs
@@ -1,11 +1,20 @@
#[cfg(not(target_os = "redox"))]
-use nix::Error;
-#[cfg(not(target_os = "redox"))]
use nix::errno::*;
#[cfg(not(target_os = "redox"))]
use nix::fcntl::{open, OFlag, readlink};
#[cfg(not(target_os = "redox"))]
use nix::fcntl::{openat, readlinkat, renameat};
+#[cfg(all(
+ target_os = "linux",
+ target_env = "gnu",
+ any(
+ target_arch = "x86_64",
+ target_arch = "x32",
+ target_arch = "powerpc",
+ target_arch = "s390x"
+ )
+))]
+use nix::fcntl::{RenameFlags, renameat2};
#[cfg(not(target_os = "redox"))]
use nix::sys::stat::Mode;
#[cfg(not(target_os = "redox"))]
@@ -55,12 +64,138 @@ fn test_renameat() {
let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap();
assert_eq!(renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap_err(),
- Error::Sys(Errno::ENOENT));
+ Errno::ENOENT);
+ close(old_dirfd).unwrap();
+ close(new_dirfd).unwrap();
+ assert!(new_dir.path().join("new").exists());
+}
+
+#[test]
+#[cfg(all(
+ target_os = "linux",
+ target_env = "gnu",
+ any(
+ target_arch = "x86_64",
+ target_arch = "x32",
+ target_arch = "powerpc",
+ target_arch = "s390x"
+ )
+))]
+fn test_renameat2_behaves_like_renameat_with_no_flags() {
+ let old_dir = tempfile::tempdir().unwrap();
+ let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
+ let old_path = old_dir.path().join("old");
+ File::create(&old_path).unwrap();
+ let new_dir = tempfile::tempdir().unwrap();
+ let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
+ renameat2(
+ Some(old_dirfd),
+ "old",
+ Some(new_dirfd),
+ "new",
+ RenameFlags::empty(),
+ )
+ .unwrap();
+ assert_eq!(
+ renameat2(
+ Some(old_dirfd),
+ "old",
+ Some(new_dirfd),
+ "new",
+ RenameFlags::empty()
+ )
+ .unwrap_err(),
+ Errno::ENOENT
+ );
+ close(old_dirfd).unwrap();
+ close(new_dirfd).unwrap();
+ assert!(new_dir.path().join("new").exists());
+}
+
+#[test]
+#[cfg(all(
+ target_os = "linux",
+ target_env = "gnu",
+ any(
+ target_arch = "x86_64",
+ target_arch = "x32",
+ target_arch = "powerpc",
+ target_arch = "s390x"
+ )
+))]
+fn test_renameat2_exchange() {
+ let old_dir = tempfile::tempdir().unwrap();
+ let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
+ let old_path = old_dir.path().join("old");
+ {
+ let mut old_f = File::create(&old_path).unwrap();
+ old_f.write(b"old").unwrap();
+ }
+ let new_dir = tempfile::tempdir().unwrap();
+ let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
+ let new_path = new_dir.path().join("new");
+ {
+ let mut new_f = File::create(&new_path).unwrap();
+ new_f.write(b"new").unwrap();
+ }
+ renameat2(
+ Some(old_dirfd),
+ "old",
+ Some(new_dirfd),
+ "new",
+ RenameFlags::RENAME_EXCHANGE,
+ )
+ .unwrap();
+ let mut buf = String::new();
+ let mut new_f = File::open(&new_path).unwrap();
+ new_f.read_to_string(&mut buf).unwrap();
+ assert_eq!(buf, "old");
+ buf = "".to_string();
+ let mut old_f = File::open(&old_path).unwrap();
+ old_f.read_to_string(&mut buf).unwrap();
+ assert_eq!(buf, "new");
+ close(old_dirfd).unwrap();
+ close(new_dirfd).unwrap();
+}
+
+#[test]
+#[cfg(all(
+ target_os = "linux",
+ target_env = "gnu",
+ any(
+ target_arch = "x86_64",
+ target_arch = "x32",
+ target_arch = "powerpc",
+ target_arch = "s390x"
+ )
+))]
+fn test_renameat2_noreplace() {
+ let old_dir = tempfile::tempdir().unwrap();
+ let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
+ let old_path = old_dir.path().join("old");
+ File::create(&old_path).unwrap();
+ let new_dir = tempfile::tempdir().unwrap();
+ let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
+ let new_path = new_dir.path().join("new");
+ File::create(&new_path).unwrap();
+ assert_eq!(
+ renameat2(
+ Some(old_dirfd),
+ "old",
+ Some(new_dirfd),
+ "new",
+ RenameFlags::RENAME_NOREPLACE
+ )
+ .unwrap_err(),
+ Errno::EEXIST
+ );
close(old_dirfd).unwrap();
close(new_dirfd).unwrap();
assert!(new_dir.path().join("new").exists());
+ assert!(old_dir.path().join("old").exists());
}
+
#[test]
#[cfg(not(target_os = "redox"))]
fn test_readlink() {
@@ -102,11 +237,15 @@ mod linux_android {
/// resulting file is read and should contain the contents `bar`.
/// The from_offset should be updated by the call to reflect
/// the 3 bytes read (6).
- ///
- /// FIXME: This test is disabled for linux based builds, because Travis
- /// Linux version is too old for `copy_file_range`.
#[test]
- #[ignore]
+ // QEMU does not support copy_file_range. Skip platforms that use QEMU in CI
+ #[cfg_attr(all(target_os = "linux", any(
+ target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "mips64",
+ target_arch = "powerpc64"
+ )), ignore)]
fn test_copy_file_range() {
const CONTENTS: &[u8] = b"foobarbaz";
@@ -381,7 +520,7 @@ mod test_posix_fallocate {
assert_eq!(tmp.read(&mut data).expect("read failure"), LEN);
assert_eq!(&data[..], &[0u8; LEN][..]);
}
- Err(nix::Error::Sys(Errno::EINVAL)) => {
+ Err(Errno::EINVAL) => {
// POSIX requires posix_fallocate to return EINVAL both for
// invalid arguments (i.e. len < 0) and if the operation is not
// supported by the file system.
@@ -397,12 +536,8 @@ mod test_posix_fallocate {
fn errno() {
let (rd, _wr) = pipe().unwrap();
let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err();
- use nix::Error::Sys;
match err {
- Sys(Errno::EINVAL)
- | Sys(Errno::ENODEV)
- | Sys(Errno::ESPIPE)
- | Sys(Errno::EBADF) => (),
+ Errno::EINVAL | Errno::ENODEV | Errno::ESPIPE | Errno::EBADF => (),
errno =>
panic!(
"unexpected errno {}",
diff --git a/test/test_kmod/mod.rs b/test/test_kmod/mod.rs
index fb7260b..7626330 100644
--- a/test/test_kmod/mod.rs
+++ b/test/test_kmod/mod.rs
@@ -130,7 +130,7 @@ fn test_finit_module_invalid() {
let f = File::open(kmod_path).expect("unable to open kernel module");
let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty());
- assert_eq!(result.unwrap_err(), Error::Sys(Errno::EINVAL));
+ assert_eq!(result.unwrap_err(), Error::from(Errno::EINVAL));
}
#[test]
@@ -147,7 +147,7 @@ fn test_finit_module_twice_and_delete_module() {
let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty());
- assert_eq!(result.unwrap_err(), Error::Sys(Errno::EEXIST));
+ assert_eq!(result.unwrap_err(), Error::from(Errno::EEXIST));
delete_module(
&CString::new(kmod_name).unwrap(),
@@ -163,5 +163,5 @@ fn test_delete_module_not_loaded() {
let result = delete_module(&CString::new("hello").unwrap(), DeleteModuleFlags::empty());
- assert_eq!(result.unwrap_err(), Error::Sys(Errno::ENOENT));
+ assert_eq!(result.unwrap_err(), Error::from(Errno::ENOENT));
}
diff --git a/test/test_mq.rs b/test/test_mq.rs
index 1667a35..d082692 100644
--- a/test/test_mq.rs
+++ b/test/test_mq.rs
@@ -1,8 +1,7 @@
use std::ffi::CString;
use std::str;
-use nix::errno::Errno::*;
-use nix::Error::Sys;
+use nix::errno::Errno;
use nix::mqueue::{mq_open, mq_close, mq_send, mq_receive, mq_attr_member_t};
use nix::mqueue::{MqAttr, MQ_OFlag};
use nix::sys::stat::Mode;
@@ -16,7 +15,7 @@ fn test_mq_send_and_receive() {
let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
let r0 = mq_open(mq_name, oflag0, mode, Some(&attr));
- if let Err(Sys(ENOSYS)) = r0 {
+ if let Err(Errno::ENOSYS) = r0 {
println!("message queues not supported or module not loaded?");
return;
};
@@ -47,7 +46,7 @@ fn test_mq_getattr() {
let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
- if let Err(Sys(ENOSYS)) = r {
+ if let Err(Errno::ENOSYS) = r {
println!("message queues not supported or module not loaded?");
return;
};
@@ -70,7 +69,7 @@ fn test_mq_setattr() {
let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
- if let Err(Sys(ENOSYS)) = r {
+ if let Err(Errno::ENOSYS) = r {
println!("message queues not supported or module not loaded?");
return;
};
@@ -107,7 +106,7 @@ fn test_mq_set_nonblocking() {
let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
- if let Err(Sys(ENOSYS)) = r {
+ if let Err(Errno::ENOSYS) = r {
println!("message queues not supported or module not loaded?");
return;
};
@@ -132,7 +131,7 @@ fn test_mq_unlink() {
let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
let r = mq_open(mq_name_opened, oflag, mode, Some(&initial_attr));
- if let Err(Sys(ENOSYS)) = r {
+ if let Err(Errno::ENOSYS) = r {
println!("message queues not supported or module not loaded?");
return;
};
@@ -142,9 +141,9 @@ fn test_mq_unlink() {
assert_eq!(res_unlink, Ok(()) );
let res_unlink_not_opened = mq_unlink(mq_name_not_opened);
- assert_eq!(res_unlink_not_opened, Err(Sys(ENOENT)) );
+ assert_eq!(res_unlink_not_opened, Err(Errno::ENOENT) );
mq_close(mqd).unwrap();
let res_unlink_after_close = mq_unlink(mq_name_opened);
- assert_eq!(res_unlink_after_close, Err(Sys(ENOENT)) );
+ assert_eq!(res_unlink_after_close, Err(Errno::ENOENT) );
}
diff --git a/test/test_nmount.rs b/test/test_nmount.rs
new file mode 100644
index 0000000..4c74ecf
--- /dev/null
+++ b/test/test_nmount.rs
@@ -0,0 +1,51 @@
+use crate::*;
+use nix::{
+ errno::Errno,
+ mount::{MntFlags, Nmount, unmount}
+};
+use std::{
+ ffi::CString,
+ fs::File,
+ path::Path
+};
+use tempfile::tempdir;
+
+#[test]
+fn ok() {
+ require_mount!("nullfs");
+
+ let mountpoint = tempdir().unwrap();
+ let target = tempdir().unwrap();
+ let _sentry = File::create(target.path().join("sentry")).unwrap();
+
+ let fstype = CString::new("fstype").unwrap();
+ let nullfs = CString::new("nullfs").unwrap();
+ Nmount::new()
+ .str_opt(&fstype, &nullfs)
+ .str_opt_owned("fspath", mountpoint.path().to_str().unwrap())
+ .str_opt_owned("target", target.path().to_str().unwrap())
+ .nmount(MntFlags::empty()).unwrap();
+
+ // Now check that the sentry is visible through the mountpoint
+ let exists = Path::exists(&mountpoint.path().join("sentry"));
+
+ // Cleanup the mountpoint before asserting
+ unmount(mountpoint.path(), MntFlags::empty()).unwrap();
+
+ assert!(exists);
+}
+
+#[test]
+fn bad_fstype() {
+ let mountpoint = tempdir().unwrap();
+ let target = tempdir().unwrap();
+ let _sentry = File::create(target.path().join("sentry")).unwrap();
+
+ let e = Nmount::new()
+ .str_opt_owned("fspath", mountpoint.path().to_str().unwrap())
+ .str_opt_owned("target", target.path().to_str().unwrap())
+ .nmount(MntFlags::empty()).unwrap_err();
+
+ assert_eq!(e.error(), Errno::EINVAL);
+ assert_eq!(e.errmsg(), Some("Invalid fstype"));
+}
diff --git a/test/test_poll.rs b/test/test_poll.rs
index acfaad8..0395512 100644
--- a/test/test_poll.rs
+++ b/test/test_poll.rs
@@ -1,5 +1,4 @@
use nix::{
- Error,
errno::Errno,
poll::{PollFlags, poll, PollFd},
unistd::{write, pipe}
@@ -10,7 +9,7 @@ macro_rules! loop_while_eintr {
loop {
match $poll_expr {
Ok(nfds) => break nfds,
- Err(Error::Sys(Errno::EINTR)) => (),
+ Err(Errno::EINTR) => (),
Err(e) => panic!("{}", e)
}
}
diff --git a/test/test_ptymaster_drop.rs b/test/test_ptymaster_drop.rs
index ff939b9..a68f81e 100644
--- a/test/test_ptymaster_drop.rs
+++ b/test/test_ptymaster_drop.rs
@@ -12,10 +12,6 @@ mod t {
/// race condition.
#[test]
#[should_panic(expected = "Closing an invalid file descriptor!")]
- // In Travis on i686-unknown-linux-musl, this test gets SIGABRT. I don't
- // know why. It doesn't happen on any other target, and it doesn't happen
- // on my PC.
- #[cfg_attr(all(target_env = "musl", target_arch = "x86"), ignore)]
fn test_double_close() {
let m = posix_openpt(OFlag::O_RDWR).unwrap();
close(m.as_raw_fd()).unwrap();
diff --git a/test/test_stat.rs b/test/test_stat.rs
index 27fcee5..424371f 100644
--- a/test/test_stat.rs
+++ b/test/test_stat.rs
@@ -15,7 +15,7 @@ use libc::{S_IFMT, S_IFLNK};
use libc::mode_t;
#[cfg(not(target_os = "redox"))]
-use nix::{fcntl, Error};
+use nix::fcntl;
#[cfg(not(target_os = "redox"))]
use nix::errno::Errno;
#[cfg(not(target_os = "redox"))]
@@ -304,5 +304,5 @@ fn test_mkdirat_fail() {
let dirfd = fcntl::open(&tempdir.path().join(not_dir_filename), fcntl::OFlag::O_CREAT,
stat::Mode::empty()).unwrap();
let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err();
- assert_eq!(result, Error::Sys(Errno::ENOTDIR));
+ assert_eq!(result, Errno::ENOTDIR);
}
diff --git a/test/test_unistd.rs b/test/test_unistd.rs
index 94d2d1b..b95f154 100644
--- a/test/test_unistd.rs
+++ b/test/test_unistd.rs
@@ -1,6 +1,6 @@
#[cfg(not(target_os = "redox"))]
use nix::fcntl::{self, open, readlink};
-use nix::fcntl::{fcntl, FcntlArg, FdFlag, OFlag};
+use nix::fcntl::OFlag;
use nix::unistd::*;
use nix::unistd::ForkResult::*;
#[cfg(not(target_os = "redox"))]
@@ -10,17 +10,15 @@ use nix::sys::stat::{self, Mode, SFlag};
#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
use nix::pty::{posix_openpt, grantpt, unlockpt, ptsname};
use nix::errno::Errno;
-#[cfg(not(target_os = "redox"))]
-use nix::Error;
use std::{env, iter};
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "fuchsia", target_os = "redox")))]
use std::ffi::CString;
#[cfg(not(target_os = "redox"))]
use std::fs::DirBuilder;
use std::fs::{self, File};
use std::io::Write;
use std::os::unix::prelude::*;
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "fuchsia", target_os = "redox")))]
use std::path::Path;
use tempfile::{tempdir, tempfile};
use libc::{_exit, mode_t, off_t};
@@ -135,6 +133,8 @@ fn test_mkfifoat_none() {
target_os = "macos", target_os = "ios",
target_os = "android", target_os = "redox")))]
fn test_mkfifoat() {
+ use nix::fcntl;
+
let tempdir = tempdir().unwrap();
let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
let mkfifoat_name = "mkfifoat_name";
@@ -258,7 +258,7 @@ fn test_initgroups() {
setgroups(&old_groups).unwrap();
}
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "fuchsia", target_os = "redox")))]
macro_rules! execve_test_factory(
($test_name:ident, $syscall:ident, $exe: expr $(, $pathname:expr, $flags:expr)*) => (
@@ -669,6 +669,8 @@ fn test_pipe() {
target_os = "solaris"))]
#[test]
fn test_pipe2() {
+ use nix::fcntl::{fcntl, FcntlArg, FdFlag};
+
let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap();
let f0 = FdFlag::from_bits_truncate(fcntl(fd0, FcntlArg::F_GETFD).unwrap());
assert!(f0.contains(FdFlag::FD_CLOEXEC));
@@ -968,7 +970,7 @@ fn test_unlinkat_dir_noremovedir() {
// Attempt unlink dir at relative path without proper flag
let err_result = unlinkat(Some(dirfd), dirname, UnlinkatFlags::NoRemoveDir).unwrap_err();
- assert!(err_result == Error::Sys(Errno::EISDIR) || err_result == Error::Sys(Errno::EPERM));
+ assert!(err_result == Errno::EISDIR || err_result == Errno::EPERM);
}
#[test]
@@ -1011,7 +1013,7 @@ fn test_unlinkat_file() {
fn test_access_not_existing() {
let tempdir = tempdir().unwrap();
let dir = tempdir.path().join("does_not_exist.txt");
- assert_eq!(access(&dir, AccessFlags::F_OK).err().unwrap().as_errno().unwrap(),
+ assert_eq!(access(&dir, AccessFlags::F_OK).err().unwrap(),
Errno::ENOENT);
}
@@ -1090,13 +1092,13 @@ fn test_ttyname() {
fn test_ttyname_not_pty() {
let fd = File::open("/dev/zero").unwrap();
assert!(fd.as_raw_fd() > 0);
- assert_eq!(ttyname(fd.as_raw_fd()), Err(Error::Sys(Errno::ENOTTY)));
+ assert_eq!(ttyname(fd.as_raw_fd()), Err(Errno::ENOTTY));
}
#[test]
#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
fn test_ttyname_invalid_fd() {
- assert_eq!(ttyname(-1), Err(Error::Sys(Errno::EBADF)));
+ assert_eq!(ttyname(-1), Err(Errno::EBADF));
}
#[test]