diff options
-rw-r--r-- | toys/pending/nsenter.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/toys/pending/nsenter.c b/toys/pending/nsenter.c new file mode 100644 index 00000000..33db873e --- /dev/null +++ b/toys/pending/nsenter.c @@ -0,0 +1,104 @@ +/* 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); +} |