diff options
author | David Herrmann <dh.herrmann@gmail.com> | 2015-09-22 14:09:54 +0200 |
---|---|---|
committer | David Herrmann <dh.herrmann@gmail.com> | 2015-09-22 14:09:54 +0200 |
commit | d960371482d75711e61896f27ea0d3740ea69fe0 (patch) | |
tree | 6e7ffbd22d6dfb9ed71976e11999abcb93c31e9d /src/basic | |
parent | 8e112c803cb9b1ab1d564d0e5a7f06af59a2a30a (diff) |
util: introduce {send,receive}_one_fd()
Introduce two new helpers that send/receive a single fd via a unix
transport. Also make nspawn use them instead of hard-coding it.
Based on a patch by Krzesimir Nowak.
Diffstat (limited to 'src/basic')
-rw-r--r-- | src/basic/util.c | 69 | ||||
-rw-r--r-- | src/basic/util.h | 3 |
2 files changed, 72 insertions, 0 deletions
diff --git a/src/basic/util.c b/src/basic/util.c index e3b2af8e02..40d9e34f85 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -6775,3 +6775,72 @@ int fgetxattr_malloc(int fd, const char *name, char **value) { return -errno; } } + +int send_one_fd(int transport_fd, int fd) { + 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; + ssize_t k; + + assert(transport_fd >= 0); + assert(fd >= 0); + + 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), &fd, sizeof(int)); + + mh.msg_controllen = CMSG_SPACE(sizeof(int)); + k = sendmsg(transport_fd, &mh, MSG_NOSIGNAL); + if (k < 0) + return -errno; + + return 0; +} + +int receive_one_fd(int transport_fd) { + 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; + ssize_t k; + + assert(transport_fd >= 0); + + /* + * Receive a single FD via @transport_fd. We don't care for the + * transport-type, but the caller must assure that no other CMSG types + * than SCM_RIGHTS is enabled. We also retrieve a single FD at most, so + * for packet-based transports, the caller must ensure to send only a + * single FD per packet. + * This is best used in combination with send_one_fd(). + */ + + k = recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC); + if (k < 0) + return -errno; + + cmsg = CMSG_FIRSTHDR(&mh); + if (!cmsg || CMSG_NXTHDR(&mh, cmsg) || + cmsg->cmsg_level != SOL_SOCKET || + cmsg->cmsg_type != SCM_RIGHTS || + cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || + *(const int *)CMSG_DATA(cmsg) < 0) { + cmsg_close_all(&mh); + return -EIO; + } + + return *(const int *)CMSG_DATA(cmsg); +} diff --git a/src/basic/util.h b/src/basic/util.h index 8abaa740b2..905f375263 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -938,3 +938,6 @@ int reset_uid_gid(void); int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink); int fgetxattr_malloc(int fd, const char *name, char **value); + +int send_one_fd(int transport_fd, int fd); +int receive_one_fd(int transport_fd); |