passfd: speed up configure and drop unused code
[gnulib.git] / lib / passfd.c
1 /* Copyright (C) 2011 Free Software Foundation, Inc.
2
3    This program is free software: you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 3 of the License, or
6    (at your option) any later version.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12
13    You should have received a copy of the GNU General Public License
14    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
15
16 #include <config.h>
17
18 /* Specification.  */
19 #include "passfd.h"
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stddef.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28
29 #include <sys/socket.h>
30
31 #include "cloexec.h"
32
33 #ifndef MSG_CMSG_CLOEXEC
34 # define MSG_CMSG_CLOEXEC 0
35 #endif
36
37 #if HAVE_SENDMSG
38 /* sendfd sends the file descriptor fd along the socket
39    to a process calling recvfd on the other end.
40
41    Return 0 on success, or -1 with errno set in case of error.
42 */
43 int
44 sendfd (int sock, int fd)
45 {
46   char send = 0;
47   struct iovec iov;
48   struct msghdr msg;
49 # ifdef CMSG_FIRSTHDR
50   struct cmsghdr *cmsg;
51   char buf[CMSG_SPACE (sizeof fd)];
52 # endif
53
54   /* send at least one char */
55   memset (&msg, 0, sizeof msg);
56   iov.iov_base = &send;
57   iov.iov_len = 1;
58   msg.msg_iov = &iov;
59   msg.msg_iovlen = 1;
60   msg.msg_name = NULL;
61   msg.msg_namelen = 0;
62
63 # ifdef CMSG_FIRSTHDR
64   msg.msg_control = buf;
65   msg.msg_controllen = sizeof buf;
66   cmsg = CMSG_FIRSTHDR (&msg);
67   cmsg->cmsg_level = SOL_SOCKET;
68   cmsg->cmsg_type = SCM_RIGHTS;
69   cmsg->cmsg_len = CMSG_LEN (sizeof fd);
70   /* Initialize the payload: */
71   memcpy (CMSG_DATA (cmsg), &fd, sizeof fd);
72 # elif HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
73   msg.msg_accrights = &fd;
74   msg.msg_accrightslen = sizeof fd;
75 # else
76   errno = ENOSYS;
77   return -1;
78 # endif
79
80   if (sendmsg (sock, &msg, 0) != iov.iov_len)
81     return -1;
82   return 0;
83 }
84 #else
85 int
86 sendfd (int sock _GL_UNUSED, int fd _GL_UNUSED)
87 {
88   errno = ENOSYS;
89   return -1;
90 }
91 #endif
92
93
94 #if HAVE_RECVMSG
95 /* recvfd receives a file descriptor through the socket.
96    The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>).
97
98    Return 0 on success, or -1 with errno set in case of error.
99 */
100 int
101 recvfd (int sock, int flags)
102 {
103   char recv = 0;
104   struct iovec iov;
105   struct msghdr msg;
106   int fd = -1;
107 # ifdef CMSG_FIRSTHDR
108   struct cmsghdr *cmsg;
109   char buf[CMSG_SPACE (sizeof fd)];
110   int flags_recvmsg = flags & O_CLOEXEC ? MSG_CMSG_CLOEXEC : 0;
111 # endif
112
113   if ((flags & ~O_CLOEXEC) != 0)
114     {
115       errno = EINVAL;
116       return -1;
117     }
118
119   /* send at least one char */
120   memset (&msg, 0, sizeof msg);
121   iov.iov_base = &recv;
122   iov.iov_len = 1;
123   msg.msg_iov = &iov;
124   msg.msg_iovlen = 1;
125   msg.msg_name = NULL;
126   msg.msg_namelen = 0;
127
128 # ifdef CMSG_FIRSTHDR
129   msg.msg_control = buf;
130   msg.msg_controllen = sizeof buf;
131   cmsg = CMSG_FIRSTHDR (&msg);
132   cmsg->cmsg_level = SOL_SOCKET;
133   cmsg->cmsg_type = SCM_RIGHTS;
134   cmsg->cmsg_len = CMSG_LEN (sizeof fd);
135   /* Initialize the payload: */
136   memcpy (CMSG_DATA (cmsg), &fd, sizeof fd);
137   msg.msg_controllen = cmsg->cmsg_len;
138
139   if (recvmsg (sock, &msg, flags_recvmsg) < 0)
140     return -1;
141
142   cmsg = CMSG_FIRSTHDR (&msg);
143   /* be paranoiac */
144   if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN (sizeof fd)
145       || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
146     {
147       /* fake errno: at end the file is not available */
148       errno = EACCES;
149       return -1;
150     }
151
152   memcpy (&fd, CMSG_DATA (cmsg), sizeof fd);
153
154   /* set close-on-exec flag */
155   if (!MSG_CMSG_CLOEXEC && (flags & O_CLOEXEC))
156     {
157       if (set_cloexec_flag (fd, true) < 0)
158         {
159           int saved_errno = errno;
160           (void) close (fd);
161           errno = saved_errno;
162           return -1;
163         }
164     }
165
166 # elif HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
167   msg.msg_accrights = &fd;
168   msg.msg_accrightslen = sizeof fd;
169   if (recvmsg (sock, &msg, 0) < 0)
170     return -1;
171
172   /* set close-on-exec flag */
173   if (flags & O_CLOEXEC)
174     {
175       if (set_cloexec_flag (fd, true) < 0)
176         {
177           int saved_errno = errno;
178           close (fd);
179           errno = saved_errno;
180           return -1;
181         }
182     }
183 # else
184   errno = ENOSYS;
185 # endif
186
187   return fd;
188 }
189 #else
190 int
191 recvfd (int sock _GL_UNUSED, int flags _GL_UNUSED)
192 {
193   errno = ENOSYS;
194   return -1;
195 }
196 #endif