/* ns_child_exec.c Copyright 2013, Michael Kerrisk Licensed under GNU General Public License v2 or later Create a child process that executes a shell command in new namespace(s). */ #define _GNU_SOURCE #include #include #include #include #include #include /* A simple error-handling function: print an error message based on the value in 'errno' and terminate the calling process */ #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) static void usage(char *pname) { fprintf(stderr, "Usage: %s [options] cmd [arg...]\n", pname); fprintf(stderr, "Options can be:\n"); fprintf(stderr, " -i new IPC namespace\n"); fprintf(stderr, " -m new mount namespace\n"); fprintf(stderr, " -n new network namespace\n"); fprintf(stderr, " -p new PID namespace\n"); fprintf(stderr, " -u new UTS namespace\n"); fprintf(stderr, " -U new user namespace\n"); fprintf(stderr, " -v Display verbose messages\n"); exit(EXIT_FAILURE); } static int /* Start function for cloned child */ childFunc(void *arg) { char **argv = arg; execvp(argv[0], &argv[0]); errExit("execvp"); } #define STACK_SIZE (1024 * 1024) static char child_stack[STACK_SIZE]; /* Space for child's stack */ int main(int argc, char *argv[]) { int flags, opt, verbose; pid_t child_pid; flags = 0; verbose = 0; /* Parse command-line options. The initial '+' character in the final getopt() argument prevents GNU-style permutation of command-line options. That's useful, since sometimes the 'command' to be executed by this program itself has command-line options. We don't want getopt() to treat those as options to this program. */ while ((opt = getopt(argc, argv, "+imnpuUv")) != -1) { switch (opt) { case 'i': flags |= CLONE_NEWIPC; break; case 'm': flags |= CLONE_NEWNS; break; case 'n': flags |= CLONE_NEWNET; break; case 'p': flags |= CLONE_NEWPID; break; case 'u': flags |= CLONE_NEWUTS; break; case 'U': flags |= CLONE_NEWUSER; break; case 'v': verbose = 1; break; default: usage(argv[0]); } } child_pid = clone(childFunc, child_stack + STACK_SIZE, flags | SIGCHLD, &argv[optind]); if (child_pid == -1) errExit("clone"); if (verbose) printf("%s: PID of child created by clone() is %ld\n", argv[0], (long) child_pid); /* Parent falls through to here */ if (waitpid(child_pid, NULL, 0) == -1) /* Wait for child */ errExit("waitpid"); if (verbose) printf("%s: terminating\n", argv[0]); exit(EXIT_SUCCESS); }