OrionLibC
Barry Importing existing Orion LibC 03048a9 (3 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;
+}