Tests for module 'logbl'.
[gnulib.git] / lib / passfd.c
index 2f84a13..188c7d1 100644 (file)
@@ -1,8 +1,8 @@
-/* Copyright (C) 2011 Free Software Foundation, Inc.
+/* Copyright (C) 2011-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
 #include <config.h>
 
 /* Specification.  */
 #include <config.h>
 
 /* Specification.  */
+#include "passfd.h"
+
 #include <errno.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include <stddef.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #include <sys/socket.h>
-#endif
-#ifdef HAVE_SYS_UN_H
-#include <sys/un.h>
-#endif
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
+
+#include "cloexec.h"
+
+/* The code that uses CMSG_FIRSTHDR is enabled on
+   Linux, MacOS 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
 
 #endif
 
-/* Sendfd sends the file descriptor fd along the socket
+#if HAVE_SENDMSG
+/* sendfd sends the file descriptor fd along the socket
    to a process calling recvfd on the other end.
    to a process calling recvfd on the other end.
-   
-   return -1 in case of error, 0 on success
+
+   Return 0 on success, or -1 with errno set in case of error.
 */
 int
 sendfd (int sock, int fd)
 {
 */
 int
 sendfd (int sock, int fd)
 {
-  char send = 0;
-  struct iovec iov[1];
+  char byte = 0;
+  struct iovec iov;
   struct msghdr msg;
   struct msghdr msg;
+# ifdef CMSG_FIRSTHDR
+  struct cmsghdr *cmsg;
+  char buf[CMSG_SPACE (sizeof fd)];
+# endif
 
   /* send at least one char */
 
   /* send at least one char */
-  iov[0].iov_base = &send;
-  iov[0].iov_len = 1;
-  msg.msg_iov = iov;
+  memset (&msg, 0, sizeof msg);
+  iov.iov_base = &byte;
+  iov.iov_len = 1;
+  msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
   msg.msg_iovlen = 1;
-  msg.msg_name = 0;
+  msg.msg_name = NULL;
   msg.msg_namelen = 0;
 
   msg.msg_namelen = 0;
 
-  {
-#ifdef HAVE_UNIXSOCKET_SCM_RIGHTS_BSD44_WAY
-    struct cmsghdr *cmsg;
-    char buf[CMSG_SPACE (sizeof (fd))];
-
-    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 (int));
-    /* Initialize the payload: */
-    memcpy (CMSG_DATA (cmsg), &fd, sizeof (fd));
-    msg.msg_controllen = cmsg->cmsg_len;
-#elif HAVE_UNIXSOCKET_SCM_RIGHTS_BSD43_WAY
-    msg.msg_accrights = &fd;
-    msg.msg_accrightslen = sizeof (fd);
-#else
-    errno = ENOSYS;
-    return -1;
-#endif
-  }
-
-  if (sendmsg (sock, &msg, 0) != iov[0].iov_len)
+# ifdef CMSG_FIRSTHDR
+  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);
+# elif HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
+  msg.msg_accrights = &fd;
+  msg.msg_accrightslen = sizeof fd;
+# else
+  errno = ENOSYS;
+  return -1;
+# endif
+
+  if (sendmsg (sock, &msg, 0) != iov.iov_len)
     return -1;
   return 0;
 }
     return -1;
   return 0;
 }
+#else
+int
+sendfd (int sock _GL_UNUSED, int fd _GL_UNUSED)
+{
+  errno = ENOSYS;
+  return -1;
+}
+#endif
 
 
-/* Sendfd sends the file descriptor fd along the socket 
-   to a process calling recvfd on the other end.
 
 
-   return -1 in case of error, fd on success
+#if HAVE_RECVMSG
+/* recvfd receives a file descriptor through the socket.
+   The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>).
+
+   Return 0 on success, or -1 with errno set in case of error.
 */
 int
 */
 int
