First commit
diff --git a/mnexec.c b/mnexec.c
new file mode 100644
index 0000000..42a9cf6
--- /dev/null
+++ b/mnexec.c
@@ -0,0 +1,179 @@
+/* mnexec: execution utility for mininet
+ *
+ * Starts up programs and does things that are slow or
+ * difficult in Python, including:
+ *
+ *  - closing all file descriptors except stdin/out/error
+ *  - detaching from a controlling tty using setsid
+ *  - running in a network namespace
+ *  - printing out the pid of a process so we can identify it later
+ *  - attaching to a namespace and cgroup
+ *  - setting RT scheduling
+ *
+ * Partially based on public domain setsid(1)
+*/
+
+#include <stdio.h>
+#include <linux/sched.h>
+#include <unistd.h>
+#include <limits.h>
+#include <syscall.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <sched.h>
+
+#if !defined(VERSION)
+#define VERSION "(devel)"
+#endif
+
+void usage(char *name) 
+{
+    printf("Execution utility for Mininet\n\n"
+           "Usage: %s [-cdnp] [-a pid] [-g group] [-r rtprio] cmd args...\n\n"
+           "Options:\n"
+           "  -c: close all file descriptors except stdin/out/error\n"
+           "  -d: detach from tty by calling setsid()\n"
+           "  -n: run in new network namespace\n"
+           "  -p: print ^A + pid\n"
+           "  -a pid: attach to pid's network namespace\n"
+           "  -g group: add to cgroup\n"
+           "  -r rtprio: run with SCHED_RR (usually requires -g)\n"
+           "  -v: print version\n",
+           name);
+}
+
+
+int setns(int fd, int nstype)
+{
+	return syscall(308, fd, nstype);
+}
+
+/* Validate alphanumeric path foo1/bar2/baz */
+void validate(char *path)
+{
+    char *s;
+    for (s=path; *s; s++) {
+        if (!isalnum(*s) && *s != '/') {
+            fprintf(stderr, "invalid path: %s\n", path);
+            exit(1);
+        }
+    }
+}
+
+/* Add our pid to cgroup */
+int cgroup(char *gname)
+{
+    static char path[PATH_MAX];
+    static char *groups[] = {
+        "cpu", "cpuacct", "cpuset", NULL
+    };
+    char **gptr;
+    pid_t pid = getpid();
+    int count = 0;
+    validate(gname);
+    for (gptr = groups; *gptr; gptr++) {
+        FILE *f;
+        snprintf(path, PATH_MAX, "/sys/fs/cgroup/%s/%s/tasks",
+                 *gptr, gname);
+        f = fopen(path, "w");
+        if (f) {
+            count++;
+            fprintf(f, "%d\n", pid);
+            fclose(f);
+        }
+    }
+    if (!count) {
+        fprintf(stderr, "cgroup: could not add to cgroup %s\n",
+            gname);
+        exit(1);
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    char c;
+    int fd;
+    char path[PATH_MAX];
+    int nsid;
+    int pid;
+    static struct sched_param sp;
+    while ((c = getopt(argc, argv, "+cdnpa:g:r:vh")) != -1)
+        switch(c) {
+        case 'c':
+            /* close file descriptors except stdin/out/error */
+            for (fd = getdtablesize(); fd > 2; fd--)
+                close(fd);
+            break;
+        case 'd':
+            /* detach from tty */
+            if (getpgrp() == getpid()) {
+                switch(fork()) {
+                    case -1:
+                        perror("fork");
+                        return 1;
+                    case 0:		/* child */
+                        break;
+                    default:	/* parent */
+                        return 0;
+                }
+            }
+            setsid();
+            break;
+        case 'n':
+            /* run in network namespace */
+            if (unshare(CLONE_NEWNET) == -1) {
+                perror("unshare");
+                return 1;
+            }
+            break;
+        case 'p':
+            /* print pid */
+            printf("\001%d\n", getpid());
+            fflush(stdout);
+            break;
+        case 'a':
+            /* Attach to pid's network namespace */
+            pid = atoi(optarg);
+            sprintf(path, "/proc/%d/ns/net", pid );
+            nsid = open(path, O_RDONLY);
+            if (nsid < 0) {
+                perror(path);
+                return 1;
+            }
+            if (setns(nsid, 0) != 0) {
+                perror("setns");
+                return 1;
+            }
+            break;
+        case 'g':
+            /* Attach to cgroup */
+            cgroup(optarg);
+            break;
+        case 'r':
+            /* Set RT scheduling priority */
+            sp.sched_priority = atoi(optarg);
+            if (sched_setscheduler(getpid(), SCHED_RR, &sp) < 0) {
+                perror("sched_setscheduler");
+                return 1;
+            }
+            break;
+        case 'v':
+            printf("%s\n", VERSION);
+            exit(0);
+        case 'h':
+            usage(argv[0]);
+            exit(0);
+        default:
+            usage(argv[0]);
+            exit(1); 
+        }
+
+    if (optind < argc) {
+        execvp(argv[optind], &argv[optind]);
+        perror(argv[optind]);
+        return 1;
+    }
+    
+    usage(argv[0]);
+}