BarryServer : Git

All the code for all my projects
// BarryServer : Git / OrionLibC / commit / 03048a95d88cc7a78171393371f5c22a0250a014

// Related

OrionLibC

Barry Importing existing Orion LibC 03048a9 (2 years, 2 months ago)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..dff8645
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+build/
+*.a
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..fe29407
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,50 @@
+PRODUCT=libc.a
+
+CC=i686-orion-gcc
+CFLAGS=
+
+AS=i686-orion-as
+AFLAGS=
+
+AR=i686-orion-ar
+
+AS_SOURCES := $(shell find . -name '*.S')
+OBJS += $(subst ./,build/,$(subst .S,.o,$(AS_SOURCES)))
+
+C_SOURCES := $(shell find . -name '*.c')
+OBJS += $(subst ./,build/,$(subst .c,.o,$(C_SOURCES)))
+
+.PHONY: install-headers clean all install
+
+all: $(PRODUCT)
+
+clean:
+	@echo "REMOVING OBJECT FILES"
+	@mkdir -p build
+	@rm -rf build
+	@touch $(PRODUCT)
+	@rm $(PRODUCT)
+
+install-headers:
+	@echo "INSTALLING HEADERS"
+	@mkdir -p ${SYSROOT}/usr/include/
+	@cp -r include/* ${SYSROOT}/usr/include/
+
+install: $(PRODUCT) build/crt0.o build/crti.o build/crtn.o
+	@echo "INSTALLING $^"
+	@install -Dm 644 $^ -t ${SYSROOT}/usr/lib/
+
+$(PRODUCT): $(OBJS)
+	@echo "LINKING $@"
+	@mkdir -p $(@D)
+	@$(AR) rcs $@ $^
+
+build/%.o: %.c
+	@echo "COMPILING $<"
+	@mkdir -p $(@D)
+	@$(CC) -c $< -o $@ $(CFLAGS)
+
+build/%.o: %.S
+	@echo "ASSEMBLING $<"
+	@mkdir -p $(@D)
+	@$(AS) $< -o $@ $(AFLAGS)
diff --git a/crt0.S b/crt0.S
new file mode 100644
index 0000000..fb9f6b4
--- /dev/null
+++ b/crt0.S
@@ -0,0 +1,18 @@
+.section .text
+
+.global _start
+_start:
+	movl	0(%esp), %eax          # argc
+	leal	4(%esp), %edx          # argv
+	leal	8(%esp, %eax, 4), %ecx # envp
+
+	pushl	%ecx       # envp
+	pushl	%edx       # argv
+	pushl	%eax       # argc
+	xorl	%ebp, %ebp # mark first stack frame
+
+	call	main
+
+	pushl	%eax
+	call	exit
+.size _start, . - _start
diff --git a/crti.S b/crti.S
new file mode 100644
index 0000000..df534de
--- /dev/null
+++ b/crti.S
@@ -0,0 +1,13 @@
+.section .init
+.global _init
+.type _init, @function
+_init:
+	push %ebp
+	movl %esp, %ebp
+
+.section .fini
+.global _fini
+.type _fini, @function
+_fini:
+	push %ebp
+	movl %esp, %ebp
diff --git a/crtn.S b/crtn.S
new file mode 100644
index 0000000..4c72785
--- /dev/null
+++ b/crtn.S
@@ -0,0 +1,7 @@
+.section .init
+	popl %ebp
+	ret
+
+.section .fini
+	popl %ebp
+	ret
diff --git a/dirent.c b/dirent.c
new file mode 100644
index 0000000..e896020
--- /dev/null
+++ b/dirent.c
@@ -0,0 +1,16 @@
+#include <sys/syscall.h>
+#include <dirent.h>
+#include <errno.h>
+
+/* Get directory entries */
+size_t
+getdents(int fd, void *buf, size_t count)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_GETDENTS),
+	             "c" (3), "S" (&fd));
+	if (ret >= 0)
+		return (size_t) ret;
+	errno = -ret;
+	return -1;
+}
diff --git a/exit.c b/exit.c
new file mode 100644
index 0000000..ffd0620
--- /dev/null
+++ b/exit.c
@@ -0,0 +1,12 @@
+#include <sys/syscall.h>
+
+/* Exit the current program */
+void
+exit(int status)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_EXIT),
+	             "c" (1), "S" (&status));
+	while (1);
+	/* UNREACHED */
+}
diff --git a/grp/getgr.c b/grp/getgr.c
new file mode 100644
index 0000000..e77d50c
--- /dev/null
+++ b/grp/getgr.c
@@ -0,0 +1,142 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <grp.h>
+
+/* Parts of a /etc/group line */
+enum GroupParts {
+	GROUP_NAME,
+	GROUP_GID,
+	GROUP_USERS,
+};
+
+static Group entry;
+static char entryName[33];
+static char *entryMembers[64];
+static char entryUsers[64 * 33];
+
+/* Get part of a password line */
+static char *
+get_part(char *line, int index, char *buf)
+{
+	int i, len = 0;
+	char *start;
+	for (i = 0; i < index; i++)
+		while (*line++ != ':');
+	start = line;
+	while (*line != ':' && *line != '\n') {
+		line++;
+		len++;
+	}
+	memcpy(buf, start, len);
+	buf[len] = '\0';
+	return buf;
+}
+
+/* Convert a string to a number */
+static int
+number(char *str)
+{
+	int num = 0, col = 1, len;
+	for (len = 0; str[len] >= '0' && str[len] <= '9'; len++);
+	while (len--) {
+		num += (str[len] - '0') * col;
+		col *= 10;
+	}
+	return num;
+}
+
+/* Move to next line */
+static char *
+next_line(char *line)
+{
+	while (*line++ != '\n');
+	return line;
+}
+
+/* Convert line to Grouop */
+static Group *
+line_to_group(char *line)
+{
+	if (!*line)
+		return NULL;
+
+	char gidstr[8];
+	get_part(line, GROUP_NAME, entryName);
+	get_part(line, GROUP_GID, gidstr);
+	get_part(line, GROUP_USERS, entryUsers);
+
+	int i, j = 0;
+	char *prev = entryUsers;
+	for (i = 0; entryUsers[i]; i++) {
+		if (entryUsers[i] != ' ')
+			continue;
+		entryUsers[i] = '\0';
+		entryMembers[j] = prev;
+		prev = entryUsers + 1;
+		j++;
+	}
+
+	entry.name = entryName;
+	entry.gid = number(gidstr);
+	entry.members = entryMembers;
+
+	return &entry;
+}
+
+/* Get group file entry by name */
+Group *
+getgrname(const char *name)
+{
+	int fd = open("/etc/group", O_RDONLY);
+	if (fd < 0)
+		return (Group *) fd;
+	size_t sz = lseek(fd, 0, SEEK_END);
+	lseek(fd, 0, SEEK_SET);
+	char *buf = malloc(sz);
+	read(fd, buf, sz);
+	close(fd);
+
+	char *line, tmp[33];
+	for (line = buf; *line; line = next_line(line)) {
+		get_part(line, GROUP_NAME, tmp);
+		if (!strcmp(name, tmp))
+			break;
+	}
+
+	Group *res = line_to_group(line);
+
+	free(buf);
+	return res;
+}
+
+/* Get group file entry by ID */
+Group *
+getgrgid(gid_t gid)
+{
+	int fd = open("/etc/group", O_RDONLY);
+	if (fd < 0)
+		return (Group *) fd;
+	size_t sz = lseek(fd, 0, SEEK_END);
+	lseek(fd, 0, SEEK_SET);
+	char *buf = malloc(sz);
+	read(fd, buf, sz);
+	close(fd);
+
+	char *line, tmp[8];
+	gid_t gidLine;
+	for (line = buf; *line; line = next_line(line)) {
+		get_part(line, GROUP_GID, tmp);
+		gidLine = number(tmp);
+		if (gid == gidLine)
+			break;
+	}
+
+	Group *res = line_to_group(line);
+
+	free(buf);
+	return res;
+}
diff --git a/include/arpa/inet.h b/include/arpa/inet.h
new file mode 100644
index 0000000..4de8dc6
--- /dev/null
+++ b/include/arpa/inet.h
@@ -0,0 +1,15 @@
+#ifndef _ARPA_INET_H
+#define _ARPA_INET_H
+
+typedef struct InAddr {
+	uint32_t addr;
+} InAddr;
+
+typedef struct SockAddrIn {
+	int16_t family;
+	uint16_t port;
+	InAddr inAddr;
+	char zero[8];
+} SockAddrIn;
+
+#endif
diff --git a/include/ctype.h b/include/ctype.h
new file mode 100644
index 0000000..262a90d
--- /dev/null
+++ b/include/ctype.h
@@ -0,0 +1,6 @@
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+
+
+#endif
diff --git a/include/dirent.h b/include/dirent.h
new file mode 100644
index 0000000..abdad04
--- /dev/null
+++ b/include/dirent.h
@@ -0,0 +1,36 @@
+#ifndef _DIRENT_H
+#define _DIRENT_H
+
+#include <stddef.h>
+#include <sys/types.h>
+
+enum DirType {
+	DT_UNKNOWN,
+	DT_REG,
+	DT_DIR,
+	DT_CHR,
+	DT_BLK,
+	DT_FIFO,
+	DT_SOCK,
+	DT_LNK,
+};
+
+/* Structure for a Directory Entry */
+typedef struct dirent {
+	ino_t ino;
+	enum DirType type;
+	size_t namelen;
+	char name[];
+} DirEnt;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+size_t getdents(int fd, void *buf, size_t count);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/errno.h b/include/errno.h
new file mode 100644
index 0000000..b47e18c
--- /dev/null
+++ b/include/errno.h
@@ -0,0 +1,28 @@
+#ifndef _ERRNO_H
+#define _ERRNO_H
+
+enum {
+	ENONE,
+	EPERM,
+	ENOENT,
+	ESRCH,
+	EINVAL,
+	EBADF,
+	ENOEXEC,
+	EMFILE,
+	EFAULT,
+	EISDIR,
+	ENOTDIR,
+	EACCES,
+	ENODEV,
+	EEXIST,
+	ENXIO,
+	ENOTBLK,
+	ENOMEM,
+	ECHILD,
+	ENOTTY,
+};
+
+extern int errno;
+
+#endif
diff --git a/include/fcntl.h b/include/fcntl.h
new file mode 100644
index 0000000..5274e33
--- /dev/null
+++ b/include/fcntl.h
@@ -0,0 +1,25 @@
+#ifndef _FCNTL_H
+#define _FCNTL_H
+
+#include <sys/types.h>
+
+#define O_ACCMODE 0003
+#define O_RDONLY    00
+#define O_WRONLY    01
+#define O_RDWR      02
+
+#define O_CREATE 0100
+#define O_TRUNC  0200
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int open(const char *name, int flags, ...); /* mode_t mode */
+int create(const char *name, mode_t mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/grp.h b/include/grp.h
new file mode 100644
index 0000000..a6e07d6
--- /dev/null
+++ b/include/grp.h
@@ -0,0 +1,14 @@
+#ifndef _GRP_H
+#define _GRP_H
+
+/* Structure of a group entry */
+typedef struct group {
+	char *name;
+	gid_t gid;
+	char **members;
+} Group;
+
+Group *getgrname(const char *name);
+Group *getgrgid(gid_t gid);
+
+#endif
diff --git a/include/inttypes.h b/include/inttypes.h
new file mode 100644
index 0000000..855bf37
--- /dev/null
+++ b/include/inttypes.h
@@ -0,0 +1,13 @@
+#ifndef _INTTYPES_H
+#define _INTTYPES_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/* Structure for the imaxdiv() function */
+typedef struct {
+	__extension__ long long int quot;
+	__extension__ long long int rem;
+} imaxdiv_t;
+
+#endif
diff --git a/include/limits.h b/include/limits.h
new file mode 100644
index 0000000..d165525
--- /dev/null
+++ b/include/limits.h
@@ -0,0 +1,6 @@
+#ifndef _LIMITS_H
+#define _LIMITS_H
+
+#include <sys/limits.h>
+
+#endif
diff --git a/include/pwd.h b/include/pwd.h
new file mode 100644
index 0000000..df872d4
--- /dev/null
+++ b/include/pwd.h
@@ -0,0 +1,20 @@
+#ifndef _PWD_H
+#define _PWD_H
+
+#include <sys/types.h>
+
+/* Structure of a password entry */
+typedef struct passwd {
+	char *username;
+	char *password;
+	uid_t uid;
+	gid_t gid;
+	char *info;
+	char *homedir;
+	char *shell;
+} Passwd;
+
+Passwd *getpwname(const char *username);
+Passwd *getpwuid(uid_t uid);
+
+#endif
diff --git a/include/setjmp.h b/include/setjmp.h
new file mode 100644
index 0000000..ded0ecd
--- /dev/null
+++ b/include/setjmp.h
@@ -0,0 +1,19 @@
+#ifndef _SETJMP_H
+#define _SETJMP_H
+
+#include <signal.h>
+
+#define setjmp __builtin_setjmp
+#define longjmp __builtin_longjmp
+
+typedef int __jmp_buf[6];
+
+struct __jmp_buf_tag {
+	__jmp_buf __jmpbuf;
+	int __saved;
+	__sigset_t __mask;
+};
+
+typedef struct __jmp_buf_tag jmp_buf[1];
+
+#endif
diff --git a/include/signal.h b/include/signal.h
new file mode 100644
index 0000000..3999125
--- /dev/null
+++ b/include/signal.h
@@ -0,0 +1,39 @@
+#ifndef _SIGNAL_H
+#define _SIGNAL_H
+
+#include <sys/types.h>
+
+typedef unsigned long int __sigset_t;
+#ifndef sigset_t
+typedef __sigset_t sigset_t;
+#endif
+#ifndef sig_atomic_t
+typedef int sig_atomic_t;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum Signals {
+	SIGHUP = 1,
+	SIGINT,
+	SIGQUIT,
+	SIGILL,
+	SIGABRT,
+	SIGFPE,
+	SIGKILL,
+	SIGSEGV,
+	SIGPIPE,
+	
+};
+
+void (*signal(int sig, void (*func)(int)))(int);
+int tgkill(pid_t tgid, pid_t tid, int sig);
+int kill(pid_t pid, int sig);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/stdio.h b/include/stdio.h
new file mode 100644
index 0000000..b38bba5
--- /dev/null
+++ b/include/stdio.h
@@ -0,0 +1,66 @@
+#ifndef _STDIO_H
+#define _STDIO_H
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#define EOF ((int) -1)
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+typedef struct {
+	size_t count;
+	char *buf, *ptr;
+	int flags;
+	int fd;
+} FILE;
+
+enum FILEFlags {
+	FILE_READ  =  1,
+	FILE_WRITE =  2,
+	FILE_UNBUF =  4,
+	FILE_EOF   = 10,
+	FILE_ERR   = 20,
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern FILE *stdin;
+extern FILE *stdout;
+extern FILE *stderr;
+#define stdin stdin
+#define stdout stdout
+#define stderr stderr
+
+int fclose(FILE *);
+int fflush(FILE *);
+FILE *fopen(const char *, const char *);
+int fprintf(FILE *, const char *, ...);
+size_t fread(void *, size_t, size_t, FILE *);
+int fseek(FILE *, long, int);
+long ftell(FILE *);
+size_t fwrite(const void *, size_t, size_t, FILE *);
+void setbuf(FILE *stream, char *buf);
+int vfprintf(FILE *stream, const char *fmt, va_list);
+int sprintf(char *buf, const char *fmt, ...);
+void dbgprintf(char *fmt, ...);
+void dbgputs(char *str);
+int printf(const char *fmt, ...);
+void perror(const char *s);
+int getc(FILE *stream);
+int getchar(void);
+int puts(const char *s);
+int putc(int c, FILE *stream);
+int putchar(int c);
+
+int rename(const char *oldpath, const char *newpath);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/stdlib.h b/include/stdlib.h
new file mode 100644
index 0000000..b1265c2
--- /dev/null
+++ b/include/stdlib.h
@@ -0,0 +1,25 @@
+#ifndef _STDLIB_H
+#define _STDLIB_H
+
+#define EXIT_SUCCESS 0
+#define EXIT_FAILURE 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_Noreturn void abort(void);
+int atexit(void (*)(void));
+int atoi(const char *);
+void free(void *);
+char *getenv(const char *);
+void *malloc(size_t);
+void *calloc(size_t, size_t);
+_Noreturn void exit(int status);
+int abs(int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/string.h b/include/string.h
new file mode 100644
index 0000000..470b759
--- /dev/null
+++ b/include/string.h
@@ -0,0 +1,26 @@
+#ifndef _STRING_H
+#define _STRING_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int memcmp(void *s1, void *s2, size_t n);
+void *memcpy(void *dest, const void *src, size_t len);
+void *memset(void *dest, int byte, size_t len);
+int strcmp(const char *s1, const char *s2);
+int strncmp(const char *s1, const char *s2, size_t n);
+char *strcpy(char *dest, const char *src);
+char *strncpy(char *dest, const char *src, size_t n);
+size_t strlen(const char *str);
+size_t strnlen(const char *str, size_t maxlen);
+char *strcat(char *dest, const char *src);
+char *strchr(char *s, int c);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/sys/fb.h b/include/sys/fb.h
new file mode 100644
index 0000000..b56497e
--- /dev/null
+++ b/include/sys/fb.h
@@ -0,0 +1,26 @@
+#ifndef _SYS_FB_H
+#define _SYS_FB_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/* ioctl() calls */
+enum FrameBufferIoctls {
+	FBIOGET_VSCREENINFO,
+	FBIOPUT_VSCREENINFO,
+	FBIOGET_FSCREENINFO,
+};
+
+/* Structure for fixed framebuffer info */
+typedef struct FBFixInfo {
+	uintptr_t fbmem;
+	size_t fbmemLen;
+} FBFixInfo;
+
+/* Structure for variable framebuffer info */
+typedef struct FBVarInfo {
+	uint32_t xres, yres;
+	uint32_t bpp;
+} FBVarInfo;
+
+#endif
diff --git a/include/sys/ioctl.h b/include/sys/ioctl.h
new file mode 100644
index 0000000..9c95275
--- /dev/null
+++ b/include/sys/ioctl.h
@@ -0,0 +1,6 @@
+#ifndef _SYS_IOCTL_H
+#define _SYS_IOCTL_H
+
+int ioctl(int fd, unsigned long request, ...);
+
+#endif
diff --git a/include/sys/ipc.h b/include/sys/ipc.h
new file mode 100644
index 0000000..e81e077
--- /dev/null
+++ b/include/sys/ipc.h
@@ -0,0 +1,38 @@
+#ifndef _SYS_IPC_H
+#define _SYS_IPC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+/* Processes */
+enum Process {
+        NO_PROCESS,
+        SYSTEM,
+
+        ANY = 0xFFFFFFFF
+};
+
+/* Message encodings */
+typedef union MessageContent MessageContent;
+union MessageContent {
+	/* Generics */
+	char raw[16];
+	void *ptr;
+	uint32_t num;
+} __attribute__((__transparent_union__));
+
+/* Structure for a message */
+typedef struct Message Message;
+struct Message {
+	pid_t from;
+	uint16_t type;
+	MessageContent msg;
+	Message *next;
+} __attribute__((packed));
+
+Message *nb_send_msg(pid_t to, uint16_t type, MessageContent *msg);
+Message *send_msg(pid_t to, uint16_t type, MessageContent *msg);
+pid_t nb_recv_msg(Message *buf, pid_t from);
+pid_t recv_msg(Message *buf, pid_t from);
+
+#endif
diff --git a/include/sys/limits.h b/include/sys/limits.h
new file mode 100644
index 0000000..835e765
--- /dev/null
+++ b/include/sys/limits.h
@@ -0,0 +1,9 @@
+#ifndef _SYS_LIMITS_H
+#define _SYS_LIMITS_H
+
+#define NAME_MAX 255
+#define PATH_MAX 1024
+
+#define HOST_NAME_MAX 64
+
+#endif
diff --git a/include/sys/mman.h b/include/sys/mman.h
new file mode 100644
index 0000000..0e9518e
--- /dev/null
+++ b/include/sys/mman.h
@@ -0,0 +1,35 @@
+#ifndef _SYS_MMAN_H
+#define _SYS_MMAN_H
+
+#include <stddef.h>
+#include <sys/types.h>
+
+/* Virtual Memory Region Protection */
+enum VMRegionProt {
+	PROT_NONE,
+	PROT_EXEC = (1 << 0),
+	PROT_WRITE = (1 << 1),
+	PROT_READ = (1 << 2),
+};
+
+/* Virtual Memory Region flags */
+enum VMRegionFlag {
+	MAP_SHARED,
+	MAP_PRIVATE = (1 << 0),
+	MAP_ANONYMOUS = (1 << 1),
+};
+
+#define MAP_ANON MAP_ANONYMOUS
+#define MAP_FAILED ((void *) -1)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/sys/mount.h b/include/sys/mount.h
new file mode 100644
index 0000000..c5508ae
--- /dev/null
+++ b/include/sys/mount.h
@@ -0,0 +1,20 @@
+#ifndef _SYS_MOUNT_H
+#define _SYS_MOUNT_H
+
+#define MS_REMOUNT (1 << 0)
+#define MS_BIND    (1 << 1)
+#define MS_MOVE    (1 << 2)
+#define MS_RDONLY  (1 << 3)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int mount(const char *src, const char *target, const char *type,
+          unsigned long flags, void *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/sys/param.h b/include/sys/param.h
new file mode 100644
index 0000000..11ca58a
--- /dev/null
+++ b/include/sys/param.h
@@ -0,0 +1,32 @@
+#ifndef _SYS_PARAM_H
+#define _SYS_PARAM_H
+
+#include <stddef.h>
+#include <sys/types.h>
+
+#define NBBY 8
+
+/* Bit map related macros.  */
+#define setbit(a,i)     ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
+#define clrbit(a,i)     ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
+#define isset(a,i)      ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
+#define isclr(a,i)      (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
+
+/* Macros for counting and rounding.  */
+#ifndef howmany
+# define howmany(x, y)  (((x) + ((y) - 1)) / (y))
+#endif
+#ifdef __GNUC__
+# define roundup(x, y)  (__builtin_constant_p (y) && powerof2 (y)             \
+                         ? (((x) + (y) - 1) & ~((y) - 1))                     \
+                         : ((((x) + ((y) - 1)) / (y)) * (y)))
+#else
+# define roundup(x, y)  ((((x) + ((y) - 1)) / (y)) * (y))
+#endif
+#define powerof2(x)     ((((x) - 1) & (x)) == 0)
+
+/* Macros for min/max.  */
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+#endif
diff --git a/include/sys/sched.h b/include/sys/sched.h
new file mode 100644
index 0000000..fe17753
--- /dev/null
+++ b/include/sys/sched.h
@@ -0,0 +1,19 @@
+#ifndef _SYS_SCHED_H
+#define _SYS_SCHED_H
+
+#include <sys/types.h>
+
+/* Flags for clone syscall */
+enum CloneFlag {
+	CLONE_NONE   = (1 << 0),
+	CLONE_PARENT = (1 << 1),
+	CLONE_THREAD = (1 << 2),
+	CLONE_FILES  = (1 << 3),
+	CLONE_FS     = (1 << 4),
+	CLONE_VM     = (1 << 5),
+	CLONE_IPC    = (1 << 6), // TODO: Add IPC namespace
+};
+
+pid_t clone(int flags);
+
+#endif
diff --git a/include/sys/stat.h b/include/sys/stat.h
new file mode 100644
index 0000000..b83cf2d
--- /dev/null
+++ b/include/sys/stat.h
@@ -0,0 +1,67 @@
+#ifndef _SYS_STAT_H
+#define _SYS_STAT_H
+
+#include <stddef.h>
+#include <sys/types.h>
+
+#define S_IFMT   0170000
+
+#define S_IFSOCK 0140000
+#define S_IFLNK  0120000
+#define S_IFREG  0100000
+#define S_IFBLK  0060000
+#define S_IFDIR  0040000
+#define S_IFCHR  0020000
+#define S_IFIFO  0010000
+
+#define S_ISREG(m) ((m & S_IFMT) == S_IFREG)
+#define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
+#define S_ISCHR(m) ((m & S_IFMT) == S_IFCHR)
+#define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK)
+#define S_ISFIFO(m) ((m & S_IFMT) == S_IFIFO)
+#define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK)
+#define S_ISSOCK(m) ((m & S_IFMT) == S_IFSOCK)
+
+#define S_ISUID 04000
+#define S_ISGID 02000
+#define S_ISVTX 01000
+
+#define S_IRWXU 00700
+#define S_IRUSR 00400
+#define S_IWUSR 00200
+#define S_IXUSR 00100
+
+#define S_IRWXG 00070
+#define S_IRGRP 00040
+#define S_IWGRP 00020
+#define S_IXGRP 00010
+
+#define S_IRWXO 00007
+#define S_IROTH 00004
+#define S_IWOTH 00002
+#define S_IXOTH 00001
+
+/* Structure for a stat() call */
+typedef struct stat {
+	ino_t inode;
+	mode_t mode;
+	nlink_t nlink;
+	uid_t uid;
+	gid_t gid;
+	size_t size;
+} Stat;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int mkdir(const char *pathname, mode_t mode);
+int mknod(const char *pathname, mode_t mode, dev_t dev);
+int stat(const char *pathname, struct stat *statbuf);
+int fstat(int fd, struct stat *statbuf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/sys/syscall.h b/include/sys/syscall.h
new file mode 100644
index 0000000..d732c59
--- /dev/null
+++ b/include/sys/syscall.h
@@ -0,0 +1,60 @@
+#ifndef _SYS_SYSCALL_H
+#define _SYS_SYSCALL_H
+
+enum SystemCall {
+	/* Tasking */
+	SYSCALL_DBGPRINTF,
+	SYSCALL_CLONE,
+	SYSCALL_EXIT,
+	SYSCALL_GETPID,
+	SYSCALL_GETUID,
+	SYSCALL_SETUID,
+	SYSCALL_GETEUID,
+	SYSCALL_SETEUID,
+	SYSCALL_GETGID,
+	SYSCALL_SETGID,
+	SYSCALL_GETEGID,
+	SYSCALL_SETEGID,
+	SYSCALL_EXECVE,
+	SYSCALL_WAITPID,
+	SYSCALL_TGKILL,
+	SYSCALL_KILL,
+	SYSCALL_TIME,
+	SYSCALL_TIMES,
+	SYSCALL_SLEEP,
+
+	/* Files */
+	SYSCALL_OPEN,
+	SYSCALL_CLOSE,
+	SYSCALL_READ,
+	SYSCALL_WRITE,
+	SYSCALL_IOCTL,
+	SYSCALL_LSEEK,
+	SYSCALL_STAT,
+	SYSCALL_FSTAT,
+	SYSCALL_GETDENTS,
+	SYSCALL_MKDIR,
+	SYSCALL_RMDIR,
+	SYSCALL_MKNOD,
+	SYSCALL_RENAME,
+	SYSCALL_DUP,
+	SYSCALL_DUP2,
+	SYSCALL_ISATTY,
+
+	/* File System */
+	SYSCALL_MOUNT,
+	SYSCALL_CHDIR,
+	SYSCALL_CHROOT,
+	SYSCALL_GETCWD,
+
+	/* Memory */
+	SYSCALL_MMAP,
+
+	/* Messaging */
+	SYSCALL_NB_SEND_MSG,
+	SYSCALL_SEND_MSG,
+	SYSCALL_NB_RECV_MSG,
+	SYSCALL_RECV_MSG,
+};
+
+#endif
diff --git a/include/sys/times.h b/include/sys/times.h
new file mode 100644
index 0000000..70d57f0
--- /dev/null
+++ b/include/sys/times.h
@@ -0,0 +1,18 @@
+#ifndef _SYS_TIMES_H
+#define _SYS_TIMES_H
+
+#include <time.h>
+
+typedef uint64_t clock_t;
+
+/* Structure for a times call */
+typedef struct tms {
+	clock_t utime;
+	clock_t stime;
+	clock_t cutime;
+	clock_t cstime;
+} Times;
+
+clock_t times(Times *buf);
+
+#endif
diff --git a/include/sys/types.h b/include/sys/types.h
new file mode 100644
index 0000000..f8d727a
--- /dev/null
+++ b/include/sys/types.h
@@ -0,0 +1,14 @@
+#ifndef _SYS_TYPES_H
+#define _SYS_TYPES_H
+
+typedef int pid_t;
+typedef unsigned short uid_t;
+typedef unsigned short gid_t;
+typedef unsigned int dev_t;
+typedef int ino_t;
+typedef int off_t;
+typedef int mode_t;
+typedef int nlink_t;
+typedef int refcount_t;
+
+#endif
diff --git a/include/sys/wait.h b/include/sys/wait.h
new file mode 100644
index 0000000..47ff26c
--- /dev/null
+++ b/include/sys/wait.h
@@ -0,0 +1,22 @@
+#ifndef _SYS_INCLUDE_H
+#define _SYS_INCLUDE_H
+
+#include <sys/types.h>
+
+#define WIFEXITED(status) (status & (1 << 31))
+#define WEXITSTATUS(status) (status & 0x0F)
+#define WIFSIGNALED(status) (!(status & (1 << 31)))
+#define WTERMSIG(status) (status & 0xFF)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+pid_t wait(int *wstatus);
+pid_t waitpid(pid_t pid, int *wstatus, int options);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/termios.h b/include/termios.h
new file mode 100644
index 0000000..259695b
--- /dev/null
+++ b/include/termios.h
@@ -0,0 +1,33 @@
+#ifndef _TERMIOS_H
+#define _TERMIOS_H
+
+/* ioctl() calls */
+enum TTYIoctls {
+	TCGETS,
+	TCSETS,
+	TCGWINSZ,
+};
+
+enum TTYLineDiscipline {
+	ISIG = (1 << 0),
+	ICANON = (1 << 1),
+	ECHO = (1 << 2),
+};
+
+typedef unsigned int tcflag_t;
+
+/* Terminal I/O Settings */
+typedef struct Termios {
+	tcflag_t iflag;
+	tcflag_t oflag;
+	tcflag_t cflag;
+	tcflag_t lflag;
+} Termios;
+
+/* Terminal Window Size */
+typedef struct Winsize {
+	unsigned short rows, cols;
+	unsigned short xres, yres;
+} Winsize;
+
+#endif
diff --git a/include/time.h b/include/time.h
new file mode 100644
index 0000000..24dee55
--- /dev/null
+++ b/include/time.h
@@ -0,0 +1,11 @@
+#ifndef _TIME_H
+#define _TIME_H
+
+#include <stdint.h>
+
+typedef uint32_t time_t;
+
+int sleep(uint32_t ms);
+time_t time(time_t *tloc);
+
+#endif
diff --git a/include/unistd.h b/include/unistd.h
new file mode 100644
index 0000000..c250e84
--- /dev/null
+++ b/include/unistd.h
@@ -0,0 +1,46 @@
+#ifndef _UNISTD_H
+#define _UNISTD_H
+
+#include <sys/types.h>
+#include <stddef.h>
+
+typedef int intptr_t;
+
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int execv(const char *, char *[]);
+int execve(const char *, char *[], char *[]);
+int execvp(const char *, char *[]);
+pid_t fork(void);
+pid_t getpid(void);
+uid_t getuid(void);
+int setuid(uid_t uid);
+uid_t geteuid(void);
+int seteuid(uid_t euid);
+gid_t getgid(void);
+int setgid(gid_t gid);
+gid_t getegid(void);
+int setegid(gid_t egid);
+int isatty(int fd);
+int close(int fd);
+int dup(int oldfd);
+int dup2(int oldfd, int newfd);
+size_t read(int fd, void *buf, size_t count);
+size_t write(int fd, void *buf, size_t count);
+off_t lseek(int fd, off_t offset, int whence);
+int rmdir(const char *pathname);
+int chroot(const char *path);
+int chdir(const char *path);
+char *getcwd(char *buf, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/init.c b/init.c
new file mode 100644
index 0000000..d0cbc60
--- /dev/null
+++ b/init.c
@@ -0,0 +1,5 @@
+void
+init_std_lib(void)
+{
+	/* Do setup here */
+}
diff --git a/pwd/getpw.c b/pwd/getpw.c
new file mode 100644
index 0000000..116cf97
--- /dev/null
+++ b/pwd/getpw.c
@@ -0,0 +1,148 @@
+#include <sys/limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pwd.h>
+
+#include <stdio.h>
+
+/* Parts of a /etc/passwd line */
+enum PasswordParts {
+	PASSWD_USERNAME,
+	PASSWD_PASSWORD,
+	PASSWD_UID,
+	PASSWD_GID,
+	PASSWD_INFO,
+	PASSWD_HOMEDIR,
+	PASSWD_SHELL,
+};
+
+static Passwd entry;
+static char entryUsername[33];
+static char entryPassword[128];
+static char entryInfo[1024];
+static char entryHomeDir[PATH_MAX];
+static char entryShell[PATH_MAX];
+
+/* Get part of a password line */
+static char *
+get_part(char *line, int index, char *buf)
+{
+	int i, len = 0;
+	char *start;
+	for (i = 0; i < index; i++)
+		while (*line++ != ':');
+	start = line;
+	while (*line != ':' && *line != '\n') {
+		line++;
+		len++;
+	}
+	memcpy(buf, start, len);
+	buf[len] = '\0';
+	return buf;
+}
+
+/* Convert a string to a number */
+static int
+number(char *str)
+{
+	int num = 0, col = 1, len;
+	for (len = 0; str[len] >= '0' && str[len] <= '9'; len++);
+	while (len--) {
+		num += (str[len] - '0') * col;
+		col *= 10;
+	}
+	return num;
+}
+
+/* Move to next line */
+static char *
+next_line(char *line)
+{
+	while (*line++ != '\n');
+	return line;
+}
+
+/* Convert line to Passwd */
+static Passwd *
+line_to_passwd(char *line)
+{
+	if (!*line)
+		return NULL;
+
+	char uidstr[8], gidstr[8];
+	get_part(line, PASSWD_USERNAME, entryUsername);
+	get_part(line, PASSWD_PASSWORD, entryPassword);
+	get_part(line, PASSWD_UID, uidstr);
+	get_part(line, PASSWD_GID, gidstr);
+	get_part(line, PASSWD_INFO, entryInfo);
+	get_part(line, PASSWD_HOMEDIR, entryHomeDir);
+	get_part(line, PASSWD_SHELL, entryShell);
+
+	entry.username = entryUsername;
+	entry.password = entryPassword;
+	entry.uid = number(uidstr);
+	entry.gid = number(gidstr);
+	entry.info = entryInfo;
+	entry.homedir = entryHomeDir;
+	entry.shell = entryShell;
+
+	return &entry;
+}
+
+/* Get password file entry by name */
+Passwd *
+getpwname(const char *username)
+{
+
+	int fd = open("/etc/passwd", O_RDONLY);
+	if (fd < 0)
+		return (Passwd *) fd;
+	size_t sz = lseek(fd, 0, SEEK_END);
+	lseek(fd, 0, SEEK_SET);
+	char *buf = malloc(sz);
+	read(fd, buf, sz);
+	close(fd);
+
+	char *line, tmp[33];
+	for (line = buf; *line; line = next_line(line)) {
+		get_part(line, PASSWD_USERNAME, tmp);
+		if (!strcmp(username, tmp))
+			break;
+	}
+
+	Passwd *res = line_to_passwd(line);
+
+	free(buf);
+	return res;
+}
+
+/* Get password file entry by ID */
+Passwd *
+getpwuid(uid_t uid)
+{
+	int fd = open("/etc/passwd", O_RDONLY);
+	if (fd < 0)
+		return (Passwd *) fd;
+	size_t sz = lseek(fd, 0, SEEK_END);
+	lseek(fd, 0, SEEK_SET);
+	char *buf = malloc(sz);
+	read(fd, buf, sz);
+	close(fd);
+
+	char *line, tmp[8];
+	uid_t uidLine;
+	for (line = buf; *line; line = next_line(line)) {
+		get_part(line, PASSWD_UID, tmp);
+		uidLine = number(tmp);
+		if (uid == uidLine)
+			break;
+	}
+
+	Passwd *res = line_to_passwd(line);
+
+	free(buf);
+	return res;
+}
diff --git a/signal/kill.c b/signal/kill.c
new file mode 100644
index 0000000..34dc776
--- /dev/null
+++ b/signal/kill.c
@@ -0,0 +1,16 @@
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <errno.h>
+
+/* Send a signal to a process */
+int
+kill(pid_t pid, int sig)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_KILL),
+	             "c" (2), "S" (&pid));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
diff --git a/signal/tgkill.c b/signal/tgkill.c
new file mode 100644
index 0000000..760795b
--- /dev/null
+++ b/signal/tgkill.c
@@ -0,0 +1,16 @@
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <errno.h>
+
+/* Send a signal to a thread */
+int
+tgkill(pid_t tgid, pid_t tid, int sig)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_TGKILL),
+	             "c" (3), "S" (&tgid));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
diff --git a/stdio/dbgprintf.c b/stdio/dbgprintf.c
new file mode 100644
index 0000000..c1f5729
--- /dev/null
+++ b/stdio/dbgprintf.c
@@ -0,0 +1,30 @@
+#include <stdarg.h>
+#include <sys/syscall.h>
+
+int vsprintf(char *buf, const char *fmt, va_list args);
+
+/* Send message to Kernel Output */
+void
+dbgprintf(char *fmt, ...)
+{
+	char buf[1024];
+	va_list args;
+	va_start(args, fmt);
+	vsprintf(buf, fmt, args);
+	va_end(args);
+
+	int ret;
+	char *p = buf;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_DBGPRINTF),
+	             "c" (1), "S" (&p));
+}
+
+/* Send an unformatted message to Kernel Output */
+void
+dbgputs(char *str)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_DBGPRINTF),
+	             "c" (1), "S" (&str));
+
+}
diff --git a/stdio/fopen.c b/stdio/fopen.c
new file mode 100644
index 0000000..69aecca
--- /dev/null
+++ b/stdio/fopen.c
@@ -0,0 +1,39 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/* Open a file */
+FILE *
+fopen(const char *name, const char *mode)
+{
+	int fd;
+	FILE *fp;
+
+	if (*mode != 'r' && *mode != 'w' && *mode != 'a')
+		return NULL;
+
+	fp = malloc(sizeof(FILE));
+	if (!fp)
+		return NULL;
+
+	if (*mode == 'w')
+		fd = create(name, 0666);
+	else if (*mode == 'a')
+		fd = open(name, O_CREATE | O_WRONLY, 0);
+	else
+		fd = open(name, O_RDONLY, 0);
+	if (fd < 0) {
+		free(fp);
+		return NULL;
+	}
+	if (*mode == 'a')
+		lseek(fd, 0, SEEK_END);
+
+	fp->fd = fd;
+	fp->count = 0;
+	fp->buf = NULL;
+	fp->flags = (*mode == 'r') ? FILE_READ : FILE_WRITE;
+
+	return fp;
+}
diff --git a/stdio/getc.c b/stdio/getc.c
new file mode 100644
index 0000000..e1a8a8f
--- /dev/null
+++ b/stdio/getc.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Allocate and fill a file's buffer */
+static int
+_fillbuf(FILE *fp)
+{
+	int bufsize;
+
+	if ((fp->flags & (FILE_READ | FILE_EOF | FILE_ERR)) != FILE_READ)
+		return EOF;
+	bufsize = (fp->flags & FILE_UNBUF) ? 1 : 1024;
+
+	/* Create buffer */
+	if (fp->buf == NULL) {
+		fp->buf = malloc(bufsize);
+		if (!fp->buf)
+			return EOF;
+	}
+	fp->ptr = fp->buf;
+	fp->count = read(fp->fd, fp->ptr, bufsize);
+	if (--fp->count < 0) {
+		if (fp->count == -1)
+			fp->flags |= FILE_EOF;
+		else
+			fp->flags |= FILE_ERR;
+		fp->count = 0;
+		return EOF;
+	}
+	return (unsigned char) *fp->ptr++;
+}
+
+/* Get a character from a stream */
+inline int
+getc(FILE *stream)
+{
+	if (--stream->count >= 0)
+		return (unsigned char) *stream->ptr++;
+	return _fillbuf(stream);
+}
+
+/* Get a character from standard input */
+int
+getchar(void)
+{
+	getc(stdin);
+}
diff --git a/stdio/perror.c b/stdio/perror.c
new file mode 100644
index 0000000..c852582
--- /dev/null
+++ b/stdio/perror.c
@@ -0,0 +1,39 @@
+#include <stdio.h>
+#include <errno.h>
+
+int errno;
+const char *errorList[] = {
+	[ENONE]   = "No error",
+	[EPERM]   = "Operation not permitted",
+	[ENOENT]  = "No such file or directory",
+	[ESRCH]   = "No such process",
+	[EINVAL]  = "Invalid argument",
+	[EBADF]   = "Bad file descriptor",
+	[ENOEXEC] = "Exec format error",
+	[EMFILE]  = "Too many open files",
+	[EFAULT]  = "Bad address",
+	[EISDIR]  = "Is a directory",
+	[ENOTDIR] = "Not a directory",
+	[EACCES]  = "Permission denied",
+	[ENODEV]  = "No such device",
+	[EEXIST]  = "File exists",
+	[ENXIO]   = "No such device or address",
+	[ENOTBLK] = "Block device required",
+	[ENOMEM]  = "Cannot allocate memory",
+	[ECHILD]  = "No child processes",
+	[ENOTTY]  = "Inappropriate ioctl for device",
+};
+
+/* Display an error message for errno */
+void
+perror(const char *s)
+{
+	if (errno < 0 || errno >= (sizeof(errorList)/sizeof(errorList[0])))
+		return;
+	if (!s)
+		printf("%s\n", errorList[errno]);
+	else if (!s[0])
+		printf("%s\n", errorList[errno]);
+	else
+		printf("%s: %s\n", s, errorList[errno]);
+}
diff --git a/stdio/printf.c b/stdio/printf.c
new file mode 100644
index 0000000..de0d9a4
--- /dev/null
+++ b/stdio/printf.c
@@ -0,0 +1,21 @@
+#include <unistd.h>
+#include <stdarg.h>
+#include <sys/syscall.h>
+#include <stdio.h>
+
+int vsprintf(char *buf, const char *fmt, va_list args);
+
+/* Write a formatted string to stdout */
+int
+printf(const char *fmt, ...)
+{
+	int len;
+	char buf[8196];
+	va_list args;
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
+
+	len = write(STDOUT_FILENO, buf, len);
+	return len;
+}
diff --git a/stdio/puts.c b/stdio/puts.c
new file mode 100644
index 0000000..45113ef
--- /dev/null
+++ b/stdio/puts.c
@@ -0,0 +1,21 @@
+#include <unistd.h>
+#include <string.h>
+
+/* Write a string to stdout */
+int
+puts(const char *str)
+{
+	char end[] = "\n";
+	int len = strlen(str);
+	len = write(STDOUT_FILENO, (void *) str, len);
+	return len + write(STDOUT_FILENO, end, 1);
+}
+
+/* Write a character to stdout */
+int
+putchar(int c)
+{
+	char str[] = {(char) c, 0};
+	write(STDOUT_FILENO, str, 1);
+	return c;
+}
diff --git a/stdio/vsprintf.c b/stdio/vsprintf.c
new file mode 100644
index 0000000..88e2f9f
--- /dev/null
+++ b/stdio/vsprintf.c
@@ -0,0 +1,244 @@
+#include <stdarg.h>
+#include <string.h>
+
+#define is_digit(c)	((c) >= '0' && (c) <= '9')
+
+/* Do not convert */
+static int
+skip_atoi(const char **s)
+{
+	int i = 0;
+
+	while (is_digit(**s))
+		i = i*10 + *((*s)++) - '0';
+
+	return i;
+}
+
+#define ZEROPAD	1		/* pad with zero */
+#define SIGN	2		/* unsigned/signed long */
+#define PLUS	4		/* show plus */
+#define SPACE	8		/* space if plus */
+#define LEFT	16		/* left justified */
+#define SPECIAL	32		/* 0x */
+#define SMALL	64		/* use 'abcdef' instead of 'ABCDEF' */
+
+#define do_div(n,base) ({ \
+int __res; \
+__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \
+__res; })
+
+/* Convert a number to ASCII */
+static char *
+number(char *str, int num, int base, int size, int precision, int type)
+{
+	char c, sign, tmp[36];
+	const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	int i;
+
+	if (type & SMALL)
+		digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+	if (type & LEFT)
+		type &= ~ZEROPAD;
+	if (base < 2 || base > 36)
+		return 0;
+	c = (type & ZEROPAD) ? '0' : ' ' ;
+	if (type & SIGN && num < 0) {
+		sign = '-';
+		num = -num;
+	} else {
+		sign = (type & PLUS) ? '+' : ((type & SPACE) ? ' ' : 0);
+	}
+	if (sign)
+		size--;
+	if (type & SPECIAL)
+		if (base == 16)
+			size -= 2;
+		else if (base == 8)
+			size--;
+	i = 0;
+	if (num == 0)
+		tmp[i++] = '0';
+	else while (num != 0)
+		tmp[i++] = digits[do_div(num,base)];
+	if (i > precision)
+		precision = i;
+	size -= precision;
+	if (!(type & (ZEROPAD + LEFT)))
+		while (size-- > 0)
+			*str++ = ' ';
+	if (sign)
+		*str++ = sign;
+	if (type & SPECIAL)
+		if (base == 8) {
+			*str++ = '0';
+		} else if (base == 16) {
+			*str++ = '0';
+			*str++ = digits[33];
+		}
+	if (!(type & LEFT))
+		while (size-- > 0)
+			*str++ = c;
+	while (i < precision--)
+		*str++ = '0';
+	while (i-- > 0)
+		*str++ = tmp[i];
+	while (size-- > 0)
+		*str++ = ' ';
+	return str;
+}
+
+/* Print formatted to a buffer */
+int
+vsprintf(char *buf, const char *fmt, va_list args)
+{
+	int len, i;
+	char *str, *s;
+	int *ip, flags;
+	int field_width, precision, qualifier;
+
+	for (str = buf; *fmt; fmt++) {
+		if (*fmt != '%') {
+			*str++ = *fmt;
+			continue;
+		}
+
+		/* Process flags */
+		flags = 0;
+repeat:
+		fmt++;
+		switch (*fmt) {
+		case '-':
+			flags |= LEFT;
+			goto repeat;
+		case '+':
+			flags |= PLUS;
+			goto repeat;
+		case ' ':
+			flags |= SPACE;
+			goto repeat;
+		case '#':
+			flags |= SPECIAL;
+			goto repeat;
+		case '0':
+			flags |= ZEROPAD;
+			goto repeat;
+		}
+
+		/* Get field width */
+		field_width = -1;
+		if (is_digit(*fmt)) {
+			field_width = skip_atoi(&fmt);
+		} else if (*fmt == '*') {
+			field_width = va_arg(args, int);
+			fmt++;
+			if (field_width < 0) {
+				field_width = -field_width;
+				flags |= LEFT;
+			}
+		}
+
+		/* Get the precision */
+		precision = -1;
+		if (*fmt == '.') {
+			fmt++;
+			if (is_digit(*fmt)) {
+				precision = skip_atoi(&fmt);
+			} else if (*fmt == '*') {
+				precision = va_arg(args, int);
+				fmt++;
+			}
+			if (precision < 0)
+				precision = 0;
+		}
+
+		/* Get the conversion qualifier */
+		qualifier = -1;
+		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
+			qualifier = *fmt;
+			fmt++;
+		}
+
+		switch (*fmt) {
+		case 'c':
+			if (!(flags & LEFT))
+				while (--field_width > 0)
+					*str++ = ' ';
+			*str++ = (unsigned char) va_arg(args, int);
+			while (--field_width > 0)
+				*str++ = ' ';
+			break;
+
+		case 's':
+			s = va_arg(args, char *);
+			len = strlen(s);
+			if (precision < 0)
+				precision = len;
+			else if (len > precision)
+				len = precision;
+
+			if (!(flags & LEFT))
+				while (len < field_width--)
+					*str++ = ' ';
+			for (i = 0; i < len; ++i)
+				*str++ = *s++;
+			while (len < field_width--)
+				*str++ = ' ';
+			break;
+
+		case 'o':
+			str = number(str, va_arg(args, unsigned long), 8,
+				field_width, precision, flags);
+			break;
+
+		case 'p':
+			if (field_width == -1) {
+				field_width = 8;
+				flags |= ZEROPAD;
+			}
+			str = number(str,
+				(unsigned long) va_arg(args, void *), 16,
+				field_width, precision, flags);
+			break;
+
+		case 'x':
+			flags |= SMALL;
+			/* FALLTHROUGH */
+		case 'X':
+			str = number(str, va_arg(args, unsigned long), 16,
+				field_width, precision, flags);
+			break;
+
+		case 'd': /* FALLTHROUGH */
+		case 'i':
+			flags |= SIGN;
+			/* FALLTHROUGH */
+		case 'u':
+			str = number(str, va_arg(args, unsigned long), 10,
+				field_width, precision, flags);
+			break;
+
+		case 'f':
+			str = number(str,
+				(unsigned long) va_arg(args, double), 10,
+				field_width, precision, flags);
+			break;
+
+		case 'n':
+			ip = va_arg(args, int *);
+			*ip = (str - buf);
+			break;
+
+		default:
+			if (*fmt != '%')
+				*str++ = '%';
+			if (*fmt)
+				*str++ = *fmt;
+			else
+				--fmt;
+			break;
+		}
+	}
+	*str = '\0';
+	return str-buf;
+}
diff --git a/stdlib/abort.c b/stdlib/abort.c
new file mode 100644
index 0000000..a45a8fd
--- /dev/null
+++ b/stdlib/abort.c
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+
+/* Abnormally terminate the current process */
+_Noreturn void
+abort(void)
+{
+	/* In future, this should raise the SIGABRT signal */
+	exit(EXIT_FAILURE);
+}
diff --git a/stdlib/malloc.c b/stdlib/malloc.c
new file mode 100644
index 0000000..cd19760
--- /dev/null
+++ b/stdlib/malloc.c
@@ -0,0 +1,157 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#define BLOCK_SIZE 16
+
+typedef struct Header Header;
+typedef struct Arena Arena;
+
+extern char _end[];
+
+/* Structure for a Memory Header */
+struct Header {
+	Header *prev, *next;
+	size_t size;
+	char magic[4];
+};
+
+/* Structure for a Memory Arena */
+struct Arena {
+	Arena *next;
+	void *start, *end;
+	size_t size;
+};
+
+Arena primaryArena = {
+	.next = NULL,
+	.start = NULL,
+	.end = NULL,
+	.size = 0
+};
+
+/* Allocate a region of memory in an arena */
+static void *
+arena_malloc(Arena *arena, size_t size)
+{
+	size_t blockSize, gapSize;
+	intptr_t blockEnd;
+	Header *prev, *head, *next;
+	head = prev = arena->start;
+	next = NULL;
+
+	/* Minimum allocation */
+	if (size % BLOCK_SIZE)
+		size += BLOCK_SIZE - (size % BLOCK_SIZE);
+
+	/* Block does not exist, create heap */
+	if (head->prev != head || memcmp(head->magic, "HEAP", 4)) {
+		head->prev = head;
+		head->next = NULL;
+		head->size = size;
+		memcpy(head->magic, "HEAP", 4);
+		memset((void *) (head + 1), 0, size);
+		return (void *) (head + 1);
+	}
+
+	/* Find gap */
+	while (head->next) {
+		next = head->next;
+		blockSize = sizeof(Header) + head->size;
+		blockEnd = (uintptr_t) head + blockSize;
+		gapSize = (size_t) next - blockEnd;
+		prev = head;
+
+		/* Fit in gap */
+		if (gapSize >= size + sizeof(Header)) {
+			head = (void *) blockEnd;
+			head->next = next;
+			head->prev = prev;
+			prev->next = head;
+			next->prev = head;
+			head->size = size;
+			memcpy(head->magic, "HEAP", 4);
+			memset((void *) (head + 1), 0, size);
+			return (void *) (head + 1);
+		}
+
+		head = head->next;
+	}
+
+	/* Add to end */
+	blockSize = sizeof(Header) + head->size;
+	blockEnd = (uintptr_t) head + blockSize;
+	/* Ensure more arenas can be allocated */
+	gapSize = (size_t) arena->end - blockEnd - sizeof(Arena);
+	/* Fit in gap */
+	if (gapSize >= size + sizeof(Header)) {
+		prev = head;
+		head = (void *) blockEnd;
+		head->next = NULL;
+		head->prev = prev;
+		prev->next = head;
+		head->size = size;
+		memcpy(head->magic, "HEAP", 4);
+		memset((void *) (head + 1), 0, size);
+		return (void *) (head + 1);
+	}
+
+	return NULL;
+}
+
+/* Allocate a region of memory */
+void *
+malloc(size_t size)
+{
+	void *addr = NULL;
+	Arena *arena;
+	size_t arenaSize = 64 * 1024;
+	while (arenaSize < size + sizeof(Arena))
+		arenaSize += 64 * 1024;
+
+	for (arena = &primaryArena; !addr; arena = arena->next) {
+		/* Allocate a new arena */
+		if (!arena->size) {
+			arena->size = arenaSize;
+			arena->start = mmap(NULL, arena->size,
+			                    PROT_READ | PROT_WRITE,
+			                    MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+			if (arena->start == MAP_FAILED) {
+				errno = ENOMEM;
+				return NULL;
+			}
+			arena->end = arena->start + arena->size;
+		}
+
+		/* Attempt to use arena */
+		addr = arena_malloc(arena, size);
+		if (!addr && !arena->next)
+			arena->next = arena_malloc(arena, sizeof(Arena));
+	}
+
+	return addr;
+}
+
+/* Free an allocated region of memory */
+void
+free(void *addr)
+{
+	Header *prev, *head, *next;
+	head = (Header *) addr - 1;
+	if (memcmp(head->magic, "HEAP", 4)) {
+		printf("free(): invalid pointer\n");
+		abort();
+	}
+	prev = head->prev;
+	next = head->next;
+	memset(head, 0, sizeof(Header));
+
+	if (prev != head)
+		prev->next = next;
+	if (next)
+		next->prev = prev;
+}
diff --git a/string/memcmp.c b/string/memcmp.c
new file mode 100644
index 0000000..e4c18fc
--- /dev/null
+++ b/string/memcmp.c
@@ -0,0 +1,13 @@
+#include <stddef.h>
+
+/* Copy one region of memory to another */
+int
+memcmp(void *s1, void *s2, size_t n)
+{
+	unsigned char *a = (unsigned char *) s1,
+	              *b = (unsigned char *) s2;
+	while (n-- > 0)
+			if (*a++ != *b++)
+				return a[-1] - b[-1];
+	return 0;
+}
diff --git a/string/memcpy.c b/string/memcpy.c
new file mode 100644
index 0000000..4988f38
--- /dev/null
+++ b/string/memcpy.c
@@ -0,0 +1,12 @@
+#include <stddef.h>
+
+/* Copy one region of memory to another */
+void *
+memcpy(void *dest, void *src, size_t n)
+{
+	unsigned char *a = (unsigned char *) dest,
+	              *b = (unsigned char *) src;
+	while (n-- > 0)
+		*a++ = *b++;
+	return dest;
+}
diff --git a/string/memset.c b/string/memset.c
new file mode 100644
index 0000000..f9c0902
--- /dev/null
+++ b/string/memset.c
@@ -0,0 +1,13 @@
+#include <stddef.h>
+
+/* Fill a region of memory with specified byte */
+void *
+memset(void *dest, int byte, size_t len)
+{
+	unsigned char *a = dest;
+	if (len > 0)  {
+		while (len-- > 0)
+			*a++ = byte;
+	}
+	return dest;
+}
diff --git a/string/strcmp.c b/string/strcmp.c
new file mode 100644
index 0000000..37b62a4
--- /dev/null
+++ b/string/strcmp.c
@@ -0,0 +1,18 @@
+#include <stddef.h>
+
+/* Compare two strings */
+int
+strcmp(char *s1, char *s2)
+{
+	for (; *s1 == *s2 && *s1 && *s2; s1++, s2++);
+	return *(unsigned char *) s1 - *(unsigned char *) s2;
+}
+
+/* Compare two limited strings */
+int
+strncmp(char *s1, char *s2, size_t n)
+{
+	if (!n--) return 0;
+	for (; *s1 == *s2 && *s1 && *s2 && n; s1++, s2++, n--);
+	return *(unsigned char *) s1 - *(unsigned char *) s2;
+}
diff --git a/string/strcpy.c b/string/strcpy.c
new file mode 100644
index 0000000..ce725a2
--- /dev/null
+++ b/string/strcpy.c
@@ -0,0 +1,23 @@
+#include <stddef.h>
+
+/* Copy a string */
+char *
+strcpy(char *dest, const char *src)
+{
+	char *ret = dest;
+	while (*src)
+		*dest++ = *src++;
+	*dest = '\0';
+	return ret;
+}
+
+/* Copy a limited string */
+char *
+strncpy(char *dest, const char *src, size_t n)
+{
+	char *ret = dest;
+	while (*src && n--)
+		*dest++ = *src++;
+	*dest = '\0';
+	return ret;
+}
diff --git a/string/strlen.c b/string/strlen.c
new file mode 100644
index 0000000..a8d506c
--- /dev/null
+++ b/string/strlen.c
@@ -0,0 +1,12 @@
+#include <string.h>
+
+/* Find length of string */
+size_t
+strlen(const char *str)
+{
+	if (!str)
+		return 0;
+	size_t i;
+	for (i = 0; str[i]; i++);
+	return i;
+}
diff --git a/sys/ioctl.c b/sys/ioctl.c
new file mode 100644
index 0000000..db6d27d
--- /dev/null
+++ b/sys/ioctl.c
@@ -0,0 +1,17 @@
+#include <sys/syscall.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+/* Send an I/O Control request to a file descriptor */
+int
+ioctl(int fd, unsigned long request, ...)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_IOCTL),
+	             "c" (3), "S" (&fd));
+
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
diff --git a/sys/ipc.c b/sys/ipc.c
new file mode 100644
index 0000000..3a563fe
--- /dev/null
+++ b/sys/ipc.c
@@ -0,0 +1,43 @@
+#include <stdint.h>
+#include <sys/ipc.h>
+#include <sys/syscall.h>
+
+/* Send a message without blocking */
+Message *
+nb_send_msg(pid_t to, uint16_t type, MessageContent *msg)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_NB_SEND_MSG),
+	             "c" (3), "S" (&to));
+	return (Message *) ret;
+}
+
+/* Send a message and block until delivery */
+Message *
+send_msg(pid_t to, uint16_t type, MessageContent *msg)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_SEND_MSG),
+	             "c" (3), "S" (&to));
+	return (Message *) ret;
+}
+
+/* Receive a message if available */
+pid_t
+nb_recv_msg(Message *buf, pid_t from)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_NB_RECV_MSG),
+	             "c" (2), "S" (&buf));
+	return (pid_t) ret;
+}
+
+/* Block until a message is received */
+pid_t
+recv_msg(Message *buf, pid_t from)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_RECV_MSG),
+	             "c" (2), "S" (&buf));
+	return (pid_t) ret;
+}
diff --git a/sys/mkdir.c b/sys/mkdir.c
new file mode 100644
index 0000000..0c6e7e4
--- /dev/null
+++ b/sys/mkdir.c
@@ -0,0 +1,16 @@
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <errno.h>
+
+/* Make a directory */
+int
+mkdir(const char *pathname, mode_t mode)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_MKDIR),
+	             "c" (2), "S" (&pathname));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
diff --git a/sys/mmap.c b/sys/mmap.c
new file mode 100644
index 0000000..b80a2aa
--- /dev/null
+++ b/sys/mmap.c
@@ -0,0 +1,16 @@
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <errno.h>
+
+void *
+mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_MMAP),
+	             "c" (6), "S" (&addr));
+	if (ret >= 0)
+		return (void *) ret;
+	errno = -ret;
+	return MAP_FAILED;
+}
diff --git a/sys/mount.c b/sys/mount.c
new file mode 100644
index 0000000..ec2f200
--- /dev/null
+++ b/sys/mount.c
@@ -0,0 +1,16 @@
+#include <sys/mount.h>
+#include <sys/syscall.h>
+#include <errno.h>
+
+int
+mount(const char *src, const char *target, const char *type,
+      unsigned long flags, void *data)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_MOUNT),
+	             "c" (6), "S" (&src));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
diff --git a/sys/stat.c b/sys/stat.c
new file mode 100644
index 0000000..3c42fd9
--- /dev/null
+++ b/sys/stat.c
@@ -0,0 +1,31 @@
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <errno.h>
+
+/* Get file status */
+int
+stat(const char *pathname, struct stat *statbuf)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_STAT),
+	             "c" (2), "S" (&pathname));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+
+}
+
+/* Get file status by file descriptor */
+int
+fstat(int fd, struct stat *statbuf)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_FSTAT),
+	             "c" (2), "S" (&fd));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+
+}
diff --git a/sys/wait.c b/sys/wait.c
new file mode 100644
index 0000000..912712a
--- /dev/null
+++ b/sys/wait.c
@@ -0,0 +1,23 @@
+#include <sys/syscall.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+/* Wait for a process to change state */
+pid_t
+wait(int *wstatus)
+{
+	return waitpid(-1, wstatus, 0);
+}
+
+/* Wait for a specific process to change state */
+pid_t
+waitpid(pid_t pid, int *wstatus, int options)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_WAITPID),
+	             "c" (3), "S" (&pid));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
diff --git a/time/sleep.c b/time/sleep.c
new file mode 100644
index 0000000..dd01751
--- /dev/null
+++ b/time/sleep.c
@@ -0,0 +1,16 @@
+#include <sys/syscall.h>
+#include <time.h>
+#include <errno.h>
+
+/* Sleep for a specified time (milliseconds) */
+int
+sleep(uint32_t ms)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_SLEEP),
+	             "c" (1), "S" (&ms));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
diff --git a/time/time.c b/time/time.c
new file mode 100644
index 0000000..dd43c31
--- /dev/null
+++ b/time/time.c
@@ -0,0 +1,30 @@
+#include <sys/syscall.h>
+#include <sys/times.h>
+#include <time.h>
+#include <errno.h>
+
+/* Get epoch time */
+time_t
+time(time_t *tloc)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_TIME),
+	             "c" (1), "S" (&tloc));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
+
+/* Get process times */
+clock_t
+times(Times *buf)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_TIMES),
+	             "c" (1), "S" (&buf));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
diff --git a/unistd/chdir.c b/unistd/chdir.c
new file mode 100644
index 0000000..c146c8c
--- /dev/null
+++ b/unistd/chdir.c
@@ -0,0 +1,15 @@
+#include <sys/syscall.h>
+#include <errno.h>
+
+/* Change the process' file system current working directory */
+int
+chdir(const char *path)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_CHDIR),
+	             "c" (1), "S" (&path));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
diff --git a/unistd/chroot.c b/unistd/chroot.c
new file mode 100644
index 0000000..e9fd64c
--- /dev/null
+++ b/unistd/chroot.c
@@ -0,0 +1,15 @@
+#include <sys/syscall.h>
+#include <errno.h>
+
+/* Change the process' file system root */
+int
+chroot(const char *path)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_CHROOT),
+	             "c" (1), "S" (&path));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
diff --git a/unistd/clone.c b/unistd/clone.c
new file mode 100644
index 0000000..f7f4b34
--- /dev/null
+++ b/unistd/clone.c
@@ -0,0 +1,13 @@
+#include <stddef.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+
+/* Fork the current process */
+pid_t
+clone(int flags)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_CLONE),
+	             "c" (1), "S" (&flags));
+	return ret;
+}
diff --git a/unistd/close.c b/unistd/close.c
new file mode 100644
index 0000000..d2cf9fc
--- /dev/null
+++ b/unistd/close.c
@@ -0,0 +1,15 @@
+#include <sys/syscall.h>
+#include <errno.h>
+
+/* Close a file */
+int
+close(int fd)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_CLOSE),
+	             "c" (1), "S" (&fd));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
diff --git a/unistd/dup.c b/unistd/dup.c
new file mode 100644
index 0000000..a4aabfc
--- /dev/null
+++ b/unistd/dup.c
@@ -0,0 +1,28 @@
+#include <sys/syscall.h>
+#include <errno.h>
+
+/* Duplicate an open file descriptor */
+int
+dup(int oldfd)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_DUP),
+	             "c" (1), "S" (&oldfd));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
+
+/* Duplicate an open file descriptor to a specified file descriptor */
+int
+dup2(int oldfd, int newfd)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_DUP2),
+	             "c" (2), "S" (&oldfd));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
diff --git a/unistd/execve.c b/unistd/execve.c
new file mode 100644
index 0000000..6fcf69f
--- /dev/null
+++ b/unistd/execve.c
@@ -0,0 +1,32 @@
+#include <stddef.h>
+#include <sys/syscall.h>
+#include <errno.h>
+
+/* Execute a binary with the specified arguments and environment */
+int
+execve(const char *path, char *argv[], char *envp[])
+{
+	struct {
+		const char *path;
+		char **argv, **envp;
+	} args;
+	args.path = path;
+	args.argv = argv;
+	args.envp = envp;
+
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_EXECVE),
+	             "c" (3), "S" (&args));
+
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
+
+/* Execute a binary with the specified arguments */
+int
+execv(const char *path, char *argv[])
+{
+	return execve(path, argv, NULL); /* FIXME: environment */
+}
diff --git a/unistd/fork.c b/unistd/fork.c
new file mode 100644
index 0000000..f827758
--- /dev/null
+++ b/unistd/fork.c
@@ -0,0 +1,11 @@
+#include <stddef.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/sched.h>
+
+/* Fork the current process */
+pid_t
+fork(void)
+{
+	return clone(CLONE_NONE);
+}
diff --git a/unistd/getcwd.c b/unistd/getcwd.c
new file mode 100644
index 0000000..0107f2f
--- /dev/null
+++ b/unistd/getcwd.c
@@ -0,0 +1,16 @@
+#include <stddef.h>
+#include <sys/syscall.h>
+#include <errno.h>
+
+/* Get the current working directory's path */
+char *
+getcwd(char *buf, size_t size)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_GETCWD),
+	             "c" (2), "S" (&buf));
+	if ((char *) ret == buf)
+		return (char *) ret;
+	errno = -ret;
+	return NULL;
+}
diff --git a/unistd/getpid.c b/unistd/getpid.c
new file mode 100644
index 0000000..dc5d86a
--- /dev/null
+++ b/unistd/getpid.c
@@ -0,0 +1,13 @@
+#include <stddef.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+
+/* Get the current process' id */
+pid_t
+getpid(void)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_GETPID),
+	             "c" (0), "S" (NULL));
+	return ret;
+}
diff --git a/unistd/getuid.c b/unistd/getuid.c
new file mode 100644
index 0000000..3e7174d
--- /dev/null
+++ b/unistd/getuid.c
@@ -0,0 +1,43 @@
+#include <stddef.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+
+/* Get the current process' user id */
+uid_t
+getuid(void)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_GETUID),
+	             "c" (0), "S" (NULL));
+	return ret;
+}
+
+/* Get the current process' effective user id */
+uid_t
+geteuid(void)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_GETEUID),
+	             "c" (0), "S" (NULL));
+	return ret;
+}
+
+/* Get the current process' group id */
+gid_t
+getgid(void)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_GETGID),
+	             "c" (0), "S" (NULL));
+	return ret;
+}
+
+/* Get the current process' effective group id */
+gid_t
+getegid(void)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_GETEGID),
+	             "c" (0), "S" (NULL));
+	return ret;
+}
diff --git a/unistd/isatty.c b/unistd/isatty.c
new file mode 100644
index 0000000..823019a
--- /dev/null
+++ b/unistd/isatty.c
@@ -0,0 +1,15 @@
+#include <sys/syscall.h>
+#include <errno.h>
+
+/* Check if fd refers to a terminal */
+int
+isatty(int fd)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_ISATTY),
+	             "c" (1), "S" (&fd));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return 0;
+}
diff --git a/unistd/lseek.c b/unistd/lseek.c
new file mode 100644
index 0000000..aa6510a
--- /dev/null
+++ b/unistd/lseek.c
@@ -0,0 +1,15 @@
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <errno.h>
+
+off_t
+lseek(int fd, off_t offset, int whence)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_LSEEK),
+	             "c" (3), "S" (&fd));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
diff --git a/unistd/open.c b/unistd/open.c
new file mode 100644
index 0000000..02603d8
--- /dev/null
+++ b/unistd/open.c
@@ -0,0 +1,30 @@
+#include <fcntl.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <errno.h>
+
+/* Open a file */
+int
+open(const char *name, int flags, ...)
+{
+	int ret;
+	if (flags & O_CREATE) {
+		asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_OPEN),
+		             "c" (3), "S" (&name));
+	} else {
+		asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_OPEN),
+		             "c" (2), "S" (&name));
+	}
+
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
+
+/* Create a file */
+int
+create(const char *name, mode_t mode)
+{
+	return open(name, O_CREATE | O_WRONLY | O_TRUNC, mode);
+}
diff --git a/unistd/read.c b/unistd/read.c
new file mode 100644
index 0000000..f4d2d75
--- /dev/null
+++ b/unistd/read.c
@@ -0,0 +1,16 @@
+#include <stddef.h>
+#include <sys/syscall.h>
+#include <errno.h>
+
+/* Read from a file */
+int
+read(int fd, void *buf, size_t count)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_READ),
+	             "c" (3), "S" (&fd));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}
diff --git a/unistd/setuid.c b/unistd/setuid.c
new file mode 100644
index 0000000..7dcca04
--- /dev/null
+++ b/unistd/setuid.c
@@ -0,0 +1,43 @@
+#include <stddef.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+
+/* Set the current process' user id */
+int
+setuid(uid_t uid)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_SETUID),
+	             "c" (1), "S" (&uid));
+	return ret;
+}
+
+/* Set the current process' effective user id */
+int
+seteuid(uid_t euid)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_SETEUID),
+	             "c" (1), "S" (&euid));
+	return ret;
+}
+
+/* Set the current process' group id */
+int
+setgid(gid_t gid)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_SETGID),
+	             "c" (1), "S" (&gid));
+	return ret;
+}
+
+/* Set the current process' effective group id */
+int
+setegid(gid_t egid)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_SETEGID),
+	             "c" (1), "S" (&egid));
+	return ret;
+}
diff --git a/unistd/write.c b/unistd/write.c
new file mode 100644
index 0000000..90862b2
--- /dev/null
+++ b/unistd/write.c
@@ -0,0 +1,16 @@
+#include <stddef.h>
+#include <sys/syscall.h>
+#include <errno.h>
+
+/* Write to a file */
+int
+write(int fd, void *buf, size_t count)
+{
+	int ret;
+	asm volatile("int $0x80" : "=a" (ret) : "0" (SYSCALL_WRITE),
+	             "c" (3), "S" (&fd));
+	if (ret >= 0)
+		return ret;
+	errno = -ret;
+	return -1;
+}