-recvfd (int sock)
+recvfd (int sock, int flags)
 {
 {
-  char recv = 0;
-  const int mone = -1;
-  int fd;
-  struct iovec iov[1];
+  char byte = 0;
+  struct iovec iov;
   struct msghdr msg;
   struct msghdr msg;
+  int fd = -1;
+# ifdef CMSG_FIRSTHDR
+  struct cmsghdr *cmsg;
+  char buf[CMSG_SPACE (sizeof fd)];
+  int flags_recvmsg = flags & O_CLOEXEC ? MSG_CMSG_CLOEXEC : 0;
+# endif
+
+  if ((flags & ~O_CLOEXEC) != 0)
+    {
+      errno = EINVAL;
+      return -1;
+    }
 
   /* send at least one char */
 
   /* send at least one char */
-  iov[0].iov_base = &recv;
-  iov[0].iov_len = 1;
-  msg.msg_iov = iov;
+  memset (&msg, 0, sizeof msg);
+  iov.iov_base = &byte;
+  iov.iov_len = 1;
+  msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
   msg.msg_iovlen = 1;
-  msg.msg_name = 0;
+  msg.msg_name = NULL;
   msg.msg_namelen = 0;
 
   msg.msg_namelen = 0;
 
-  {
-#ifdef HAVE_UNIXSOCKET_SCM_RIGHTS_BSD44_WAY
-    struct cmsghdr *cmsg;
-    char buf[CMSG_SPACE (sizeof (fd))];
-
-    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 (int));
-    /* Initialize the payload: */
-    memcpy (CMSG_DATA (cmsg), &mone, sizeof (mone));
-    msg.msg_controllen = cmsg->cmsg_len;
-
-    if (recvmsg (sock, &msg, 0) < 0)
-      return -1;
+# ifdef CMSG_FIRSTHDR
+  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 (recvmsg (sock, &msg, flags_recvmsg) < 0)
+    return -1;
 
 
-    cmsg = CMSG_FIRSTHDR (&msg);
-    /* be paranoiac */
-    if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN (sizeof (int))
-       || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
-      {
-       /* fake errno: at end the file is not available */
-       errno = EACCES;
-       return -1;
-      }
-
-    memcpy (&fd, CMSG_DATA (cmsg), sizeof (fd));
-    return fd;
-#elif HAVE_UNIXSOCKET_SCM_RIGHTS_BSD43_WAY
-    msg.msg_accrights = &fd;
-    msg.msg_accrightslen = sizeof (fd);
-    if (recvmsg (sock, &msg, 0) < 0)
+  cmsg = CMSG_FIRSTHDR (&msg);
+  /* be paranoiac */
+  if (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 = EACCES;
       return -1;
       return -1;
-    return fd;
-#else
-    errno = ENOSYS;
+    }
+
+  memcpy (&fd, CMSG_DATA (cmsg), sizeof fd);
+
+  /* set close-on-exec flag */
+  if (!MSG_CMSG_CLOEXEC && (flags & O_CLOEXEC))
+    {
+      if (set_cloexec_flag (fd, true) < 0)
+        {
+          int saved_errno = errno;
+          (void) close (fd);
+          errno = saved_errno;
+          return -1;
+        }
+    }
+
+# elif HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
+  msg.msg_accrights = &fd;
+  msg.msg_accrightslen = sizeof fd;
+  if (recvmsg (sock, &msg, 0) < 0)
     return -1;
     return -1;
-#endif
-  }
+
+  /* set close-on-exec flag */
+  if (flags & O_CLOEXEC)
+    {
+      if (set_cloexec_flag (fd, true) < 0)
+        {
+          int saved_errno = errno;
+          close (fd);
+          errno = saved_errno;
+          return -1;
+        }
+    }
+# else
+  errno = ENOSYS;
+# endif
+
+  return fd;
 }
 }
+#else
+int
+recvfd (int sock _GL_UNUSED, int flags _GL_UNUSED)
+{
+  errno = ENOSYS;
+  return -1;
+}
+#endif