[Toybox] [PATCH] nsenter: A tool to use setns(2)
Rob Landley
rob at landley.net
Sun Oct 19 14:48:56 PDT 2014
I imported the first one, but applied the second as a patch because new
commands go in the "pending" directory so I don't lose track of what
I've fully reviewed yet.
On 10/17/14 22:01, Andy Lutomirski wrote:
> nsenter: A tool to use setns(2)
I don't have this command on my host system, and it's not even in the
python "install this package if you want this command" thing.
> This implements all of the namespace parts of nsenter, but UID and GID
> switching are missing, as are -r and -w (both because they're not strictly
> necessary and because the nsenter manpage has an insufficient
> description of how they work).
>
> diff -r 5330d3f88fa3 -r 5520248c82b2 toys/other/nsenter.c
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/toys/other/nsenter.c Fri Oct 17 20:00:58 2014 -0700
> @@ -0,0 +1,104 @@
> +/* nsenter.c - Enter existing namespaces
> + *
> + * Copyright 2014 andy Lutomirski <luto at 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))
All the ";" characters mean you can only supply the option to a longopt
with =, as in "--ipc=abc" but "--ipc abc" are considered two separate
arguments (as in "--ipc= abc").
(Because ls --color works that way. Because gnu, apparently.)
I'm guessing this is _not_ the behavior you want? I don't even remember
what I made the short options do in that case, I designed it to apply to
a bare longopt that needed it.
> +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
Lower case above, capital here.
> + -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.
> +*/
Lower case again. and I note that the lib/args.c option parsing
infrastructure isn't really designed to work that way. (I can probably
extend it, just... What command are you copying the behavior of?)
> +#define FOR_nsenter
> +#define _GNU_SOURCE
I never do that. This is not a GNU project, it's a Linux project. (If
anything it stands in opposition to gnu.)
The headers have #define _ALL_SOURCE for musl, for the rest I do fixups
in portabilty.h as necessary (and include linux/*.h headers from the
local command, since that doesn't belong in the global headers either).
> +#include "toys.h"
> +#include <errno.h>
> +#include <sched.h>
> +#include <linux/sched.h>
I note toys.h already includes errno.h and sched.h in the standard
headers, and I already did the sched.h namespace dance for this stuff in
unshare.c. I'll probably put this command in that file so they can share
the infrastructure.
> +#define NUM_NSTYPES 6
We have an ARRAY_LEN() macro.
> +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"},
> +};
If you leave the array's [] empty it'll automatically allocate space for
the number of entries you provide, and then you can ARRAY_LEN to see the
length.
That said, if unhare already has an array of these symbols we can reuse
that and then ahve the names just be a "user\0uts\0pid\0net\0mnt\ipc"
string.
Also, I try not to define global data outside the GLOBALS block. If it
needs to be initialized, I do that in the function's main(). (There are
times when having static global data is sufficiently cheaper to be worth
it, but it's not my first choice. Finding a way to avoid needing it is
my first choice.)
(P.S. I can do this cleanup, just explaining conceptually how I'd
simplify it.)
> +GLOBALS(
> + char *nsnames[6];
> + long targetpid;
> +)
You have a macro above, and a hardwired 6 here. (I know the macro
doesn't apply to globals, but if you're willing to hardwire 6 here
having the macro at all is not a net win.)
> +static void enter_by_name(int idx)
> +{
This function has exactly one caller, and can be inlined at that
callsite. Doing so often reveals opportunities for further simplification.
> + int fd, rc;
> + char buf[64];
We have "toybuf", a static 4k global char array, available to all
commands. (And there's another one "libbuf" for library code.)
> + char *filename = TT.nsnames[idx];
> +
> + if (!(toys.optflags & (1<<idx))) return;
> +
> + if (!filename || !*filename) {
Ok, I'll bite: where did TT.nsnames[] get set to anything other than
NULL, so that filename would not be NULL here? (The GLOBALS block starts
zeroed.)
Sorry to trail off halfway through, I have to go run an errand before a
place closes...
Rob
1413755336.0
More information about the Toybox
mailing list