diff --git a/Cargo.toml b/Cargo.toml index 8ac35a168c..8beb203508 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ signalfd = [] [dependencies] libc = "0.2.7" bitflags = "0.4" +cfg-if = "0.1.0" [dev-dependencies] rand = "0.3.8" diff --git a/src/lib.rs b/src/lib.rs index f6c19868d1..f368fc5739 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,9 @@ #[macro_use] extern crate bitflags; +#[macro_use] +extern crate cfg_if; + pub extern crate libc; #[cfg(test)] diff --git a/src/unistd.rs b/src/unistd.rs index 6d793aec2d..193086df38 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -3,7 +3,7 @@ use {Errno, Error, Result, NixPath}; use fcntl::{fcntl, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC}; use fcntl::FcntlArg::{F_SETFD, F_SETFL}; -use libc::{c_char, c_void, c_int, size_t, pid_t, off_t, uid_t, gid_t}; +use libc::{self, c_char, c_void, c_int, size_t, pid_t, off_t, uid_t, gid_t}; use std::mem; use std::ffi::CString; use std::os::unix::io::RawFd; @@ -11,62 +11,6 @@ use std::os::unix::io::RawFd; #[cfg(any(target_os = "linux", target_os = "android"))] pub use self::linux::*; -mod ffi { - use libc::{c_char, c_int, size_t}; - pub use libc::{fork, close, read, write, pipe, ftruncate, unlink, setpgid, getegid, geteuid, getgid, getpid, getppid, getuid, setuid, setgid, chown}; - - #[allow(improper_ctypes)] - extern { - // duplicate a file descriptor - // doc: http://man7.org/linux/man-pages/man2/dup.2.html - pub fn dup(oldfd: c_int) -> c_int; - pub fn dup2(oldfd: c_int, newfd: 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; - - // Execute PATH with arguments ARGV and environment from `environ'. - // doc: http://man7.org/linux/man-pages/man3/execv.3.html - pub fn execv(path: *const c_char, argv: *const *const c_char) -> c_int; - - // execute program - // doc: http://man7.org/linux/man-pages/man2/execve.2.html - pub fn execve(path: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> c_int; - - // Execute FILE, searching in the `PATH' environment variable if it contains - // no slashes, with arguments ARGV and environment from `environ'. - // doc: http://man7.org/linux/man-pages/man3/execvp.3.html - pub fn execvp(filename: *const c_char, argv: *const *const c_char) -> c_int; - - // doc: http://man7.org/linux/man-pages/man3/exec.3.html - #[cfg(any(target_os = "linux", target_os = "android"))] - #[cfg(feature = "execvpe")] - pub fn execvpe(filename: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> c_int; - - // run the current process in the background - // doc: http://man7.org/linux/man-pages/man3/daemon.3.html - pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int; - - // sets the hostname to the value given - // doc: http://man7.org/linux/man-pages/man2/gethostname.2.html - pub fn gethostname(name: *mut c_char, len: size_t) -> c_int; - - // gets the hostname - // doc: http://man7.org/linux/man-pages/man2/sethostname.2.html - pub fn sethostname(name: *const c_char, len: size_t) -> c_int; - - // change root directory - // doc: http://man7.org/linux/man-pages/man2/chroot.2.html - pub fn chroot(path: *const c_char) -> c_int; - - // synchronize a file's in-core state with storage device - // doc: http://man7.org/linux/man-pages/man2/fsync.2.html - pub fn fsync(fd: c_int) -> c_int; - pub fn fdatasync(fd: c_int) -> c_int; - } -} - #[derive(Clone, Copy)] pub enum Fork { Parent(pid_t), @@ -90,7 +34,7 @@ impl Fork { } pub fn fork() -> Result { - let res = unsafe { ffi::fork() }; + let res = unsafe { libc::fork() }; Errno::result(res).map(|res| match res { 0 => Fork::Child, @@ -100,28 +44,28 @@ pub fn fork() -> Result { #[inline] pub fn getpid() -> pid_t { - unsafe { ffi::getpid() } // no error handling, according to man page: "These functions are always successful." + unsafe { libc::getpid() } // no error handling, according to man page: "These functions are always successful." } #[inline] pub fn getppid() -> pid_t { - unsafe { ffi::getppid() } // no error handling, according to man page: "These functions are always successful." + unsafe { libc::getppid() } // no error handling, according to man page: "These functions are always successful." } #[inline] pub fn setpgid(pid: pid_t, pgid: pid_t) -> Result<()> { - let res = unsafe { ffi::setpgid(pid, pgid) }; + let res = unsafe { libc::setpgid(pid, pgid) }; Errno::result(res).map(drop) } #[inline] pub fn dup(oldfd: RawFd) -> Result { - let res = unsafe { ffi::dup(oldfd) }; + let res = unsafe { libc::dup(oldfd) }; Errno::result(res) } #[inline] pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result { - let res = unsafe { ffi::dup2(oldfd, newfd) }; + let res = unsafe { libc::dup2(oldfd, newfd) }; Errno::result(res) } @@ -151,7 +95,7 @@ fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result { #[inline] pub fn chdir(path: &P) -> Result<()> { let res = try!(path.with_nix_path(|cstr| { - unsafe { ffi::chdir(cstr.as_ptr()) } + unsafe { libc::chdir(cstr.as_ptr()) } })); Errno::result(res).map(drop) @@ -161,7 +105,7 @@ pub fn chdir(path: &P) -> Result<()> { pub fn chown(path: &P, owner: Option, group: Option) -> Result<()> { let res = try!(path.with_nix_path(|cstr| { // We use `0 - 1` to get `-1 : {u,g}id_t` which is specified as the no-op value for chown(3). - unsafe { ffi::chown(cstr.as_ptr(), owner.unwrap_or(0 - 1), group.unwrap_or(0 - 1)) } + unsafe { libc::chown(cstr.as_ptr(), owner.unwrap_or(0 - 1), group.unwrap_or(0 - 1)) } })); Errno::result(res).map(drop) @@ -181,7 +125,7 @@ pub fn execv(path: &CString, argv: &[CString]) -> Result<()> { let args_p = to_exec_array(argv); unsafe { - ffi::execv(path.as_ptr(), args_p.as_ptr()) + libc::execv(path.as_ptr(), args_p.as_ptr()) }; Err(Error::Sys(Errno::last())) @@ -193,7 +137,7 @@ pub fn execve(path: &CString, args: &[CString], env: &[CString]) -> Result<()> { let env_p = to_exec_array(env); unsafe { - ffi::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) + libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) }; Err(Error::Sys(Errno::last())) @@ -204,22 +148,30 @@ pub fn execvp(filename: &CString, args: &[CString]) -> Result<()> { let args_p = to_exec_array(args); unsafe { - ffi::execvp(filename.as_ptr(), args_p.as_ptr()) + libc::execvp(filename.as_ptr(), args_p.as_ptr()) }; Err(Error::Sys(Errno::last())) } pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> { - let res = unsafe { ffi::daemon(nochdir as c_int, noclose as c_int) }; + let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) }; Errno::result(res).map(drop) } pub fn sethostname(name: &[u8]) -> Result<()> { + // Handle some differences in type of the len arg across platforms. + cfg_if! { + if #[cfg(any(target_os = "macos", target_os = "ios"))] { + type sethostname_len_t = c_int; + } else { + type sethostname_len_t = size_t; + } + } let ptr = name.as_ptr() as *const c_char; - let len = name.len() as size_t; + let len = name.len() as sethostname_len_t; - let res = unsafe { ffi::sethostname(ptr, len) }; + let res = unsafe { libc::sethostname(ptr, len) }; Errno::result(res).map(drop) } @@ -227,23 +179,23 @@ pub fn gethostname(name: &mut [u8]) -> Result<()> { let ptr = name.as_mut_ptr() as *mut c_char; let len = name.len() as size_t; - let res = unsafe { ffi::gethostname(ptr, len) }; + let res = unsafe { libc::gethostname(ptr, len) }; Errno::result(res).map(drop) } pub fn close(fd: RawFd) -> Result<()> { - let res = unsafe { ffi::close(fd) }; + let res = unsafe { libc::close(fd) }; Errno::result(res).map(drop) } pub fn read(fd: RawFd, buf: &mut [u8]) -> Result { - let res = unsafe { ffi::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) }; + let res = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) }; Errno::result(res).map(|r| r as usize) } pub fn write(fd: RawFd, buf: &[u8]) -> Result { - let res = unsafe { ffi::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) }; + let res = unsafe { libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) }; Errno::result(res).map(|r| r as usize) } @@ -252,7 +204,7 @@ pub fn pipe() -> Result<(RawFd, RawFd)> { unsafe { let mut fds: [c_int; 2] = mem::uninitialized(); - let res = ffi::pipe(fds.as_mut_ptr()); + let res = libc::pipe(fds.as_mut_ptr()); try!(Errno::result(res)); @@ -264,7 +216,7 @@ pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> { unsafe { let mut fds: [c_int; 2] = mem::uninitialized(); - let res = ffi::pipe(fds.as_mut_ptr()); + let res = libc::pipe(fds.as_mut_ptr()); try!(Errno::result(res)); @@ -300,7 +252,7 @@ fn pipe2_setflags(fd1: RawFd, fd2: RawFd, flags: OFlag) -> Result<()> { } pub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> { - Errno::result(unsafe { ffi::ftruncate(fd, len) }).map(drop) + Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop) } pub fn isatty(fd: RawFd) -> Result { @@ -323,7 +275,7 @@ pub fn isatty(fd: RawFd) -> Result { pub fn unlink(path: &P) -> Result<()> { let res = try!(path.with_nix_path(|cstr| { unsafe { - ffi::unlink(cstr.as_ptr()) + libc::unlink(cstr.as_ptr()) } })); @@ -333,7 +285,7 @@ pub fn unlink(path: &P) -> Result<()> { #[inline] pub fn chroot(path: &P) -> Result<()> { let res = try!(path.with_nix_path(|cstr| { - unsafe { ffi::chroot(cstr.as_ptr()) } + unsafe { libc::chroot(cstr.as_ptr()) } })); Errno::result(res).map(drop) @@ -341,14 +293,19 @@ pub fn chroot(path: &P) -> Result<()> { #[inline] pub fn fsync(fd: RawFd) -> Result<()> { - let res = unsafe { ffi::fsync(fd) }; + let res = unsafe { libc::fsync(fd) }; Errno::result(res).map(drop) } +// `fdatasync(2) is in POSIX, but in libc it is only defined in `libc::notbsd`. +// TODO: exclude only Apple systems after https://github.com/rust-lang/libc/pull/211 +#[cfg(any(target_os = "linux", + target_os = "android", + target_os = "emscripten"))] #[inline] pub fn fdatasync(fd: RawFd) -> Result<()> { - let res = unsafe { ffi::fdatasync(fd) }; + let res = unsafe { libc::fdatasync(fd) }; Errno::result(res).map(drop) } @@ -361,34 +318,34 @@ pub fn fdatasync(fd: RawFd) -> Result<()> { // - http://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html #[inline] pub fn getuid() -> uid_t { - unsafe { ffi::getuid() } + unsafe { libc::getuid() } } #[inline] pub fn geteuid() -> uid_t { - unsafe { ffi::geteuid() } + unsafe { libc::geteuid() } } #[inline] pub fn getgid() -> gid_t { - unsafe { ffi::getgid() } + unsafe { libc::getgid() } } #[inline] pub fn getegid() -> gid_t { - unsafe { ffi::getegid() } + unsafe { libc::getegid() } } #[inline] pub fn setuid(uid: uid_t) -> Result<()> { - let res = unsafe { ffi::setuid(uid) }; + let res = unsafe { libc::setuid(uid) }; Errno::result(res).map(drop) } #[inline] pub fn setgid(gid: gid_t) -> Result<()> { - let res = unsafe { ffi::setgid(gid) }; + let res = unsafe { libc::setgid(gid) }; Errno::result(res).map(drop) }