• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2012 Collabora, Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 #define _GNU_SOURCE
27 
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 #include <sys/epoll.h>
34 
35 #include "../config.h"
36 #include "wayland-os.h"
37 
38 static int
set_cloexec_or_close(int fd)39 set_cloexec_or_close(int fd)
40 {
41 	long flags;
42 
43 	if (fd == -1)
44 		return -1;
45 
46 	flags = fcntl(fd, F_GETFD);
47 	if (flags == -1)
48 		goto err;
49 
50 	if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
51 		goto err;
52 
53 	return fd;
54 
55 err:
56 	close(fd);
57 	return -1;
58 }
59 
60 int
wl_os_socket_cloexec(int domain,int type,int protocol)61 wl_os_socket_cloexec(int domain, int type, int protocol)
62 {
63 	int fd;
64 
65 	fd = socket(domain, type | SOCK_CLOEXEC, protocol);
66 	if (fd >= 0)
67 		return fd;
68 	if (errno != EINVAL)
69 		return -1;
70 
71 	fd = socket(domain, type, protocol);
72 	return set_cloexec_or_close(fd);
73 }
74 
75 int
wl_os_dupfd_cloexec(int fd,long minfd)76 wl_os_dupfd_cloexec(int fd, long minfd)
77 {
78 	int newfd;
79 
80 	newfd = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
81 	if (newfd >= 0)
82 		return newfd;
83 	if (errno != EINVAL)
84 		return -1;
85 
86 	newfd = fcntl(fd, F_DUPFD, minfd);
87 	return set_cloexec_or_close(newfd);
88 }
89 
90 static ssize_t
recvmsg_cloexec_fallback(int sockfd,struct msghdr * msg,int flags)91 recvmsg_cloexec_fallback(int sockfd, struct msghdr *msg, int flags)
92 {
93 	ssize_t len;
94 	struct cmsghdr *cmsg;
95 	unsigned char *data;
96 	int *fd;
97 	int *end;
98 
99 	len = recvmsg(sockfd, msg, flags);
100 	if (len == -1)
101 		return -1;
102 
103 	if (!msg->msg_control || msg->msg_controllen == 0)
104 		return len;
105 
106 	cmsg = CMSG_FIRSTHDR(msg);
107 	for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
108 		if (cmsg->cmsg_level != SOL_SOCKET ||
109 		    cmsg->cmsg_type != SCM_RIGHTS)
110 			continue;
111 
112 		data = CMSG_DATA(cmsg);
113 		end = (int *)(data + cmsg->cmsg_len - CMSG_LEN(0));
114 		for (fd = (int *)data; fd < end; ++fd)
115 			*fd = set_cloexec_or_close(*fd);
116 	}
117 
118 	return len;
119 }
120 
121 ssize_t
wl_os_recvmsg_cloexec(int sockfd,struct msghdr * msg,int flags)122 wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags)
123 {
124 	ssize_t len;
125 
126 	len = recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC);
127 	if (len >= 0)
128 		return len;
129 	if (errno != EINVAL)
130 		return -1;
131 
132 	return recvmsg_cloexec_fallback(sockfd, msg, flags);
133 }
134 
135 int
wl_os_epoll_create_cloexec(void)136 wl_os_epoll_create_cloexec(void)
137 {
138 	int fd;
139 
140 #ifdef EPOLL_CLOEXEC
141 	fd = epoll_create1(EPOLL_CLOEXEC);
142 	if (fd >= 0)
143 		return fd;
144 	if (errno != EINVAL)
145 		return -1;
146 #endif
147 
148 	fd = epoll_create(1);
149 	return set_cloexec_or_close(fd);
150 }
151 
152 int
wl_os_accept_cloexec(int sockfd,struct sockaddr * addr,socklen_t * addrlen)153 wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
154 {
155 	int fd;
156 
157 #ifdef HAVE_ACCEPT4
158 	fd = accept4(sockfd, addr, addrlen, SOCK_CLOEXEC);
159 	if (fd >= 0)
160 		return fd;
161 	if (errno != ENOSYS)
162 		return -1;
163 #endif
164 
165 	fd = accept(sockfd, addr, addrlen);
166 	return set_cloexec_or_close(fd);
167 }
168