diff --git a/.travis.yml b/.travis.yml
index dae224e1a481144c90e8f81b63e116cdc60ece19..15083598be4e0726fba9aa4840687cef44533d82 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,6 +5,7 @@ cache: cargo
 before_script:
   - rustup component add rustfmt-preview
   - rustup target add x86_64-unknown-redox
+  - rustup target add aarch64-unknown-linux-gnu
 script:
   - bash ./ci.sh
 notifications:
diff --git a/Cargo.lock b/Cargo.lock
index 06030c19ea05d5922a0af3a6571c44f193a17294..f2bdefd4a5261e3fd2c2c34996d0a79ddba7ed6b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -31,6 +31,11 @@ dependencies = [
  "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "cc"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "cfg-if"
 version = "0.1.2"
@@ -105,11 +110,6 @@ name = "fuchsia-zircon-sys"
 version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "gcc"
-version = "0.3.54"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "grp"
 version = "0.1.0"
@@ -258,6 +258,7 @@ dependencies = [
  "mman 0.1.0",
  "platform 0.1.0",
  "semaphore 0.1.0",
+ "stat 0.1.0",
  "stdio 0.1.0",
  "stdlib 0.1.0",
  "string 0.1.0",
@@ -440,6 +441,14 @@ dependencies = [
  "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "stat"
+version = "0.1.0"
+dependencies = [
+ "cbindgen 0.5.0",
+ "platform 0.1.0",
+]
+
 [[package]]
 name = "stdio"
 version = "0.1.0"
@@ -456,6 +465,7 @@ version = "0.1.0"
 dependencies = [
  "cbindgen 0.5.0",
  "ctype 0.1.0",
+ "errno 0.1.0",
  "platform 0.1.0",
  "ralloc 1.0.0",
 ]
@@ -576,7 +586,7 @@ dependencies = [
 name = "va_list-helper"
 version = "0.0.2"
 dependencies = [
- "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -625,13 +635,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455"
 "checksum atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8352656fd42c30a0c3c89d26dea01e3b77c0ab2af18230835c15e2e13cd51859"
 "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
+"checksum cc 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9be26b24e988625409b19736d130f0c7d224f01d06454b5f81d8d23d6c1a618f"
 "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
 "checksum clap 2.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1c07b9257a00f3fc93b7f3c417fc15607ec7a56823bc2c37ec744e266387de5b"
 "checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins.git)" = "<none>"
 "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
 "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
 "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
-"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
 "checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
 "checksum libc 0.2.37 (registry+https://github.com/rust-lang/crates.io-index)" = "56aebce561378d99a0bb578f8cb15b6114d2a1814a6c7949bbe646d968bb4fa9"
diff --git a/Cargo.toml b/Cargo.toml
index 4bb5d97b8abd64fbed9189f57220bf525c32f17c..6d7103c8f7ae425671273f2a989ad4ed8dd5addb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,6 +19,7 @@ fcntl = { path = "src/fcntl" }
 grp = { path = "src/grp" }
 semaphore = { path = "src/semaphore" }
 mman = { path = "src/mman" }
+stat = { path = "src/stat" }
 stdio = { path = "src/stdio" }
 stdlib = { path = "src/stdlib" }
 string = { path = "src/string" }
diff --git a/README.md b/README.md
index a48d27fe7a8ecc2202122374885f32294e49ed47..59d8525083085602fcd77d4118225f79b650d88d 100644
--- a/README.md
+++ b/README.md
@@ -5,3 +5,13 @@ The motivation for this project is twofold: Reduce issues the redox crew was hav
 
 ## Contributing
 Just search for any invocation of the `unimplemented` macro, and hop in! The ci server checks builds for linux and redox, checks formatting (via rustfmt), and runs the test suite. Run `ci.sh` locally to check that your changes will pass travis. Use `fmt.sh` to format your code and `test.sh` to run the C test suite.
+
+## Supported OSes
+
+ - RedoxOS
+ - Linux
+
+## Supported architectures
+
+ - x86\_64
+ - Aarch64
diff --git a/bindgen_transform.sh b/bindgen_transform.sh
index a5ddde9fbbed90f12efac15637e8e7759725127b..b0f122edb8de0f2d59add943c96d3a895246e35f 100755
--- a/bindgen_transform.sh
+++ b/bindgen_transform.sh
@@ -1,4 +1,4 @@
-sed -i 's/::std::os::raw::/libc::/g' $1
+sed -i 's/::std::os::raw:://g' $1
 perl -i -p0e 's/extern "C" \{\n    pub fn/#[no_mangle]\npub extern "C" fn/g' $1 
 perl -i -p0e 's/;\n\}/ {\n    unimplemented!();\n\}\n/g' $1
 rustfmt $1
diff --git a/ci.sh b/ci.sh
index 6fe90aaf9e6d9f94d658d9700b2e1588ed7c94c7..fd7dd91a480ac2b1f8ee9d3230b3210b3367440d 100755
--- a/ci.sh
+++ b/ci.sh
@@ -4,3 +4,9 @@ set -ex
 ./fmt.sh -- --write-mode=diff
 ./test.sh
 cargo build --target=x86_64-unknown-redox
+if [ $(arch) == "x86_64" ]
+then
+    cargo build --target=aarch64-unknown-linux-gnu
+else
+    cargo build --target=x86_64-unknown-linux-gnu
+fi
diff --git a/include/sys/stat.h b/include/sys/stat.h
new file mode 100644
index 0000000000000000000000000000000000000000..97836d36b0c98f591924a3791dd675753bc2ecb1
--- /dev/null
+++ b/include/sys/stat.h
@@ -0,0 +1,39 @@
+#ifndef _STAT_H
+#define _STAT_H
+
+#include <sys/types.h>
+
+struct stat {
+  dev_t st_dev;
+  ino_t st_ino;
+  nlink_t st_nlink;
+  mode_t st_mode;
+  uid_t st_uid;
+  gid_t st_gid;
+  dev_t st_rdev;
+  off_t st_size;
+  blksize_t st_blksize;
+  time_t st_atim;
+  time_t st_mtim;
+  time_t st_ctim;
+};
+
+int chmod(const char *path, mode_t mode);
+
+int fchmod(int fildes, mode_t mode);
+
+int fstat(int fildes, struct stat *buf);
+
+int lstat(const char *path, struct stat *buf);
+
+int mkdir(const char *path, mode_t mode);
+
+int mkfifo(const char *path, mode_t mode);
+
+int mknod(const char *path, mode_t mode, dev_t dev);
+
+int stat(const char *file, struct stat *buf);
+
+mode_t umask(mode_t mask);
+
+#endif /* _STAT_H */
diff --git a/include/sys/types.h b/include/sys/types.h
index 6f770aa64c19aa215a00a8c898ad6a1d66a68c45..0813cddfe4974a14426f1475a8693c66cb23498d 100644
--- a/include/sys/types.h
+++ b/include/sys/types.h
@@ -1,17 +1,27 @@
 #ifndef _SYS_TYPES_H
 #define _SYS_TYPES_H
 
+typedef long blksize_t;
+
+typedef long dev_t;
+
+typedef unsigned long ino_t;
+
 typedef int gid_t;
 typedef int uid_t;
 
 typedef int mode_t;
 
+typedef unsigned long nlink_t;
+
 typedef long off_t;
 
 typedef int pid_t;
 
 typedef long ssize_t;
 
+typedef long time_t;
+
 typedef int useconds_t;
 
 #endif /* _SYS_TYPES_H */
diff --git a/src/lib.rs b/src/lib.rs
index 52053e45801c335ca0518b57d5c4c0a1d6e3c7ce..cd56891d761912eec73aaab3d046adbcb96f9c1f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -10,6 +10,7 @@ extern crate fcntl;
 extern crate grp;
 extern crate mman;
 extern crate semaphore;
+extern crate stat;
 extern crate stdio;
 extern crate stdlib;
 extern crate string;
diff --git a/src/platform/src/linux/mod.rs b/src/platform/src/linux/mod.rs
index 5f0066c2a4fc0df618407780d173978868092e57..daff60cb5760fde81bd0776f39f94af6f3fd73ea 100644
--- a/src/platform/src/linux/mod.rs
+++ b/src/platform/src/linux/mod.rs
@@ -4,6 +4,7 @@ use errno;
 use types::*;
 
 const AT_FDCWD: c_int = -100;
+const AT_REMOVEDIR: c_int = 0x200;
 
 pub fn e(sys: usize) -> usize {
     if (sys as isize) < 0 && (sys as isize) >= -256 {
@@ -67,7 +68,7 @@ pub fn fcntl(fildes: c_int, cmd: c_int, arg: c_int) -> c_int {
 }
 
 pub fn fork() -> pid_t {
-    e(unsafe { syscall!(FORK) }) as pid_t
+    e(unsafe { syscall!(CLONE, 17, 0) }) as pid_t
 }
 
 pub fn fsync(fildes: c_int) -> c_int {
@@ -115,7 +116,11 @@ pub fn getuid() -> uid_t {
 }
 
 pub fn link(path1: *const c_char, path2: *const c_char) -> c_int {
-    e(unsafe { syscall!(LINKAT, AT_FDCWD, path1, path2) }) as c_int
+    e(unsafe { syscall!(LINKAT, AT_FDCWD, path1, AT_FDCWD, path2, 0) }) as c_int
+}
+
+pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int {
+    e(unsafe { syscall!(MKDIRAT, AT_FDCWD, path, mode) }) as c_int
 }
 
 pub fn open(path: *const c_char, oflag: c_int, mode: mode_t) -> c_int {
@@ -130,6 +135,26 @@ pub fn read(fildes: c_int, buf: &mut [u8]) -> ssize_t {
     e(unsafe { syscall!(READ, fildes, buf.as_mut_ptr(), buf.len()) }) as ssize_t
 }
 
+pub fn rmdir(path: *const c_char) -> c_int {
+    e(unsafe { syscall!(UNLINKAT, AT_FDCWD, path, AT_REMOVEDIR) }) as c_int
+}
+
+pub fn setpgid(pid: pid_t, pgid: pid_t) -> c_int {
+    e(unsafe { syscall!(SETPGID, pid, pgid) }) as c_int
+}
+
+pub fn setregid(rgid: gid_t, egid: gid_t) -> c_int {
+    e(unsafe { syscall!(SETREGID, rgid, egid) }) as c_int
+}
+
+pub fn setreuid(ruid: uid_t, euid: uid_t) -> c_int {
+    e(unsafe { syscall!(SETREUID, ruid, euid) }) as c_int
+}
+
+pub fn unlink(path: *const c_char) -> c_int {
+    e(unsafe { syscall!(UNLINKAT, AT_FDCWD, path, 0) }) as c_int
+}
+
 pub fn write(fildes: c_int, buf: &[u8]) -> ssize_t {
     e(unsafe { syscall!(WRITE, fildes, buf.as_ptr(), buf.len()) }) as ssize_t
 }
diff --git a/src/platform/src/redox/mod.rs b/src/platform/src/redox/mod.rs
index edf9ad1724f70436954c433dda23a61acc96e18b..0ea4bda2073454a74f9968f0c351413b5471f741 100644
--- a/src/platform/src/redox/mod.rs
+++ b/src/platform/src/redox/mod.rs
@@ -1,6 +1,7 @@
 use core::ptr;
 use core::slice;
 use syscall;
+use syscall::flag::*;
 
 use c_str;
 use errno;
@@ -122,6 +123,18 @@ pub fn link(path1: *const c_char, path2: *const c_char) -> c_int {
     e(unsafe { syscall::link(path1.as_ptr(), path2.as_ptr()) }) as c_int
 }
 
+pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int {
+    let flags = O_CREAT | O_EXCL | O_CLOEXEC | O_DIRECTORY | mode as usize & 0o777;
+    let path = unsafe { c_str(path) };
+    match syscall::open(path, flags) {
+        Ok(fd) => {
+            syscall::close(fd);
+            0
+        }
+        Err(err) => e(Err(err)) as c_int,
+    }
+}
+
 pub fn open(path: *const c_char, oflag: c_int, mode: mode_t) -> c_int {
     let path = unsafe { c_str(path) };
     e(syscall::open(path, (oflag as usize) | (mode as usize))) as c_int
@@ -139,6 +152,28 @@ pub fn read(fd: c_int, buf: &mut [u8]) -> ssize_t {
     e(syscall::read(fd as usize, buf)) as ssize_t
 }
 
+pub fn rmdir(path: *const c_char) -> c_int {
+    let path = unsafe { c_str(path) };
+    e(syscall::rmdir(path)) as c_int
+}
+
+pub fn setpgid(pid: pid_t, pgid: pid_t) -> c_int {
+    e(syscall::setpgid(pid as usize, pgid as usize)) as c_int
+}
+
+pub fn setregid(rgid: gid_t, egid: gid_t) -> c_int {
+    e(syscall::setregid(rgid as usize, egid as usize)) as c_int
+}
+
+pub fn setreuid(ruid: uid_t, euid: uid_t) -> c_int {
+    e(syscall::setreuid(ruid as usize, euid as usize)) as c_int
+}
+
+pub fn unlink(path: *const c_char) -> c_int {
+    let path = unsafe { c_str(path) };
+    e(syscall::unlink(path)) as c_int
+}
+
 pub fn write(fd: c_int, buf: &[u8]) -> ssize_t {
     e(syscall::write(fd as usize, buf)) as ssize_t
 }
diff --git a/src/platform/src/types.rs b/src/platform/src/types.rs
index 0057825f297576d2cfc74c6d42f7683b22a64314..786af774d50c671dd6e66d39fed20e7c35181512 100644
--- a/src/platform/src/types.rs
+++ b/src/platform/src/types.rs
@@ -52,6 +52,10 @@ pub type time_t = i64;
 pub type pid_t = usize;
 pub type gid_t = usize;
 pub type uid_t = usize;
+pub type dev_t = usize;
+pub type ino_t = usize;
+pub type nlink_t = usize;
+pub type blksize_t = isize;
 
 pub type useconds_t = i32;
 pub type suseconds_t = i64;
diff --git a/src/stat/Cargo.toml b/src/stat/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..7b779a2cf59d360792e692074bfa66fd4925f1d7
--- /dev/null
+++ b/src/stat/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "stat"
+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/stat/build.rs b/src/stat/build.rs
new file mode 100644
index 0000000000000000000000000000000000000000..74a9a42fe9884469a1fe3e598c65b4179da6b0f6
--- /dev/null
+++ b/src/stat/build.rs
@@ -0,0 +1,13 @@
+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/sys/stat.h");
+     */
+}
diff --git a/src/stat/cbindgen.toml b/src/stat/cbindgen.toml
new file mode 100644
index 0000000000000000000000000000000000000000..d4f38953dbe8afa0f97c39791403b2ac7df5ae95
--- /dev/null
+++ b/src/stat/cbindgen.toml
@@ -0,0 +1,6 @@
+sys_includes = ["sys/types.h"]
+include_guard = "_SYS_STAT_H"
+language = "C"
+
+[enum]
+prefix_with_name = true
diff --git a/src/stat/src/lib.rs b/src/stat/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..b8e2db57439020188be9511bc3c62235eee8e940
--- /dev/null
+++ b/src/stat/src/lib.rs
@@ -0,0 +1,75 @@
+//! stat implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/sysstat.h.html
+
+#![no_std]
+
+extern crate platform;
+
+use platform::types::*;
+
+#[repr(C)]
+pub struct stat {
+    pub st_dev: dev_t,
+    pub st_ino: ino_t,
+    pub st_nlink: nlink_t,
+    pub st_mode: mode_t,
+    pub st_uid: uid_t,
+    pub st_gid: gid_t,
+    pub st_rdev: dev_t,
+    pub st_size: off_t,
+    pub st_blksize: blksize_t,
+    pub st_atim: time_t,
+    pub st_mtim: time_t,
+    pub st_ctim: time_t,
+}
+
+#[no_mangle]
+pub extern "C" fn chmod(path: *const c_char, mode: mode_t) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn fchmod(fildes: c_int, mode: mode_t) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn fstat(fildes: c_int, buf: *mut stat) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn lstat(path: *const c_char, buf: *mut stat) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn mkdir(path: *const c_char, mode: mode_t) -> c_int {
+    platform::mkdir(path, mode)
+}
+
+#[no_mangle]
+pub extern "C" fn mkfifo(path: *const c_char, mode: mode_t) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn mknod(path: *const c_char, mode: mode_t, dev: dev_t) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn stat(file: *const c_char, buf: *mut stat) -> c_int {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub extern "C" fn umask(mask: mode_t) -> mode_t {
+    unimplemented!();
+}
+
+/*
+#[no_mangle]
+pub extern "C" fn func(args) -> c_int {
+    unimplemented!();
+}
+*/
diff --git a/src/stdio/src/printf.rs b/src/stdio/src/printf.rs
index d1ce976cbd28a8da41c9c77ded26de8a6911a4e3..093ee82c122d6f902e00d8f9c05f2653dcdbc432 100644
--- a/src/stdio/src/printf.rs
+++ b/src/stdio/src/printf.rs
@@ -1,13 +1,9 @@
-use core::fmt;
+use core::{fmt, mem, slice, str};
 
 use platform::types::*;
 use vl::VaList;
 
 pub unsafe fn printf<W: fmt::Write>(mut w: W, format: *const c_char, mut ap: VaList) -> c_int {
-    use core::fmt::Write;
-    use core::slice;
-    use core::str;
-
     extern "C" {
         fn strlen(s: *const c_char) -> size_t;
     }
@@ -39,6 +35,13 @@ pub unsafe fn printf<W: fmt::Write>(mut w: W, format: *const c_char, mut ap: VaL
 
                     found_percent = false;
                 }
+                'f' | 'F' => {
+                    let a = ap.get::<f64>();
+
+                    w.write_fmt(format_args!("{}", a));
+
+                    found_percent = false;
+                }
                 'n' => {
                     let _a = ap.get::<c_int>();
 
@@ -82,6 +85,13 @@ pub unsafe fn printf<W: fmt::Write>(mut w: W, format: *const c_char, mut ap: VaL
 
                     found_percent = false;
                 }
+                'o' => {
+                    let a = ap.get::<c_uint>();
+
+                    w.write_fmt(format_args!("{:o}", a));
+
+                    found_percent = false;
+                }
                 '-' => {}
                 '+' => {}
                 ' ' => {}
diff --git a/src/stdlib/Cargo.toml b/src/stdlib/Cargo.toml
index 4a2fb9f88ef60db4aa7c58e6dfebd7b123631a47..97f5d44187b6fc477f3bb8ece793d9fd6d56fddd 100644
--- a/src/stdlib/Cargo.toml
+++ b/src/stdlib/Cargo.toml
@@ -11,3 +11,4 @@ cbindgen = { path = "../../cbindgen" }
 platform = { path = "../platform" }
 ralloc = { path = "../../ralloc", default-features = false }
 ctype = { path = "../ctype" }
+errno = { path = "../errno" }
diff --git a/src/stdlib/src/lib.rs b/src/stdlib/src/lib.rs
index fd25f5b731be06d721a4e98f50f34b5ca11983a7..dea8dbd13a4b17def216925f39324048faca1c66 100644
--- a/src/stdlib/src/lib.rs
+++ b/src/stdlib/src/lib.rs
@@ -5,9 +5,13 @@
 #![feature(global_allocator)]
 
 extern crate ctype;
+extern crate errno;
 extern crate platform;
 extern crate ralloc;
 
+use core::{ptr, str};
+
+use errno::*;
 use platform::types::*;
 
 #[global_allocator]
@@ -52,8 +56,8 @@ pub unsafe extern "C" fn atexit(func: Option<extern "C" fn()>) -> c_int {
 }
 
 #[no_mangle]
-pub extern "C" fn atof(s: *const c_char) -> c_double {
-    unimplemented!();
+pub unsafe extern "C" fn atof(s: *const c_char) -> c_double {
+    strtod(s, ptr::null_mut())
 }
 
 macro_rules! dec_num_from_ascii {
@@ -396,13 +400,208 @@ pub extern "C" fn srandom(seed: c_uint) {
 }
 
 #[no_mangle]
-pub extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c_double {
-    unimplemented!();
+pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c_double {
+    //TODO: endptr
+
+    use core::str::FromStr;
+
+    let s_str = str::from_utf8_unchecked(platform::c_str(s));
+    match f64::from_str(s_str) {
+        Ok(ok) => ok as c_double,
+        Err(_err) => {
+            platform::errno = EINVAL;
+            0.0
+        }
+    }
 }
 
 #[no_mangle]
-pub extern "C" fn strtol(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_long {
-    unimplemented!();
+pub unsafe extern "C" fn strtol(
+    s: *const c_char,
+    endptr: *mut *const c_char,
+    base: c_int,
+) -> c_long {
+    let set_endptr = |idx: isize| {
+        if !endptr.is_null() {
+            *endptr = s.offset(idx);
+        }
+    };
+
+    let invalid_input = || {
+        platform::errno = EINVAL;
+        set_endptr(0);
+    };
+
+    // only valid bases are 2 through 36
+    if base != 0 && (base < 2 || base > 36) {
+        invalid_input();
+        return 0;
+    }
+
+    let mut idx = 0;
+
+    // skip any whitespace at the beginning of the string
+    while ctype::isspace(*s.offset(idx) as c_int) != 0 {
+        idx += 1;
+    }
+
+    // check for +/-
+    let positive = match is_positive(*s.offset(idx)) {
+        Some((pos, i)) => {
+            idx += i;
+            pos
+        }
+        None => {
+            invalid_input();
+            return 0;
+        }
+    };
+
+    // convert the string to a number
+    let num_str = s.offset(idx);
+    let res = match base {
+        0 => detect_base(num_str).and_then(|(base, i)| convert_integer(num_str.offset(i), base)),
+        8 => convert_octal(num_str),
+        16 => convert_hex(num_str),
+        _ => convert_integer(num_str, base),
+    };
+
+    // check for error parsing octal/hex prefix
+    // also check to ensure a number was indeed parsed
+    let (num, i, _) = match res {
+        Some(res) => res,
+        None => {
+            invalid_input();
+            return 0;
+        }
+    };
+    idx += i;
+
+    // account for the sign
+    let mut num = num as c_long;
+    num = if num.is_negative() {
+        platform::errno = ERANGE;
+        if positive {
+            c_long::max_value()
+        } else {
+            c_long::min_value()
+        }
+    } else {
+        if positive {
+            num
+        } else {
+            -num
+        }
+    };
+
+    set_endptr(idx);
+
+    num
+}
+
+fn is_positive(ch: c_char) -> Option<(bool, isize)> {
+    match ch {
+        0 => None,
+        ch if ch == b'+' as c_char => Some((true, 1)),
+        ch if ch == b'-' as c_char => Some((false, 1)),
+        _ => Some((true, 0)),
+    }
+}
+
+fn detect_base(s: *const c_char) -> Option<(c_int, isize)> {
+    let first = unsafe { *s } as u8;
+    match first {
+        0 => None,
+        b'0' => {
+            let second = unsafe { *s.offset(1) } as u8;
+            if second == b'X' || second == b'x' {
+                Some((16, 2))
+            } else if second >= b'0' && second <= b'7' {
+                Some((8, 1))
+            } else {
+                // in this case, the prefix (0) is going to be the number
+                Some((8, 0))
+            }
+        }
+        _ => Some((10, 0)),
+    }
+}
+
+unsafe fn convert_octal(s: *const c_char) -> Option<(c_ulong, isize, bool)> {
+    if *s != 0 && *s == b'0' as c_char {
+        if let Some((val, idx, overflow)) = convert_integer(s.offset(1), 8) {
+            Some((val, idx + 1, overflow))
+        } else {
+            // in case the prefix is not actually a prefix
+            Some((0, 1, false))
+        }
+    } else {
+        None
+    }
+}
+
+unsafe fn convert_hex(s: *const c_char) -> Option<(c_ulong, isize, bool)> {
+    if (*s != 0 && *s == b'0' as c_char)
+        && (*s.offset(1) != 0 && (*s.offset(1) == b'x' as c_char || *s.offset(1) == b'X' as c_char))
+    {
+        convert_integer(s.offset(2), 16).map(|(val, idx, overflow)| (val, idx + 2, overflow))
+    } else {
+        None
+    }
+}
+
+fn convert_integer(s: *const c_char, base: c_int) -> Option<(c_ulong, isize, bool)> {
+    // -1 means the character is invalid
+    #[cfg_attr(rustfmt, rustfmt_skip)]
+    const LOOKUP_TABLE: [c_long; 256] = [
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+         0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
+        -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+        25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+        -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+        25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    ];
+
+    let mut num: c_ulong = 0;
+    let mut idx = 0;
+    let mut overflowed = false;
+
+    loop {
+        let val = unsafe { LOOKUP_TABLE[*s.offset(idx) as usize] };
+        if val == -1 || val as c_int >= base {
+            break;
+        } else {
+            if let Some(res) = num.checked_mul(base as c_ulong)
+                .and_then(|num| num.checked_add(val as c_ulong))
+            {
+                num = res;
+            } else {
+                unsafe {
+                    platform::errno = ERANGE;
+                }
+                num = c_ulong::max_value();
+                overflowed = true;
+            }
+
+            idx += 1;
+        }
+    }
+
+    if idx > 0 {
+        Some((num, idx, overflowed))
+    } else {
+        None
+    }
 }
 
 #[no_mangle]
diff --git a/src/unistd/src/lib.rs b/src/unistd/src/lib.rs
index ea4609ba50405de7305fd72437092fa666a23e92..8a1d149f887b8aad5ab05f60d54d8c3607a60f31 100644
--- a/src/unistd/src/lib.rs
+++ b/src/unistd/src/lib.rs
@@ -225,7 +225,7 @@ pub extern "C" fn getpgid(pid: pid_t) -> pid_t {
 
 #[no_mangle]
 pub extern "C" fn getpgrp() -> pid_t {
-    unimplemented!();
+    platform::getpgid(platform::getpid())
 }
 
 #[no_mangle]
@@ -336,7 +336,7 @@ pub extern "C" fn readlink(path: *const c_char, buf: *mut c_char, bufsize: size_
 
 #[no_mangle]
 pub extern "C" fn rmdir(path: *const c_char) -> c_int {
-    unimplemented!();
+    platform::rmdir(path)
 }
 
 #[no_mangle]
@@ -351,7 +351,7 @@ pub extern "C" fn setgid(gid: gid_t) -> c_int {
 
 #[no_mangle]
 pub extern "C" fn setpgid(pid: pid_t, pgid: pid_t) -> c_int {
-    unimplemented!();
+    platform::setpgid(pid, pgid)
 }
 
 #[no_mangle]
@@ -361,12 +361,12 @@ pub extern "C" fn setpgrp() -> pid_t {
 
 #[no_mangle]
 pub extern "C" fn setregid(rgid: gid_t, egid: gid_t) -> c_int {
-    unimplemented!();
+    platform::setregid(rgid, egid)
 }
 
 #[no_mangle]
 pub extern "C" fn setreuid(ruid: uid_t, euid: uid_t) -> c_int {
-    unimplemented!();
+    platform::setreuid(ruid, euid)
 }
 
 #[no_mangle]
@@ -436,7 +436,7 @@ pub extern "C" fn ualarm(useconds: useconds_t, interval: useconds_t) -> useconds
 
 #[no_mangle]
 pub extern "C" fn unlink(path: *const c_char) -> c_int {
-    unimplemented!();
+    platform::unlink(path)
 }
 
 #[no_mangle]
diff --git a/tests/.gitignore b/tests/.gitignore
index e5819ec54577f63583b4398ca86d61af361a7ef1..42fe4750c666a6810fd66def2384df6045e3cc7c 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,5 +1,7 @@
+/gen/
 /alloc
 /args
+/atof
 /atoi
 /brk
 /chdir
@@ -10,6 +12,7 @@
 /dup.out
 /error
 /fchdir
+/fcntl
 /fsync
 /ftruncate
 /ftruncate.out
@@ -19,4 +22,8 @@
 /math
 /pipe
 /printf
+/rmdir
+/setid
+/unlink
+/stdlib/strtol
 /write
diff --git a/tests/Makefile b/tests/Makefile
index d7fafcdb2eb5b54690b6b79f32b755644c04a106..24f1ba3a0443600b3e3d3433ca2f644ca1e9e223 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,5 +1,6 @@
 BINS=\
 	alloc \
+	atof \
 	atoi \
 	brk \
 	args \
@@ -17,6 +18,10 @@ BINS=\
 	math \
 	pipe \
 	printf \
+	rmdir \
+	setid \
+	unlink \
+	stdlib/strtol \
 	write
 
 all: $(BINS)
@@ -25,7 +30,33 @@ clean:
 	rm -f $(BINS) *.out
 
 run: $(BINS)
-	for bin in $(BINS); do echo "# $${bin} #"; "./$${bin}" test args; done
+	for bin in $(BINS); \
+	do \
+		echo "# $${bin} #"; \
+		"./$${bin}" test args; \
+	done
+
+expected: $(BINS)
+	rm -rf expected
+	mkdir -p expected
+	for bin in $(BINS); \
+	do \
+		echo "# $${bin} #"; \
+		mkdir -p expected/`dirname $${bin}`; \
+		"./$${bin}" test args > "expected/$${bin}.stdout" 2> "expected/$${bin}.stderr"; \
+	done
+
+verify: $(BINS)
+	rm -rf gen
+	mkdir -p gen
+	for bin in $(BINS); \
+	do \
+		echo "# $${bin} #"; \
+		mkdir -p gen/`dirname $${bin}`; \
+		"./$${bin}" test args > "gen/$${bin}.stdout" 2> "gen/$${bin}.stderr"; \
+		diff -u "gen/$${bin}.stdout" "expected/$${bin}.stdout"; \
+		diff -u "gen/$${bin}.stderr" "expected/$${bin}.stderr"; \
+	done
 
 GCCHEAD=\
 	-nostdinc \
diff --git a/tests/atof.c b/tests/atof.c
new file mode 100644
index 0000000000000000000000000000000000000000..1bfb9d0e220d4029fadb86716017705061958146
--- /dev/null
+++ b/tests/atof.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(int argc, char* argv[]) {
+    double d = atof("-3.14");
+    printf("%f\n", d);
+    return 0;
+}
diff --git a/tests/expected/alloc.stderr b/tests/expected/alloc.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/alloc.stdout b/tests/expected/alloc.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..74753f94e3cfa3f1e9b0374f2f82e4dff032316f
--- /dev/null
+++ b/tests/expected/alloc.stdout
@@ -0,0 +1,2 @@
+malloc 0x55ac6c472618
+calloc 0x55ac6c472618
diff --git a/tests/expected/args.stderr b/tests/expected/args.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/args.stdout b/tests/expected/args.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..3b9ef538c3b9a209e24658fe4ef796b8983cc835
--- /dev/null
+++ b/tests/expected/args.stdout
@@ -0,0 +1 @@
+./args test args 
diff --git a/tests/expected/atof.stderr b/tests/expected/atof.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/atof.stdout b/tests/expected/atof.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..01e913dbfe725d2fdb0b96b99af47aed063f1792
--- /dev/null
+++ b/tests/expected/atof.stdout
@@ -0,0 +1 @@
+-3.14
diff --git a/tests/expected/atoi.stderr b/tests/expected/atoi.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/atoi.stdout b/tests/expected/atoi.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..d90e37cceac826425a16f83375fa2271261c4541
--- /dev/null
+++ b/tests/expected/atoi.stdout
@@ -0,0 +1,6 @@
+-42
+555
+1234567890
+-42
+555
+1234567890
diff --git a/tests/expected/brk.stderr b/tests/expected/brk.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/brk.stdout b/tests/expected/brk.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..c7e87198e01823db56563f4fe0fefe5b192dfb30
--- /dev/null
+++ b/tests/expected/brk.stdout
@@ -0,0 +1 @@
+brk exited with status code 0
diff --git a/tests/expected/chdir.stderr b/tests/expected/chdir.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/chdir.stdout b/tests/expected/chdir.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..6d79e11be0b87900d32ef232c49b0b99fc526f48
--- /dev/null
+++ b/tests/expected/chdir.stdout
@@ -0,0 +1,2 @@
+initial cwd: /home/jeremy/Projects/relibc/tests
+final cwd: /home/jeremy/Projects/relibc
diff --git a/tests/expected/create.stderr b/tests/expected/create.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/create.stdout b/tests/expected/create.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/ctype.stderr b/tests/expected/ctype.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/ctype.stdout b/tests/expected/ctype.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..e83b1e5f11ff31bed1bbfd1ab18e5f793a440275
--- /dev/null
+++ b/tests/expected/ctype.stdout
@@ -0,0 +1 @@
+Success: 0
diff --git a/tests/expected/dup.stderr b/tests/expected/dup.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/dup.stdout b/tests/expected/dup.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..20ec3fc2838660ac3a4dcb4428bd025b248e4fc5
--- /dev/null
+++ b/tests/expected/dup.stdout
@@ -0,0 +1 @@
+fd 4 duped into fd 5
diff --git a/tests/expected/error.stderr b/tests/expected/error.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..4eb19d82f37676f845b7b3a59a4991ce5a22996a
--- /dev/null
+++ b/tests/expected/error.stderr
@@ -0,0 +1 @@
+perror: No such file or directory
diff --git a/tests/expected/error.stdout b/tests/expected/error.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..f4ea5c920d19509171eff96610dc67881b4d6e04
--- /dev/null
+++ b/tests/expected/error.stdout
@@ -0,0 +1 @@
+errno: 2 = No such file or directory
diff --git a/tests/expected/fchdir.stderr b/tests/expected/fchdir.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/fchdir.stdout b/tests/expected/fchdir.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..4c110c289b34afe90d556803fc35c38e5967d250
--- /dev/null
+++ b/tests/expected/fchdir.stdout
@@ -0,0 +1 @@
+fchdir exited with status code 0
diff --git a/tests/expected/fcntl.stderr b/tests/expected/fcntl.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/fcntl.stdout b/tests/expected/fcntl.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..20ec3fc2838660ac3a4dcb4428bd025b248e4fc5
--- /dev/null
+++ b/tests/expected/fcntl.stdout
@@ -0,0 +1 @@
+fd 4 duped into fd 5
diff --git a/tests/expected/fsync.stderr b/tests/expected/fsync.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/fsync.stdout b/tests/expected/fsync.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..0b3deee6ecb6b6d14b65744dafc7e1fe7e4e7312
--- /dev/null
+++ b/tests/expected/fsync.stdout
@@ -0,0 +1 @@
+fsync exited with status code 0
diff --git a/tests/expected/ftruncate.stderr b/tests/expected/ftruncate.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/ftruncate.stdout b/tests/expected/ftruncate.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..5f0c8d705411b4e130d4da724c02e521b8f75927
--- /dev/null
+++ b/tests/expected/ftruncate.stdout
@@ -0,0 +1 @@
+ftruncate exited with status code 0
diff --git a/tests/expected/getid.stderr b/tests/expected/getid.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/getid.stdout b/tests/expected/getid.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..a51fd84a302264be258b90f328bf59ade1eacb18
--- /dev/null
+++ b/tests/expected/getid.stdout
@@ -0,0 +1 @@
+egid: 1000, euid: 1000, gid: 1000, pgid: 23916, pid: 23933, ppid 23918, uid 1000
diff --git a/tests/expected/link.stderr b/tests/expected/link.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/link.stdout b/tests/expected/link.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/math.stderr b/tests/expected/math.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/math.stdout b/tests/expected/math.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/pipe.stderr b/tests/expected/pipe.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/pipe.stdout b/tests/expected/pipe.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/printf.stderr b/tests/expected/printf.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/printf.stdout b/tests/expected/printf.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..ad30d8fbca48dc82518f2786cbb220d29dd075d3
--- /dev/null
+++ b/tests/expected/printf.stdout
@@ -0,0 +1,8 @@
+percent: %
+string: String
+char: c
+int: -16
+uint: 32
+hex: beef
+HEX: C0FFEE
+string: end
diff --git a/tests/expected/rmdir.stderr b/tests/expected/rmdir.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/rmdir.stdout b/tests/expected/rmdir.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..be0153a5a554b913c6bc7a1309b0d6eeed423649
--- /dev/null
+++ b/tests/expected/rmdir.stdout
@@ -0,0 +1 @@
+rmdir exited with status code 0
diff --git a/tests/expected/write.stderr b/tests/expected/write.stderr
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/expected/write.stdout b/tests/expected/write.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..980a0d5f19a64b4b30a87d4206aade58726b60e3
--- /dev/null
+++ b/tests/expected/write.stdout
@@ -0,0 +1 @@
+Hello World!
diff --git a/tests/fcntl b/tests/fcntl
deleted file mode 100755
index 4499cb1482f3157fa2e77cac3c4a42fcd72fedf3..0000000000000000000000000000000000000000
Binary files a/tests/fcntl and /dev/null differ
diff --git a/tests/link.c b/tests/link.c
index 3e36df81fbfd72fb472c5245aad3db84c05c5c6d..383575e8ce60e3a7d7fd57b71e2cb9b7d41f7c8e 100644
--- a/tests/link.c
+++ b/tests/link.c
@@ -1,5 +1,6 @@
 #include <unistd.h>
 
 int main(int argc, char** argv) {
-    int status = link("link.c", "link.out");
+    link("./link.c", "./link.out");
+    perror("link");
 }
diff --git a/tests/rmdir.c b/tests/rmdir.c
new file mode 100644
index 0000000000000000000000000000000000000000..cd9889380b802e770b11e462029d33b6cb20aeb7
--- /dev/null
+++ b/tests/rmdir.c
@@ -0,0 +1,9 @@
+#include <unistd.h>
+#include <sys/stat.h>
+#include <stdio.h>
+
+int main(int argc, char** argv) {
+    mkdir("foo", 0);
+    int status = rmdir("foo");
+    printf("rmdir exited with status code %d\n", status);
+}
diff --git a/tests/setid.c b/tests/setid.c
new file mode 100644
index 0000000000000000000000000000000000000000..ce2b42ea93e4ba464faaf9341ea38fd2da171f11
--- /dev/null
+++ b/tests/setid.c
@@ -0,0 +1,26 @@
+/*
+ * The process joins process group 0.
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+int main( void )
+  {
+    if( setpgid( getpid(), 0 ) == -1 ) {
+        perror( "setpgid" );
+    }
+    printf( "%d belongs to process group %d\n",
+         getpid(), getpgrp() );
+
+    if( setregid(-1, -1) == -1 ) {
+        perror( "setregid" );
+    }
+    printf("%d has egid %d and gid %d\n", getpid(), getegid(), getgid());
+
+    if( setreuid(-1, -1) == -1 ) {
+        perror( "setreuid" );
+    }
+    printf("%d has euid %d and uid %d\n", getpid(), geteuid(), getuid());
+  }
diff --git a/tests/stdlib/strtol.c b/tests/stdlib/strtol.c
new file mode 100644
index 0000000000000000000000000000000000000000..7d09883c64bb0daaa992ccbb3a7bab5eaec7e13b
--- /dev/null
+++ b/tests/stdlib/strtol.c
@@ -0,0 +1,30 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(int argc, char* argv[]) {
+    printf("%ld\n", strtol("         -42", NULL, 0));
+    printf("%ld\n", strtol(" +555", NULL, 0));
+    printf("%ld\n", strtol("   1234567890    ", NULL, 0));
+
+    printf("%ld\n", strtol("         -42", NULL, 10));
+    printf("%ld\n", strtol(" +555", NULL, 10));
+    printf("%ld\n", strtol("   1234567890    ", NULL, 10));
+
+    printf("%lx\n", strtol("  0x38Acfg", NULL, 0));
+    printf("%lx\n", strtol("0Xabcdef12", NULL, 16));
+
+    printf("%lo\n", strtol("  073189", NULL, 0));
+    printf("%lo\n", strtol("     073189", NULL, 8));
+
+    printf("%lo\n", strtol("  0b", NULL, 8));
+    if(errno != 0) {
+        printf("errno is not 0 (%d), something went wrong\n", errno);
+    }
+    printf("%lo\n", strtol("  0b", NULL, 0));
+    if(errno != 0) {
+        printf("errno is not 0 (%d), something went wrong\n", errno);
+    }
+
+    return 0;
+}
diff --git a/tests/unlink.c b/tests/unlink.c
new file mode 100644
index 0000000000000000000000000000000000000000..0eceae0ac2891215ab2f531157476b6188952444
--- /dev/null
+++ b/tests/unlink.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+#include <stdio.h>
+
+int main(int argc, char** argv) {
+    link("./unlink.c", "./unlink.out");
+    perror("unlink");
+}
diff --git a/va_list b/va_list
index 4762a184501beedbb58ea218f0c84fea85685c35..ba5a07a744915b501acadb17e05db0f5d6552f72 160000
--- a/va_list
+++ b/va_list
@@ -1 +1 @@
-Subproject commit 4762a184501beedbb58ea218f0c84fea85685c35
+Subproject commit ba5a07a744915b501acadb17e05db0f5d6552f72