diff --git a/Cargo.lock b/Cargo.lock
index 11a8c3c49aa00b24c1061e917287d555a278f52f..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,6 +462,7 @@ name = "string"
 version = "0.1.0"
 dependencies = [
  "cbindgen 0.5.0",
+ "errno 0.1.0",
  "platform 0.1.0",
  "stdlib 0.1.0",
 ]
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/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..8a28cb6d3e9c956858cd3923c12c357deded209d
--- /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..90c269714d878e2a52b802b887c726e547ebc201 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,6 +5,7 @@ extern crate compiler_builtins;
 extern crate platform;
 
 extern crate ctype;
+extern crate errno;
 extern crate fcntl;
 extern crate grp;
 extern crate mman;
diff --git a/src/string/Cargo.toml b/src/string/Cargo.toml
index 36b34042a9f483286ddf34b2c4503fb76462e9a4..d00a3e5c11839ef8c485e9612172252cd0992c63 100644
--- a/src/string/Cargo.toml
+++ b/src/string/Cargo.toml
@@ -10,3 +10,4 @@ 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 4b091e399ff55b2e701e2070a93c488098597f7f..744e5411a9bafbe5be415e5492fc0a6dea2c3171 100644
--- a/src/string/src/lib.rs
+++ b/src/string/src/lib.rs
@@ -4,8 +4,10 @@
 
 extern crate platform;
 extern crate stdlib;
+extern crate errno;
 
 use platform::types::*;
+use errno::*;
 use core::cmp;
 use core::usize;
 
@@ -95,9 +97,9 @@ pub unsafe extern "C" fn strndup(s1: *const c_char, size: usize) -> *mut c_char
     // the "+ 1" is to account for the NUL byte
     let len = strnlen(s1, size) + 1;
 
-    let buffer = stdlib::malloc(len) as *mut _;
+    let buffer = stdlib::malloc(len) as *mut c_char;
     if buffer.is_null() {
-        // TODO: set errno
+        platform::errno = Errno::ENOMEM as c_int;
     } else {
         //memcpy(buffer, s1, len)
         for i in 0..len as isize {