Add system()

diff --git a/klibc/Makefile b/klibc/Makefile
index 7fad849..f5143e2 100644
--- a/klibc/Makefile
+++ b/klibc/Makefile
@@ -17,7 +17,7 @@
 	  strtoimax.o strtoumax.o \
 	  globals.o exitc.o atexit.o onexit.o \
 	  execl.o execle.o execv.o execvpe.o execvp.o execlp.o execlpe.o \
-	  fork.o wait.o wait3.o waitpid.o setpgrp.o \
+	  fork.o wait.o wait3.o waitpid.o system.o setpgrp.o \
 	  printf.o vprintf.o fprintf.o vfprintf.o perror.o \
 	  fopen.o fread.o fread2.o fgetc.o fgets.o \
 	  fwrite.o fwrite2.o fputc.o fputs.o puts.o \
diff --git a/klibc/system.c b/klibc/system.c
new file mode 100644
index 0000000..643bf5e
--- /dev/null
+++ b/klibc/system.c
@@ -0,0 +1,61 @@
+/*
+ * system.c
+ *
+ * The system() function.  If this turns out to actually be *used*,
+ * we may want to try to detect the very simple cases (no shell magic)
+ * and handle them internally, instead of requiring that /bin/sh be
+ * present.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+int system(const char *string)
+{
+  pid_t pid;
+  struct sigaction ignore, old_int, old_quit;
+  sigset_t masked, oldmask;
+  static const char *argv[] = { "/bin/sh", "-c", NULL, NULL };
+  int status;
+
+  /* Block SIGCHLD and ignore SIGINT and SIGQUIT */
+  /* Do this before the fork() to avoid races */
+
+  ignore.sa_handler = SIG_IGN;
+  sigemptyset(&ignore.sa_mask);
+  ignore.sa_flags = 0;
+  sigaction(SIGINT,  &ignore, &old_int);
+  sigaction(SIGQUIT, &ignore, &old_quit);
+
+  sigemptyset(&masked);
+  sigaddset(&masked, SIGCHLD);
+  sigprocmask(SIG_BLOCK, &masked, &oldmask);
+
+  pid = fork();
+
+  if ( pid < 0 )
+    return -1;
+  else if ( pid == 0 ) {
+    sigaction(SIGINT,  &old_int, NULL);
+    sigaction(SIGQUIT, &old_quit, NULL);
+    sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+    argv[2] = string;
+
+    execve(argv[0], (char * const *)argv, (char * const *)environ);
+    _exit(127);
+  }
+
+  /* else... */
+
+  waitpid(pid, &status, 0);
+
+  sigaction(SIGINT,  &old_int, NULL);
+  sigaction(SIGQUIT, &old_quit, NULL);
+  sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+  return status;
+}