This is a simplified variant of gnulib's passfd module
without the portability code that we do not require.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
---
src/libvirt_private.syms | 5 ++
src/qemu/qemu_interface.c | 4 +-
src/rpc/virnetsocket.c | 5 +-
src/util/virfile.c | 5 +-
src/util/virsocket.c | 142 +++++++++++++++++++++++++++++++++++++-
src/util/virsocket.h | 3 +
6 files changed, 154 insertions(+), 10 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index fa046051a3..4fe93e785c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -3004,6 +3004,11 @@ virSecretLookupFormatSecret;
virSecretLookupParseSecret;
+# util/virsocket.h
+virSocketRecvFD;
+virSocketSendFD;
+
+
# util/virsocketaddr.h
virSocketAddrBroadcast;
virSocketAddrBroadcastByPrefix;
diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c
index bb62b53c04..48bb0043fe 100644
--- a/src/qemu/qemu_interface.c
+++ b/src/qemu/qemu_interface.c
@@ -25,7 +25,6 @@
#include "domain_audit.h"
#include "domain_nwfilter.h"
#include "qemu_interface.h"
-#include "passfd.h"
#include "viralloc.h"
#include "virlog.h"
#include "virstring.h"
@@ -34,6 +33,7 @@
#include "virnetdevmacvlan.h"
#include "virnetdevbridge.h"
#include "virnetdevvportprofile.h"
+#include "virsocket.h"
#include <sys/stat.h>
#include <fcntl.h>
@@ -347,7 +347,7 @@ qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg,
}
do {
- *tapfd = recvfd(pair[0], 0);
+ *tapfd = virSocketRecvFD(pair[0], 0);
} while (*tapfd < 0 && errno == EINTR);
if (*tapfd < 0) {
diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c
index 973827ebde..687099720f 100644
--- a/src/rpc/virnetsocket.c
+++ b/src/rpc/virnetsocket.c
@@ -56,7 +56,6 @@
#include "virprobe.h"
#include "virprocess.h"
#include "virstring.h"
-#include "passfd.h"
#if WITH_SSH2
# include "virnetsshsession.h"
@@ -2045,7 +2044,7 @@ int virNetSocketSendFD(virNetSocketPtr sock, int fd)
virObjectLock(sock);
PROBE(RPC_SOCKET_SEND_FD,
"sock=%p fd=%d", sock, fd);
- if (sendfd(sock->fd, fd) < 0) {
+ if (virSocketSendFD(sock->fd, fd) < 0) {
if (errno == EAGAIN)
ret = 0;
else
@@ -2078,7 +2077,7 @@ int virNetSocketRecvFD(virNetSocketPtr sock, int *fd)
}
virObjectLock(sock);
- if ((*fd = recvfd(sock->fd, O_CLOEXEC)) < 0) {
+ if ((*fd = virSocketRecvFD(sock->fd, O_CLOEXEC)) < 0) {
if (errno == EAGAIN)
ret = 0;
else
diff --git a/src/util/virfile.c b/src/util/virfile.c
index b3a63fa2ea..51a0d40b50 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -25,7 +25,6 @@
#include <config.h>
#include "internal.h"
-#include <passfd.h>
#include <fcntl.h>
#ifndef WIN32
# include <termios.h>
@@ -2268,7 +2267,7 @@ virFileOpenForked(const char *path, int openflags, mode_t mode,
}
do {
- ret = sendfd(pair[1], fd);
+ ret = virSocketSendFD(pair[1], fd);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
@@ -2302,7 +2301,7 @@ virFileOpenForked(const char *path, int openflags, mode_t mode,
VIR_FORCE_CLOSE(pair[1]);
do {
- fd = recvfd(pair[0], 0);
+ fd = virSocketRecvFD(pair[0], 0);
} while (fd < 0 && errno == EINTR);
VIR_FORCE_CLOSE(pair[0]); /* NB: this preserves errno */
if (fd < 0)
diff --git a/src/util/virsocket.c b/src/util/virsocket.c
index 96b9ece2b7..0e3775ac44 100644
--- a/src/util/virsocket.c
+++ b/src/util/virsocket.c
@@ -19,10 +19,12 @@
#include <config.h>
#include "virsocket.h"
+#include "virutil.h"
+#include "virfile.h"
-#ifdef WIN32
+#include <fcntl.h>
-# include <fcntl.h>
+#ifdef WIN32
# define FD2SK(fd) _get_osfhandle(fd)
# define SK2FD(sk) (_open_osfhandle((intptr_t) (sk), O_RDWR | O_BINARY))
@@ -365,3 +367,139 @@ vir_socket(int domain, int type, int protocol)
}
#endif /* WIN32 */
+
+/* The code that uses CMSG_FIRSTHDR is enabled on
+ Linux, Mac OS X, FreeBSD, OpenBSD, NetBSD, AIX, OSF/1, Cygwin.
+ The code that uses HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS is enabled on
+ HP-UX, IRIX, Solaris. */
+
+/* MSG_CMSG_CLOEXEC is defined only on Linux, as of 2011. */
+#ifndef MSG_CMSG_CLOEXEC
+# define MSG_CMSG_CLOEXEC 0
+#endif
+
+#ifndef WIN32
+/* virSocketSendFD sends the file descriptor fd along the socket
+ to a process calling recvfd on the other end.
+
+ Return 0 on success, or -1 with errno set in case of error.
+*/
+int
+virSocketSendFD(int sock, int fd)
+{
+ char byte = 0;
+ struct iovec iov;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ char buf[CMSG_SPACE(sizeof(fd))];
+
+ /* send at least one char */
+ memset(&msg, 0, sizeof(msg));
+ iov.iov_base = &byte;
+ iov.iov_len = 1;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+
+ msg.msg_control = buf;
+ msg.msg_controllen = sizeof(buf);
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+ /* Initialize the payload: */
+ memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
+ msg.msg_controllen = cmsg->cmsg_len;
+
+ if (sendmsg(sock, &msg, 0) != iov.iov_len)
+ return -1;
+ return 0;
+}
+#else
+int
+virSocketSendFD(int sock G_GNUC_UNUSED, int fd G_GNUC_UNUSED)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+
+#ifndef WIN32
+/* virSocketRecvFD receives a file descriptor through the socket.
+ The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>).
+
+ Return the fd on success, or -1 with errno set in case of error.
+*/
+int
+virSocketRecvFD(int sock, int fdflags)
+{
+ char byte = 0;
+ struct iovec iov;
+ struct msghdr msg;
+ int fd = -1;
+ ssize_t len;
+ struct cmsghdr *cmsg;
+ char buf[CMSG_SPACE(sizeof(fd))];
+ int fdflags_recvmsg = fdflags & O_CLOEXEC ? MSG_CMSG_CLOEXEC : 0;
+
+ if ((fdflags & ~O_CLOEXEC) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* send at least one char */
+ memset(&msg, 0, sizeof(msg));
+ iov.iov_base = &byte;
+ iov.iov_len = 1;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+
+ msg.msg_control = buf;
+ msg.msg_controllen = sizeof(buf);
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+ /* Initialize the payload: */
+ memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
+ msg.msg_controllen = cmsg->cmsg_len;
+
+ len = recvmsg(sock, &msg, fdflags_recvmsg);
+ if (len < 0)
+ return -1;
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ /* be paranoiac */
+ if (len == 0 || cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(sizeof(fd))
+ || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
+ /* fake errno: at end the file is not available */
+ errno = len ? EACCES : ENOTCONN;
+ return -1;
+ }
+
+ memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd));
+
+ /* set close-on-exec flag */
+ if (!MSG_CMSG_CLOEXEC && (fdflags & O_CLOEXEC)) {
+ if (virSetCloseExec(fd) < 0) {
+ int saved_errno = errno;
+ VIR_FORCE_CLOSE(fd);
+ errno = saved_errno;
+ return -1;
+ }
+ }
+
+ return fd;
+}
+#else
+int
+virSocketRecvFD(int sock G_GNUC_UNUSED, int fdflags G_GNUC_UNUSED)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
diff --git a/src/util/virsocket.h b/src/util/virsocket.h
index 33f237886f..e1e7d08bb4 100644
--- a/src/util/virsocket.h
+++ b/src/util/virsocket.h
@@ -20,6 +20,9 @@
#include "internal.h"
+int virSocketSendFD(int sock, int fd);
+int virSocketRecvFD(int sock, int fdflags);
+
#ifdef WIN32
# define WIN32_LEAN_AND_MEAN
--
2.24.1