diff --git a/Cargo.lock b/Cargo.lock
index 9c7e66eeda8340639307a303b33fa29fd4965264..c2ea9141fbbff9f429b00d75e80ce7a7fb5824d5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -75,6 +75,14 @@ name = "dtoa"
 version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "errno"
+version = "0.1.0"
+dependencies = [
+ "cbindgen 0.5.0",
+ "platform 0.1.0",
+]
+
 [[package]]
 name = "fcntl"
 version = "0.1.0"
@@ -244,6 +252,7 @@ version = "0.1.0"
 dependencies = [
  "compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins.git)",
  "ctype 0.1.0",
+ "errno 0.1.0",
  "fcntl 0.1.0",
  "grp 0.1.0",
  "mman 0.1.0",
@@ -453,7 +462,9 @@ name = "string"
 version = "0.1.0"
 dependencies = [
  "cbindgen 0.5.0",
+ "errno 0.1.0",
  "platform 0.1.0",
+ "stdlib 0.1.0",
 ]
 
 [[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 750853e3d4577dea02c7776e6d71ca7632ffedb7..5c7f356e871b6e904f7e0753e0c75e713ee61f12 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,6 +14,7 @@ members = ["src/crt0"]
 compiler_builtins = { git = "https://github.com/rust-lang-nursery/compiler-builtins.git", default-features = false, features = ["mem"] }
 platform = { path = "src/platform" }
 ctype = { path = "src/ctype" }
+errno = { path = "src/errno" }
 fcntl = { path = "src/fcntl" }
 grp = { path = "src/grp" }
 semaphore = { path = "src/semaphore" }
diff --git a/include/errno.h b/include/errno.h
index f1761777c5bd1cdff39b0b42764baac82aee1c12..02b7e0c00f57580b0e132baa1c6679fa4a44a3b2 100644
--- a/include/errno.h
+++ b/include/errno.h
@@ -1 +1 @@
-extern int errno;
+extern __thread int errno;
diff --git a/src/errno/Cargo.toml b/src/errno/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..cfaaad846516b32966aeee42efc7b2399cfcc070
--- /dev/null
+++ b/src/errno/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "errno"
+version = "0.1.0"
+authors = ["Alex Lyon <arcterus@mail.com>"]
+build = "build.rs"
+
+[build-dependencies]
+cbindgen = { path = "../../cbindgen" }
+
+[dependencies]
+platform = { path = "../platform" }
diff --git a/src/errno/build.rs b/src/errno/build.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5de392d433998a6e0f7412671017b5bd5659eec0
--- /dev/null
+++ b/src/errno/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/errno.h");
+}
diff --git a/src/errno/cbindgen.toml b/src/errno/cbindgen.toml
new file mode 100644
index 0000000000000000000000000000000000000000..e71467bc3cc2a9abf964813b4d7a08c4b0c56cb9
--- /dev/null
+++ b/src/errno/cbindgen.toml
@@ -0,0 +1,6 @@
+sys_includes = []
+include_guard = "_ERRNO_H"
+language = "C"
+
+[enum]
+prefix_with_name = true
diff --git a/src/errno/src/lib.rs b/src/errno/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3cb5cd036c4cdd178d54ab15f1fc25d18aa9c124
--- /dev/null
+++ b/src/errno/src/lib.rs
@@ -0,0 +1,166 @@
+//! errno implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/errno.h.html
+
+#![no_std]
+
+extern crate platform;
+
+pub enum Errno {
+    // Argument list too long
+    E2BIG = 1,
+    // Permission denied
+    EACCES,
+    // Address in use
+    EADDRINUSE,
+    // Address not available
+    EADDRNOTAVAIL,
+    // Address family not supported
+    EAFNOSUPPORT,
+    // Resource unavailable, try again (may be the same value as [EWOULDBLOCK])
+    EAGAIN,
+    // Connection already in progress
+    EALREADY,
+    // Bad file descriptor
+    EBADF,
+    // Bad message
+    EBADMSG,
+    // Device or resource busy
+    EBUSY,
+    // Operation canceled
+    ECANCELED,
+    // No child processes
+    ECHILD,
+    // Connection aborted
+    ECONNABORTED,
+    // Connection refused
+    ECONNREFUSED,
+    // Connection reset
+    ECONNRESET,
+    // Resource deadlock would occur
+    EDEADLK,
+    // Destination address required
+    EDESTADDRREQ,
+    // Mathematics argument out of domain of function
+    EDOM,
+    // Reserved
+    EDQUOT,
+    // File exists
+    EEXIST,
+    // Bad address
+    EFAULT,
+    // File too large
+    EFBIG,
+    // Host is unreachable
+    EHOSTUNREACH,
+    // Identifier removed
+    EIDRM,
+    // Illegal byte sequence
+    EILSEQ,
+    // Operation in progress
+    EINPROGRESS,
+    // Interrupted function
+    EINTR,
+    // Invalid argument
+    EINVAL,
+    // I/O error
+    EIO,
+    // Socket is connected
+    EISCONN,
+    // Is a directory
+    EISDIR,
+    // Too many levels of symbolic links
+    ELOOP,
+    // Too many open files
+    EMFILE,
+    // Too many links
+    EMLINK,
+    // Message too large
+    EMSGSIZE,
+    // Reserved
+    EMULTIHOP,
+    // Filename too long
+    ENAMETOOLONG,
+    // Network is down
+    ENETDOWN,
+    // Connection aborted by network
+    ENETRESET,
+    // Network unreachable
+    ENETUNREACH,
+    // Too many files open in system
+    ENFILE,
+    // No buffer space available
+    ENOBUFS,
+    // No message is available on the STREAM head read queue
+    ENODATA,
+    // No such device
+    ENODEV,
+    // No such file or directory
+    ENOENT,
+    // Executable file format error
+    ENOEXEC,
+    // No locks available
+    ENOLCK,
+    // Reserved
+    ENOLINK,
+    // Not enough space
+    ENOMEM,
+    // No message of the desired type
+    ENOMSG,
+    // Protocol not available
+    ENOPROTOOPT,
+    // No space left on device
+    ENOSPC,
+    // No STREAM resources
+    ENOSR,
+    // Not a STREAM
+    ENOSTR,
+    // Function not supported
+    ENOSYS,
+    // The socket is not connected
+    ENOTCONN,
+    // Not a directory
+    ENOTDIR,
+    // Directory not empty
+    ENOTEMPTY,
+    // Not a socket
+    ENOTSOCK,
+    // Not supported
+    ENOTSUP,
+    // Inappropriate I/O control operation
+    ENOTTY,
+    // No such device or address
+    ENXIO,
+    // Operation not supported on socket
+    EOPNOTSUPP,
+    // Value too large to be stored in data type
+    EOVERFLOW,
+    // Operation not permitted
+    EPERM,
+    // Broken pipe
+    EPIPE,
+    // Protocol error
+    EPROTO,
+    // Protocol not supported
+    EPROTONOSUPPORT,
+    // Protocol wrong type for socket
+    EPROTOTYPE,
+    // Result too large
+    ERANGE,
+    // Read-only file system
+    EROFS,
+    // Invalid seek
+    ESPIPE,
+    // No such process
+    ESRCH,
+    // Reserved
+    ESTALE,
+    // Stream ioctl() timeout
+    ETIME,
+    // Connection timed out
+    ETIMEDOUT,
+    // Text file busy
+    ETXTBSY,
+    // Operation would block (may be the same value as [EAGAIN])
+    EWOULDBLOCK,
+    // Cross-device link
+    EXDEV,
+}
diff --git a/src/lib.rs b/src/lib.rs
index c4245e69c8e27a6c04ab7b8e80c7456c3709b373..b3b38a57b8c4c8b2e3d8ec4ec6313c4aca166b25 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,9 +5,11 @@ extern crate compiler_builtins;
 extern crate platform;
 
 extern crate ctype;
+extern crate errno;
 extern crate fcntl;
 extern crate grp;
 extern crate mman;
+extern crate semaphore;
 extern crate stdio;
 extern crate stdlib;
 extern crate string;
diff --git a/src/platform/src/lib.rs b/src/platform/src/lib.rs
index 0719f8b84307ba8e69946064d4bc8347a750dbcc..6e5841a965681dd62e48e6e0e193f72088a491ef 100644
--- a/src/platform/src/lib.rs
+++ b/src/platform/src/lib.rs
@@ -33,18 +33,9 @@ use types::*;
 pub static mut errno: c_int = 0;
 
 pub unsafe fn c_str(s: *const c_char) -> &'static [u8] {
-    use core::slice;
-
-    let mut size = 0;
-
-    loop {
-        if *s.offset(size) == 0 {
-            break;
-        }
-        size += 1;
-    }
+    use core::usize;
 
-    slice::from_raw_parts(s as *const u8, size as usize)
+    c_str_n(s, usize::MAX)
 }
 
 pub unsafe fn c_str_n(s: *const c_char, n: usize) -> &'static [u8] {
diff --git a/src/string/Cargo.toml b/src/string/Cargo.toml
index a5678f9b05d3c9f856885fd2f03ec7b7cc6e5d51..d00a3e5c11839ef8c485e9612172252cd0992c63 100644
--- a/src/string/Cargo.toml
+++ b/src/string/Cargo.toml
@@ -9,3 +9,5 @@ cbindgen = { path = "../../cbindgen" }
 
 [dependencies]
 platform = { path = "../platform" }
+stdlib = { path = "../stdlib" }
+errno = { path = "../errno" }
\ No newline at end of file
diff --git a/src/string/src/lib.rs b/src/string/src/lib.rs
index c1b30f2289b544998b3fce5e1b3002fee625a893..f8a6f4250943d3d4e0d8408b49b7250f61174df7 100644
--- a/src/string/src/lib.rs
+++ b/src/string/src/lib.rs
@@ -2,10 +2,14 @@
 
 #![no_std]
 
+extern crate errno;
 extern crate platform;
+extern crate stdlib;
 
 use platform::types::*;
+use errno::*;
 use core::cmp;
+use core::usize;
 
 #[no_mangle]
 pub extern "C" fn memccpy(s1: *mut c_void, s2: *const c_void, c: c_int, n: usize) -> *mut c_void {
@@ -54,8 +58,8 @@ pub extern "C" fn memchr(s: *const c_void, c: c_int, n: usize) -> *mut c_void {
 // }
 
 #[no_mangle]
-pub extern "C" fn strcat(s1: *mut c_char, s2: *const c_char) -> *mut c_char {
-    unimplemented!();
+pub unsafe extern "C" fn strcat(s1: *mut c_char, s2: *const c_char) -> *mut c_char {
+    strncat(s1, s2, usize::MAX)
 }
 
 #[no_mangle]
@@ -64,8 +68,8 @@ pub extern "C" fn strchr(s: *const c_char, c: c_int) -> *mut c_char {
 }
 
 #[no_mangle]
-pub extern "C" fn strcmp(s1: *const c_char, s2: *const c_char) -> c_int {
-    unimplemented!();
+pub unsafe extern "C" fn strcmp(s1: *const c_char, s2: *const c_char) -> c_int {
+    strncmp(s1, s2, usize::MAX)
 }
 
 #[no_mangle]
@@ -74,8 +78,8 @@ pub extern "C" fn strcoll(s1: *const c_char, s2: *const c_char) -> c_int {
 }
 
 #[no_mangle]
-pub extern "C" fn strcpy(s1: *mut c_char, s2: *const c_char) -> *mut c_char {
-    unimplemented!();
+pub unsafe extern "C" fn strcpy(s1: *mut c_char, s2: *const c_char) -> *mut c_char {
+    strncpy(s1, s2, usize::MAX)
 }
 
 #[no_mangle]
@@ -84,8 +88,27 @@ pub extern "C" fn strcspn(s1: *const c_char, s2: *const c_char) -> c_ulong {
 }
 
 #[no_mangle]
-pub extern "C" fn strdup(s1: *const c_char) -> *mut c_char {
-    unimplemented!();
+pub unsafe extern "C" fn strdup(s1: *const c_char) -> *mut c_char {
+    strndup(s1, usize::MAX)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strndup(s1: *const c_char, size: usize) -> *mut c_char {
+    let len = strnlen(s1, size);
+
+    // the "+ 1" is to account for the NUL byte
+    let buffer = stdlib::malloc(len + 1) as *mut c_char;
+    if buffer.is_null() {
+        platform::errno = Errno::ENOMEM as c_int;
+    } else {
+        //memcpy(buffer, s1, len)
+        for i in 0..len as isize {
+            *buffer.offset(i) = *s1.offset(i);
+        }
+        *buffer.offset(len as isize) = 0;
+    }
+
+    buffer
 }
 
 #[no_mangle]
@@ -95,7 +118,12 @@ pub extern "C" fn strerror(errnum: c_int) -> *mut c_char {
 
 #[no_mangle]
 pub unsafe extern "C" fn strlen(s: *const c_char) -> size_t {
-    platform::c_str(s).len() as size_t
+    strnlen(s, usize::MAX)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strnlen(s: *const c_char, size: usize) -> size_t {
+    platform::c_str_n(s, size).len() as size_t
 }
 
 #[no_mangle]