diff options
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/util.c | 86 | ||||
-rw-r--r-- | src/shared/util.h | 2 |
2 files changed, 88 insertions, 0 deletions
diff --git a/src/shared/util.c b/src/shared/util.c index 6bd278e790..97ff320bc8 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -7473,3 +7473,89 @@ int ptsname_malloc(int fd, char **ret) { l *= 2; } } + +int openpt_in_namespace(pid_t pid, int flags) { + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1; + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control = {}; + struct msghdr mh = { + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg; + siginfo_t si; + pid_t child; + int r; + + assert(pid > 0); + + r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd); + if (r < 0) + return r; + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) + return -errno; + + child = fork(); + if (child < 0) + return -errno; + + if (child == 0) { + int master; + + pair[0] = safe_close(pair[0]); + + r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd); + if (r < 0) + _exit(EXIT_FAILURE); + + master = posix_openpt(flags); + if (master < 0) + _exit(EXIT_FAILURE); + + cmsg = CMSG_FIRSTHDR(&mh); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsg), &master, sizeof(int)); + + mh.msg_controllen = cmsg->cmsg_len; + + if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + pair[1] = safe_close(pair[1]); + + r = wait_for_terminate(child, &si); + if (r < 0) + return r; + if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) + return -EIO; + + if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0) + return -errno; + + for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + int *fds; + unsigned n_fds; + + fds = (int*) CMSG_DATA(cmsg); + n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + + if (n_fds != 1) { + close_many(fds, n_fds); + return -EIO; + } + + return fds[0]; + } + + return -EIO; +} diff --git a/src/shared/util.h b/src/shared/util.h index d3e78e43ca..ec0a6639ca 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -1054,3 +1054,5 @@ int sethostname_idempotent(const char *s); #define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW) int ptsname_malloc(int fd, char **ret); + +int openpt_in_namespace(pid_t pid, int flags); |