]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
util: introduce {send,receive}_one_fd()
authorDavid Herrmann <dh.herrmann@gmail.com>
Tue, 22 Sep 2015 12:09:54 +0000 (14:09 +0200)
committerDavid Herrmann <dh.herrmann@gmail.com>
Tue, 22 Sep 2015 12:09:54 +0000 (14:09 +0200)
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.

src/basic/util.c
src/basic/util.h
src/nspawn/nspawn-expose-ports.c
src/nspawn/nspawn.c

index e3b2af8e02f849b8d789535de48aebaa6ba03b96..40d9e34f855a7d3078bf52dfaee5c97ca743d631 100644 (file)
@@ -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);
+}
index 8abaa740b22d32048a081dc56080a812f7d7d7a5..905f3752636cfa352c525a5cf20752d883f32435 100644 (file)
@@ -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);
index 38250b6e02367a99d8e2e63cc0dcbff0ce9b93c9..9e63d88b69b24ad51b214834135533243076d13b 100644 (file)
@@ -183,17 +183,8 @@ int expose_port_execute(sd_netlink *rtnl, ExposePort *l, union in_addr_union *ex
 }
 
 int expose_port_send_rtnl(int send_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;
         _cleanup_close_ int fd = -1;
-        ssize_t k;
+        int r;
 
         assert(send_fd >= 0);
 
@@ -201,19 +192,11 @@ int expose_port_send_rtnl(int send_fd) {
         if (fd < 0)
                 return log_error_errno(errno, "Failed to allocate container netlink: %m");
 
-        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->cmsg_len;
-
         /* Store away the fd in the socket, so that it stays open as
          * long as we run the child */
-        k = sendmsg(send_fd, &mh, MSG_NOSIGNAL);
-        if (k < 0)
-                return log_error_errno(errno, "Failed to send netlink fd: %m");
+        r = send_one_fd(send_fd, fd);
+        if (r < 0)
+                return log_error_errno(r, "Failed to send netlink fd: %m");
 
         return 0;
 }
@@ -224,33 +207,16 @@ int expose_port_watch_rtnl(
                 sd_netlink_message_handler_t handler,
                 union in_addr_union *exposed,
                 sd_netlink **ret) {
-
-        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;
         _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
         int fd, r;
-        ssize_t k;
 
         assert(event);
         assert(recv_fd >= 0);
         assert(ret);
 
-        k = recvmsg(recv_fd, &mh, MSG_NOSIGNAL);
-        if (k < 0)
-                return log_error_errno(errno, "Failed to recv netlink fd: %m");
-
-        cmsg = CMSG_FIRSTHDR(&mh);
-        assert(cmsg->cmsg_level == SOL_SOCKET);
-        assert(cmsg->cmsg_type == SCM_RIGHTS);
-        assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int)));
-        memcpy(&fd, CMSG_DATA(cmsg), sizeof(int));
+        fd = receive_one_fd(recv_fd);
+        if (fd < 0)
+                return log_error_errno(fd, "Failed to recv netlink fd: %m");
 
         r = sd_netlink_open_fd(&rtnl, fd);
         if (r < 0) {
index 5702df8ab47c6716ae83afb461803038eec91f3d..955490b752b637ffb4ded187fecfbc8afe466c36 100644 (file)
@@ -1264,16 +1264,7 @@ static int setup_dev_console(const char *dest, const char *console) {
 static int setup_kmsg(const char *dest, int kmsg_socket) {
         const char *from, *to;
         _cleanup_umask_ mode_t u;
-        int fd, k;
-        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;
+        int fd, r;
 
         assert(kmsg_socket >= 0);
 
@@ -1298,21 +1289,13 @@ static int setup_kmsg(const char *dest, int kmsg_socket) {
         if (fd < 0)
                 return log_error_errno(errno, "Failed to open fifo: %m");
 
-        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->cmsg_len;
-
         /* Store away the fd in the socket, so that it stays open as
          * long as we run the child */
-        k = sendmsg(kmsg_socket, &mh, MSG_NOSIGNAL);
+        r = send_one_fd(kmsg_socket, fd);
         safe_close(fd);
 
-        if (k < 0)
-                return log_error_errno(errno, "Failed to send FIFO fd: %m");
+        if (r < 0)
+                return log_error_errno(r, "Failed to send FIFO fd: %m");
 
         /* And now make the FIFO unavailable as /run/kmsg... */
         (void) unlink(from);