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);
+}
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);
}
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);
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;
}
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) {
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);
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);