diff options
-rw-r--r-- | toys/other/nsenter.c | 116 | ||||
-rw-r--r-- | toys/other/unshare.c | 42 | ||||
-rw-r--r-- | toys/pending/nsenter.c | 104 |
3 files changed, 116 insertions, 146 deletions
diff --git a/toys/other/nsenter.c b/toys/other/nsenter.c new file mode 100644 index 00000000..d53de41e --- /dev/null +++ b/toys/other/nsenter.c @@ -0,0 +1,116 @@ +/* nsenter.c - Enter existing namespaces + * + * Copyright 2014 andy Lutomirski <luto@amacapital.net> + * + * No standard + * + * unshare.c - run command in new context + * + * Copyright 2011 Rob Landley <rob@landley.net> + * + * No Standard + * + +// Note: flags go in same order (right to left) for shared subset +USE_NSENTER(NEWTOY(nsenter, "<1F(no-fork)t#<1(target)i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);", TOYFLAG_USR|TOYFLAG_BIN)) +USE_UNSHARE(NEWTOY(unshare, "<1^imnpuU", TOYFLAG_USR|TOYFLAG_BIN)) + +config UNSHARE + bool "unshare" + default y + depends on TOYBOX_CONTAINER + help + usage: unshare [-imnpuU] COMMAND... + + Create new namespace(s) for this process and its children, so some + attribute is not shared with the parent process. This is part of + Linux Containers. Each process can have its own: + + -i SysV IPC (message queues, semaphores, shared memory) + -m Mount/unmount tree + -n Network address, sockets, routing, iptables + -p Process IDs and init + -u Host and domain names + -U UIDs, GIDs, capabilities + +config NSENTER + bool "nsenter" + default n + help + usage: nsenter [-t pid] [-F] [-i] [-m] [-n] [-p] [-u] [-U] COMMAND... + + Run COMMAND in a different set of namespaces. + + -t PID to take namespaces from (--target) + -F don't fork, even if -p is used (--no-fork) + + The namespaces to switch are: + + -i SysV IPC: message queues, semaphores, shared memory (--ipc) + -m Mount/unmount tree (--mnt) + -n Network address, sockets, routing, iptables (--net) + -p Process IDs and init, will fork unless -F is used (--pid) + -u Host and domain names (--uts) + -U UIDs, GIDs, capabilities (--user) + + If -t isn't specified, each namespace argument must provide a path + to a namespace file, ala "-i=/proc/$PID/ns/ipc" +*/ + +#define FOR_nsenter +#include "toys.h" +#include <linux/sched.h> +int unshare(int flags); +int setns(int fd, int nstype); + +GLOBALS( + char *nsnames[6]; + long targetpid; +) + +void unshare_main(void) +{ + unsigned flags[]={CLONE_NEWUSER, CLONE_NEWUTS, CLONE_NEWPID, CLONE_NEWNET, + CLONE_NEWNS, CLONE_NEWIPC}, f = 0; + int i, fd; + + // Create new namespace(s)? + if (CFG_UNSHARE && toys.which->name[0]) { + for (i = 0; i<ARRAY_LEN(flags); i++) + if (toys.optflags & (1<<i)) f |= flags[i]; + + if (unshare(f)) perror_exit(0); + + // Bind to existing namespace(s)? + } else if (CFG_NSENTER) { + char *nsnames = "user\0uts\0pid\0net\0mnt\0ipc"; + + for (i = 0; i<ARRAY_LEN(flags); i++) { + char *filename = TT.nsnames[i]; + + if (toys.optflags & (1<<i)) { + if (!filename || !*filename) { + if (!(toys.optflags & FLAG_t)) error_exit("need -t or =filename"); + sprintf(toybuf, "/proc/%ld/ns/%s", TT.targetpid, nsnames); + filename = toybuf; + } + + if (setns(fd = xopen(filename, O_RDONLY), flags[i])) + perror_exit("setns"); + close(fd); + } + nsnames += strlen(nsnames)+1; + } + + if ((toys.optflags & FLAG_p) && !(toys.optflags & FLAG_F)) { + pid_t pid = xfork(); + + if (pid) { + while (waitpid(pid, 0, 0) == -1 && errno == EINTR); + return; + } + } + } + + xexec_optargs(0); +} diff --git a/toys/other/unshare.c b/toys/other/unshare.c deleted file mode 100644 index 68c1ebdd..00000000 --- a/toys/other/unshare.c +++ /dev/null @@ -1,42 +0,0 @@ -/* unshare.c - run command in new context - * - * Copyright 2011 Rob Landley <rob@landley.net> - -USE_UNSHARE(NEWTOY(unshare, "<1^imnpuU", TOYFLAG_USR|TOYFLAG_BIN)) - -config UNSHARE - bool "unshare" - default y - depends on TOYBOX_CONTAINER - help - usage: unshare [-imnpuU] COMMAND... - - Create new namespace(s) for this process and its children, so some - attribute is not shared with the parent process. This is part of - Linux Containers. Each process can have its own: - - -i SysV IPC (message queues, semaphores, shared memory) - -m Mount/unmount tree - -n Network address, sockets, routing, iptables - -p Process IDs and init - -u Host and domain names - -U UIDs, GIDs, capabilities -*/ - -#include "toys.h" -#include <linux/sched.h> -extern int unshare (int __flags); - -void unshare_main(void) -{ - unsigned flags[]={CLONE_NEWUSER, CLONE_NEWUTS, CLONE_NEWPID, CLONE_NEWNET, - CLONE_NEWNS, CLONE_NEWIPC, 0}; - unsigned f=0; - int i; - - for (i=0; flags[i]; i++) if (toys.optflags & (1<<i)) f |= flags[i]; - - if (unshare(f)) perror_exit("failed"); - - xexec_optargs(0); -} diff --git a/toys/pending/nsenter.c b/toys/pending/nsenter.c deleted file mode 100644 index 33db873e..00000000 --- a/toys/pending/nsenter.c +++ /dev/null @@ -1,104 +0,0 @@ -/* nsenter.c - Enter existing namespaces - * - * Copyright 2014 andy Lutomirski <luto@amacapital.net> - -USE_NSENTER(NEWTOY(nsenter, "<1F(no-fork)t#(target)i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);", TOYFLAG_USR|TOYFLAG_BIN)) - -config NSENTER - bool "nsenter" - default n - help - usage: nsenter [-t pid] [-F] [-i] [-m] [-n] [-p] [-u] [-U] COMMAND... - - Run COMMAND in a different set of namespaces. - - -T PID to take namespaces from - -F don't fork, even if -p is set - - The namespaces to switch are: - - -i SysV IPC (message queues, semaphores, shared memory) - -m Mount/unmount tree - -n Network address, sockets, routing, iptables - -p Process IDs and init (will fork unless -F is used) - -u Host and domain names - -U UIDs, GIDs, capabilities - - Each of those options takes an optional argument giving the path of - the namespace file (usually in /proc). This optional argument is - mandatory unless -t is used. -*/ - -#define FOR_nsenter -#define _GNU_SOURCE -#include "toys.h" -#include <errno.h> -#include <sched.h> -#include <linux/sched.h> - -#define NUM_NSTYPES 6 - -struct nstype { - int type; - const char *name; -}; - -struct nstype nstypes[NUM_NSTYPES] = { - {CLONE_NEWUSER, "user"}, /* must be first to allow non-root operation */ - {CLONE_NEWUTS, "uts"}, - {CLONE_NEWPID, "pid"}, - {CLONE_NEWNET, "net"}, - {CLONE_NEWNS, "mnt"}, - {CLONE_NEWIPC, "ipc"}, -}; - -GLOBALS( - char *nsnames[6]; - long targetpid; -) - -static void enter_by_name(int idx) -{ - int fd, rc; - char buf[64]; - char *filename = TT.nsnames[idx]; - - if (!(toys.optflags & (1<<idx))) return; - - if (!filename || !*filename) { - if (!(toys.optflags & (1<<NUM_NSTYPES))) - error_exit("either -t or an ns filename is required"); - sprintf(buf, "/proc/%ld/ns/%s", TT.targetpid, nstypes[idx].name); - filename = buf; - } - - fd = open(filename, O_RDONLY | O_CLOEXEC); - if (fd == -1) perror_exit(filename); - - rc = setns(fd, nstypes[idx].type); - if (CFG_TOYBOX_FREE) close(fd); - if (rc != 0) perror_exit("setns"); -} - -void nsenter_main(void) -{ - int i; - - for (i = 0; i < NUM_NSTYPES; i++) - enter_by_name(i); - - if ((toys.optflags & (1<<2)) && !(toys.optflags & 1<<(NUM_NSTYPES+1))) { - /* changed PID ns and --no-fork wasn't set, so fork. */ - pid_t pid = fork(); - - if (pid == -1) { - perror_exit("fork"); - } else if (pid != 0) { - while (waitpid(pid, 0, 0) == -1 && errno == EINTR) - ; - return; - } - } - - xexec_optargs(0); -} |