From 4914fce77be7764332ca2b56a3496ea73ad2f042 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 6 Apr 2023 13:28:06 +1000 Subject: nstool: Rename nsholder to nstool In preparation for extending what it does. Signed-off-by: David Gibson Signed-off-by: Stefano Brivio --- test/nstool.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 test/nstool.c (limited to 'test/nstool.c') diff --git a/test/nstool.c b/test/nstool.c new file mode 100644 index 0000000..9d6ee0c --- /dev/null +++ b/test/nstool.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* nstool - maintain a namespace to be entered by other processes + * + * Copyright Red Hat + * Author: David Gibson + * + * Can run in 3 modes: + * + * nstool hold + * Designed to be run inside a namespace, opens a Unix domain + * control socket at and waits until instructed to stop + * with "nstool stop" + * nstool pid + * Prints the PID of the nstool hold process with control + * socket . This is given in the PID namespace where + * nstool pid is executed, not the one where nstool hold is + * running + * nstool stop + * Instruct the nstool hold with control socket at to exit. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include + +#define die(...) \ + do { \ + fprintf(stderr, __VA_ARGS__); \ + exit(1); \ + } while (0) + +static void usage(void) +{ + die("Usage: nstool hold|pid\n"); +} + +static void hold(int fd, const struct sockaddr_un *addr) +{ + int rc; + + rc = bind(fd, (struct sockaddr *)addr, sizeof(*addr)); + if (rc < 0) + die("bind(): %s\n", strerror(errno)); + + rc = listen(fd, 0); + if (rc < 0) + die("listen(): %s\n", strerror(errno)); + + printf("nstool: local PID=%d local UID=%u local GID=%u\n", + getpid(), getuid(), getgid()); + do { + int afd = accept(fd, NULL, NULL); + char buf; + + if (afd < 0) + die("accept(): %s\n", strerror(errno)); + + rc = read(afd, &buf, sizeof(buf)); + if (rc < 0) + die("read(): %s\n", strerror(errno)); + } while (rc == 0); + + unlink(addr->sun_path); +} + +static void pid(int fd, const struct sockaddr_un *addr) +{ + int rc; + struct ucred peercred; + socklen_t optlen = sizeof(peercred); + + do { + rc = connect(fd, (struct sockaddr *)addr, sizeof(*addr)); + if (rc < 0 && errno != ENOENT && errno != ECONNREFUSED) + die("connect(): %s\n", strerror(errno)); + } while (rc < 0); + + rc = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, + &peercred, &optlen); + if (rc < 0) + die("getsockopet(SO_PEERCRED): %s\n", strerror(errno)); + + close(fd); + + printf("%d\n", peercred.pid); +} + +static void stop(int fd, const struct sockaddr_un *addr) +{ + int rc; + char buf = 'Q'; + + rc = connect(fd, (struct sockaddr *)addr, sizeof(*addr)); + if (rc < 0) + die("connect(): %s\n", strerror(errno)); + + rc = write(fd, &buf, sizeof(buf)); + if (rc < 0) + die("write(): %s\n", strerror(errno)); + + close(fd); +} + +int main(int argc, char *argv[]) +{ + int fd; + const char *sockname; + struct sockaddr_un sockaddr = { + .sun_family = AF_UNIX, + }; + + if (argc != 3) + usage(); + + sockname = argv[1]; + strncpy(sockaddr.sun_path, sockname, UNIX_PATH_MAX); + + fd = socket(AF_UNIX, SOCK_STREAM, PF_UNIX); + if (fd < 0) + die("socket(): %s\n", strerror(errno)); + + if (strcmp(argv[2], "hold") == 0) + hold(fd, &sockaddr); + else if (strcmp(argv[2], "pid") == 0) + pid(fd, &sockaddr); + else if (strcmp(argv[2], "stop") == 0) + stop(fd, &sockaddr); + else + usage(); + + exit(0); +} -- cgit v1.2.3