diff --git a/Cargo.toml b/Cargo.toml
index 9f0b62d88af19eac380b3aadbdf0eda404547dfb..11148175fe47c910fc5ec90a2b9f4f37a530b20a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,6 +16,7 @@ platform = { path = "platform" }
 ctype = { path = "src/ctype" }
 fcntl = { path = "src/fcntl" }
 grp = { path = "src/grp" }
+semaphore = { path = "src/semaphore" }
 mman = { path = "src/mman" }
 stdio = { path = "src/stdio" }
 stdlib = { path = "src/stdlib" }
diff --git a/platform/src/rawfile.rs b/platform/src/rawfile.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d4ee4bee60b820c45edb7459ab55be0a22292de4
--- /dev/null
+++ b/platform/src/rawfile.rs
@@ -0,0 +1,27 @@
+use core::ops::Deref;
+
+pub struct RawFile(usize);
+
+impl RawFile {
+    pub fn open<T: AsRef<[u8]>>(path: T, flags: usize) -> Result<RawFile> {
+        open(path, flags).map(RawFile)
+    }
+
+    pub fn dup(&self, buf: &[u8]) -> Result<RawFile> {
+        dup(self.0, buf).map(RawFile)
+    }
+}
+
+impl Drop for RawFile {
+    fn drop(&mut self) {
+        let _ = close(self.0);
+    }
+}
+
+impl Deref for RawFile {
+    type Target = usize;
+
+    fn deref(&self) -> &usize {
+        &self.0
+    }
+}
diff --git a/src/semaphore/Cargo.toml b/src/semaphore/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..5bc1c215846febf3c7c1835a5b60369509c03d46
--- /dev/null
+++ b/src/semaphore/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "semaphore"
+version = "0.1.0"
+authors = ["Jeremy Soller <jackpot51@gmail.com>"]
+build = "build.rs"
+
+[build-dependencies]
+cbindgen = { path = "../../cbindgen" }
+
+[dependencies]
+platform = { path = "../../platform" }
diff --git a/src/semaphore/build.rs b/src/semaphore/build.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e24ff4d6925bf5e90ddf88318b6cb95e8006eddb
--- /dev/null
+++ b/src/semaphore/build.rs
@@ -0,0 +1,11 @@
+extern crate cbindgen;
+
+use std::{env, fs};
+
+fn main() {
+    let crate_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
+    fs::create_dir_all("../../target/include").expect("failed to create include directory");
+    cbindgen::generate(crate_dir)
+      .expect("failed to generate bindings")
+      .write_to_file("../../target/include/semaphore.h");
+}
diff --git a/src/semaphore/cbindgen.toml b/src/semaphore/cbindgen.toml
new file mode 100644
index 0000000000000000000000000000000000000000..db95e2fec95470a7fade7468b9c0ef3ff310118c
--- /dev/null
+++ b/src/semaphore/cbindgen.toml
@@ -0,0 +1,6 @@
+sys_includes = []
+include_guard = "_SEMAPHORE_H"
+language = "C"
+
+[enum]
+prefix_with_name = true
diff --git a/src/semaphore/src/lib.rs b/src/semaphore/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..676946c04c34a585f1ace367e187a8615cced16d
--- /dev/null
+++ b/src/semaphore/src/lib.rs
@@ -0,0 +1,67 @@
+#![no_std]
+
+extern crate platform;
+
+use platform::types::*;
+
+#[repr(C)]
+#[derive(Copy)]
+pub union sem_t {
+    pub size: [c_char; 32usize],
+    pub align: c_long,
+    _bindgen_union_align: [u64; 4usize],
+}
+impl Clone for sem_t {
+    fn clone(&self) -> Self { *self }
+}
+#[no_mangle]
+pub extern "C" fn sem_init(sem: *mut sem_t, pshared: c_int,
+                    value: c_uint) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn sem_destroy(sem: *mut sem_t) -> c_int {
+    unimplemented!();
+}
+
+/*
+ *#[no_mangle]
+ *pub extern "C" fn sem_open(name: *const c_char,
+ *                    oflag: c_int, ...) -> *mut sem_t {
+ *    unimplemented!();
+ *}
+ */
+
+#[no_mangle]
+pub extern "C" fn sem_close(sem: *mut sem_t) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn sem_unlink(name: *const c_char)
+     -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn sem_wait(sem: *mut sem_t) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn sem_trywait(sem: *mut sem_t) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn sem_post(sem: *mut sem_t) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int)
+     -> c_int {
+    unimplemented!();
+}
+
diff --git a/src/todo/semaphore/lib.rs b/src/todo/semaphore/lib.rs
deleted file mode 100644
index c047a45fc9d15dd278ec054a22dd34addad3f2dc..0000000000000000000000000000000000000000
--- a/src/todo/semaphore/lib.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-#[repr(C)]
-#[derive(Copy)]
-pub union sem_t {
-    pub size: [libc::c_char; 32usize],
-    pub align: libc::c_long,
-    _bindgen_union_align: [u64; 4usize],
-}
-impl Clone for sem_t {
-    fn clone(&self) -> Self { *self }
-}
-#[no_mangle]
-pub extern "C" fn sem_init(sem: *mut sem_t, pshared: libc::c_int,
-                    value: libc::c_uint) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn sem_destroy(sem: *mut sem_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn sem_open(name: *const libc::c_char,
-                    oflag: libc::c_int, ...) -> *mut sem_t {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn sem_close(sem: *mut sem_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn sem_unlink(name: *const libc::c_char)
-     -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn sem_wait(sem: *mut sem_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn sem_timedwait(sem: *mut sem_t, abstime: *const timespec)
-     -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn sem_trywait(sem: *mut sem_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn sem_post(sem: *mut sem_t) -> libc::c_int {
-    unimplemented!();
-}
-
-#[no_mangle]
-pub extern "C" fn sem_getvalue(sem: *mut sem_t, sval: *mut libc::c_int)
-     -> libc::c_int {
-    unimplemented!();
-}
-