summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md12
-rw-r--r--Cargo.toml1
-rw-r--r--src/sys/epoll.rs35
-rw-r--r--src/sys/eventfd.rs6
-rw-r--r--src/sys/socket/mod.rs18
-rw-r--r--src/unistd.rs61
-rw-r--r--test/sys/mod.rs3
-rw-r--r--test/sys/test_epoll.rs24
-rw-r--r--test/test_unistd.rs19
9 files changed, 150 insertions, 29 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c87c867e..335098bf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -31,8 +31,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
([#457](https://github.com/nix-rust/nix/pull/457))
- Added `getpgrp` in `::nix::unistd`
([#491](https://github.com/nix-rust/nix/pull/491))
+- Added `fchdir` in `::nix::unistd`
+ ([#497](https://github.com/nix-rust/nix/pull/497))
### Changed
+- `epoll_ctl` now could accept None as argument `event`
+ when op is `EpollOp::EpollCtlDel`.
+ ([#480](https://github.com/nix-rust/nix/pull/480))
- Removed the `bad` keyword from the `ioctl!` macro
([#478](https://github.com/nix-rust/nix/pull/478))
- Changed `TimeVal` into an opaque Newtype
@@ -64,6 +69,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- `SigFlags` in `::nix::sys::signal` has be renamed to `SigmaskHow` and its type
has changed from `bitflags` to `enum` in order to conform to our conventions.
([#460](https://github.com/nix-rust/nix/pull/460))
+- `sethostname` now takes a `&str` instead of a `&[u8]` as this provides an API
+ that makes more sense in normal, correct usage of the API.
+- `gethostname` previously did not expose the actual length of the hostname
+ written from the underlying system call at all. This has been updated to
+ return a `&CStr` within the provided buffer that is always properly
+ NUL-terminated (this is not guaranteed by the call with all platforms/libc
+ implementations).
### Fixed
- Fixed multiple issues with Unix domain sockets on non-Linux OSes
diff --git a/Cargo.toml b/Cargo.toml
index 6e758846..43b074ee 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,6 +7,7 @@ authors = ["The nix-rust Project Developers"]
homepage = "https://github.com/nix-rust/nix"
repository = "https://github.com/nix-rust/nix"
license = "MIT"
+categories = ["os::unix-apis"]
exclude = [
".gitignore",
".travis.yml",
diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs
index 9774318f..eb28ffb9 100644
--- a/src/sys/epoll.rs
+++ b/src/sys/epoll.rs
@@ -1,6 +1,9 @@
use {Errno, Result};
use libc::{self, c_int};
use std::os::unix::io::RawFd;
+use std::ptr;
+use std::mem;
+use ::Error;
bitflags!(
#[repr(C)]
@@ -23,7 +26,7 @@ bitflags!(
}
);
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Eq, PartialEq)]
#[repr(C)]
pub enum EpollOp {
EpollCtlAdd = 1,
@@ -44,10 +47,14 @@ pub struct EpollEvent {
}
impl EpollEvent {
- pub fn new(events: EpollFlags, data: u64) -> EpollEvent {
+ pub fn new(events: EpollFlags, data: u64) -> Self {
EpollEvent { event: libc::epoll_event { events: events.bits(), u64: data } }
}
+ pub fn empty() -> Self {
+ unsafe { mem::zeroed::<EpollEvent>() }
+ }
+
pub fn events(&self) -> EpollFlags {
EpollFlags::from_bits(self.event.events).unwrap()
}
@@ -57,6 +64,16 @@ impl EpollEvent {
}
}
+impl<'a> Into<&'a mut EpollEvent> for Option<&'a mut EpollEvent> {
+ #[inline]
+ fn into(self) -> &'a mut EpollEvent {
+ match self {
+ Some(epoll_event) => epoll_event,
+ None => unsafe { &mut *ptr::null_mut::<EpollEvent>() }
+ }
+ }
+}
+
#[inline]
pub fn epoll_create() -> Result<RawFd> {
let res = unsafe { libc::epoll_create(1024) };
@@ -72,10 +89,16 @@ pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
}
#[inline]
-pub fn epoll_ctl(epfd: RawFd, op: EpollOp, fd: RawFd, event: &mut EpollEvent) -> Result<()> {
- let res = unsafe { libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event) };
-
- Errno::result(res).map(drop)
+pub fn epoll_ctl<'a, T>(epfd: RawFd, op: EpollOp, fd: RawFd, event: T) -> Result<()>
+ where T: Into<&'a mut EpollEvent>
+{
+ let event: &mut EpollEvent = event.into();
+ if event as *const EpollEvent == ptr::null() && op != EpollOp::EpollCtlDel {
+ Err(Error::Sys(Errno::EINVAL))
+ } else {
+ let res = unsafe { libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event) };
+ Errno::result(res).map(drop)
+ }
}
#[inline]
diff --git a/src/sys/eventfd.rs b/src/sys/eventfd.rs
index e6e410ec..8058e207 100644
--- a/src/sys/eventfd.rs
+++ b/src/sys/eventfd.rs
@@ -4,9 +4,9 @@ use {Errno, Result};
libc_bitflags! {
flags EfdFlags: libc::c_int {
- const EFD_CLOEXEC, // Since Linux 2.6.27
- const EFD_NONBLOCK, // Since Linux 2.6.27
- const EFD_SEMAPHORE, // Since Linux 2.6.30
+ EFD_CLOEXEC, // Since Linux 2.6.27
+ EFD_NONBLOCK, // Since Linux 2.6.27
+ EFD_SEMAPHORE, // Since Linux 2.6.30
}
}
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
index e041e6b6..645dfe41 100644
--- a/src/sys/socket/mod.rs
+++ b/src/sys/socket/mod.rs
@@ -50,17 +50,8 @@ pub use self::multicast::{
};
pub use self::consts::*;
-#[cfg(any(not(target_os = "linux"), not(target_arch = "x86")))]
pub use libc::sockaddr_storage;
-// Working around rust-lang/rust#23425
-#[cfg(all(target_os = "linux", target_arch = "x86"))]
-pub struct sockaddr_storage {
- pub ss_family: sa_family_t,
- pub __ss_align: u32,
- pub __ss_pad2: [u8; 120],
-}
-
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(i32)]
pub enum SockType {
@@ -238,8 +229,13 @@ impl<'a> ControlMessage<'a> {
let padlen = cmsg_align(mem::size_of_val(&cmsg)) -
mem::size_of_val(&cmsg);
- let buf2 = &mut &mut buf[padlen..];
- copy_bytes(fds, buf2);
+
+ let mut tmpbuf = &mut [][..];
+ mem::swap(&mut tmpbuf, buf);
+ let (_padding, mut remainder) = tmpbuf.split_at_mut(padlen);
+ mem::swap(buf, &mut remainder);
+
+ copy_bytes(fds, buf);
},
ControlMessage::Unknown(UnknownCmsg(orig_cmsg, bytes)) => {
copy_bytes(orig_cmsg, buf);
diff --git a/src/unistd.rs b/src/unistd.rs
index f7efbdee..187154bd 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -5,8 +5,8 @@ use fcntl::{fcntl, OFlag, O_CLOEXEC, FD_CLOEXEC};
use fcntl::FcntlArg::F_SETFD;
use libc::{self, c_char, c_void, c_int, c_uint, size_t, pid_t, off_t, uid_t, gid_t, mode_t};
use std::mem;
-use std::ffi::{CString, CStr, OsString};
-use std::os::unix::ffi::{OsStringExt};
+use std::ffi::{CString, CStr, OsString, OsStr};
+use std::os::unix::ffi::{OsStringExt, OsStrExt};
use std::os::unix::io::RawFd;
use std::path::{PathBuf};
use void::Void;
@@ -249,6 +249,19 @@ pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> {
Errno::result(res).map(drop)
}
+/// Change the current working directory of the process to the one
+/// given as an open file descriptor (see
+/// [fchdir(2)](http://man7.org/linux/man-pages/man2/fchdir.2.html)).
+///
+/// This function may fail in a number of different scenarios. See the man
+/// pages for additional details on possible failure cases.
+#[inline]
+pub fn fchdir(dirfd: RawFd) -> Result<()> {
+ let res = unsafe { libc::fchdir(dirfd) };
+
+ Errno::result(res).map(drop)
+}
+
/// Creates new directory `path` with access rights `mode`.
///
/// # Errors
@@ -480,7 +493,14 @@ pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
Errno::result(res).map(drop)
}
-pub fn sethostname(name: &[u8]) -> Result<()> {
+/// Set the system host name (see
+/// [gethostname(2)](http://man7.org/linux/man-pages/man2/gethostname.2.html)).
+///
+/// Given a name, attempt to update the system host name to the given string.
+/// On some systems, the host name is limited to as few as 64 bytes. An error
+/// will be return if the name is not valid or the current process does not have
+/// permissions to update the host name.
+pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> {
// Handle some differences in type of the len arg across platforms.
cfg_if! {
if #[cfg(any(target_os = "dragonfly",
@@ -492,19 +512,42 @@ pub fn sethostname(name: &[u8]) -> Result<()> {
type sethostname_len_t = size_t;
}
}
- let ptr = name.as_ptr() as *const c_char;
- let len = name.len() as sethostname_len_t;
+ let ptr = name.as_ref().as_bytes().as_ptr() as *const c_char;
+ let len = name.as_ref().len() as sethostname_len_t;
let res = unsafe { libc::sethostname(ptr, len) };
Errno::result(res).map(drop)
}
-pub fn gethostname(name: &mut [u8]) -> Result<()> {
- let ptr = name.as_mut_ptr() as *mut c_char;
- let len = name.len() as size_t;
+/// Get the host name and store it in the provided buffer, returning a pointer
+/// the CStr in that buffer on success (see
+/// [gethostname(2)](http://man7.org/linux/man-pages/man2/gethostname.2.html)).
+///
+/// This function call attempts to get the host name for the running system and
+/// store it in a provided buffer. The buffer will be populated with bytes up
+/// to the length of the provided slice including a NUL terminating byte. If
+/// the hostname is longer than the length provided, no error will be provided.
+/// The posix specification does not specify whether implementations will
+/// null-terminate in this case, but the nix implementation will ensure that the
+/// buffer is null terminated in this case.
+///
+/// ```no_run
+/// use nix::unistd;
+///
+/// let mut buf = [0u8; 64];
+/// let hostname_cstr = unistd::gethostname(&mut buf).expect("Failed getting hostname");
+/// let hostname = hostname_cstr.to_str().expect("Hostname wasn't valid UTF-8");
+/// println!("Hostname: {}", hostname);
+/// ```
+pub fn gethostname<'a>(buffer: &'a mut [u8]) -> Result<&'a CStr> {
+ let ptr = buffer.as_mut_ptr() as *mut c_char;
+ let len = buffer.len() as size_t;
let res = unsafe { libc::gethostname(ptr, len) };
- Errno::result(res).map(drop)
+ Errno::result(res).map(|_| {
+ buffer[len - 1] = 0; // ensure always null-terminated
+ unsafe { CStr::from_ptr(buffer.as_ptr() as *const c_char) }
+ })
}
pub fn close(fd: RawFd) -> Result<()> {
diff --git a/test/sys/mod.rs b/test/sys/mod.rs
index 25c9a92f..5e5eed41 100644
--- a/test/sys/mod.rs
+++ b/test/sys/mod.rs
@@ -9,3 +9,6 @@ mod test_ioctl;
mod test_wait;
mod test_select;
mod test_uio;
+
+#[cfg(target_os = "linux")]
+mod test_epoll;
diff --git a/test/sys/test_epoll.rs b/test/sys/test_epoll.rs
new file mode 100644
index 00000000..a73fea6d
--- /dev/null
+++ b/test/sys/test_epoll.rs
@@ -0,0 +1,24 @@
+use nix::sys::epoll::{EpollCreateFlags, EpollOp, EpollEvent};
+use nix::sys::epoll::{EPOLLIN, EPOLLERR};
+use nix::sys::epoll::{epoll_create1, epoll_ctl};
+use nix::{Error, Errno};
+
+#[test]
+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));
+
+ let result = epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, None);
+ assert!(result.is_err());
+ assert_eq!(result.unwrap_err(), Error::Sys(Errno::EINVAL));
+}
+
+#[test]
+pub fn test_epoll_ctl() {
+ let efd = epoll_create1(EpollCreateFlags::empty()).unwrap();
+ let mut event = EpollEvent::new(EPOLLIN | EPOLLERR, 1);
+ epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, &mut event).unwrap();
+ epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None).unwrap();
+}
diff --git a/test/test_unistd.rs b/test/test_unistd.rs
index d281f9b2..76ab442a 100644
--- a/test/test_unistd.rs
+++ b/test/test_unistd.rs
@@ -6,6 +6,7 @@ use nix::sys::wait::*;
use nix::sys::stat;
use std::iter;
use std::ffi::CString;
+use std::fs::File;
use std::io::{Write, Read};
use std::os::unix::prelude::*;
use std::env::current_dir;
@@ -142,6 +143,24 @@ macro_rules! execve_test_factory(
);
#[test]
+fn test_fchdir() {
+ let tmpdir = TempDir::new("test_fchdir").unwrap();
+ let tmpdir_path = tmpdir.path().canonicalize().unwrap();
+ let tmpdir_fd = File::open(&tmpdir_path).unwrap().into_raw_fd();
+ let olddir_path = getcwd().unwrap();
+ let olddir_fd = File::open(&olddir_path).unwrap().into_raw_fd();
+
+ assert!(fchdir(tmpdir_fd).is_ok());
+ assert_eq!(getcwd().unwrap(), tmpdir_path);
+
+ assert!(fchdir(olddir_fd).is_ok());
+ assert_eq!(getcwd().unwrap(), olddir_path);
+
+ assert!(close(olddir_fd).is_ok());
+ assert!(close(tmpdir_fd).is_ok());
+}
+
+#[test]
fn test_getcwd() {
let tmp_dir = TempDir::new("test_getcwd").unwrap();
assert!(chdir(tmp_dir.path()).is_ok());