summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Lerche <me@carllerche.com>2014-10-06 22:02:26 -0700
committerCarl Lerche <me@carllerche.com>2014-10-06 22:02:26 -0700
commit7c4fa8232df48dc324119ff8d742a35458dec02e (patch)
tree8bbf26a4bd015eb7989900c2d470f9a2824d8e12
parent2b08916431fb5dc9791c9074e310c7a7d22b37e6 (diff)
downloadnix-7c4fa8232df48dc324119ff8d742a35458dec02e.zip
Implement dup3
-rw-r--r--src/lib.rs1
-rw-r--r--src/unistd.rs44
2 files changed, 34 insertions, 11 deletions
diff --git a/src/lib.rs b/src/lib.rs
index f97923c2..68424196 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,6 +2,7 @@
#![feature(globs)]
#![feature(linkage)]
+#![feature(if_let)]
#![allow(non_camel_case_types)]
extern crate libc;
diff --git a/src/unistd.rs b/src/unistd.rs
index c793bf4c..14e6e66e 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -18,9 +18,6 @@ mod ffi {
pub fn dup(oldfd: c_int) -> c_int;
pub fn dup2(oldfd: c_int, newfd: c_int) -> c_int;
- // TODO: dup3 is only available in newer linux kernels and possibly a few *bsds
- // pub fn dup3(oldfd: c_int, newfd: c_int, flags: c_int) -> c_int;
-
// change working directory
// doc: http://man7.org/linux/man-pages/man2/chdir.2.html
pub fn chdir(path: *const c_char) -> c_int;
@@ -98,19 +95,44 @@ pub fn dup2(oldfd: Fd, newfd: Fd) -> SysResult<Fd> {
Ok(res)
}
-/*
-Same TODO as above
-#[inline]
pub fn dup3(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
- let res = unsafe { ffi::dup3(oldfd, newfd, flags.bits()) };
+ use errno::EINVAL;
- if res < 0 {
- return Err(SysError::last());
+ type F = unsafe extern "C" fn(c_int, c_int, c_int) -> c_int;
+
+ extern {
+ #[linkage = "extern_weak"]
+ static dup3: *const ();
}
- Ok(res)
+ if !dup3.is_null() {
+ let res = unsafe {
+ mem::transmute::<*const (), F>(dup3)(
+ oldfd, newfd, flags.bits())
+ };
+
+ if res < 0 {
+ return Err(SysError::last());
+ }
+
+ Ok(res)
+ } else {
+ if oldfd == newfd {
+ return Err(SysError { kind: EINVAL });
+ }
+
+ let fd = try!(dup2(oldfd, newfd));
+
+ if flags.contains(O_CLOEXEC) {
+ if let Err(e) = fcntl(fd, F_SETFD(FD_CLOEXEC)) {
+ let _ = close(fd);
+ return Err(e);
+ }
+ }
+
+ Ok(fd)
+ }
}
-*/
#[inline]
pub fn chdir<S: ToCStr>(path: S) -> SysResult<()> {