Usually we need to set O_CLOEXEC, which is platform-specific. Add a
wrapper like qemu_open() but for qemu_recvmsg().
Signed-off-by: Stefan Hajnoczi <stefanha(a)linux.vnet.ibm.com>
---
block.c | 5 +----
osdep.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
qemu-common.h | 2 ++
3 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/block.c b/block.c
index d3bf443..e66d64f 100644
--- a/block.c
+++ b/block.c
@@ -176,10 +176,7 @@ int file_open(const char *filename, int flags, mode_t mode)
msg.msg_control = &msg_control;
msg.msg_controllen = sizeof(msg_control);
- do {
- ret = recvmsg(remote_file_fd, &msg, 0);
- } while (ret == -1 && errno == EINTR);
- if (ret != sizeof(OpenResponse)) {
+ if (qemu_recvmsg(remote_file_fd, &msg, 0) != sizeof(OpenResponse)) {
errno = EPIPE;
return -1;
}
diff --git a/osdep.c b/osdep.c
index 3e6bada..834e78f 100644
--- a/osdep.c
+++ b/osdep.c
@@ -103,6 +103,52 @@ int qemu_open(const char *name, int flags, ...)
}
/*
+ * Receive a message from a socket
+ *
+ * This behaves like recvmsg(2) except that EINTR is handled internally and
+ * never returned. Passed file descriptors will have O_CLOEXEC set.
+ */
+ssize_t qemu_recvmsg(int fd, struct msghdr *msg, int flags)
+{
+ ssize_t ret;
+
+#ifdef MSG_CMSG_CLOEXEC
+ /* Receive file descriptors with O_CLOEXEC */
+ flags |= MSG_CMSG_CLOEXEC;
+#endif
+
+ do {
+ ret = recvmsg(fd, msg, flags);
+ } while (ret == -1 && errno == EINTR);
+ if (ret < 0) {
+ return ret;
+ }
+
+#ifndef MSG_CMSG_CLOEXEC
+ /* As a fallback, set O_CLOEXEC in a way that is not thread-safe */
+ {
+ struct cmsghdr *cmsg;
+ for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+ int new_fd;
+
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
+ cmsg->cmsg_level != SOL_SOCKET ||
+ cmsg->cmsg_type != SCM_RIGHTS) {
+ continue;
+ }
+
+ new_fd = *((int *)CMSG_DATA(cmsg));
+ if (new_fd >= 0) {
+ qemu_set_cloexec(new_fd);
+ }
+ }
+ }
+#endif
+
+ return ret;
+}
+
+/*
* A variant of write(2) which handles partial write.
*
* Return the number of bytes transferred.
diff --git a/qemu-common.h b/qemu-common.h
index 50f659a..e3a6c4d 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -184,6 +184,8 @@ const char *path(const char *pathname);
void *qemu_oom_check(void *ptr);
int qemu_open(const char *name, int flags, ...);
+struct msghdr;
+ssize_t qemu_recvmsg(int fd, struct msghdr *msg, int flags);
ssize_t qemu_write_full(int fd, const void *buf, size_t count)
QEMU_WARN_UNUSED_RESULT;
ssize_t qemu_send_full(int fd, const void *buf, size_t count, int flags)
--
1.7.10