From c4ae4232380559e76953e16004cabf4a1cab85a6 Mon Sep 17 00:00:00 2001 From: Bob Lantz Date: Sat, 13 Mar 2010 18:19:23 -0800 Subject: [PATCH] Support for control-C. Finally. I've changed the way things work a bit: 1. netns is replaced by mnexec, a general-purpose mininet helper. 2. For interactive commands, we now use mnexec -p, which prints out the pid, so we can kill it when someone hits control-C! 3. We close file descriptors for subshells. This might save memory, but who knows. 4. We detach our subshells from the tty using mnexec -s; thus control-C should not terminate everything. 5. Given 4, mn -c is now necessary if you kill mininet. --- mnexec.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 mnexec.c diff --git a/mnexec.c b/mnexec.c new file mode 100644 index 0000000..2a7e5c7 --- /dev/null +++ b/mnexec.c @@ -0,0 +1,80 @@ +/* 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 + * + * Partially based on public domain setsid(1) +*/ + +#include +#include +#include + +void usage(char *name) +{ + printf("Execution utility for Mininet.\n" + "usage: %s [-cdnp]\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", name); +} + +int main(int argc, char *argv[]) +{ + char c; + int fd; + int opt; + + while ((c = getopt(argc, argv, "+cdnp")) != -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; + default: + usage(argv[0]); + break; + } + + if (optind < argc) { + execvp(argv[optind], &argv[optind]); + perror("execvp"); + return 1; + } + + usage(argv[0]); +}