From a821f9630cbe3ee12846625fa63abc768b59d1a0 Mon Sep 17 00:00:00 2001 From: Andreas Fuchs Date: Sun, 1 May 2016 12:52:20 -0700 Subject: [PATCH 01/49] Add mkstemp(3) --- src/unistd.rs | 13 +++++++++++++ test/test_unistd.rs | 10 ++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/unistd.rs b/src/unistd.rs index 714482489e..3136779124 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -374,6 +374,19 @@ pub fn sleep(seconds: libc::c_uint) -> c_uint { unsafe { libc::sleep(seconds) } } +#[inline] +pub fn mkstemp(template: &P) -> Result { + let res = try!(template.with_nix_path(|path| { + let mut path_copy = path.to_bytes_with_nul().to_owned(); + let c_template: *mut c_char = path_copy.as_mut_ptr() as *mut c_char; + unsafe { + libc::mkstemp(c_template) + } + })); + Errno::result(res) + +} + #[cfg(any(target_os = "linux", target_os = "android"))] mod linux { use sys::syscall::{syscall, SYSPIVOTROOT}; diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 410a32d520..50ff8e877b 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -45,6 +45,16 @@ fn test_wait() { } } +#[test] +fn test_mkstemp() { + let result = mkstemp("/tmp/tempfile.XXXXXXXX"); + match result { + Ok(fd) => { + close(fd).expect("Couldn't close the file descriptor"); + } + Err(e) => panic!("mkstemp failed: {}", e) + } +} #[test] fn test_getpid() { From e42183fcbea64ee8def85e487d25a96129ed1d6d Mon Sep 17 00:00:00 2001 From: Andreas Fuchs Date: Sun, 1 May 2016 15:06:59 -0700 Subject: [PATCH 02/49] Remove dependency on Result::expect --- test/test_unistd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 50ff8e877b..677c16721f 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -50,7 +50,7 @@ fn test_mkstemp() { let result = mkstemp("/tmp/tempfile.XXXXXXXX"); match result { Ok(fd) => { - close(fd).expect("Couldn't close the file descriptor"); + close(fd).unwrap(); } Err(e) => panic!("mkstemp failed: {}", e) } From 23a7ea64938cc73d476e42b80a243fefbe7111b2 Mon Sep 17 00:00:00 2001 From: Andreas Fuchs Date: Sun, 1 May 2016 17:20:12 -0700 Subject: [PATCH 03/49] Return both the fd and the created path --- src/unistd.rs | 27 ++++++++++++++++++--------- test/test_unistd.rs | 5 +++-- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index 3136779124..8db441634f 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -5,8 +5,10 @@ use fcntl::{fcntl, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC}; use fcntl::FcntlArg::{F_SETFD, F_SETFL}; use libc::{self, c_char, c_void, c_int, c_uint, size_t, pid_t, off_t, uid_t, gid_t}; use std::mem; -use std::ffi::CString; +use std::ffi::{CString, OsStr}; +use std::os::unix::ffi::OsStrExt; use std::os::unix::io::RawFd; +use std::path::{PathBuf, Path}; use void::Void; #[cfg(any(target_os = "linux", target_os = "android"))] @@ -375,16 +377,23 @@ pub fn sleep(seconds: libc::c_uint) -> c_uint { } #[inline] -pub fn mkstemp(template: &P) -> Result { - let res = try!(template.with_nix_path(|path| { - let mut path_copy = path.to_bytes_with_nul().to_owned(); - let c_template: *mut c_char = path_copy.as_mut_ptr() as *mut c_char; +pub fn mkstemp(template: &P) -> Result<(RawFd, PathBuf)> { + let res = template.with_nix_path(|path| { + let owned_path = path.to_owned(); + let path_ptr = owned_path.into_raw(); unsafe { - libc::mkstemp(c_template) + (libc::mkstemp(path_ptr), CString::from_raw(path_ptr)) } - })); - Errno::result(res) - + }); + match res { + Ok((fd, pathname)) => { + try!(Errno::result(fd)); + Ok((fd, Path::new(OsStr::from_bytes(pathname.as_bytes())).to_owned())) + } + Err(e) => { + Err(e) + } + } } #[cfg(any(target_os = "linux", target_os = "android"))] diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 677c16721f..9b4bff2cbd 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -47,10 +47,11 @@ fn test_wait() { #[test] fn test_mkstemp() { - let result = mkstemp("/tmp/tempfile.XXXXXXXX"); + let result = mkstemp("/tmp/nix_tempfile.XXXXXXXX"); match result { - Ok(fd) => { + Ok((fd, path)) => { close(fd).unwrap(); + unlink(path.as_path()).unwrap(); } Err(e) => panic!("mkstemp failed: {}", e) } From aa426634ad2a1c94df8367ce1a8a6ba7a1ac62b6 Mon Sep 17 00:00:00 2001 From: Murarth Date: Thu, 25 Aug 2016 14:10:59 -0700 Subject: [PATCH 04/49] Implement `Clone` for `FdSet` on Mac/iOS --- src/sys/select.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sys/select.rs b/src/sys/select.rs index 1b47d759a9..28b664aa75 100644 --- a/src/sys/select.rs +++ b/src/sys/select.rs @@ -8,6 +8,7 @@ pub const FD_SETSIZE: RawFd = 1024; #[cfg(any(target_os = "macos", target_os = "ios"))] #[repr(C)] +#[derive(Clone)] pub struct FdSet { bits: [i32; FD_SETSIZE as usize / 32] } From ae6635f7a6b0a941e05c2d4e4fc2a485df282034 Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Fri, 26 Aug 2016 03:05:29 +0200 Subject: [PATCH 05/49] Add FcntlArg::F_FULLFSYNC https://developer.apple.com/library/ios/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fsync.2.html --- src/fcntl.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fcntl.rs b/src/fcntl.rs index 75e1254960..1d9ba4998d 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -46,6 +46,8 @@ pub enum FcntlArg<'a> { F_ADD_SEALS(SealFlag), #[cfg(target_os = "linux")] F_GET_SEALS, + #[cfg(any(target_os = "macos", target_os = "ios"))] + F_FULLFSYNC, // TODO: Rest of flags } @@ -69,6 +71,8 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result { F_ADD_SEALS(flag) => libc::fcntl(fd, ffi::F_ADD_SEALS, flag.bits()), #[cfg(target_os = "linux")] F_GET_SEALS => libc::fcntl(fd, ffi::F_GET_SEALS), + #[cfg(any(target_os = "macos", target_os = "ios"))] + F_FULLFSYNC => libc::fcntl(fd, libc::F_FULLFSYNC), #[cfg(any(target_os = "linux", target_os = "android"))] _ => unimplemented!() } From e2d3495fa4f7829b5cfa00d370ba21a34cc2a24e Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Sun, 28 Aug 2016 09:20:02 +0200 Subject: [PATCH 06/49] Updated CHANGELOG.md for #405 and #407. Closes #408. --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d2e6bf805..08939e0064 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added new module `::nix::sys::reboot` with enumeration `RebootMode` and functions `reboot` and `set_cad_enabled`. Currently for _linux_ only. ([#386](https://github.com/nix-rust/nix/pull/386)) +- `FdSet` in `::nix::sys::select` now also implements `Clone`. + ([#405](https://github.com/nix-rust/nix/pull/405)) +- Added `F_FULLFSYNC` to `FcntlArg` in `::nix::fcntl` for _apple_ targets. + ([#407](https://github.com/nix-rust/nix/pull/407)) ### Changed - Replaced the reexported integer constants for signals by the enumeration From 899a13061fcecfdd9d0e94bf6ebce7c152266b0d Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Mon, 15 Aug 2016 21:02:59 +0200 Subject: [PATCH 07/49] Replace parts of ffi module by libc functions in sched.rs --- CHANGELOG.md | 8 ++ src/sched.rs | 226 +++++++++++++++------------------------------------ 2 files changed, 74 insertions(+), 160 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08939e0064..04e9322f64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#405](https://github.com/nix-rust/nix/pull/405)) - Added `F_FULLFSYNC` to `FcntlArg` in `::nix::fcntl` for _apple_ targets. ([#407](https://github.com/nix-rust/nix/pull/407)) +- Added `CpuSet::unset` in `::nix::sched`. + ([#402](https://github.com/nix-rust/nix/pull/402)) ### Changed - Replaced the reexported integer constants for signals by the enumeration @@ -28,10 +30,16 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#362](https://github.com/nix-rust/nix/pull/362)) - Renamed `EventFdFlag` to `EfdFlags` in `::nix::sys::eventfd`. ([#383](https://github.com/nix-rust/nix/pull/383)) +- Changed the result types of `CpuSet::is_set` and `CpuSet::set` in + `::nix::sched` to `Result` and `Result<()>`, respectively. They now + return `EINVAL`, if an invalid argument for the `field` parameter is passed. + ([#402](https://github.com/nix-rust/nix/pull/402)) ### Removed - Type alias `SigNum` from `::nix::sys::signal`. ([#362](https://github.com/nix-rust/nix/pull/362)) +- Type alias `CpuMask` from `::nix::shed`. + ([#402](https://github.com/nix-rust/nix/pull/402)) ### Fixed - Fixed the build problem for NetBSD (Note, that we currently do not support diff --git a/src/sched.rs b/src/sched.rs index 934ce13ff9..91a7c42a9a 100644 --- a/src/sched.rs +++ b/src/sched.rs @@ -1,204 +1,110 @@ use std::mem; use std::os::unix::io::RawFd; use std::option::Option; -use libc::{self, c_int, c_void, c_ulong, pid_t}; -use {Errno, Result}; +use libc::{self, c_int, c_void, pid_t}; +use {Errno, Error, Result}; // For some functions taking with a parameter of type CloneFlags, // only a subset of these flags have an effect. -bitflags!{ - flags CloneFlags: c_int { - const CLONE_VM = libc::CLONE_VM, - const CLONE_FS = libc::CLONE_FS, - const CLONE_FILES = libc::CLONE_FILES, - const CLONE_SIGHAND = libc::CLONE_SIGHAND, - const CLONE_PTRACE = libc::CLONE_PTRACE, - const CLONE_VFORK = libc::CLONE_VFORK, - const CLONE_PARENT = libc::CLONE_PARENT, - const CLONE_THREAD = libc::CLONE_THREAD, - const CLONE_NEWNS = libc::CLONE_NEWNS, - const CLONE_SYSVSEM = libc::CLONE_SYSVSEM, - const CLONE_SETTLS = libc::CLONE_SETTLS, - const CLONE_PARENT_SETTID = libc::CLONE_PARENT_SETTID, - const CLONE_CHILD_CLEARTID = libc::CLONE_CHILD_CLEARTID, - const CLONE_DETACHED = libc::CLONE_DETACHED, - const CLONE_UNTRACED = libc::CLONE_UNTRACED, - const CLONE_CHILD_SETTID = libc::CLONE_CHILD_SETTID, - // TODO: Once, we use a version containing - // https://github.com/rust-lang-nursery/libc/pull/147 - // get rid of the casts. - const CLONE_NEWUTS = libc::CLONE_NEWUTS as c_int, - const CLONE_NEWIPC = libc::CLONE_NEWIPC as c_int, - const CLONE_NEWUSER = libc::CLONE_NEWUSER as c_int, - const CLONE_NEWPID = libc::CLONE_NEWPID as c_int, - const CLONE_NEWNET = libc::CLONE_NEWNET as c_int, - const CLONE_IO = libc::CLONE_IO as c_int, - } -} - -// Support a maximum CPU set of 1024 nodes -#[cfg(all(target_arch = "x86_64", target_os = "linux"))] -mod cpuset_attribs { - use super::CpuMask; - pub const CPU_SETSIZE: usize = 1024; - pub const CPU_MASK_BITS: usize = 64; - - #[inline] - pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask { - cur | (1u64 << bit) - } - - #[inline] - pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask { - cur & !(1u64 << bit) - } -} - -#[cfg(all(target_arch = "x86", target_os = "linux"))] -mod cpuset_attribs { - use super::CpuMask; - pub const CPU_SETSIZE: usize = 1024; - pub const CPU_MASK_BITS: usize = 32; - - #[inline] - pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask { - cur | (1u32 << bit) - } - - #[inline] - pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask { - cur & !(1u32 << bit) - } -} - -#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))] -mod cpuset_attribs { - use super::CpuMask; - pub const CPU_SETSIZE: usize = 1024; - pub const CPU_MASK_BITS: usize = 64; - - #[inline] - pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask { - cur | (1u64 << bit) - } - - #[inline] - pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask { - cur & !(1u64 << bit) - } -} - -#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "android"))] -mod cpuset_attribs { - use super::CpuMask; - // bionic only supports up to 32 independent CPUs, instead of 1024. - pub const CPU_SETSIZE: usize = 32; - pub const CPU_MASK_BITS: usize = 32; - - #[inline] - pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask { - cur | (1u32 << bit) - } - - #[inline] - pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask { - cur & !(1u32 << bit) - } -} - -#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "linux"))] -mod cpuset_attribs { - use super::CpuMask; - pub const CPU_SETSIZE: usize = 1024; - pub const CPU_MASK_BITS: usize = 32; - - #[inline] - pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask { - cur | (1u32 << bit) - } - - #[inline] - pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask { - cur & !(1u32 << bit) +libc_bitflags!{ + flags CloneFlags: libc::c_int { + CLONE_VM, + CLONE_FS, + CLONE_FILES, + CLONE_SIGHAND, + CLONE_PTRACE, + CLONE_VFORK, + CLONE_PARENT, + CLONE_THREAD, + CLONE_NEWNS, + CLONE_SYSVSEM, + CLONE_SETTLS, + CLONE_PARENT_SETTID, + CLONE_CHILD_CLEARTID, + CLONE_DETACHED, + CLONE_UNTRACED, + CLONE_CHILD_SETTID, + CLONE_NEWUTS, + CLONE_NEWIPC, + CLONE_NEWUSER, + CLONE_NEWPID, + CLONE_NEWNET, + CLONE_IO, } } pub type CloneCb<'a> = Box isize + 'a>; -// A single CPU mask word -pub type CpuMask = c_ulong; - -// Structure representing the CPU set to apply #[repr(C)] #[derive(Clone, Copy)] pub struct CpuSet { - cpu_mask: [CpuMask; cpuset_attribs::CPU_SETSIZE/cpuset_attribs::CPU_MASK_BITS] + cpu_set: libc::cpu_set_t, } impl CpuSet { pub fn new() -> CpuSet { - CpuSet { - cpu_mask: unsafe { mem::zeroed() } - } + CpuSet { cpu_set: unsafe { mem::zeroed() } } } - pub fn set(&mut self, field: usize) { - let word = field / cpuset_attribs::CPU_MASK_BITS; - let bit = field % cpuset_attribs::CPU_MASK_BITS; - - self.cpu_mask[word] = cpuset_attribs::set_cpu_mask_flag(self.cpu_mask[word], bit); + pub fn is_set(&self, field: usize) -> Result { + if field >= 8 * mem::size_of::() { + Err(Error::Sys(Errno::EINVAL)) + } else { + Ok(unsafe { libc::CPU_ISSET(field, &self.cpu_set) }) + } } - pub fn unset(&mut self, field: usize) { - let word = field / cpuset_attribs::CPU_MASK_BITS; - let bit = field % cpuset_attribs::CPU_MASK_BITS; + pub fn set(&mut self, field: usize) -> Result<()> { + if field >= 8 * mem::size_of::() { + Err(Error::Sys(Errno::EINVAL)) + } else { + Ok(unsafe { libc::CPU_SET(field, &mut self.cpu_set) }) + } + } - self.cpu_mask[word] = cpuset_attribs::clear_cpu_mask_flag(self.cpu_mask[word], bit); + pub fn unset(&mut self, field: usize) -> Result<()> { + if field >= 8 * mem::size_of::() { + Err(Error::Sys(Errno::EINVAL)) + } else { + Ok(unsafe { libc::CPU_CLR(field, &mut self.cpu_set) }) + } } } mod ffi { - use libc::{c_void, c_int, pid_t, size_t}; - use super::CpuSet; + use libc::{c_void, c_int}; - pub type CloneCb = extern "C" fn (data: *const super::CloneCb) -> c_int; + pub type CloneCb = extern "C" fn(data: *const super::CloneCb) -> c_int; // We cannot give a proper #[repr(C)] to super::CloneCb #[allow(improper_ctypes)] - extern { + extern "C" { // create a child process // doc: http://man7.org/linux/man-pages/man2/clone.2.html - pub fn clone( - cb: *const CloneCb, - child_stack: *mut c_void, - flags: c_int, - arg: *mut super::CloneCb, - ...) -> c_int; - - // disassociate parts of the process execution context - // doc: http://man7.org/linux/man-pages/man2/unshare.2.html - pub fn unshare(flags: c_int) -> c_int; - - // reassociate thread with a namespace - // doc: http://man7.org/linux/man-pages/man2/setns.2.html - pub fn setns(fd: c_int, nstype: c_int) -> c_int; - - // Set the current CPU set that a task is allowed to run on - pub fn sched_setaffinity(__pid: pid_t, __cpusetsize: size_t, __cpuset: *const CpuSet) -> c_int; + pub fn clone(cb: *const CloneCb, + child_stack: *mut c_void, + flags: c_int, + arg: *mut super::CloneCb, + ...) + -> c_int; } } pub fn sched_setaffinity(pid: isize, cpuset: &CpuSet) -> Result<()> { - use libc::{pid_t, size_t}; - let res = unsafe { - ffi::sched_setaffinity(pid as pid_t, mem::size_of::() as size_t, mem::transmute(cpuset)) + libc::sched_setaffinity(pid as libc::pid_t, + mem::size_of::() as libc::size_t, + mem::transmute(cpuset)) }; Errno::result(res).map(drop) } -pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags, signal: Option) -> Result { +pub fn clone(mut cb: CloneCb, + stack: &mut [u8], + flags: CloneFlags, + signal: Option) + -> Result { extern "C" fn callback(data: *mut CloneCb) -> c_int { let cb: &mut CloneCb = unsafe { &mut *data }; (*cb)() as c_int @@ -217,13 +123,13 @@ pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags, signal: Optio } pub fn unshare(flags: CloneFlags) -> Result<()> { - let res = unsafe { ffi::unshare(flags.bits()) }; + let res = unsafe { libc::unshare(flags.bits()) }; Errno::result(res).map(drop) } pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> { - let res = unsafe { ffi::setns(fd, nstype.bits()) }; + let res = unsafe { libc::setns(fd, nstype.bits()) }; Errno::result(res).map(drop) } From 93dc2387bd336d843c3d39f0a44b906b637ec2f8 Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Thu, 11 Aug 2016 21:25:09 +0200 Subject: [PATCH 08/49] Use libc in poll.rs --- src/poll.rs | 92 +++++++++++++++++------------------------------ test/test_poll.rs | 10 ++---- 2 files changed, 36 insertions(+), 66 deletions(-) diff --git a/src/poll.rs b/src/poll.rs index 88ca982573..6ba9f5e45b 100644 --- a/src/poll.rs +++ b/src/poll.rs @@ -1,74 +1,48 @@ -use libc::c_int; +use libc; use {Errno, Result}; -pub use self::ffi::PollFd; -pub use self::ffi::consts::*; - -mod ffi { - use libc::c_int; - pub use self::consts::*; - - #[derive(Clone, Copy, Debug)] - #[repr(C)] - pub struct PollFd { - pub fd: c_int, - pub events: EventFlags, - pub revents: EventFlags - } - - #[cfg(target_os = "linux")] - pub mod consts { - use libc::{c_short, c_ulong}; +#[repr(C)] +#[derive(Clone, Copy)] +pub struct PollFd { + pollfd: libc::pollfd, +} - bitflags! { - flags EventFlags: c_short { - const POLLIN = 0x001, - const POLLPRI = 0x002, - const POLLOUT = 0x004, - const POLLRDNORM = 0x040, - const POLLWRNORM = 0x100, - const POLLRDBAND = 0x080, - const POLLWRBAND = 0x200, - const POLLERR = 0x008, - const POLLHUP = 0x010, - const POLLNVAL = 0x020, - } +impl PollFd { + pub fn new(fd: libc::c_int, events: EventFlags, revents: EventFlags) -> PollFd { + PollFd { + pollfd: libc::pollfd { + fd: fd, + events: events.bits(), + revents: revents.bits(), + }, } - - pub type nfds_t = c_ulong; } - #[cfg(target_os = "macos")] - pub mod consts { - use libc::{c_short, c_uint}; - - bitflags! { - flags EventFlags: c_short { - const POLLIN = 0x0001, - const POLLPRI = 0x0002, - const POLLOUT = 0x0004, - const POLLRDNORM = 0x0040, - const POLLWRNORM = 0x0004, - const POLLRDBAND = 0x0080, - const POLLWRBAND = 0x0100, - const POLLERR = 0x0008, - const POLLHUP = 0x0010, - const POLLNVAL = 0x0020, - } - } - - pub type nfds_t = c_uint; + pub fn revents(&self) -> Option { + EventFlags::from_bits(self.pollfd.revents) } +} - #[allow(improper_ctypes)] - extern { - pub fn poll(fds: *mut PollFd, nfds: nfds_t, timeout: c_int) -> c_int; +libc_bitflags! { + flags EventFlags: libc::c_short { + POLLIN, + POLLPRI, + POLLOUT, + POLLRDNORM, + POLLWRNORM, + POLLRDBAND, + POLLWRBAND, + POLLERR, + POLLHUP, + POLLNVAL, } } -pub fn poll(fds: &mut [PollFd], timeout: c_int) -> Result { +pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result { let res = unsafe { - ffi::poll(fds.as_mut_ptr(), fds.len() as ffi::nfds_t, timeout) + libc::poll(fds.as_mut_ptr() as *mut libc::pollfd, + fds.len() as libc::nfds_t, + timeout) }; Errno::result(res) diff --git a/test/test_poll.rs b/test/test_poll.rs index 54fd4029c0..13a95d2cde 100644 --- a/test/test_poll.rs +++ b/test/test_poll.rs @@ -4,19 +4,15 @@ use nix::unistd::{write, pipe}; #[test] fn test_poll() { let (r, w) = pipe().unwrap(); - let mut fds = [PollFd { - fd: r, - events: POLLIN, - revents: EventFlags::empty() - }]; + let mut fds = [PollFd::new(r, POLLIN, EventFlags::empty())]; let nfds = poll(&mut fds, 100).unwrap(); assert_eq!(nfds, 0); - assert!(!fds[0].revents.contains(POLLIN)); + assert!(!fds[0].revents().unwrap().contains(POLLIN)); write(w, b".").unwrap(); let nfds = poll(&mut fds, 100).unwrap(); assert_eq!(nfds, 1); - assert!(fds[0].revents.contains(POLLIN)); + assert!(fds[0].revents().unwrap().contains(POLLIN)); } From b0e69e6e729a987cb2acc1e9452241b01554c30b Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Wed, 3 Aug 2016 22:12:31 +0200 Subject: [PATCH 09/49] Replace ffi module by libc functions in mqueue.rs --- src/lib.rs | 2 +- src/mqueue.rs | 154 ++++++++++++++++++++++-------------------------- test/test_mq.rs | 8 ++- 3 files changed, 75 insertions(+), 89 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b983a9c213..8dbf9fe018 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,7 +40,7 @@ pub mod fcntl; #[cfg(any(target_os = "linux", target_os = "android"))] pub mod mount; -#[cfg(any(target_os = "linux"))] +#[cfg(target_os = "linux")] pub mod mqueue; #[cfg(any(target_os = "linux", target_os = "macos"))] diff --git a/src/mqueue.rs b/src/mqueue.rs index b8a2250e06..2dd2dbd963 100644 --- a/src/mqueue.rs +++ b/src/mqueue.rs @@ -4,114 +4,99 @@ use {Errno, Result}; -use libc::{c_int, c_long, c_char, size_t, mode_t}; +use libc::{self, c_char,c_long,mode_t,mqd_t,size_t}; use std::ffi::CString; use sys::stat::Mode; -use std::ptr; - -pub use self::consts::*; - -pub type MQd = c_int; - -#[cfg(target_os = "linux")] -mod consts { - use libc::c_int; - - bitflags!( - flags MQ_OFlag: c_int { - const O_RDONLY = 0o00000000, - const O_WRONLY = 0o00000001, - const O_RDWR = 0o00000002, - const O_CREAT = 0o00000100, - const O_EXCL = 0o00000200, - const O_NONBLOCK = 0o00004000, - const O_CLOEXEC = 0o02000000, - } - ); - - bitflags!( - flags FdFlag: c_int { - const FD_CLOEXEC = 1 - } - ); +use std::mem; + +libc_bitflags!{ + flags MQ_OFlag: libc::c_int { + O_RDONLY, + O_WRONLY, + O_RDWR, + O_CREAT, + O_EXCL, + O_NONBLOCK, + O_CLOEXEC, + } } -mod ffi { - use libc::{c_char, size_t, ssize_t, c_uint, c_int}; - use super::MQd; - use super::MqAttr; - - #[allow(improper_ctypes)] - extern "C" { - pub fn mq_open(name: *const c_char, oflag: c_int, ...) -> MQd; - - pub fn mq_close (mqd: MQd) -> c_int; - - pub fn mq_unlink(name: *const c_char) -> c_int; - - pub fn mq_receive (mqd: MQd, msg_ptr: *const c_char, msg_len: size_t, msq_prio: *const c_uint) -> ssize_t; - - pub fn mq_send (mqd: MQd, msg_ptr: *const c_char, msg_len: size_t, msq_prio: c_uint) -> c_int; - - pub fn mq_getattr(mqd: MQd, attr: *mut MqAttr) -> c_int; - - pub fn mq_setattr(mqd: MQd, newattr: *const MqAttr, oldattr: *mut MqAttr) -> c_int; +libc_bitflags!{ + flags FdFlag: libc::c_int { + FD_CLOEXEC, } } #[repr(C)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy)] pub struct MqAttr { - pub mq_flags: c_long, - pub mq_maxmsg: c_long, - pub mq_msgsize: c_long, - pub mq_curmsgs: c_long, - pad: [c_long; 4] + mq_attr: libc::mq_attr } -impl MqAttr { - pub fn new(mq_flags: c_long, mq_maxmsg: c_long, mq_msgsize: c_long, mq_curmsgs: c_long) -> MqAttr { - MqAttr { mq_flags: mq_flags, mq_maxmsg: mq_maxmsg, mq_msgsize: mq_msgsize, mq_curmsgs: mq_curmsgs, pad: [0; 4] } - } +impl PartialEq for MqAttr { + fn eq(&self, other: &MqAttr) -> bool { + let self_attr = self.mq_attr; + let other_attr = other.mq_attr; + self_attr.mq_flags == other_attr.mq_flags && + self_attr.mq_maxmsg == other_attr.mq_maxmsg && + self_attr.mq_msgsize == other_attr.mq_msgsize && + self_attr.mq_curmsgs == other_attr.mq_curmsgs + } } +impl MqAttr { + pub fn new(mq_flags: c_long, mq_maxmsg: c_long, mq_msgsize: c_long, mq_curmsgs: c_long) -> MqAttr { + let mut attr = unsafe { mem::uninitialized::() }; + attr.mq_flags = mq_flags; + attr.mq_maxmsg = mq_maxmsg; + attr.mq_msgsize = mq_msgsize; + attr.mq_curmsgs = mq_curmsgs; + MqAttr{mq_attr: attr} + } + + pub fn flags(&self) -> c_long { + self.mq_attr.mq_flags + } +} -pub fn mq_open(name: &CString, oflag: MQ_OFlag, mode: Mode, attr: Option<&MqAttr>) -> Result { - let attr_p = attr.map(|attr| attr as *const MqAttr).unwrap_or(ptr::null()); - let res = unsafe { ffi::mq_open(name.as_ptr(), oflag.bits(), mode.bits() as mode_t, attr_p) }; +pub fn mq_open(name: &CString, oflag: MQ_OFlag, mode: Mode, attr: Option<&MqAttr>) -> Result { + let res = match attr { + Some(mq_attr) => { + unsafe { libc::mq_open(name.as_ptr(), oflag.bits(), mode.bits() as mode_t, &mq_attr.mq_attr as *const libc::mq_attr) } + }, + None => { + unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) } + } + }; Errno::result(res) } pub fn mq_unlink(name: &CString) -> Result<()> { - let res = unsafe { ffi::mq_unlink(name.as_ptr()) }; + let res = unsafe { libc::mq_unlink(name.as_ptr()) }; Errno::result(res).map(drop) } -pub fn mq_close(mqdes: MQd) -> Result<()> { - let res = unsafe { ffi::mq_close(mqdes) }; +pub fn mq_close(mqdes: mqd_t) -> Result<()> { + let res = unsafe { libc::mq_close(mqdes) }; Errno::result(res).map(drop) } - -pub fn mq_receive(mqdes: MQd, message: &mut [u8], msq_prio: u32) -> Result { +pub fn mq_receive(mqdes: mqd_t, message: &mut [u8], msg_prio: &mut u32) -> Result { let len = message.len() as size_t; - let res = unsafe { ffi::mq_receive(mqdes, message.as_mut_ptr() as *mut c_char, len, &msq_prio) }; - + let res = unsafe { libc::mq_receive(mqdes, message.as_mut_ptr() as *mut c_char, len, msg_prio as *mut u32) }; Errno::result(res).map(|r| r as usize) } -pub fn mq_send(mqdes: MQd, message: &[u8], msq_prio: u32) -> Result<()> { - let res = unsafe { ffi::mq_send(mqdes, message.as_ptr() as *const c_char, message.len(), msq_prio) }; - +pub fn mq_send(mqdes: mqd_t, message: &[u8], msq_prio: u32) -> Result<()> { + let res = unsafe { libc::mq_send(mqdes, message.as_ptr() as *const c_char, message.len(), msq_prio) }; Errno::result(res).map(drop) } -pub fn mq_getattr(mqd: MQd) -> Result { - let mut attr = MqAttr::new(0, 0, 0, 0); - let res = unsafe { ffi::mq_getattr(mqd, &mut attr) }; - try!(Errno::result(res)); - Ok(attr) +pub fn mq_getattr(mqd: mqd_t) -> Result { + let mut attr = unsafe { mem::uninitialized::() }; + let res = unsafe { libc::mq_getattr(mqd, &mut attr) }; + Errno::result(res).map(|_| MqAttr { mq_attr: attr }) } /// Set the attributes of the message queue. Only `O_NONBLOCK` can be set, everything else will be ignored @@ -119,27 +104,26 @@ pub fn mq_getattr(mqd: MQd) -> Result { /// It is recommend to use the `mq_set_nonblock()` and `mq_remove_nonblock()` convenience functions as they are easier to use /// /// [Further reading](http://man7.org/linux/man-pages/man3/mq_setattr.3.html) -pub fn mq_setattr(mqd: MQd, newattr: &MqAttr) -> Result { - let mut attr = MqAttr::new(0, 0, 0, 0); - let res = unsafe { ffi::mq_setattr(mqd, newattr as *const MqAttr, &mut attr) }; - try!(Errno::result(res)); - Ok(attr) +pub fn mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result { + let mut attr = unsafe { mem::uninitialized::() }; + let res = unsafe { libc::mq_setattr(mqd, &newattr.mq_attr as *const libc::mq_attr, &mut attr) }; + Errno::result(res).map(|_| MqAttr { mq_attr: attr }) } /// Convenience function. /// Sets the `O_NONBLOCK` attribute for a given message queue descriptor /// Returns the old attributes -pub fn mq_set_nonblock(mqd: MQd) -> Result<(MqAttr)> { +pub fn mq_set_nonblock(mqd: mqd_t) -> Result<(MqAttr)> { let oldattr = try!(mq_getattr(mqd)); - let newattr = MqAttr::new(O_NONBLOCK.bits() as c_long, oldattr.mq_maxmsg, oldattr.mq_msgsize, oldattr.mq_curmsgs); + let newattr = MqAttr::new(O_NONBLOCK.bits() as c_long, oldattr.mq_attr.mq_maxmsg, oldattr.mq_attr.mq_msgsize, oldattr.mq_attr.mq_curmsgs); mq_setattr(mqd, &newattr) } /// Convenience function. /// Removes `O_NONBLOCK` attribute for a given message queue descriptor /// Returns the old attributes -pub fn mq_remove_nonblock(mqd: MQd) -> Result<(MqAttr)> { +pub fn mq_remove_nonblock(mqd: mqd_t) -> Result<(MqAttr)> { let oldattr = try!(mq_getattr(mqd)); - let newattr = MqAttr::new(0, oldattr.mq_maxmsg, oldattr.mq_msgsize, oldattr.mq_curmsgs); + let newattr = MqAttr::new(0, oldattr.mq_attr.mq_maxmsg, oldattr.mq_attr.mq_msgsize, oldattr.mq_attr.mq_curmsgs); mq_setattr(mqd, &newattr) } diff --git a/test/test_mq.rs b/test/test_mq.rs index 94431a04a0..fd050d47b1 100644 --- a/test/test_mq.rs +++ b/test/test_mq.rs @@ -33,7 +33,9 @@ fn test_mq_send_and_receive() { let mq_name_in_child = &CString::new(b"/a_nix_test_queue".as_ref()).unwrap(); let mqd_in_child = mq_open(mq_name_in_child, O_CREAT | O_RDONLY, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, Some(&attr)).unwrap(); let mut buf = [0u8; 32]; - mq_receive(mqd_in_child, &mut buf, 1).unwrap(); + let mut prio = 0u32; + mq_receive(mqd_in_child, &mut buf, &mut prio).unwrap(); + assert!(prio == 1); write(writer, &buf).unwrap(); // pipe result to parent process. Otherwise cargo does not report test failures correctly mq_close(mqd_in_child).unwrap(); } @@ -99,10 +101,10 @@ fn test_mq_set_nonblocking() { let mqd = mq_open(mq_name, O_CREAT | O_WRONLY, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, Some(&initial_attr)).unwrap(); mq_set_nonblock(mqd).unwrap(); let new_attr = mq_getattr(mqd); - assert!(new_attr.unwrap().mq_flags == O_NONBLOCK.bits() as c_long); + assert!(new_attr.unwrap().flags() == O_NONBLOCK.bits() as c_long); mq_remove_nonblock(mqd).unwrap(); let new_attr = mq_getattr(mqd); - assert!(new_attr.unwrap().mq_flags == 0); + assert!(new_attr.unwrap().flags() == 0); mq_close(mqd).unwrap(); } From 5d50193fb5761d3cd92eead0901f2642406d9339 Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Sat, 6 Aug 2016 09:46:38 +0200 Subject: [PATCH 10/49] Describe changes to mqueue in change log --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04e9322f64..1dfd04cc84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,18 @@ This project adheres to [Semantic Versioning](http://semver.org/). `::nix::sched` to `Result` and `Result<()>`, respectively. They now return `EINVAL`, if an invalid argument for the `field` parameter is passed. ([#402](https://github.com/nix-rust/nix/pull/402)) +- `MqAttr` in `::nix::mqueue` is now an opaque proxy for `::libc::mq_attr`, + which has the same structure as the old `MqAttr`. The field `mq_flags` of + `::libc::mq_attr` is readable using the new method `flags()` of `MqAttr`. + `MqAttr` also no longer implements `Debug`. + ([#0](https://github.com/nix-rust/nix/pull/0)) +- The parameter `msq_prio` of `mq_receive` with type `u32` in `::nix::mqueue` + was replaced by a parameter named `msg_prio` with type `&mut u32`, so that + the message priority can be obtained by the caller. + ([#0](https://github.com/nix-rust/nix/pull/0)) +- The type alias `MQd` in `::nix::queue` was replaced by the type alias + `libc::mqd_t`, both of which are aliases for the same type. + ([#0](https://github.com/nix-rust/nix/pull/0)) ### Removed - Type alias `SigNum` from `::nix::sys::signal`. From 8ed552100dc63589017f09adc0413235d3a89599 Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Sat, 6 Aug 2016 09:49:22 +0200 Subject: [PATCH 11/49] Run rustfmt on mqueue.rs --- src/mqueue.rs | 62 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/src/mqueue.rs b/src/mqueue.rs index 2dd2dbd963..9bf6e77edb 100644 --- a/src/mqueue.rs +++ b/src/mqueue.rs @@ -4,7 +4,7 @@ use {Errno, Result}; -use libc::{self, c_char,c_long,mode_t,mqd_t,size_t}; +use libc::{self, c_char, c_long, mode_t, mqd_t, size_t}; use std::ffi::CString; use sys::stat::Mode; use std::mem; @@ -30,28 +30,31 @@ libc_bitflags!{ #[repr(C)] #[derive(Clone, Copy)] pub struct MqAttr { - mq_attr: libc::mq_attr + mq_attr: libc::mq_attr, } impl PartialEq for MqAttr { fn eq(&self, other: &MqAttr) -> bool { let self_attr = self.mq_attr; let other_attr = other.mq_attr; - self_attr.mq_flags == other_attr.mq_flags && - self_attr.mq_maxmsg == other_attr.mq_maxmsg && - self_attr.mq_msgsize == other_attr.mq_msgsize && - self_attr.mq_curmsgs == other_attr.mq_curmsgs + self_attr.mq_flags == other_attr.mq_flags && self_attr.mq_maxmsg == other_attr.mq_maxmsg && + self_attr.mq_msgsize == other_attr.mq_msgsize && + self_attr.mq_curmsgs == other_attr.mq_curmsgs } } impl MqAttr { - pub fn new(mq_flags: c_long, mq_maxmsg: c_long, mq_msgsize: c_long, mq_curmsgs: c_long) -> MqAttr { + pub fn new(mq_flags: c_long, + mq_maxmsg: c_long, + mq_msgsize: c_long, + mq_curmsgs: c_long) + -> MqAttr { let mut attr = unsafe { mem::uninitialized::() }; attr.mq_flags = mq_flags; attr.mq_maxmsg = mq_maxmsg; attr.mq_msgsize = mq_msgsize; attr.mq_curmsgs = mq_curmsgs; - MqAttr{mq_attr: attr} + MqAttr { mq_attr: attr } } pub fn flags(&self) -> c_long { @@ -60,14 +63,19 @@ impl MqAttr { } -pub fn mq_open(name: &CString, oflag: MQ_OFlag, mode: Mode, attr: Option<&MqAttr>) -> Result { +pub fn mq_open(name: &CString, + oflag: MQ_OFlag, + mode: Mode, + attr: Option<&MqAttr>) + -> Result { let res = match attr { - Some(mq_attr) => { - unsafe { libc::mq_open(name.as_ptr(), oflag.bits(), mode.bits() as mode_t, &mq_attr.mq_attr as *const libc::mq_attr) } + Some(mq_attr) => unsafe { + libc::mq_open(name.as_ptr(), + oflag.bits(), + mode.bits() as mode_t, + &mq_attr.mq_attr as *const libc::mq_attr) }, - None => { - unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) } - } + None => unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) }, }; Errno::result(res) } @@ -77,19 +85,29 @@ pub fn mq_unlink(name: &CString) -> Result<()> { Errno::result(res).map(drop) } -pub fn mq_close(mqdes: mqd_t) -> Result<()> { +pub fn mq_close(mqdes: mqd_t) -> Result<()> { let res = unsafe { libc::mq_close(mqdes) }; Errno::result(res).map(drop) } pub fn mq_receive(mqdes: mqd_t, message: &mut [u8], msg_prio: &mut u32) -> Result { let len = message.len() as size_t; - let res = unsafe { libc::mq_receive(mqdes, message.as_mut_ptr() as *mut c_char, len, msg_prio as *mut u32) }; + let res = unsafe { + libc::mq_receive(mqdes, + message.as_mut_ptr() as *mut c_char, + len, + msg_prio as *mut u32) + }; Errno::result(res).map(|r| r as usize) } pub fn mq_send(mqdes: mqd_t, message: &[u8], msq_prio: u32) -> Result<()> { - let res = unsafe { libc::mq_send(mqdes, message.as_ptr() as *const c_char, message.len(), msq_prio) }; + let res = unsafe { + libc::mq_send(mqdes, + message.as_ptr() as *const c_char, + message.len(), + msq_prio) + }; Errno::result(res).map(drop) } @@ -115,7 +133,10 @@ pub fn mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result { /// Returns the old attributes pub fn mq_set_nonblock(mqd: mqd_t) -> Result<(MqAttr)> { let oldattr = try!(mq_getattr(mqd)); - let newattr = MqAttr::new(O_NONBLOCK.bits() as c_long, oldattr.mq_attr.mq_maxmsg, oldattr.mq_attr.mq_msgsize, oldattr.mq_attr.mq_curmsgs); + let newattr = MqAttr::new(O_NONBLOCK.bits() as c_long, + oldattr.mq_attr.mq_maxmsg, + oldattr.mq_attr.mq_msgsize, + oldattr.mq_attr.mq_curmsgs); mq_setattr(mqd, &newattr) } @@ -124,6 +145,9 @@ pub fn mq_set_nonblock(mqd: mqd_t) -> Result<(MqAttr)> { /// Returns the old attributes pub fn mq_remove_nonblock(mqd: mqd_t) -> Result<(MqAttr)> { let oldattr = try!(mq_getattr(mqd)); - let newattr = MqAttr::new(0, oldattr.mq_attr.mq_maxmsg, oldattr.mq_attr.mq_msgsize, oldattr.mq_attr.mq_curmsgs); + let newattr = MqAttr::new(0, + oldattr.mq_attr.mq_maxmsg, + oldattr.mq_attr.mq_msgsize, + oldattr.mq_attr.mq_curmsgs); mq_setattr(mqd, &newattr) } From f4a52b3640137116fb641a57cd0568721a7f27bc Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Wed, 31 Aug 2016 20:30:56 +0200 Subject: [PATCH 12/49] Document changes to poll.rs in CHANGELOG.md --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04e9322f64..933a771ea3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,12 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#407](https://github.com/nix-rust/nix/pull/407)) - Added `CpuSet::unset` in `::nix::sched`. ([#402](https://github.com/nix-rust/nix/pull/402)) +- Added constructor method `new()` to `PollFd` in `::nix::poll`, in order to + allow creation of objects, after removing public access to members. + ([#399](https://github.com/nix-rust/nix/pull/399)) +- Added method `revents()` to `PollFd` in `::nix::poll`, in order to provide + read access to formerly public member `revents`. + ([#399](https://github.com/nix-rust/nix/pull/399)) ### Changed - Replaced the reexported integer constants for signals by the enumeration @@ -40,6 +46,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#362](https://github.com/nix-rust/nix/pull/362)) - Type alias `CpuMask` from `::nix::shed`. ([#402](https://github.com/nix-rust/nix/pull/402)) +- Removed public fields from `PollFd` in `::nix::poll`. (See also added method + `revents()`. + ([#399](https://github.com/nix-rust/nix/pull/399)) ### Fixed - Fixed the build problem for NetBSD (Note, that we currently do not support From ac642737967525226dc36f43e6e99d58328d5c6c Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Fri, 2 Sep 2016 22:57:39 +0200 Subject: [PATCH 13/49] implemented getcwd (returning Result, reconciling all calls to expect into proper try handling), needs testing still --- src/unistd.rs | 42 +++++++++++++++++++++++++++++++++++++++++- test/test_unistd.rs | 5 +++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/unistd.rs b/src/unistd.rs index d4da60da68..34e9b6a93f 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -5,9 +5,10 @@ use fcntl::{fcntl, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC}; use fcntl::FcntlArg::{F_SETFD, F_SETFL}; use libc::{self, c_char, c_void, c_int, c_uint, size_t, pid_t, off_t, uid_t, gid_t}; use std::mem; -use std::ffi::CString; +use std::ffi::{CString,CStr}; use std::os::unix::io::RawFd; use void::Void; +use std::path::PathBuf; #[cfg(any(target_os = "linux", target_os = "android"))] pub use self::linux::*; @@ -111,6 +112,45 @@ pub fn chdir(path: &P) -> Result<()> { Errno::result(res).map(drop) } +// #[inline] +// pub fn mkdir(path: &P) -> Result<()> { +// Errno::result(0) +// } + +#[inline] +pub fn getcwd() -> Result { + let mut buf = Vec::with_capacity(512); + loop { + unsafe { + let ptr = buf.as_mut_ptr() as *mut libc::c_char; + + // The buffer must be large enough to store the absolute pathname plus + // a terminating null byte, or else null is returned. + // To safely handle this we start with a reasonable size (512 bytes) + // and double the buffer size upon every error + if !libc::getcwd(ptr, buf.capacity()).is_null() { + let len = CStr::from_ptr(ptr).to_bytes().len(); + buf.set_len(len); + buf.shrink_to_fit(); + let s = try!(CString::new(buf).map_err(|_| Error::Sys(Errno::EILSEQ))); + let s = try!(s.into_string().map_err(|_| Error::Sys(Errno::EILSEQ))); + return Ok(PathBuf::from(&s)); + } else { + let error = Errno::last(); + if error == Errno::ERANGE { + return Err(Error::Sys(error)); + } + } + + // Trigger the internal buffer resizing logic of `Vec` by requiring + // more space than the current capacity. + let cap = buf.capacity(); + buf.set_len(cap); + buf.reserve(1); + } + } +} + #[inline] pub fn chown(path: &P, owner: Option, group: Option) -> Result<()> { let res = try!(path.with_nix_path(|cstr| { diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 188bfbeba9..48891bc3e4 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -119,6 +119,11 @@ macro_rules! execve_test_factory( ) ); +#[test] +fn test_getcwd() { + println!("{}", getcwd().unwrap().display()); +} + #[test] fn test_lseek() { const CONTENTS: &'static [u8] = b"abcdef123456"; From b03d4e5ff22e0f8988dc8655c1e7dfcc3fe29f66 Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Sat, 3 Sep 2016 22:57:58 +0200 Subject: [PATCH 14/49] added test for getcwd, still not complete (needs to check also longer directory names, need to be created with mkdir first which doesn't exist yet) --- test/test_unistd.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 48891bc3e4..2b6182b626 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -1,3 +1,5 @@ +extern crate tempdir; + use nix::unistd::*; use nix::unistd::ForkResult::*; use nix::sys::wait::*; @@ -5,11 +7,10 @@ use std::ffi::CString; use std::io::{Write, Read}; use tempfile::tempfile; +use tempdir::TempDir; use libc::off_t; use std::os::unix::prelude::*; - - #[test] fn test_fork_and_waitpid() { let pid = fork(); @@ -121,7 +122,16 @@ macro_rules! execve_test_factory( #[test] fn test_getcwd() { - println!("{}", getcwd().unwrap().display()); + // workaround for the fact that on os x TmpDir::new returns /var/folders/... but upon + // chdir into that directory getcwd returns /private/var/folders/... + let base = if cfg!(target_os = "macos") { + "/private/tmp/" + } else { + "/tmp/" + }; + let tmp_dir = TempDir::new_in(base, "test_getcwd").expect("create temp dir").into_path(); + assert!(chdir(tmp_dir.as_path()).is_ok()); + assert_eq!(getcwd().unwrap(), tmp_dir); } #[test] From 8b1828a5cd7c133156fc2bac703136e6d5abd31d Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Mon, 5 Sep 2016 21:50:06 +0200 Subject: [PATCH 15/49] implemented mkdir, extended getcwd test to include long path names --- src/unistd.rs | 20 +++++++++++++------- test/test_unistd.rs | 15 ++++++++++++++- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index 34e9b6a93f..f8e1715311 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -3,12 +3,13 @@ use {Errno, Error, Result, NixPath}; use fcntl::{fcntl, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC}; use fcntl::FcntlArg::{F_SETFD, F_SETFL}; -use libc::{self, c_char, c_void, c_int, c_uint, size_t, pid_t, off_t, uid_t, gid_t}; +use libc::{self, c_char, c_void, c_int, c_uint, size_t, pid_t, off_t, uid_t, gid_t, mode_t}; use std::mem; use std::ffi::{CString,CStr}; +use std::path::PathBuf; use std::os::unix::io::RawFd; use void::Void; -use std::path::PathBuf; +use sys::stat::Mode; #[cfg(any(target_os = "linux", target_os = "android"))] pub use self::linux::*; @@ -112,10 +113,14 @@ pub fn chdir(path: &P) -> Result<()> { Errno::result(res).map(drop) } -// #[inline] -// pub fn mkdir(path: &P) -> Result<()> { -// Errno::result(0) -// } +#[inline] +pub fn mkdir(path: &P, mode: Mode) -> Result<()> { + let res = try!(path.with_nix_path(|cstr| { + unsafe { libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t) } + })); + + Errno::result(res).map(drop) +} #[inline] pub fn getcwd() -> Result { @@ -137,7 +142,8 @@ pub fn getcwd() -> Result { return Ok(PathBuf::from(&s)); } else { let error = Errno::last(); - if error == Errno::ERANGE { + // ERANGE means buffer was too small to store directory name + if error != Errno::ERANGE { return Err(Error::Sys(error)); } } diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 2b6182b626..26746426f6 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -3,6 +3,8 @@ extern crate tempdir; use nix::unistd::*; use nix::unistd::ForkResult::*; use nix::sys::wait::*; +use nix::sys::stat; +use std::iter; use std::ffi::CString; use std::io::{Write, Read}; @@ -129,7 +131,18 @@ fn test_getcwd() { } else { "/tmp/" }; - let tmp_dir = TempDir::new_in(base, "test_getcwd").expect("create temp dir").into_path(); + let mut tmp_dir = TempDir::new_in(base, "test_getcwd").expect("create temp dir").into_path(); + assert!(chdir(tmp_dir.as_path()).is_ok()); + assert_eq!(getcwd().unwrap(), tmp_dir); + + // make path 500 chars longer so that buffer doubling in getcwd kicks in. + // Note: One path cannot be longer than 255 bytes (NAME_MAX) + // whole path cannot be longer than PATH_MAX (usually 4096 on linux, 1024 on macos) + for _ in 0..5 { + let newdir = iter::repeat("a").take(100).collect::(); + tmp_dir.push(newdir); + assert!(mkdir(tmp_dir.as_path(), stat::S_IRWXU).is_ok()); + } assert!(chdir(tmp_dir.as_path()).is_ok()); assert_eq!(getcwd().unwrap(), tmp_dir); } From 8fbd8e91ff9ef518287bb4f2a012d3f62332f1ca Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Tue, 6 Sep 2016 17:17:21 +0200 Subject: [PATCH 16/49] made it running with rust 1.2.0: the code for getcwd is now an exact copy of the implementation in std --- src/unistd.rs | 9 ++++----- test/test_unistd.rs | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index f8e1715311..6c3a1ebf6c 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -5,7 +5,8 @@ use fcntl::{fcntl, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC}; use fcntl::FcntlArg::{F_SETFD, F_SETFL}; use libc::{self, c_char, c_void, c_int, c_uint, size_t, pid_t, off_t, uid_t, gid_t, mode_t}; use std::mem; -use std::ffi::{CString,CStr}; +use std::ffi::{CString,CStr,OsString}; +use std::os::unix::ffi::OsStringExt; use std::path::PathBuf; use std::os::unix::io::RawFd; use void::Void; @@ -134,12 +135,10 @@ pub fn getcwd() -> Result { // To safely handle this we start with a reasonable size (512 bytes) // and double the buffer size upon every error if !libc::getcwd(ptr, buf.capacity()).is_null() { - let len = CStr::from_ptr(ptr).to_bytes().len(); + let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len(); buf.set_len(len); buf.shrink_to_fit(); - let s = try!(CString::new(buf).map_err(|_| Error::Sys(Errno::EILSEQ))); - let s = try!(s.into_string().map_err(|_| Error::Sys(Errno::EILSEQ))); - return Ok(PathBuf::from(&s)); + return Ok(PathBuf::from(OsString::from_vec(buf))); } else { let error = Errno::last(); // ERANGE means buffer was too small to store directory name diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 26746426f6..06a9cd99ab 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -131,7 +131,7 @@ fn test_getcwd() { } else { "/tmp/" }; - let mut tmp_dir = TempDir::new_in(base, "test_getcwd").expect("create temp dir").into_path(); + let mut tmp_dir = TempDir::new_in(base, "test_getcwd").unwrap().into_path(); assert!(chdir(tmp_dir.as_path()).is_ok()); assert_eq!(getcwd().unwrap(), tmp_dir); From c0a578539a4ad6b1f8ad48b8e26fbacc0d55852d Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Tue, 6 Sep 2016 17:19:07 +0200 Subject: [PATCH 17/49] fixed the trailing whitespaces --- src/unistd.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index 6c3a1ebf6c..900be37975 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -144,7 +144,7 @@ pub fn getcwd() -> Result { // ERANGE means buffer was too small to store directory name if error != Errno::ERANGE { return Err(Error::Sys(error)); - } + } } // Trigger the internal buffer resizing logic of `Vec` by requiring @@ -153,7 +153,7 @@ pub fn getcwd() -> Result { buf.set_len(cap); buf.reserve(1); } - } + } } #[inline] From 50693c11b02f11e13687ee48f5a1e0131542d7f8 Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Tue, 6 Sep 2016 22:18:19 +0200 Subject: [PATCH 18/49] added documentation for getcwd and mkdir, changed test so that it compares against std::env::current_dir --- src/unistd.rs | 41 +++++++++++++++++++++++++++++++++++++++++ test/test_unistd.rs | 17 +++++------------ 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index 900be37975..52add2cdc2 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -114,6 +114,35 @@ pub fn chdir(path: &P) -> Result<()> { Errno::result(res).map(drop) } +/// Creates new directory `path` with access rights `mode`. +/// +/// # Errors +/// +/// `Err` is returned in case of an error. There are several situations where mkdir might fail. +/// For a full list consult `man mkdir(2)` +/// +/// - current user has insufficient rights in the parent directory +/// - the path already exists +/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X) +/// +/// # Example +/// +/// ```rust +/// extern crate tempdir; +/// extern crate nix; +/// +/// use nix::unistd; +/// use nix::sys::stat; +/// use tempdir::TempDir; +/// +/// fn main() { +/// let mut tmp_dir = TempDir::new("test_mkdir").unwrap().into_path(); +/// tmp_dir.push("new_dir"); +/// +/// // owner has read, write and execute rights on the new directory +/// unistd::mkdir(&tmp_dir, stat::S_IRWXU).expect("couldn't create directory"); +/// } +/// ``` #[inline] pub fn mkdir(path: &P, mode: Mode) -> Result<()> { let res = try!(path.with_nix_path(|cstr| { @@ -123,6 +152,18 @@ pub fn mkdir(path: &P, mode: Mode) -> Result<()> { Errno::result(res).map(drop) } +/// Returns the current directory as a PathBuf +/// +/// Err is returned if the current user doesn't have the permission to read or search a component of the current path. +/// +/// # Example +/// +/// ```rust +/// use nix::unistd; +/// +/// let dir = unistd::getcwd().expect("not allowed to get current directory"); +/// println!("The current directory is {:?}", dir.display()); +/// ``` #[inline] pub fn getcwd() -> Result { let mut buf = Vec::with_capacity(512); diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 06a9cd99ab..8e03c16569 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -6,12 +6,12 @@ use nix::sys::wait::*; use nix::sys::stat; use std::iter; use std::ffi::CString; - use std::io::{Write, Read}; +use std::os::unix::prelude::*; +use std::env::current_dir; use tempfile::tempfile; use tempdir::TempDir; use libc::off_t; -use std::os::unix::prelude::*; #[test] fn test_fork_and_waitpid() { @@ -124,16 +124,9 @@ macro_rules! execve_test_factory( #[test] fn test_getcwd() { - // workaround for the fact that on os x TmpDir::new returns /var/folders/... but upon - // chdir into that directory getcwd returns /private/var/folders/... - let base = if cfg!(target_os = "macos") { - "/private/tmp/" - } else { - "/tmp/" - }; - let mut tmp_dir = TempDir::new_in(base, "test_getcwd").unwrap().into_path(); + let mut tmp_dir = TempDir::new("test_getcwd").unwrap().into_path(); assert!(chdir(tmp_dir.as_path()).is_ok()); - assert_eq!(getcwd().unwrap(), tmp_dir); + assert_eq!(getcwd().unwrap(), current_dir().unwrap()); // make path 500 chars longer so that buffer doubling in getcwd kicks in. // Note: One path cannot be longer than 255 bytes (NAME_MAX) @@ -144,7 +137,7 @@ fn test_getcwd() { assert!(mkdir(tmp_dir.as_path(), stat::S_IRWXU).is_ok()); } assert!(chdir(tmp_dir.as_path()).is_ok()); - assert_eq!(getcwd().unwrap(), tmp_dir); + assert_eq!(getcwd().unwrap(), current_dir().unwrap()); } #[test] From 37e4f9756d7181e6b95f9b812874d582bfc2eec5 Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Tue, 6 Sep 2016 22:28:13 +0200 Subject: [PATCH 19/49] rust 1.2.0 doesn't support expect, switched to proper match block --- src/unistd.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index 52add2cdc2..d7bd3b91d3 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -139,8 +139,11 @@ pub fn chdir(path: &P) -> Result<()> { /// let mut tmp_dir = TempDir::new("test_mkdir").unwrap().into_path(); /// tmp_dir.push("new_dir"); /// -/// // owner has read, write and execute rights on the new directory -/// unistd::mkdir(&tmp_dir, stat::S_IRWXU).expect("couldn't create directory"); +/// // create new directory and give read, write and execute rights to the owner +/// match unistd::mkdir(&tmp_dir, stat::S_IRWXU) { +/// Ok(_) => println!("created {:?}", tmp_dir.display()), +/// Err(err) => println!("Error creating directory: {}", err), +/// } /// } /// ``` #[inline] From 5f1e144de965d10b61fbd2c8e3ac50c12099690a Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Wed, 7 Sep 2016 07:17:36 +0200 Subject: [PATCH 20/49] resolving all remarks by @posborne, fixed max line length=99, fixed rust 1.2.0 error in doc-test --- src/unistd.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index d7bd3b91d3..74d74c9c31 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -5,7 +5,7 @@ use fcntl::{fcntl, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC}; use fcntl::FcntlArg::{F_SETFD, F_SETFL}; use libc::{self, c_char, c_void, c_int, c_uint, size_t, pid_t, off_t, uid_t, gid_t, mode_t}; use std::mem; -use std::ffi::{CString,CStr,OsString}; +use std::ffi::{CString, CStr, OsString}; use std::os::unix::ffi::OsStringExt; use std::path::PathBuf; use std::os::unix::io::RawFd; @@ -118,13 +118,15 @@ pub fn chdir(path: &P) -> Result<()> { /// /// # Errors /// -/// `Err` is returned in case of an error. There are several situations where mkdir might fail. -/// For a full list consult `man mkdir(2)` +/// There are several situations where mkdir might fail: /// /// - current user has insufficient rights in the parent directory /// - the path already exists /// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X) /// +/// For a full list consult +/// [man mkdir(2)](http://man7.org/linux/man-pages/man2/mkdir.2.html#ERRORS) +/// /// # Example /// /// ```rust @@ -141,7 +143,7 @@ pub fn chdir(path: &P) -> Result<()> { /// /// // create new directory and give read, write and execute rights to the owner /// match unistd::mkdir(&tmp_dir, stat::S_IRWXU) { -/// Ok(_) => println!("created {:?}", tmp_dir.display()), +/// Ok(_) => println!("created {:?}", tmp_dir), /// Err(err) => println!("Error creating directory: {}", err), /// } /// } @@ -157,15 +159,21 @@ pub fn mkdir(path: &P, mode: Mode) -> Result<()> { /// Returns the current directory as a PathBuf /// -/// Err is returned if the current user doesn't have the permission to read or search a component of the current path. +/// Err is returned if the current user doesn't have the permission to read or search a component +/// of the current path. /// /// # Example /// /// ```rust +/// extern crate nix; +/// /// use nix::unistd; /// -/// let dir = unistd::getcwd().expect("not allowed to get current directory"); -/// println!("The current directory is {:?}", dir.display()); +/// fn main() { +/// // assume that we are allowed to get current directory +/// let dir = unistd::getcwd().unwrap(); +/// println!("The current directory is {:?}", dir); +/// } /// ``` #[inline] pub fn getcwd() -> Result { From 7dd12c6b87d79f8eb1828ecabedf1165b650493d Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Wed, 7 Sep 2016 08:21:56 +0200 Subject: [PATCH 21/49] fixed indentation --- test/test_unistd.rs | 90 ++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 8e03c16569..f7bbe0bfca 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -17,25 +17,25 @@ use libc::off_t; fn test_fork_and_waitpid() { let pid = fork(); match pid { - Ok(Child) => {} // ignore child here - Ok(Parent { child }) => { - // assert that child was created and pid > 0 - assert!(child > 0); - let wait_status = waitpid(child, None); - match wait_status { - // assert that waitpid returned correct status and the pid is the one of the child - Ok(WaitStatus::Exited(pid_t, _)) => assert!(pid_t == child), - - // panic, must never happen - Ok(_) => panic!("Child still alive, should never happen"), - - // panic, waitpid should never fail - Err(_) => panic!("Error: waitpid Failed") - } - - }, - // panic, fork should never fail unless there is a serious problem with the OS - Err(_) => panic!("Error: Fork Failed") + Ok(Child) => {} // ignore child here + Ok(Parent { child }) => { + // assert that child was created and pid > 0 + assert!(child > 0); + let wait_status = waitpid(child, None); + match wait_status { + // assert that waitpid returned correct status and the pid is the one of the child + Ok(WaitStatus::Exited(pid_t, _)) => assert!(pid_t == child), + + // panic, must never happen + Ok(_) => panic!("Child still alive, should never happen"), + + // panic, waitpid should never fail + Err(_) => panic!("Error: waitpid Failed") + } + + }, + // panic, fork should never fail unless there is a serious problem with the OS + Err(_) => panic!("Error: Fork Failed") } } @@ -43,15 +43,15 @@ fn test_fork_and_waitpid() { fn test_wait() { let pid = fork(); match pid { - Ok(Child) => {} // ignore child here - Ok(Parent { child }) => { - let wait_status = wait(); - - // just assert that (any) one child returns with WaitStatus::Exited - assert_eq!(wait_status, Ok(WaitStatus::Exited(child, 0))); - }, - // panic, fork should never fail unless there is a serious problem with the OS - Err(_) => panic!("Error: Fork Failed") + Ok(Child) => {} // ignore child here + Ok(Parent { child }) => { + let wait_status = wait(); + + // just assert that (any) one child returns with WaitStatus::Exited + assert_eq!(wait_status, Ok(WaitStatus::Exited(child, 0))); + }, + // panic, fork should never fail unless there is a serious problem with the OS + Err(_) => panic!("Error: Fork Failed") } } @@ -124,20 +124,20 @@ macro_rules! execve_test_factory( #[test] fn test_getcwd() { - let mut tmp_dir = TempDir::new("test_getcwd").unwrap().into_path(); - assert!(chdir(tmp_dir.as_path()).is_ok()); - assert_eq!(getcwd().unwrap(), current_dir().unwrap()); - - // make path 500 chars longer so that buffer doubling in getcwd kicks in. - // Note: One path cannot be longer than 255 bytes (NAME_MAX) - // whole path cannot be longer than PATH_MAX (usually 4096 on linux, 1024 on macos) - for _ in 0..5 { - let newdir = iter::repeat("a").take(100).collect::(); - tmp_dir.push(newdir); - assert!(mkdir(tmp_dir.as_path(), stat::S_IRWXU).is_ok()); - } - assert!(chdir(tmp_dir.as_path()).is_ok()); - assert_eq!(getcwd().unwrap(), current_dir().unwrap()); + let mut tmp_dir = TempDir::new("test_getcwd").unwrap().into_path(); + assert!(chdir(tmp_dir.as_path()).is_ok()); + assert_eq!(getcwd().unwrap(), current_dir().unwrap()); + + // make path 500 chars longer so that buffer doubling in getcwd kicks in. + // Note: One path cannot be longer than 255 bytes (NAME_MAX) + // whole path cannot be longer than PATH_MAX (usually 4096 on linux, 1024 on macos) + for _ in 0..5 { + let newdir = iter::repeat("a").take(100).collect::(); + tmp_dir.push(newdir); + assert!(mkdir(tmp_dir.as_path(), stat::S_IRWXU).is_ok()); + } + assert!(chdir(tmp_dir.as_path()).is_ok()); + assert_eq!(getcwd().unwrap(), current_dir().unwrap()); } #[test] @@ -150,10 +150,10 @@ fn test_lseek() { lseek(tmp.as_raw_fd(), offset, Whence::SeekSet).unwrap(); let mut buf = String::new(); - tmp.read_to_string(&mut buf).unwrap(); - assert_eq!(b"f123456", buf.as_bytes()); + tmp.read_to_string(&mut buf).unwrap(); + assert_eq!(b"f123456", buf.as_bytes()); - close(tmp.as_raw_fd()).unwrap(); + close(tmp.as_raw_fd()).unwrap(); } #[cfg(any(target_os = "linux", target_os = "android"))] From 8557e9fb8c8d49fd9ae669d92d298f723d5429d6 Mon Sep 17 00:00:00 2001 From: Kamal Marhubi Date: Wed, 7 Sep 2016 20:32:59 -0400 Subject: [PATCH 22/49] Expand on release procedure --- RELEASE_PROCEDURE.md | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/RELEASE_PROCEDURE.md b/RELEASE_PROCEDURE.md index 2613ce5a8c..80972d5b04 100644 --- a/RELEASE_PROCEDURE.md +++ b/RELEASE_PROCEDURE.md @@ -3,16 +3,36 @@ library. # Before Release -The release is prepared by a commit with the following changes. +Based on changes since the last release, pick a new version number +following semver conventions. For nix, a change that drops support for +some Rust versions counts as a breaking change, and requires a major bump. -- In CHANGELOG.md, rename the Unreleased section to the new version followed by - the date of the release. +The release is prepared as follows: + +- Make a commit with a message like "Release v0.8.3" with the following + changes: + - In `CHANGELOG.md`, rename the Unreleased section to the new version + followed by the date of the release. + - In `Cargo.toml`, update the version to the new version. + - In `README.md`, update the version in the Usage section to the new + version. +- Make a pull request. +- Once the PR is merged, tag the merge commit, eg `git tag v0.8.3 + $MERGE_COMMIT_SHA1`. +- Push the tag, eg `git push v0.8.3`. # Create Release +- Checkout the tag. +- Publish to crates.io with `cargo publish`. + # After Release After the release a commit with the following changes is added to the master branch. - Add a new Unreleased section header to CHANGELOG.md. +- In `Cargo.toml`, update the version to the next `-dev` version, eg + `v0.8.4-dev`. +- Commit with a message like "Bump to v0.8.4-dev" +- Make a pull request. From e9ede5d78f009e98207aec75326c798b6ee77f5c Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Thu, 8 Sep 2016 21:22:17 +0200 Subject: [PATCH 23/49] Mention the libc version changes in RELEASE_PROCEDURE.md --- RELEASE_PROCEDURE.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RELEASE_PROCEDURE.md b/RELEASE_PROCEDURE.md index 80972d5b04..ba107cb558 100644 --- a/RELEASE_PROCEDURE.md +++ b/RELEASE_PROCEDURE.md @@ -9,11 +9,13 @@ some Rust versions counts as a breaking change, and requires a major bump. The release is prepared as follows: +- Ask for a new libc version if, necessary. It usually is. - Make a commit with a message like "Release v0.8.3" with the following changes: - In `CHANGELOG.md`, rename the Unreleased section to the new version followed by the date of the release. - In `Cargo.toml`, update the version to the new version. + - In `Cargo.toml`, change the libc dependency to the latest version. - In `README.md`, update the version in the Usage section to the new version. - Make a pull request. @@ -34,5 +36,6 @@ branch. - Add a new Unreleased section header to CHANGELOG.md. - In `Cargo.toml`, update the version to the next `-dev` version, eg `v0.8.4-dev`. +- In `Cargo.tml`, revert the libc dependency to its git master branch. - Commit with a message like "Bump to v0.8.4-dev" - Make a pull request. From 7508fd3596b448497681e4a93fcb616939153a9c Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Sun, 10 Jul 2016 02:32:11 +0900 Subject: [PATCH 24/49] Add epoll_create1 and set EPOLL_CLOEXEC flag by default. --- src/sys/epoll.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index 2090a0df1c..67449e8783 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -8,11 +8,19 @@ mod ffi { extern { pub fn epoll_create(size: c_int) -> c_int; + pub fn epoll_create1(flags: c_int) -> c_int; pub fn epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: *const EpollEvent) -> c_int; pub fn epoll_wait(epfd: c_int, events: *mut EpollEvent, max_events: c_int, timeout: c_int) -> c_int; } } +bitflags!( + flags EpollFdFlag: c_int { + const EPOLL_NONBLOCK = 0x800, + const EPOLL_CLOEXEC = 0x80000 + } +); + bitflags!( #[repr(C)] flags EpollEventKind: u32 { @@ -79,6 +87,13 @@ pub fn epoll_create() -> Result { Errno::result(res) } +#[inline] +pub fn epoll_create1(flags: EpollFdFlag) -> Result { + let res = unsafe { ffi::epoll_create1(flags.bits() | EPOLL_CLOEXEC.bits) }; + + Errno::result(res) +} + #[inline] pub fn epoll_ctl(epfd: RawFd, op: EpollOp, fd: RawFd, event: &EpollEvent) -> Result<()> { let res = unsafe { ffi::epoll_ctl(epfd, op as c_int, fd, event as *const EpollEvent) }; From 26d211710ca4f0ad8b8e8d3e3284d253d953aef5 Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Sun, 10 Jul 2016 04:02:37 +0900 Subject: [PATCH 25/49] Not to set EPOLL_CLOEXEC by default. --- src/sys/epoll.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index 67449e8783..af938bd3a7 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -89,7 +89,7 @@ pub fn epoll_create() -> Result { #[inline] pub fn epoll_create1(flags: EpollFdFlag) -> Result { - let res = unsafe { ffi::epoll_create1(flags.bits() | EPOLL_CLOEXEC.bits) }; + let res = unsafe { ffi::epoll_create1(flags.bits()) }; Errno::result(res) } From dfcf1266769a26004d956aecefa979a0a39a4962 Mon Sep 17 00:00:00 2001 From: Hiroki Noda Date: Sat, 23 Jul 2016 14:33:12 +0900 Subject: [PATCH 26/49] Use libc's declarations --- src/sys/epoll.rs | 65 ++++++------------------------------------------ 1 file changed, 8 insertions(+), 57 deletions(-) diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index af938bd3a7..9b30f993eb 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -1,26 +1,7 @@ use {Errno, Result}; -use libc::c_int; +use libc::{self, c_int}; use std::os::unix::io::RawFd; -mod ffi { - use libc::{c_int}; - use super::EpollEvent; - - extern { - pub fn epoll_create(size: c_int) -> c_int; - pub fn epoll_create1(flags: c_int) -> c_int; - pub fn epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: *const EpollEvent) -> c_int; - pub fn epoll_wait(epfd: c_int, events: *mut EpollEvent, max_events: c_int, timeout: c_int) -> c_int; - } -} - -bitflags!( - flags EpollFdFlag: c_int { - const EPOLL_NONBLOCK = 0x800, - const EPOLL_CLOEXEC = 0x80000 - } -); - bitflags!( #[repr(C)] flags EpollEventKind: u32 { @@ -50,61 +31,31 @@ pub enum EpollOp { EpollCtlMod = 3 } -#[cfg(not(target_arch = "x86_64"))] -#[derive(Clone, Copy)] -#[repr(C)] -pub struct EpollEvent { - pub events: EpollEventKind, - pub data: u64 -} - -#[cfg(target_arch = "x86_64")] -#[derive(Clone, Copy)] -#[repr(C, packed)] -pub struct EpollEvent { - pub events: EpollEventKind, - pub data: u64 -} - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -#[test] -fn test_epoll_event_size() { - use std::mem::size_of; - assert_eq!(size_of::(), 12); -} - -#[cfg(target_arch = "arm")] -#[test] -fn test_epoll_event_size() { - use std::mem::size_of; - assert_eq!(size_of::(), 16); -} - #[inline] pub fn epoll_create() -> Result { - let res = unsafe { ffi::epoll_create(1024) }; + let res = unsafe { libc::epoll_create(1024) }; Errno::result(res) } #[inline] -pub fn epoll_create1(flags: EpollFdFlag) -> Result { - let res = unsafe { ffi::epoll_create1(flags.bits()) }; +pub fn epoll_create1(flags: c_int) -> Result { + let res = unsafe { libc::epoll_create1(flags) }; Errno::result(res) } #[inline] -pub fn epoll_ctl(epfd: RawFd, op: EpollOp, fd: RawFd, event: &EpollEvent) -> Result<()> { - let res = unsafe { ffi::epoll_ctl(epfd, op as c_int, fd, event as *const EpollEvent) }; +pub fn epoll_ctl(epfd: RawFd, op: EpollOp, fd: RawFd, event: &mut libc::epoll_event) -> Result<()> { + let res = unsafe { libc::epoll_ctl(epfd, op as c_int, fd, event as *mut libc::epoll_event) }; Errno::result(res).map(drop) } #[inline] -pub fn epoll_wait(epfd: RawFd, events: &mut [EpollEvent], timeout_ms: isize) -> Result { +pub fn epoll_wait(epfd: RawFd, events: &mut [libc::epoll_event], timeout_ms: isize) -> Result { let res = unsafe { - ffi::epoll_wait(epfd, events.as_mut_ptr(), events.len() as c_int, timeout_ms as c_int) + libc::epoll_wait(epfd, events.as_mut_ptr(), events.len() as c_int, timeout_ms as c_int) }; Errno::result(res).map(|r| r as usize) From da36438f5bef8f885fb3ea9269b73ba85df32a07 Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Wed, 31 Aug 2016 21:05:35 +0200 Subject: [PATCH 27/49] Readd EpollEvent --- src/sys/epoll.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index 9b30f993eb..2cdc663859 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -31,6 +31,18 @@ pub enum EpollOp { EpollCtlMod = 3 } +#[derive(Clone, Copy)] +#[repr(C)] +pub struct EpollEvent { + event: libc::epoll_event, +} + +impl EpollEvent { + fn new(events: EpollEventKind, data: u64) -> EpollEvent { + EpollEvent { event: libc::epoll_event { events: events.bits(), u64: data } } + } +} + #[inline] pub fn epoll_create() -> Result { let res = unsafe { libc::epoll_create(1024) }; @@ -46,16 +58,16 @@ pub fn epoll_create1(flags: c_int) -> Result { } #[inline] -pub fn epoll_ctl(epfd: RawFd, op: EpollOp, fd: RawFd, event: &mut libc::epoll_event) -> Result<()> { - let res = unsafe { libc::epoll_ctl(epfd, op as c_int, fd, event as *mut libc::epoll_event) }; +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) } #[inline] -pub fn epoll_wait(epfd: RawFd, events: &mut [libc::epoll_event], timeout_ms: isize) -> Result { +pub fn epoll_wait(epfd: RawFd, events: &mut [EpollEvent], timeout_ms: isize) -> Result { let res = unsafe { - libc::epoll_wait(epfd, events.as_mut_ptr(), events.len() as c_int, timeout_ms as c_int) + libc::epoll_wait(epfd, events.as_mut_ptr() as *mut libc::epoll_event, events.len() as c_int, timeout_ms as c_int) }; Errno::result(res).map(|r| r as usize) From 584794d79125f65537d993ae8acd1ea9e981ad0a Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Thu, 8 Sep 2016 21:14:46 +0200 Subject: [PATCH 28/49] Add property readers to EpollEvent --- src/sys/epoll.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index 2cdc663859..51f789a243 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -38,9 +38,17 @@ pub struct EpollEvent { } impl EpollEvent { - fn new(events: EpollEventKind, data: u64) -> EpollEvent { + pub fn new(events: EpollEventKind, data: u64) -> EpollEvent { EpollEvent { event: libc::epoll_event { events: events.bits(), u64: data } } } + + pub fn events(&self) -> EpollEventKind { + EpollEventKind::from_bits(self.event.events).unwrap() + } + + pub fn data(&self) -> u64 { + self.event.u64 + } } #[inline] From 6bd4fd622d4837568443f5efbd0fd4deb2784e4d Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Fri, 9 Sep 2016 06:54:35 +0200 Subject: [PATCH 29/49] described changes done in #416 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 209da157dc..ba976e7e52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - Added `lseek` and `lseek64` in `::nix::unistd` ([#377](https://github.com/nix-rust/nix/pull/377)) +- Added `mkdir` and `getcwd` in `::nix::unistd` + ([#416](https://github.com/nix-rust/nix/pull/416)) - Added accessors `sigmask_mut` and `sigmask` to `UContext` in `::nix::ucontext`. ([#370](https://github.com/nix-rust/nix/pull/370)) From 0f9cc0589c7b31d3e7dd789834d128b1e5508c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 9 Sep 2016 18:11:01 +0300 Subject: [PATCH 30/49] Add MSG_CMSG_CLOEXEC to MsgFlags on Linux Fixes #421. --- src/sys/socket/consts.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sys/socket/consts.rs b/src/sys/socket/consts.rs index aeeea5c3fe..63eaf28a01 100644 --- a/src/sys/socket/consts.rs +++ b/src/sys/socket/consts.rs @@ -98,6 +98,7 @@ mod os { const MSG_DONTWAIT = 0x0040, const MSG_EOR = 0x0080, const MSG_ERRQUEUE = 0x2000, + const MSG_CMSG_CLOEXEC = 0x40000000, } } From 6ddc7b6c023416fa17e3f40f94c68a72b567a649 Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Fri, 9 Sep 2016 20:24:57 +0200 Subject: [PATCH 31/49] Add note to CHANGELOG.md for PR #422. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba976e7e52..cfb01c7e2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added method `revents()` to `PollFd` in `::nix::poll`, in order to provide read access to formerly public member `revents`. ([#399](https://github.com/nix-rust/nix/pull/399)) +- Added `MSG_CMSG_CLOEXEC` to `MsgFlags` in `::nix::sys::socket` for _linux_ only. + ([#422](https://github.com/nix-rust/nix/pull/422)) ### Changed - Replaced the reexported integer constants for signals by the enumeration From 60370990485092b4d7cbe625b964001e912dea9a Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Fri, 9 Sep 2016 20:32:45 +0200 Subject: [PATCH 32/49] Release v0.7.0 --- CHANGELOG.md | 2 +- Cargo.toml | 4 ++-- README.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfb01c7e2e..0b4d7b03b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -## [Unreleased] +## [0.7.0] 2016-09-09 ### Added - Added `lseek` and `lseek64` in `::nix::unistd` diff --git a/Cargo.toml b/Cargo.toml index 86027b2c64..45c8470c85 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" -version = "0.6.1-pre" +version = "0.7.0" authors = ["Carl Lerche "] homepage = "https://github.com/nix-rust/nix" repository = "https://github.com/nix-rust/nix" @@ -23,7 +23,7 @@ preadv_pwritev = [] signalfd = [] [dependencies] -libc = { git = "https://github.com/rust-lang/libc" } +libc = "0.2.16" bitflags = "0.4" cfg-if = "0.1.0" void = "1.0.2" diff --git a/README.md b/README.md index d9d1dbfb99..20753af764 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ To use `nix`, first add this to your `Cargo.toml`: ```toml [dependencies] -nix = "0.6.0" +nix = "0.7.0" ``` Then, add this to your crate root: From d060cadda07fd2b74632e980411c0f99d2bd5223 Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Fri, 9 Sep 2016 21:28:52 +0200 Subject: [PATCH 33/49] Bump to 0.7.1-pre --- CHANGELOG.md | 2 ++ Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b4d7b03b5..4238ed7402 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [Unreleased] + ## [0.7.0] 2016-09-09 ### Added diff --git a/Cargo.toml b/Cargo.toml index 45c8470c85..9302181c9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "nix" description = "Rust friendly bindings to *nix APIs" -version = "0.7.0" +version = "0.7.1-pre" authors = ["Carl Lerche "] homepage = "https://github.com/nix-rust/nix" repository = "https://github.com/nix-rust/nix" @@ -23,7 +23,7 @@ preadv_pwritev = [] signalfd = [] [dependencies] -libc = "0.2.16" +libc = { git = "https://github.com/rust-lang/libc" } bitflags = "0.4" cfg-if = "0.1.0" void = "1.0.2" From f8d5f3823c29d91184530bb42523a191c4f0d666 Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Fri, 9 Sep 2016 21:32:12 +0200 Subject: [PATCH 34/49] Small fixes to RELEASE_PROCEDURE.md --- RELEASE_PROCEDURE.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASE_PROCEDURE.md b/RELEASE_PROCEDURE.md index ba107cb558..14496f2388 100644 --- a/RELEASE_PROCEDURE.md +++ b/RELEASE_PROCEDURE.md @@ -19,9 +19,9 @@ The release is prepared as follows: - In `README.md`, update the version in the Usage section to the new version. - Make a pull request. -- Once the PR is merged, tag the merge commit, eg `git tag v0.8.3 +- Once the PR is merged, tag the merge commit, e.g. `git tag v0.8.3 $MERGE_COMMIT_SHA1`. -- Push the tag, eg `git push v0.8.3`. +- Push the tag, e.g. `git push origin v0.8.3`. # Create Release @@ -34,7 +34,7 @@ After the release a commit with the following changes is added to the master branch. - Add a new Unreleased section header to CHANGELOG.md. -- In `Cargo.toml`, update the version to the next `-dev` version, eg +- In `Cargo.toml`, update the version to the next `-dev` version, e.g. `v0.8.4-dev`. - In `Cargo.tml`, revert the libc dependency to its git master branch. - Commit with a message like "Bump to v0.8.4-dev" From 71688a082a042d5c8313491bc5f3f88fcf42f854 Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Wed, 14 Sep 2016 15:48:57 -0700 Subject: [PATCH 35/49] call pipe2 directly on Linux --- src/unistd.rs | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index 74d74c9c31..2f8aa5230a 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -1,8 +1,8 @@ //! Standard symbolic constants and types //! use {Errno, Error, Result, NixPath}; -use fcntl::{fcntl, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC}; -use fcntl::FcntlArg::{F_SETFD, F_SETFL}; +use 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}; @@ -360,6 +360,25 @@ pub fn pipe() -> Result<(RawFd, RawFd)> { } } +// libc only defines `pipe2` in `libc::notbsd`. +#[cfg(any(target_os = "linux", + target_os = "android", + target_os = "emscripten"))] +pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { + unsafe { + let mut fds: [c_int; 2] = mem::uninitialized(); + + let res = libc::pipe2(fds.as_mut_ptr(), flags.bits()); + + try!(Errno::result(res)); + + Ok((fds[0], fds[1])) + } +} + +#[cfg(not(any(target_os = "linux", + target_os = "android", + target_os = "emscripten")))] pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { unsafe { let mut fds: [c_int; 2] = mem::uninitialized(); @@ -374,7 +393,13 @@ pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { } } +#[cfg(not(any(target_os = "linux", + target_os = "android", + target_os = "emscripten")))] fn pipe2_setflags(fd1: RawFd, fd2: RawFd, flags: OFlag) -> Result<()> { + use fcntl::O_NONBLOCK; + use fcntl::FcntlArg::F_SETFL; + let mut res = Ok(0); if flags.contains(O_CLOEXEC) { From b28005f658129f9130d44ad63b38a74ff2b6e69d Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Thu, 15 Sep 2016 09:52:38 -0700 Subject: [PATCH 36/49] make unsafe code more fine-grained in pipe2 --- src/unistd.rs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index 2f8aa5230a..1b2175ea3e 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -365,32 +365,28 @@ pub fn pipe() -> Result<(RawFd, RawFd)> { target_os = "android", target_os = "emscripten"))] pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { - unsafe { - let mut fds: [c_int; 2] = mem::uninitialized(); + let mut fds: [c_int; 2] = unsafe { mem::uninitialized() }; - let res = libc::pipe2(fds.as_mut_ptr(), flags.bits()); + let res = unsafe { libc::pipe2(fds.as_mut_ptr(), flags.bits()) }; - try!(Errno::result(res)); + try!(Errno::result(res)); - Ok((fds[0], fds[1])) - } + Ok((fds[0], fds[1])) } #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "emscripten")))] pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { - unsafe { - let mut fds: [c_int; 2] = mem::uninitialized(); + let mut fds: [c_int; 2] = unsafe { mem::uninitialized() }; - let res = libc::pipe(fds.as_mut_ptr()); + let res = unsafe { libc::pipe(fds.as_mut_ptr()) }; - try!(Errno::result(res)); + try!(Errno::result(res)); - try!(pipe2_setflags(fds[0], fds[1], flags)); + try!(pipe2_setflags(fds[0], fds[1], flags)); - Ok((fds[0], fds[1])) - } + Ok((fds[0], fds[1])) } #[cfg(not(any(target_os = "linux", From c9edda389b5edba97165c887aea6f4e5d11541a2 Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Thu, 15 Sep 2016 22:07:43 +0200 Subject: [PATCH 37/49] Add EpollCrateFlags bitflag type. --- src/sys/epoll.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index 51f789a243..8e18d8576a 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -31,6 +31,12 @@ pub enum EpollOp { EpollCtlMod = 3 } +libc_bitflags!{ + flags EpollCreateFlags: c_int { + EPOLL_CLOEXEC, + } +} + #[derive(Clone, Copy)] #[repr(C)] pub struct EpollEvent { @@ -59,8 +65,8 @@ pub fn epoll_create() -> Result { } #[inline] -pub fn epoll_create1(flags: c_int) -> Result { - let res = unsafe { libc::epoll_create1(flags) }; +pub fn epoll_create1(flags: EpollCreateFlags) -> Result { + let res = unsafe { libc::epoll_create1(flags.bits()) }; Errno::result(res) } From 2b0c9919acf1aa4abf5f1b1d998c4d7404284fcc Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Thu, 15 Sep 2016 22:08:04 +0200 Subject: [PATCH 38/49] Rename EpollEventKind to EpollFlags, according to convention. --- src/sys/epoll.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index 8e18d8576a..9774318f46 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -4,7 +4,7 @@ use std::os::unix::io::RawFd; bitflags!( #[repr(C)] - flags EpollEventKind: u32 { + flags EpollFlags: u32 { const EPOLLIN = 0x001, const EPOLLPRI = 0x002, const EPOLLOUT = 0x004, @@ -44,12 +44,12 @@ pub struct EpollEvent { } impl EpollEvent { - pub fn new(events: EpollEventKind, data: u64) -> EpollEvent { + pub fn new(events: EpollFlags, data: u64) -> EpollEvent { EpollEvent { event: libc::epoll_event { events: events.bits(), u64: data } } } - pub fn events(&self) -> EpollEventKind { - EpollEventKind::from_bits(self.event.events).unwrap() + pub fn events(&self) -> EpollFlags { + EpollFlags::from_bits(self.event.events).unwrap() } pub fn data(&self) -> u64 { From 40a6cafdffc21debba6a6a459766059bf9e32a06 Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Thu, 15 Sep 2016 13:32:19 -0700 Subject: [PATCH 39/49] add a CHANGELOG entry for pipe2 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4238ed7402..1d7c461920 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed +- `pipe2` now calls `libc::pipe2` where available. Previously it was emulated + using `pipe`, which meant that setting `O_CLOEXEC` was not atomic. + ## [0.7.0] 2016-09-09 ### Added From 1d262d0541c729df94351b73eef0957785d28d85 Mon Sep 17 00:00:00 2001 From: Jack O'Connor Date: Thu, 15 Sep 2016 14:43:42 -0700 Subject: [PATCH 40/49] add a GitHub link to the CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d7c461920..3f8f54de2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Changed - `pipe2` now calls `libc::pipe2` where available. Previously it was emulated using `pipe`, which meant that setting `O_CLOEXEC` was not atomic. + ([#427](https://github.com/nix-rust/nix/pull/427)) ## [0.7.0] 2016-09-09 From 80df83be2024e710c63cd0676ec46f1d2eafc6b0 Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Fri, 16 Sep 2016 17:19:14 +0200 Subject: [PATCH 41/49] fixing build for aarch64-unknown-linux-gnu (which expects the pointer to be *mut u8 whereas x86_64 and i686 expect it to be *mut i8) --- src/unistd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unistd.rs b/src/unistd.rs index 2eb218b314..2b1912c1fc 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -537,7 +537,7 @@ pub fn sleep(seconds: libc::c_uint) -> c_uint { pub fn mkstemp(template: &P) -> Result<(RawFd, PathBuf)> { let res = template.with_nix_path(|path| { let mut path_copy = path.to_bytes_with_nul().to_owned(); - let p: *mut i8 = path_copy.as_mut_ptr() as *mut i8; + let p = path_copy.as_mut_ptr() as *mut _; unsafe { (libc::mkstemp(p), OsStr::from_bytes(CStr::from_ptr(p).to_bytes())) } From 26e1b6d78563e75977c8023179b490516fb2516b Mon Sep 17 00:00:00 2001 From: Mathias Svensson Date: Sat, 17 Sep 2016 19:23:49 +0200 Subject: [PATCH 42/49] Fixed a bug where UnixAddr::new_abstract forgot to count the null-byte. --- src/sys/socket/addr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 22970d8bdc..e3c1401c5b 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -391,7 +391,7 @@ impl UnixAddr { .. mem::zeroed() }; - if path.len() > ret.sun_path.len() { + if path.len() + 1 > ret.sun_path.len() { return Err(Error::Sys(Errno::ENAMETOOLONG)); } @@ -401,7 +401,7 @@ impl UnixAddr { ret.sun_path.as_mut_ptr().offset(1) as *mut u8, path.len()); - Ok(UnixAddr(ret, path.len())) + Ok(UnixAddr(ret, path.len() + 1)) } } From 1f2d896b9692f138e4c0cfa116deb4d34ab893ea Mon Sep 17 00:00:00 2001 From: Tim Ryan Date: Sat, 17 Sep 2016 23:50:58 +0200 Subject: [PATCH 43/49] Removes SIGSTKFLT when cross-compiling to MIPS. --- src/sys/signal.rs | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index 18827332bc..bdc25b47e6 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -28,7 +28,7 @@ pub enum Signal { SIGPIPE = libc::SIGPIPE, SIGALRM = libc::SIGALRM, SIGTERM = libc::SIGTERM, - #[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))] + #[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(target_arch = "mips")))] SIGSTKFLT = libc::SIGSTKFLT, SIGCHLD = libc::SIGCHLD, SIGCONT = libc::SIGCONT, @@ -54,7 +54,7 @@ pub enum Signal { pub use self::Signal::*; -#[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))] +#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(target_arch = "mips")))] const SIGNALS: [Signal; 31] = [ SIGHUP, SIGINT, @@ -87,6 +87,38 @@ const SIGNALS: [Signal; 31] = [ SIGIO, SIGPWR, SIGSYS]; +#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), target_arch = "mips"))] +const SIGNALS: [Signal; 30] = [ + SIGHUP, + SIGINT, + SIGQUIT, + SIGILL, + SIGTRAP, + SIGABRT, + SIGBUS, + SIGFPE, + SIGKILL, + SIGUSR1, + SIGSEGV, + SIGUSR2, + SIGPIPE, + SIGALRM, + SIGTERM, + SIGCHLD, + SIGCONT, + SIGSTOP, + SIGTSTP, + SIGTTIN, + SIGTTOU, + SIGURG, + SIGXCPU, + SIGXFSZ, + SIGVTALRM, + SIGPROF, + SIGWINCH, + SIGIO, + SIGPWR, + SIGSYS]; #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "emscripten")))] const SIGNALS: [Signal; 31] = [ SIGHUP, From 95ac98a0b5bcfcbb80b0bd77d0f5c9d8126745cb Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Tue, 27 Sep 2016 21:45:26 +0200 Subject: [PATCH 44/49] move path outside closure to avoid use after free, restructed for easier readability --- src/unistd.rs | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index 2b1912c1fc..53ba334400 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -535,21 +535,13 @@ pub fn sleep(seconds: libc::c_uint) -> c_uint { /// ``` #[inline] pub fn mkstemp(template: &P) -> Result<(RawFd, PathBuf)> { - let res = template.with_nix_path(|path| { - let mut path_copy = path.to_bytes_with_nul().to_owned(); - let p = path_copy.as_mut_ptr() as *mut _; - unsafe { - (libc::mkstemp(p), OsStr::from_bytes(CStr::from_ptr(p).to_bytes())) - } - }); - match res { - Ok((fd, pathname)) => { - try!(Errno::result(fd)); - Ok((fd, PathBuf::from(pathname).to_owned())) - } - Err(e) => { - Err(e) - } + let mut path = try!(template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})); + let p = path.as_mut_ptr() as *mut _; + unsafe { + let fd = libc::mkstemp(p); + let pathname = OsStr::from_bytes(CStr::from_ptr(p).to_bytes()); + try!(Errno::result(fd)); + Ok((fd, PathBuf::from(pathname).to_owned())) } } From 700627eae2c5410b5a8aee5151d54e42b9365f73 Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Tue, 27 Sep 2016 21:45:54 +0200 Subject: [PATCH 45/49] test also that mkstemp fails when there's no X at the end --- test/test_unistd.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 8b9e6e4903..4ff7265208 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -57,14 +57,22 @@ fn test_wait() { #[test] fn test_mkstemp() { - let result = mkstemp("/tmp/nix_tempfile.XXXXXXXX"); + let result = mkstemp("/tmp/nix_tempfile.XXXXXX"); match result { Ok((fd, path)) => { close(fd).unwrap(); unlink(path.as_path()).unwrap(); - } + }, Err(e) => panic!("mkstemp failed: {}", e) } + + let result = mkstemp("/tmp/nix_tempfile"); + match result { + Ok(_) => { + panic!("mkstemp succeeded even though it should fail (no X at the end)"); + }, + Err(_) => {} + } } #[test] From 60a70c6b1e9fa201b686a6121650f27caa6ae932 Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Tue, 27 Sep 2016 22:23:36 +0200 Subject: [PATCH 46/49] Remove double copy of array (to_owned() and PathBuf::from), use OsString::from_vec on existing path var rather than construct string from pointer --- src/unistd.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/unistd.rs b/src/unistd.rs index 53ba334400..4d4e752976 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -5,8 +5,8 @@ use fcntl::{fcntl, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC}; use fcntl::FcntlArg::{F_SETFD, F_SETFL}; use libc::{self, c_char, c_void, c_int, c_uint, size_t, pid_t, off_t, uid_t, gid_t, mode_t}; use std::mem; -use std::ffi::{CString, CStr, OsString, OsStr}; -use std::os::unix::ffi::{OsStringExt, OsStrExt}; +use std::ffi::{CString, CStr, OsString}; +use std::os::unix::ffi::{OsStringExt}; use std::os::unix::io::RawFd; use std::path::{PathBuf}; use void::Void; @@ -537,12 +537,11 @@ pub fn sleep(seconds: libc::c_uint) -> c_uint { pub fn mkstemp(template: &P) -> Result<(RawFd, PathBuf)> { let mut path = try!(template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})); let p = path.as_mut_ptr() as *mut _; - unsafe { - let fd = libc::mkstemp(p); - let pathname = OsStr::from_bytes(CStr::from_ptr(p).to_bytes()); - try!(Errno::result(fd)); - Ok((fd, PathBuf::from(pathname).to_owned())) - } + let fd = unsafe { libc::mkstemp(p) }; + path.pop(); // drop the trailing nul + let pathname = OsString::from_vec(path); + try!(Errno::result(fd)); + Ok((fd, PathBuf::from(pathname))) } #[cfg(any(target_os = "linux", target_os = "android"))] From 7c0f5e3598c2489d53259253842c7a74ece773cc Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Wed, 28 Sep 2016 07:02:15 +0200 Subject: [PATCH 47/49] Add debug_assert ensuring popped byte is nul --- src/unistd.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/unistd.rs b/src/unistd.rs index 4d4e752976..4226b2f73e 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -538,7 +538,8 @@ pub fn mkstemp(template: &P) -> Result<(RawFd, PathBuf)> { let mut path = try!(template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})); let p = path.as_mut_ptr() as *mut _; let fd = unsafe { libc::mkstemp(p) }; - path.pop(); // drop the trailing nul + let last = path.pop(); // drop the trailing nul + debug_assert!(last == Some(b'\0')); let pathname = OsString::from_vec(path); try!(Errno::result(fd)); Ok((fd, PathBuf::from(pathname))) From b47120d5dcb2ab71cd0ac5ee75017eee4c4f9114 Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Wed, 28 Sep 2016 07:03:52 +0200 Subject: [PATCH 48/49] Apparently not all mkstemp implementation require the X at the end (despite its documentation\!), checking the failure of a directory now --- test/test_unistd.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 4ff7265208..856693f63b 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -66,10 +66,10 @@ fn test_mkstemp() { Err(e) => panic!("mkstemp failed: {}", e) } - let result = mkstemp("/tmp/nix_tempfile"); + let result = mkstemp("/tmp/"); match result { Ok(_) => { - panic!("mkstemp succeeded even though it should fail (no X at the end)"); + panic!("mkstemp succeeded even though it should fail (provided a directory)"); }, Err(_) => {} } From bf00bf2db5401ca4deeabefac4388cf5cd75abb0 Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Wed, 12 Oct 2016 22:14:01 +0200 Subject: [PATCH 49/49] Bring CHANGELOG.md up to date --- CHANGELOG.md | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f8f54de2c..76f7ef5f93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,30 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added +- Added function `epoll_create1` and bitflags `EpollCreateFlags` in + `::nix::sys::epoll` in order to support `::libc::epoll_create1`. + ([#410](https://github.com/nix-rust/nix/pull/410)) + ### Changed - `pipe2` now calls `libc::pipe2` where available. Previously it was emulated using `pipe`, which meant that setting `O_CLOEXEC` was not atomic. ([#427](https://github.com/nix-rust/nix/pull/427)) +- Renamed `EpollEventKind` to `EpollFlags` in `::nix::sys::epoll` in order for + it to conform with our conventions. + ([#410](https://github.com/nix-rust/nix/pull/410)) +- `EpollEvent` in `::nix::sys::epoll` is now an opaque proxy for + `::libc::epoll_event`. The formerly public field `events` is now be read-only + accessible with the new method `events()` of `EpollEvent`. Instances of + `EpollEvent` can be constructed using the new method `new()` of EpollEvent. + ([#410](https://github.com/nix-rust/nix/pull/410)) + +### Fixed +- Fixed the build on FreeBSD, and fixed the getsockopt, sendmsg, and recvmsg + functions on that same OS. + ([#397](https://github.com/nix-rust/nix/pull/397)) +- Fixed an off-by-one bug in `UnixAddr::new_abstract` in `::nix::sys::socket`. + ([#429](https://github.com/nix-rust/nix/pull/429)) ## [0.7.0] 2016-09-09 @@ -55,14 +75,14 @@ This project adheres to [Semantic Versioning](http://semver.org/). which has the same structure as the old `MqAttr`. The field `mq_flags` of `::libc::mq_attr` is readable using the new method `flags()` of `MqAttr`. `MqAttr` also no longer implements `Debug`. - ([#0](https://github.com/nix-rust/nix/pull/0)) + ([#392](https://github.com/nix-rust/nix/pull/392)) - The parameter `msq_prio` of `mq_receive` with type `u32` in `::nix::mqueue` was replaced by a parameter named `msg_prio` with type `&mut u32`, so that the message priority can be obtained by the caller. - ([#0](https://github.com/nix-rust/nix/pull/0)) + ([#392](https://github.com/nix-rust/nix/pull/392)) - The type alias `MQd` in `::nix::queue` was replaced by the type alias `libc::mqd_t`, both of which are aliases for the same type. - ([#0](https://github.com/nix-rust/nix/pull/0)) + ([#392](https://github.com/nix-rust/nix/pull/392)) ### Removed - Type alias `SigNum` from `::nix::sys::signal`.