On Fri, Dec 28, 2012 at 11:22:18AM -0500, Neil Horman wrote: > In addition to the unshare syscall, there exists the setns syscall, which allows > processes to migrate to the namepsaces of other processes. Add this > functionality into the unshare command, as they operate in a fairly simmilar > fashion. > > Note: There was discussion of adding a path based namespace argument to unshare > in the origional discussion thread, but I opted to leave that out as it didn't > seem to fit in nicely with the current argument pattern. I figure we can always > add that in later if we need to > > Signed-off-by: Neil Horman <nhorman@xxxxxxxxxxxxx> > CC: Karel Zak <kzak@xxxxxxxxxx> Ping, any further thoughts here? Neil > --- > sys-utils/unshare.1 | 34 +++++++++++++++--------- > sys-utils/unshare.c | 74 ++++++++++++++++++++++++++++++++++++++++++----------- > 2 files changed, 81 insertions(+), 27 deletions(-) > > diff --git a/sys-utils/unshare.1 b/sys-utils/unshare.1 > index 1325e34..e0393f7 100644 > --- a/sys-utils/unshare.1 > +++ b/sys-utils/unshare.1 > @@ -3,15 +3,15 @@ > .\" > .TH UNSHARE 1 "October 2008" "util-linux" "User Commands" > .SH NAME > -unshare \- run program with some namespaces unshared from parent > +unshare \- run program with some namespaces unshared or changed from parent > .SH SYNOPSIS > .B unshare > .RI [ options ] > program > .RI [ arguments ] > .SH DESCRIPTION > -Unshares specified namespaces from parent process and then executes specified > -program. Unshareable namespaces are: > +Unshares or migrates specified namespaces from parent process and then executes specified > +program. Available namespaces are: > .TP > .BR "mount namespace" > mounting and unmounting filesystems will not affect rest of the system > @@ -32,32 +32,42 @@ rules, the \fI/proc/net\fP and \fI/sys/class/net\fP directory trees, sockets > etc. (\fBCLONE_NEWNET\fP flag). > .TP > See the \fBclone\fR(2) for exact semantics of the flags. > +.TP > .SH OPTIONS > .TP > .BR \-h , " \-\-help" > Print a help message, > .TP > -.BR \-m , " \-\-mount" > -Unshare the mount namespace, > +.BR \-m\ [pid] , " \-\-mount[=pid]" > +Unshare the mount namespace, or, when a pid is specified, migrate the mount > +namespace to the one attached to the specified pid > .TP > -.BR \-u , " \-\-uts" > -Unshare the UTC namespace, > +.BR \-u\ [pid] , " \-\-uts[=pid]" > +Unshare the UTC namespace, or, when a pid is specified, migrate the uts > +namespace to the one attached to the specified pid > .TP > -.BR \-i , " \-\-ipc" > -Unshare the IPC namespace, > +.BR \-i\ [pid] , " \-\-ipc[=pid]" > +Unshare the IPC namespace, or, when a pid is specified, migrate the ipc > +namespace to the one attached to the specified pid > .TP > -.BR \-n , " \-\-net" > -Unshare the network namespace. > +.BR \-n\ [pid] , " \-\-net[=pid]" > +Unshare the network namespace, or, when a pid is specified, migrate the net > +namespace to the one attached to the specified pid > .SH NOTES > The unshare command drops potential privileges before executing the > target program. This allows to setuid unshare. > +.P > +Support for migrating processes between mnt and pid namespace is available in > +kernels 3.8 and later > .SH SEE ALSO > .BR unshare (2), > +.BR setns (2), > .BR clone (2) > .SH BUGS > None known so far. > -.SH AUTHOR > +.SH AUTHORS > Mikhail Gusarov <dottedmag@xxxxxxxxxxxxx> > +Neil Horman <nhorman@xxxxxxxxxxxxx> > .SH AVAILABILITY > The unshare command is part of the util-linux package and is available from > ftp://ftp.kernel.org/pub/linux/utils/util-linux/. > diff --git a/sys-utils/unshare.c b/sys-utils/unshare.c > index 9de997b..e67986a 100644 > --- a/sys-utils/unshare.c > +++ b/sys-utils/unshare.c > @@ -24,6 +24,7 @@ > #include <stdio.h> > #include <stdlib.h> > #include <unistd.h> > +#include <getopt.h> > > #include "nls.h" > #include "c.h" > @@ -42,6 +43,9 @@ > # define CLONE_NEWNET 0x40000000 > #endif > > +#define NUM_ENTRIES 128 > +static int ns_pids[128]; > + > #ifndef HAVE_UNSHARE > # include <sys/syscall.h> > > @@ -60,10 +64,10 @@ static void usage(int status) > _(" %s [options] <program> [args...]\n"), program_invocation_short_name); > > fputs(USAGE_OPTIONS, out); > - fputs(_(" -m, --mount unshare mounts namespace\n" > - " -u, --uts unshare UTS namespace (hostname etc)\n" > - " -i, --ipc unshare System V IPC namespace\n" > - " -n, --net unshare network namespace\n"), out); > + fputs(_(" -m, --mount unshare|migrate mounts namespace\n" > + " -u, --uts unshare|migrate UTS namespace (hostname etc)\n" > + " -i, --ipc unshare|migrate System V IPC namespace\n" > + " -n, --net unshare|migrate network namespace\n"), out); > > fputs(USAGE_SEPARATOR, out); > fputs(USAGE_HELP, out); > @@ -73,28 +77,42 @@ static void usage(int status) > exit(status); > } > > +static void close_files(void) > +{ > + int i; > + for (i=0; ns_pids[i] > 0; i++) > + close(ns_pids[i]); > + close_stdout(); > +} > + > int main(int argc, char *argv[]) > { > static const struct option longopts[] = { > { "help", no_argument, 0, 'h' }, > { "version", no_argument, 0, 'V'}, > - { "mount", no_argument, 0, 'm' }, > - { "uts", no_argument, 0, 'u' }, > - { "ipc", no_argument, 0, 'i' }, > - { "net", no_argument, 0, 'n' }, > + { "mount", optional_argument, 0, 'm' }, > + { "uts", optional_argument, 0, 'u' }, > + { "ipc", optional_argument, 0, 'i' }, > + { "net", optional_argument, 0, 'n' }, > { NULL, 0, 0, 0 } > }; > > int unshare_flags = 0; > - > + int nscount = 0; > int c; > + char *ns; > + unsigned long pid; > + char path[512]; > > + memset(ns_pids, 0, sizeof(int)*NUM_ENTRIES); > setlocale(LC_MESSAGES, ""); > bindtextdomain(PACKAGE, LOCALEDIR); > textdomain(PACKAGE); > - atexit(close_stdout); > + atexit(close_files); > + > + while((c = getopt_long(argc, argv, "hVm:u:i:n:", longopts, NULL)) != -1) { > + ns = NULL; > > - while((c = getopt_long(argc, argv, "hVmuin", longopts, NULL)) != -1) { > switch(c) { > case 'h': > usage(EXIT_SUCCESS); > @@ -102,25 +120,51 @@ int main(int argc, char *argv[]) > printf(UTIL_LINUX_VERSION); > return EXIT_SUCCESS; > case 'm': > - unshare_flags |= CLONE_NEWNS; > + ns = "mnt"; > + if (!optarg) > + unshare_flags |= CLONE_NEWNS; > break; > case 'u': > - unshare_flags |= CLONE_NEWUTS; > + ns = "uts"; > + if (!optarg) > + unshare_flags |= CLONE_NEWUTS; > break; > case 'i': > - unshare_flags |= CLONE_NEWIPC; > + ns = "ipc"; > + if (!optarg) > + unshare_flags |= CLONE_NEWIPC; > break; > case 'n': > - unshare_flags |= CLONE_NEWNET; > + ns = "net"; > + if (!optarg) > + unshare_flags |= CLONE_NEWNET; > break; > default: > usage(EXIT_FAILURE); > } > + > + if (optarg && ns) { > + if (nscount >= NUM_ENTRIES) > + err(EXIT_FAILURE, _("Too many new namespaces specified")); > + pid = strtoul(optarg, NULL, 10); > + if (pid == ULONG_MAX) > + err(EXIT_FAILURE, _("%s pid improperly specified"), ns); > + sprintf(path, "/proc/%d/ns/%s", (int)pid, ns); > + ns_pids[nscount] = open(path, O_RDONLY); > + if (ns_pids[nscount] < 0) > + err(EXIT_FAILURE, _("Can not migrate %s: Can't open %s"), ns, path); > + nscount++; > + } > + > } > > if(optind >= argc) > usage(EXIT_FAILURE); > > + for (nscount = 0; ns_pids[nscount] > 0; nscount++) > + if (-1 == setns(ns_pids[nscount], 0)) > + err(EXIT_FAILURE, _("setns failed")); > + > if(-1 == unshare(unshare_flags)) > err(EXIT_FAILURE, _("unshare failed")); > > -- > 1.7.11.7 > > -- To unsubscribe from this list: send the line "unsubscribe util-linux" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html