diff --git a/Cargo.lock b/Cargo.lock
index f662589ecc1709653f225f5ec50f22a7a8a03b10..25806ed1ec1e0a1ded234c7cc8805ec56ef3d349 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -165,23 +165,31 @@ dependencies = [
  "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ion_sys 0.1.0",
  "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
  "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "liner 0.4.5 (git+https://gitlab.redox-os.org/redox-os/liner)",
  "permutate 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallstring 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "users 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "xdg 2.1.0 (git+https://github.com/whitequark/rust-xdg)",
 ]
 
+[[package]]
+name = "ion_sys"
+version = "0.1.0"
+dependencies = [
+ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "users 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "itoa"
 version = "0.4.1"
diff --git a/Cargo.toml b/Cargo.toml
index 82cbe48f66ba72a7a7f7cf14822ea6a78749c81c..496d6d1da23fda33f51768f7c35963955c8507fd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,6 +16,9 @@ readme = "README.md"
 repository = "https://gitlab.redox-os.org/redox-os/ion"
 version = "1.0.0-alpha"
 
+[workspace]
+members = ["ion_sys"]
+
 [[bin]]
 name = "ion"
 path = "src/main.rs"
@@ -33,7 +36,6 @@ fnv = "1.0"
 glob = "0.2"
 itoa = "0.4"
 lazy_static = "1.0"
-libc = "0.2"
 liner = { git = "https://gitlab.redox-os.org/redox-os/liner" }
 permutate = "0.3"
 rand = "0.5"
@@ -42,6 +44,7 @@ smallstring = "0.1"
 smallvec = "0.6"
 unicode-segmentation = "1.2"
 xdg = { git = "https://github.com/whitequark/rust-xdg" }
+ion_sys = { path = "ion_sys" }
 
 [lib]
 path = "src/lib/lib.rs"
@@ -52,10 +55,6 @@ panic = "abort"
 
 [target."cfg(all(unix, not(target_os = \"redox\")))".dependencies]
 libloading = "0.5"
-users = "0.7"
-
-[target."cfg(target_os = \"redox\")".dependencies]
-redox_syscall = "0.1"
 
 [patch.crates-io]
 liner = { git = "https://gitlab.redox-os.org/redox-os/liner" }
diff --git a/ion_sys/Cargo.toml b/ion_sys/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..b9d20954b879d212509bdda48694baa15d4d0027
--- /dev/null
+++ b/ion_sys/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "ion_sys"
+version = "0.1.0"
+authors = ["Michael Murphy <mmstickman@gmail.com>"]
+publish = false
+
+[dependencies]
+libc = "0.2"
+
+[target."cfg(all(unix, not(target_os = \"redox\")))".dependencies]
+libloading = "0.5"
+users = "0.7"
+
+[target."cfg(target_os = \"redox\")".dependencies]
+redox_syscall = "0.1"
diff --git a/ion_sys/src/lib.rs b/ion_sys/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..7028348b2c5f7fdc0cd0fb31b2448f72d28bf0fe
--- /dev/null
+++ b/ion_sys/src/lib.rs
@@ -0,0 +1,19 @@
+#[cfg(all(unix, not(target_os = "redox")))]
+extern crate libc;
+#[cfg(all(unix, not(target_os = "redox")))]
+extern crate libloading;
+#[cfg(all(unix, not(target_os = "redox")))]
+extern crate users as users_unix;
+
+#[cfg(target_os = "redox")]
+extern crate syscall;
+
+#[cfg(target_os = "redox")]
+#[path = "sys/redox/mod.rs"]
+mod sys;
+
+#[cfg(unix)]
+#[path = "sys/unix/mod.rs"]
+mod sys;
+
+pub use self::sys::*;
diff --git a/src/lib/sys/redox/mod.rs b/ion_sys/src/sys/redox/mod.rs
similarity index 75%
rename from src/lib/sys/redox/mod.rs
rename to ion_sys/src/sys/redox/mod.rs
index cb9bf98e9b93c911fbb2de50414ac4eda003131c..71cc7736ec5d256527f1d9a9d15561f61915a2b4 100644
--- a/src/lib/sys/redox/mod.rs
+++ b/ion_sys/src/sys/redox/mod.rs
@@ -15,30 +15,30 @@ pub use syscall::{
     wstopsig as wstopsig_, wtermsig as wtermsig_, ECHILD, EINTR,
 };
 
-pub(crate) const PATH_SEPARATOR: &str = ";";
-pub(crate) const NULL_PATH: &str = "null:";
-
-pub(crate) const O_CLOEXEC: usize = syscall::O_CLOEXEC;
-pub(crate) const SIGHUP: i32 = syscall::SIGHUP as i32;
-pub(crate) const SIGINT: i32 = syscall::SIGINT as i32;
-pub(crate) const SIGTERM: i32 = syscall::SIGTERM as i32;
-pub(crate) const SIGCONT: i32 = syscall::SIGCONT as i32;
-pub(crate) const SIGSTOP: i32 = syscall::SIGSTOP as i32;
-pub(crate) const SIGTSTP: i32 = syscall::SIGTSTP as i32;
-pub(crate) const SIGPIPE: i32 = syscall::SIGPIPE as i32;
-pub(crate) const WUNTRACED: i32 = syscall::WUNTRACED as i32;
-pub(crate) const WNOHANG: i32 = syscall::WNOHANG as i32;
-pub(crate) const WCONTINUED: i32 = syscall::WCONTINUED as i32;
+pub const PATH_SEPARATOR: &str = ";";
+pub const NULL_PATH: &str = "null:";
+
+pub const O_CLOEXEC: usize = syscall::O_CLOEXEC;
+pub const SIGHUP: i32 = syscall::SIGHUP as i32;
+pub const SIGINT: i32 = syscall::SIGINT as i32;
+pub const SIGTERM: i32 = syscall::SIGTERM as i32;
+pub const SIGCONT: i32 = syscall::SIGCONT as i32;
+pub const SIGSTOP: i32 = syscall::SIGSTOP as i32;
+pub const SIGTSTP: i32 = syscall::SIGTSTP as i32;
+pub const SIGPIPE: i32 = syscall::SIGPIPE as i32;
+pub const WUNTRACED: i32 = syscall::WUNTRACED as i32;
+pub const WNOHANG: i32 = syscall::WNOHANG as i32;
+pub const WCONTINUED: i32 = syscall::WCONTINUED as i32;
 
 pub const STDIN_FILENO: RawFd = 0;
-pub(crate) const STDOUT_FILENO: RawFd = 1;
-pub(crate) const STDERR_FILENO: RawFd = 2;
+pub const STDOUT_FILENO: RawFd = 1;
+pub const STDERR_FILENO: RawFd = 2;
 
-pub(crate) fn geteuid() -> io::Result<u32> { cvt(syscall::geteuid()).map(|pid| pid as u32) }
+pub fn geteuid() -> io::Result<u32> { cvt(syscall::geteuid()).map(|pid| pid as u32) }
 
-pub(crate) fn getuid() -> io::Result<u32> { cvt(syscall::getuid()).map(|pid| pid as u32) }
+pub fn getuid() -> io::Result<u32> { cvt(syscall::getuid()).map(|pid| pid as u32) }
 
-pub(crate) fn is_root() -> bool { syscall::geteuid().map(|id| id == 0).unwrap_or(false) }
+pub fn is_root() -> bool { syscall::geteuid().map(|id| id == 0).unwrap_or(false) }
 
 pub unsafe fn fork() -> io::Result<u32> { cvt(syscall::clone(0)).map(|pid| pid as u32) }
 
@@ -70,27 +70,27 @@ pub fn strerror(errno: i32) -> &'static str {
         .unwrap_or("Unknown Error")
 }
 
-pub(crate) fn getpid() -> io::Result<u32> { cvt(syscall::getpid()).map(|pid| pid as u32) }
+pub fn getpid() -> io::Result<u32> { cvt(syscall::getpid()).map(|pid| pid as u32) }
 
-pub(crate) fn kill(pid: u32, signal: i32) -> io::Result<()> {
+pub fn kill(pid: u32, signal: i32) -> io::Result<()> {
     cvt(syscall::kill(pid as usize, signal as usize)).and(Ok(()))
 }
 
-pub(crate) fn killpg(pgid: u32, signal: i32) -> io::Result<()> {
+pub fn killpg(pgid: u32, signal: i32) -> io::Result<()> {
     cvt(syscall::kill(-(pgid as isize) as usize, signal as usize)).and(Ok(()))
 }
 
-pub(crate) fn pipe2(flags: usize) -> io::Result<(RawFd, RawFd)> {
+pub fn pipe2(flags: usize) -> io::Result<(RawFd, RawFd)> {
     let mut fds = [0; 2];
     cvt(syscall::pipe2(&mut fds, flags))?;
     Ok((fds[0], fds[1]))
 }
 
-pub(crate) fn setpgid(pid: u32, pgid: u32) -> io::Result<()> {
+pub fn setpgid(pid: u32, pgid: u32) -> io::Result<()> {
     cvt(syscall::setpgid(pid as usize, pgid as usize)).and(Ok(()))
 }
 
-pub(crate) fn fork_and_exec<F: Fn(), S: AsRef<str>>(
+pub fn fork_and_exec<F: Fn(), S: AsRef<str>>(
     prog: &str,
     args: &[S],
     stdin: Option<RawFd>,
@@ -142,7 +142,7 @@ pub(crate) fn fork_and_exec<F: Fn(), S: AsRef<str>>(
     }
 }
 
-pub(crate) fn execve<S: AsRef<str>>(prog: &str, args: &[S], clear_env: bool) -> io::Error {
+pub fn execve<S: AsRef<str>>(prog: &str, args: &[S], clear_env: bool) -> io::Error {
     // Construct a valid set of arguments to pass to execve. Ensure
     // that the program is the first argument.
     let mut cvt_args: Vec<[usize; 2]> = Vec::new();
@@ -194,7 +194,7 @@ pub(crate) fn execve<S: AsRef<str>>(prog: &str, args: &[S], clear_env: bool) ->
 }
 
 #[allow(dead_code)]
-pub(crate) fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> {
+pub fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> {
     let new = SigAction {
         sa_handler: unsafe { mem::transmute(handler) },
         sa_mask:    [0; 2],
@@ -203,7 +203,7 @@ pub(crate) fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()>
     cvt(syscall::sigaction(signal as usize, Some(&new), None)).and(Ok(()))
 }
 
-pub(crate) fn reset_signal(signal: i32) -> io::Result<()> {
+pub fn reset_signal(signal: i32) -> io::Result<()> {
     let new = SigAction {
         sa_handler: unsafe { mem::transmute(syscall::flag::SIG_DFL) },
         sa_mask:    [0; 2],
@@ -212,7 +212,7 @@ pub(crate) fn reset_signal(signal: i32) -> io::Result<()> {
     cvt(syscall::sigaction(signal as usize, Some(&new), None)).and(Ok(()))
 }
 
-pub(crate) fn tcsetpgrp(tty_fd: RawFd, pgid: u32) -> io::Result<()> {
+pub fn tcsetpgrp(tty_fd: RawFd, pgid: u32) -> io::Result<()> {
     let fd = cvt(syscall::dup(tty_fd, b"pgrp"))?;
 
     let pgid_usize = pgid as usize;
@@ -228,13 +228,13 @@ pub(crate) fn tcsetpgrp(tty_fd: RawFd, pgid: u32) -> io::Result<()> {
     cvt(res).and(Ok(()))
 }
 
-pub(crate) fn dup(fd: RawFd) -> io::Result<RawFd> { cvt(syscall::dup(fd, &[])) }
+pub fn dup(fd: RawFd) -> io::Result<RawFd> { cvt(syscall::dup(fd, &[])) }
 
-pub(crate) fn dup2(old: RawFd, new: RawFd) -> io::Result<RawFd> {
+pub fn dup2(old: RawFd, new: RawFd) -> io::Result<RawFd> {
     cvt(syscall::dup2(old, new, &[]))
 }
 
-pub(crate) fn close(fd: RawFd) -> io::Result<()> { cvt(syscall::close(fd)).and(Ok(())) }
+pub fn close(fd: RawFd) -> io::Result<()> { cvt(syscall::close(fd)).and(Ok(())) }
 
 pub fn isatty(fd: RawFd) -> bool {
     if let Ok(tfd) = syscall::dup(fd, b"termios") {
@@ -252,23 +252,23 @@ fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> {
 
 // TODO
 pub mod signals {
-    pub(crate) fn block() {}
+    pub fn block() {}
 
     /// Unblocks the SIGTSTP/SIGTTOU/SIGTTIN/SIGCHLD signals so children processes can be
     /// controlled
     /// by the shell.
-    pub(crate) fn unblock() {}
+    pub fn unblock() {}
 }
 
 pub mod variables {
     use super::libc::{self, c_char};
 
-    pub(crate) fn get_user_home(_username: &str) -> Option<String> {
+    pub fn get_user_home(_username: &str) -> Option<String> {
         // TODO
         None
     }
 
-    pub(crate) fn get_host_name() -> Option<String> {
+    pub fn get_host_name() -> Option<String> {
         let mut host_name = [0u8; 512];
 
         if unsafe { libc::gethostname(&mut host_name as *mut _ as *mut c_char, host_name.len()) }
diff --git a/src/lib/sys/unix/mod.rs b/ion_sys/src/sys/unix/mod.rs
similarity index 84%
rename from src/lib/sys/unix/mod.rs
rename to ion_sys/src/sys/unix/mod.rs
index e89b8f08d543559ced64a23a8b4ce68e73cabfac..9ee6a27a7c9ee8d474f8e311b4725fc751c4817f 100644
--- a/src/lib/sys/unix/mod.rs
+++ b/ion_sys/src/sys/unix/mod.rs
@@ -17,20 +17,20 @@ use std::{
     ptr,
 };
 
-pub(crate) const PATH_SEPARATOR: &str = ":";
-pub(crate) const NULL_PATH: &str = "/dev/null";
-
-pub(crate) const O_CLOEXEC: usize = libc::O_CLOEXEC as usize;
-pub(crate) const SIGHUP: i32 = libc::SIGHUP;
-pub(crate) const SIGINT: i32 = libc::SIGINT;
-pub(crate) const SIGTERM: i32 = libc::SIGTERM;
-pub(crate) const SIGCONT: i32 = libc::SIGCONT;
-pub(crate) const SIGSTOP: i32 = libc::SIGSTOP;
-pub(crate) const SIGTSTP: i32 = libc::SIGTSTP;
-pub(crate) const SIGPIPE: i32 = libc::SIGPIPE;
-
-pub(crate) const STDOUT_FILENO: i32 = libc::STDOUT_FILENO;
-pub(crate) const STDERR_FILENO: i32 = libc::STDERR_FILENO;
+pub const PATH_SEPARATOR: &str = ":";
+pub const NULL_PATH: &str = "/dev/null";
+
+pub const O_CLOEXEC: usize = libc::O_CLOEXEC as usize;
+pub const SIGHUP: i32 = libc::SIGHUP;
+pub const SIGINT: i32 = libc::SIGINT;
+pub const SIGTERM: i32 = libc::SIGTERM;
+pub const SIGCONT: i32 = libc::SIGCONT;
+pub const SIGSTOP: i32 = libc::SIGSTOP;
+pub const SIGTSTP: i32 = libc::SIGTSTP;
+pub const SIGPIPE: i32 = libc::SIGPIPE;
+
+pub const STDOUT_FILENO: i32 = libc::STDOUT_FILENO;
+pub const STDERR_FILENO: i32 = libc::STDERR_FILENO;
 pub const STDIN_FILENO: i32 = libc::STDIN_FILENO;
 
 // Why each platform wants to be unique in this regard is anyone's guess.
@@ -76,27 +76,27 @@ pub fn wcoredump(status: i32) -> bool { unsafe { WCOREDUMP(status) } }
 pub fn wtermsig(status: i32) -> i32 { unsafe { WTERMSIG(status) } }
 pub fn wstopsig(status: i32) -> i32 { unsafe { WSTOPSIG(status) } }
 
-pub(crate) fn geteuid() -> io::Result<u32> { Ok(unsafe { libc::geteuid() } as u32) }
+pub fn geteuid() -> io::Result<u32> { Ok(unsafe { libc::geteuid() } as u32) }
 
-pub(crate) fn getuid() -> io::Result<u32> { Ok(unsafe { libc::getuid() } as u32) }
+pub fn getuid() -> io::Result<u32> { Ok(unsafe { libc::getuid() } as u32) }
 
-pub(crate) fn is_root() -> bool { unsafe { libc::geteuid() == 0 } }
+pub fn is_root() -> bool { unsafe { libc::geteuid() == 0 } }
 
 pub unsafe fn fork() -> io::Result<u32> { cvt(libc::fork()).map(|pid| pid as u32) }
 
 pub fn fork_exit(exit_status: i32) -> ! { unsafe { libc::_exit(exit_status) } }
 
-pub(crate) fn getpid() -> io::Result<u32> { cvt(unsafe { libc::getpid() }).map(|pid| pid as u32) }
+pub fn getpid() -> io::Result<u32> { cvt(unsafe { libc::getpid() }).map(|pid| pid as u32) }
 
-pub(crate) fn kill(pid: u32, signal: i32) -> io::Result<()> {
+pub fn kill(pid: u32, signal: i32) -> io::Result<()> {
     cvt(unsafe { libc::kill(pid as pid_t, signal as c_int) }).and(Ok(()))
 }
 
-pub(crate) fn killpg(pgid: u32, signal: i32) -> io::Result<()> {
+pub fn killpg(pgid: u32, signal: i32) -> io::Result<()> {
     cvt(unsafe { libc::kill(-(pgid as pid_t), signal as c_int) }).and(Ok(()))
 }
 
-pub(crate) fn fork_and_exec<F: Fn(), S: AsRef<str>>(
+pub fn fork_and_exec<F: Fn(), S: AsRef<str>>(
     prog: &str,
     args: &[S],
     stdin: Option<RawFd>,
@@ -214,7 +214,7 @@ pub(crate) fn fork_and_exec<F: Fn(), S: AsRef<str>>(
     }
 }
 
-pub(crate) fn execve<'a, S: AsRef<str>>(prog: &str, args: &[S], clear_env: bool) -> io::Error {
+pub fn execve<'a, S: AsRef<str>>(prog: &str, args: &[S], clear_env: bool) -> io::Error {
     let prog_str = match CString::new(prog) {
         Ok(prog) => prog,
         Err(_) => {
@@ -287,7 +287,7 @@ pub(crate) fn execve<'a, S: AsRef<str>>(prog: &str, args: &[S], clear_env: bool)
     }
 }
 
-pub(crate) fn pipe2(flags: usize) -> io::Result<(RawFd, RawFd)> {
+pub fn pipe2(flags: usize) -> io::Result<(RawFd, RawFd)> {
     let mut fds = [0; 2];
 
     #[cfg(not(target_os = "macos"))]
@@ -299,12 +299,12 @@ pub(crate) fn pipe2(flags: usize) -> io::Result<(RawFd, RawFd)> {
     Ok((fds[0], fds[1]))
 }
 
-pub(crate) fn setpgid(pid: u32, pgid: u32) -> io::Result<()> {
+pub fn setpgid(pid: u32, pgid: u32) -> io::Result<()> {
     cvt(unsafe { libc::setpgid(pid as pid_t, pgid as pid_t) }).and(Ok(()))
 }
 
 #[allow(dead_code)]
-pub(crate) fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> {
+pub fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> {
     if unsafe { libc::signal(signal as c_int, handler as sighandler_t) } == libc::SIG_ERR {
         Err(io::Error::last_os_error())
     } else {
@@ -312,7 +312,7 @@ pub(crate) fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()>
     }
 }
 
-pub(crate) fn reset_signal(signal: i32) -> io::Result<()> {
+pub fn reset_signal(signal: i32) -> io::Result<()> {
     if unsafe { libc::signal(signal as c_int, libc::SIG_DFL) } == libc::SIG_ERR {
         Err(io::Error::last_os_error())
     } else {
@@ -320,17 +320,17 @@ pub(crate) fn reset_signal(signal: i32) -> io::Result<()> {
     }
 }
 
-pub(crate) fn tcsetpgrp(fd: RawFd, pgrp: u32) -> io::Result<()> {
+pub fn tcsetpgrp(fd: RawFd, pgrp: u32) -> io::Result<()> {
     cvt(unsafe { libc::tcsetpgrp(fd as c_int, pgrp as pid_t) }).and(Ok(()))
 }
 
-pub(crate) fn dup(fd: RawFd) -> io::Result<RawFd> { cvt(unsafe { libc::dup(fd) }) }
+pub fn dup(fd: RawFd) -> io::Result<RawFd> { cvt(unsafe { libc::dup(fd) }) }
 
-pub(crate) fn dup2(old: RawFd, new: RawFd) -> io::Result<RawFd> {
+pub fn dup2(old: RawFd, new: RawFd) -> io::Result<RawFd> {
     cvt(unsafe { libc::dup2(old, new) })
 }
 
-pub(crate) fn close(fd: RawFd) -> io::Result<()> { cvt(unsafe { libc::close(fd) }).and(Ok(())) }
+pub fn close(fd: RawFd) -> io::Result<()> { cvt(unsafe { libc::close(fd) }).and(Ok(())) }
 
 pub fn isatty(fd: RawFd) -> bool { unsafe { libc::isatty(fd) == 1 } }
 
@@ -360,14 +360,14 @@ pub mod variables {
     use super::libc::{self, c_char};
     use users_unix::{get_user_by_name, os::unix::UserExt};
 
-    pub(crate) fn get_user_home(username: &str) -> Option<String> {
+    pub fn get_user_home(username: &str) -> Option<String> {
         match get_user_by_name(username) {
             Some(user) => Some(user.home_dir().to_string_lossy().into_owned()),
             None => None,
         }
     }
 
-    pub(crate) fn get_host_name() -> Option<String> {
+    pub fn get_host_name() -> Option<String> {
         let mut host_name = [0u8; 512];
 
         if unsafe { libc::gethostname(&mut host_name as *mut _ as *mut c_char, host_name.len()) }
diff --git a/src/lib/sys/unix/signals.rs b/ion_sys/src/sys/unix/signals.rs
similarity index 96%
rename from src/lib/sys/unix/signals.rs
rename to ion_sys/src/sys/unix/signals.rs
index 5b466a02d4911b1169c0f4b7d6524b02f0a6eb2a..ba4166e3618932e312df4da2853b541c20be897c 100644
--- a/src/lib/sys/unix/signals.rs
+++ b/ion_sys/src/sys/unix/signals.rs
@@ -3,7 +3,7 @@ use std::{mem, ptr};
 
 /// Blocks the SIGTSTP/SIGTTOU/SIGTTIN/SIGCHLD signals so that the shell never receives
 /// them.
-pub(crate) fn block() {
+pub fn block() {
     unsafe {
         let mut sigset = mem::uninitialized::<sigset_t>();
         sigemptyset(&mut sigset as *mut sigset_t);
@@ -22,7 +22,7 @@ pub(crate) fn block() {
 /// Unblocks the SIGTSTP/SIGTTOU/SIGTTIN/SIGCHLD signals so children processes can be
 /// controlled
 /// by the shell.
-pub(crate) fn unblock() {
+pub fn unblock() {
     unsafe {
         let mut sigset = mem::uninitialized::<sigset_t>();
         sigemptyset(&mut sigset as *mut sigset_t);
diff --git a/src/lib/lib.rs b/src/lib/lib.rs
index ea9b7b20102b5d1371b44f3ca1450ba22dec7f86..e98fe96a515f44ed35bda91756ee4d91113799de 100644
--- a/src/lib/lib.rs
+++ b/src/lib/lib.rs
@@ -22,27 +22,15 @@ extern crate lazy_static;
 #[cfg(test)]
 extern crate test;
 #[cfg(all(unix, not(target_os = "redox")))]
-extern crate libc;
-#[cfg(all(unix, not(target_os = "redox")))]
 extern crate libloading;
 extern crate liner;
 extern crate regex;
 extern crate smallstring;
 extern crate smallvec;
-#[cfg(target_os = "redox")]
-extern crate syscall;
 extern crate unicode_segmentation;
-#[cfg(all(unix, not(target_os = "redox")))]
-extern crate users as users_unix;
 extern crate xdg;
 
-#[cfg(target_os = "redox")]
-#[path = "sys/redox/mod.rs"]
-pub mod sys;
-
-#[cfg(unix)]
-#[path = "sys/unix/mod.rs"]
-pub mod sys;
+pub extern crate ion_sys as sys;
 
 #[macro_use]
 mod types;