#include #include #include #include #include #include #include #include #include #include #include #include #include "clone.h" extern pid_t getpgid(pid_t pid); extern pid_t getsid(pid_t pid); static const char* procname; static void usage(const char *name) { printf("usage: %s [-h] [-c] [-muipq]" "[command [arg ..]]\n", name); printf("\n"); printf(" -h this message\n"); printf("\n"); printf(" -c use 'clone' rather than 'unshare' system call\n"); printf(" -m mount namespace\n"); printf(" -u utsname namespace\n"); printf(" -i ipc namespace\n"); printf(" -p pid namespace\n"); printf(" -q mqueue namespace\n"); printf("\n"); printf("(C) Copyright IBM Corp. 2006\n"); printf("\n"); exit(1); } static void print_my_info(const char *procname, char *ttyname) { printf("procname %s, ttyname %s, pid %d, ppid %d, pgid %d, sid %d\n", procname, ttyname, getpid(), getppid(), getpgid(0), getsid(0)); } /* * Copied following opentty() from Fedora's util-linux rpm * I just changed the "FATAL" message below from syslog() * to printf */ static void opentty(const char * tty) { int i, fd, flags; fd = open(tty, O_RDWR | O_NONBLOCK); if (fd == -1) { printf("FATAL: can't reopen tty: %s", strerror(errno)); sleep(1); exit(1); } flags = fcntl(fd, F_GETFL); flags &= ~O_NONBLOCK; fcntl(fd, F_SETFL, flags); for (i = 0; i < fd; i++) close(i); for (i = 0; i < 3; i++) if (fd != i) dup2(fd, i); if (fd >= 3) close(fd); } // Code copy end int do_child(void *vargv) { char **argv = (char **)vargv; execve(argv[0], argv, __environ); perror("execve"); return 1; } int main(int argc, char *argv[]) { int c; unsigned long flags = 0; char ttyname[256]; int status; int ret, use_clone = 0; int pid; procname = basename(argv[0]); memset(ttyname, '\0', sizeof(ttyname)); readlink("/proc/self/fd/0", ttyname, sizeof(ttyname)); while ((c = getopt(argc, argv, "+muiphqc")) != EOF) { switch (c) { case 'm': flags |= CLONE_NEWNS; break; case 'c': use_clone = 1; break; case 'u': flags |= CLONE_NEWUTS; break; case 'i': flags |= CLONE_NEWIPC; break; case 'p': flags |= CLONE_NEWPID|CLONE_NEWNS; break; case 'q': flags |= CLONE_NEWMQ; break; case 'h': default: usage(procname); } }; argv = &argv[optind]; argc = argc - optind; if (use_clone) { void *childstack, *stack = malloc(getpagesize()); if (!stack) { perror("malloc"); return -1; } childstack = stack + getpagesize(); printf("about to clone with %lx\n", flags); pid = clone(do_child, childstack, flags, (void *)argv); if (pid == -1) { perror("clone"); return -1; } } else { if ((pid = fork()) == 0) { // Child. print_my_info(procname, ttyname); opentty(ttyname); printf("about to unshare with %lx\n", flags); ret = unshare(flags); if (ret < 0) { perror("unshare"); return 1; } return do_child((void*)argv); } } printf("Parent waiting for pid %d\n", pid); if ((ret = waitpid(pid, &status, __WALL)) < 0) printf("waitpid() returns %d, errno %d\n", ret, errno); exit(0); }