Needs more testing, don't have a test environment set up for this yet...
--- /dev/null
+/* 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);
+}
+++ /dev/null
-/* 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);
-}
+++ /dev/null
-/* 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);
-}