On Tue, 4 Apr 2023 11:46:33 +1000
David Gibson <david(a)gibson.dropbear.id.au> wrote:
This combines nstool info -pw <sock> with
nsenter with various options for
a more convenient and less verbose of entering existing nstool managed
namespaces.
Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au>
---
test/nstool.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 137 insertions(+), 2 deletions(-)
diff --git a/test/nstool.c b/test/nstool.c
index 5681ce8..25079aa 100644
--- a/test/nstool.c
+++ b/test/nstool.c
@@ -17,7 +17,9 @@
#include <unistd.h>
#include <getopt.h>
#include <stdarg.h>
+#include <fcntl.h>
#include <sys/socket.h>
+#include <sys/wait.h>
#include <linux/un.h>
#include <linux/limits.h>
#include <sched.h>
@@ -75,6 +77,9 @@ static void usage(void)
" socket at SOCK\n"
" -p Print just the holder's PID as seen by the caller\n"
" -w Retry connecting to SOCK until it is ready\n"
+ " nstool exec SOCK [COMMAND [ARGS...]]\n"
+ " Execute command or shell in the namespaces of the nstool hold\n"
+ " with control socket at SOCK\n"
" nstool stop SOCK\n"
" Instruct the nstool hold with control socket at SOCK to\n"
" terminate.\n");
@@ -84,7 +89,7 @@ static int connect_ctl(const char *sockpath, bool wait,
struct holder_info *info,
struct ucred *peercred)
{
- int fd = socket(AF_UNIX, SOCK_STREAM, PF_UNIX);
+ int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, PF_UNIX);
struct sockaddr_un addr = {
.sun_family = AF_UNIX,
};
@@ -132,7 +137,7 @@ static int connect_ctl(const char *sockpath, bool wait,
static void cmd_hold(int argc, char *argv[])
{
- int fd = socket(AF_UNIX, SOCK_STREAM, PF_UNIX);
+ int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, PF_UNIX);
struct sockaddr_un addr = {
.sun_family = AF_UNIX,
};
@@ -301,6 +306,134 @@ static void cmd_info(int argc, char *argv[])
}
}
+static int openns(const char *fmt, ...)
+{
+ char nspath[PATH_MAX];
+ va_list ap;
+ int fd;
+
+ va_start(ap, fmt);
+ if (vsnprintf(nspath, sizeof(nspath), fmt, ap) >= PATH_MAX)
+ die("Truncated path \"%s\"\n", nspath);
+ va_end(ap);
+
+ fd = open(nspath, O_RDONLY | O_CLOEXEC);
+ if (fd < 0)
+ die("open() %s: %s\n", nspath, strerror(errno));
+
+ return fd;
+}
+
+static void wait_for_child(pid_t pid)
+{
+ int status;
+
+ /* Match the child's exit status, if possible */
+ for (;;) {
+ pid_t rc;
+
+ rc = waitpid(pid, &status, WUNTRACED);
+ if (rc < 0)
+ die("waitpid() on %d: %s\n", pid, strerror(errno));
+ if (rc != pid)
+ die("waitpid() on %d returned %d", pid, rc);
+ if (WIFSTOPPED(status)) {
+ /* Stop the parent to patch */
+ kill(getpid(), SIGSTOP);
+ /* We must have resumed, resume the child */
+ kill(pid, SIGCONT);
+ continue;
+ }
+
+ break;
+ }
+
+ if (WIFEXITED(status))
+ exit(WEXITSTATUS(status));
+ else if (WIFSIGNALED(status))
+ kill(getpid(), WTERMSIG(status));
An alternative could be what pasta_child_handler() does on
WIFSIGNALED(status) -- I don't actually have a preference between the
two.
Right. The idiom above I copied from unshare and nsenter in
util-linux. Seems marginally more thorough than the 128+ trick.
+
+ die("Unexpected status for child %d\n", pid);
Weird indentation in this function.
Ugh, yes. I think I did a copy paste at some point that introduced a
bunch of spaces where there should be tabs. Fixing.
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!