1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2001 Wayne Boyer International Business Machines
4f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2002-2022
5f08c3bdfSopenharmony_ci * Copyright (c) 2023 Wei Gao <wegao@suse.com>
6f08c3bdfSopenharmony_ci */
7f08c3bdfSopenharmony_ci
8f08c3bdfSopenharmony_ci/*\
9f08c3bdfSopenharmony_ci * [Description]
10f08c3bdfSopenharmony_ci *
11f08c3bdfSopenharmony_ci * Verify that recvmsg() returns the proper errno for various failure cases.
12f08c3bdfSopenharmony_ci */
13f08c3bdfSopenharmony_ci
14f08c3bdfSopenharmony_ci#include <stdio.h>
15f08c3bdfSopenharmony_ci#include <stdlib.h>
16f08c3bdfSopenharmony_ci#include <sys/wait.h>
17f08c3bdfSopenharmony_ci#include "tst_test.h"
18f08c3bdfSopenharmony_ci
19f08c3bdfSopenharmony_ci#define MSG "from recvmsg01 server"
20f08c3bdfSopenharmony_ci#define BUF_SIZE 1024
21f08c3bdfSopenharmony_ci#define CONTROL_LEN (128 * 1024)
22f08c3bdfSopenharmony_ci
23f08c3bdfSopenharmony_cistatic char recv_buf[BUF_SIZE], cbuf[BUF_SIZE];
24f08c3bdfSopenharmony_cistatic int sock;
25f08c3bdfSopenharmony_cistatic struct sockaddr_in sin1, from;
26f08c3bdfSopenharmony_cistatic struct sockaddr_un sun1;
27f08c3bdfSopenharmony_cistatic struct msghdr msgdat;
28f08c3bdfSopenharmony_cistatic struct cmsghdr *control;
29f08c3bdfSopenharmony_cistatic int controllen;
30f08c3bdfSopenharmony_cistatic struct iovec iov[1];
31f08c3bdfSopenharmony_cistatic int sfd;			/* shared between do_child and start_server */
32f08c3bdfSopenharmony_cistatic int ufd;			/* shared between do_child and start_server */
33f08c3bdfSopenharmony_cistatic pid_t pid;
34f08c3bdfSopenharmony_cistatic char tmpsunpath[BUF_SIZE];
35f08c3bdfSopenharmony_ci
36f08c3bdfSopenharmony_cistatic void setup_all(void);
37f08c3bdfSopenharmony_cistatic void setup_invalid_sock(int);
38f08c3bdfSopenharmony_cistatic void setup_valid_sock(int);
39f08c3bdfSopenharmony_cistatic void setup_valid_msg_control(int);
40f08c3bdfSopenharmony_cistatic void setup_large_msg_control(int);
41f08c3bdfSopenharmony_cistatic void cleanup_all(void);
42f08c3bdfSopenharmony_cistatic void cleanup_invalid_sock(int);
43f08c3bdfSopenharmony_cistatic void cleanup_close_sock(int);
44f08c3bdfSopenharmony_cistatic void cleanup_reset_all(int);
45f08c3bdfSopenharmony_cistatic void do_child(void);
46f08c3bdfSopenharmony_cistatic pid_t start_server(struct sockaddr_in *, struct sockaddr_un *);
47f08c3bdfSopenharmony_ci
48f08c3bdfSopenharmony_cistatic struct tcase {
49f08c3bdfSopenharmony_ci	int domain;
50f08c3bdfSopenharmony_ci	int type;
51f08c3bdfSopenharmony_ci	int protocol;
52f08c3bdfSopenharmony_ci	struct iovec *iov;
53f08c3bdfSopenharmony_ci	int iovcnt;
54f08c3bdfSopenharmony_ci	void *recv_buf;
55f08c3bdfSopenharmony_ci	int buflen;
56f08c3bdfSopenharmony_ci	struct msghdr *msg;
57f08c3bdfSopenharmony_ci	unsigned int flags;
58f08c3bdfSopenharmony_ci	struct sockaddr *from;
59f08c3bdfSopenharmony_ci	int fromlen;
60f08c3bdfSopenharmony_ci	int exp_errno;
61f08c3bdfSopenharmony_ci	void (*setup)(int n);
62f08c3bdfSopenharmony_ci	void (*cleanup)(int n);
63f08c3bdfSopenharmony_ci	char *desc;
64f08c3bdfSopenharmony_ci} tcases[] = {
65f08c3bdfSopenharmony_ci	{
66f08c3bdfSopenharmony_ci		.domain = PF_INET,
67f08c3bdfSopenharmony_ci		.type = SOCK_STREAM,
68f08c3bdfSopenharmony_ci		.iov = iov,
69f08c3bdfSopenharmony_ci		.iovcnt = 1,
70f08c3bdfSopenharmony_ci		.recv_buf = recv_buf,
71f08c3bdfSopenharmony_ci		.buflen = sizeof(recv_buf),
72f08c3bdfSopenharmony_ci		.msg = &msgdat,
73f08c3bdfSopenharmony_ci		.from = (struct sockaddr *)&from,
74f08c3bdfSopenharmony_ci		.fromlen = sizeof(from),
75f08c3bdfSopenharmony_ci		.exp_errno = EBADF,
76f08c3bdfSopenharmony_ci		.setup = setup_invalid_sock,
77f08c3bdfSopenharmony_ci		.cleanup = cleanup_invalid_sock,
78f08c3bdfSopenharmony_ci		.desc = "bad file descriptor",
79f08c3bdfSopenharmony_ci	},
80f08c3bdfSopenharmony_ci	{
81f08c3bdfSopenharmony_ci		.domain = PF_INET,
82f08c3bdfSopenharmony_ci		.type = SOCK_STREAM,
83f08c3bdfSopenharmony_ci		.iov = iov,
84f08c3bdfSopenharmony_ci		.iovcnt = 1,
85f08c3bdfSopenharmony_ci		.recv_buf = (void *)recv_buf,
86f08c3bdfSopenharmony_ci		.buflen = sizeof(recv_buf),
87f08c3bdfSopenharmony_ci		.msg = &msgdat,
88f08c3bdfSopenharmony_ci		.from = (struct sockaddr *)&from,
89f08c3bdfSopenharmony_ci		.fromlen = sizeof(from),
90f08c3bdfSopenharmony_ci		.exp_errno = ENOTSOCK,
91f08c3bdfSopenharmony_ci		.setup = setup_invalid_sock,
92f08c3bdfSopenharmony_ci		.cleanup = cleanup_invalid_sock,
93f08c3bdfSopenharmony_ci		.desc = "invalid socket",
94f08c3bdfSopenharmony_ci	},
95f08c3bdfSopenharmony_ci	{
96f08c3bdfSopenharmony_ci		.domain = PF_INET,
97f08c3bdfSopenharmony_ci		.type = SOCK_STREAM,
98f08c3bdfSopenharmony_ci		.iov = iov,
99f08c3bdfSopenharmony_ci		.iovcnt = 1,
100f08c3bdfSopenharmony_ci		.recv_buf = (void *)recv_buf,
101f08c3bdfSopenharmony_ci		.buflen = sizeof(recv_buf),
102f08c3bdfSopenharmony_ci		.msg = &msgdat,
103f08c3bdfSopenharmony_ci		.flags = -1,
104f08c3bdfSopenharmony_ci		.from = (struct sockaddr *)&from,
105f08c3bdfSopenharmony_ci		.fromlen = -1,
106f08c3bdfSopenharmony_ci		.exp_errno = EINVAL,
107f08c3bdfSopenharmony_ci		.setup = setup_valid_sock,
108f08c3bdfSopenharmony_ci		.cleanup = cleanup_close_sock,
109f08c3bdfSopenharmony_ci		.desc = "invalid socket length",
110f08c3bdfSopenharmony_ci	},
111f08c3bdfSopenharmony_ci	{
112f08c3bdfSopenharmony_ci		.domain = PF_INET,
113f08c3bdfSopenharmony_ci		.type = SOCK_STREAM,
114f08c3bdfSopenharmony_ci		.iov = iov,
115f08c3bdfSopenharmony_ci		.iovcnt = 1,
116f08c3bdfSopenharmony_ci		.recv_buf = (void *)-1,
117f08c3bdfSopenharmony_ci		.buflen = sizeof(recv_buf),
118f08c3bdfSopenharmony_ci		.msg = &msgdat,
119f08c3bdfSopenharmony_ci		.from = (struct sockaddr *)&from,
120f08c3bdfSopenharmony_ci		.fromlen = sizeof(from),
121f08c3bdfSopenharmony_ci		.exp_errno = EFAULT,
122f08c3bdfSopenharmony_ci		.setup = setup_valid_sock,
123f08c3bdfSopenharmony_ci		.cleanup = cleanup_close_sock,
124f08c3bdfSopenharmony_ci		.desc = "invalid recv buffer",
125f08c3bdfSopenharmony_ci	},
126f08c3bdfSopenharmony_ci	{
127f08c3bdfSopenharmony_ci		.domain = PF_INET,
128f08c3bdfSopenharmony_ci		.type = SOCK_STREAM,
129f08c3bdfSopenharmony_ci		.iovcnt = 1,
130f08c3bdfSopenharmony_ci		.recv_buf = recv_buf,
131f08c3bdfSopenharmony_ci		.buflen = sizeof(recv_buf),
132f08c3bdfSopenharmony_ci		.msg = &msgdat,
133f08c3bdfSopenharmony_ci		.from = (struct sockaddr *)&from,
134f08c3bdfSopenharmony_ci		.fromlen = sizeof(from),
135f08c3bdfSopenharmony_ci		.exp_errno = EFAULT,
136f08c3bdfSopenharmony_ci		.setup = setup_valid_sock,
137f08c3bdfSopenharmony_ci		.cleanup = cleanup_close_sock,
138f08c3bdfSopenharmony_ci		.desc = "invalid iovec buffer",
139f08c3bdfSopenharmony_ci	},
140f08c3bdfSopenharmony_ci	{
141f08c3bdfSopenharmony_ci		.domain = PF_INET,
142f08c3bdfSopenharmony_ci		.type = SOCK_STREAM,
143f08c3bdfSopenharmony_ci		.iov = iov,
144f08c3bdfSopenharmony_ci		.iovcnt = -1,
145f08c3bdfSopenharmony_ci		.recv_buf = recv_buf,
146f08c3bdfSopenharmony_ci		.buflen = sizeof(recv_buf),
147f08c3bdfSopenharmony_ci		.msg = &msgdat,
148f08c3bdfSopenharmony_ci		.from = (struct sockaddr *)&from,
149f08c3bdfSopenharmony_ci		.fromlen = sizeof(from),
150f08c3bdfSopenharmony_ci		.exp_errno = EMSGSIZE,
151f08c3bdfSopenharmony_ci		.setup = setup_valid_sock,
152f08c3bdfSopenharmony_ci		.cleanup = cleanup_close_sock,
153f08c3bdfSopenharmony_ci		.desc = "invalid iovec count",
154f08c3bdfSopenharmony_ci	},
155f08c3bdfSopenharmony_ci	{
156f08c3bdfSopenharmony_ci		.domain = PF_INET,
157f08c3bdfSopenharmony_ci		.type = SOCK_STREAM,
158f08c3bdfSopenharmony_ci		.iov = iov,
159f08c3bdfSopenharmony_ci		.iovcnt = 1,
160f08c3bdfSopenharmony_ci		.recv_buf = recv_buf,
161f08c3bdfSopenharmony_ci		.buflen = sizeof(recv_buf),
162f08c3bdfSopenharmony_ci		.msg = &msgdat,
163f08c3bdfSopenharmony_ci		.from = (struct sockaddr *)&from,
164f08c3bdfSopenharmony_ci		.fromlen = sizeof(from),
165f08c3bdfSopenharmony_ci		.setup = setup_valid_msg_control,
166f08c3bdfSopenharmony_ci		.cleanup = cleanup_reset_all,
167f08c3bdfSopenharmony_ci		.desc = "permission reception",
168f08c3bdfSopenharmony_ci	},
169f08c3bdfSopenharmony_ci	{
170f08c3bdfSopenharmony_ci		.domain = PF_INET,
171f08c3bdfSopenharmony_ci		.type = SOCK_STREAM,
172f08c3bdfSopenharmony_ci		.iov = iov,
173f08c3bdfSopenharmony_ci		.iovcnt = 1,
174f08c3bdfSopenharmony_ci		.recv_buf = recv_buf,
175f08c3bdfSopenharmony_ci		.buflen = sizeof(recv_buf),
176f08c3bdfSopenharmony_ci		.msg = &msgdat,
177f08c3bdfSopenharmony_ci		.flags = MSG_OOB,
178f08c3bdfSopenharmony_ci		.from = (struct sockaddr *)&from,
179f08c3bdfSopenharmony_ci		.fromlen = sizeof(from),
180f08c3bdfSopenharmony_ci		.exp_errno = EINVAL,
181f08c3bdfSopenharmony_ci		.setup = setup_valid_sock,
182f08c3bdfSopenharmony_ci		.cleanup = cleanup_close_sock,
183f08c3bdfSopenharmony_ci		.desc = "invalid MSG_OOB flag set",
184f08c3bdfSopenharmony_ci	},
185f08c3bdfSopenharmony_ci	{
186f08c3bdfSopenharmony_ci		.domain = PF_INET,
187f08c3bdfSopenharmony_ci		.type = SOCK_STREAM,
188f08c3bdfSopenharmony_ci		.iov = iov,
189f08c3bdfSopenharmony_ci		.iovcnt = 1,
190f08c3bdfSopenharmony_ci		.recv_buf = recv_buf,
191f08c3bdfSopenharmony_ci		.buflen = sizeof(recv_buf),
192f08c3bdfSopenharmony_ci		.msg = &msgdat,
193f08c3bdfSopenharmony_ci		.flags = MSG_ERRQUEUE,
194f08c3bdfSopenharmony_ci		.from = (struct sockaddr *)&from,
195f08c3bdfSopenharmony_ci		.fromlen = sizeof(from),
196f08c3bdfSopenharmony_ci		.exp_errno = EAGAIN,
197f08c3bdfSopenharmony_ci		.setup = setup_valid_sock,
198f08c3bdfSopenharmony_ci		.cleanup = cleanup_close_sock,
199f08c3bdfSopenharmony_ci		.desc = "invalid MSG_ERRQUEUE flag set",
200f08c3bdfSopenharmony_ci	},
201f08c3bdfSopenharmony_ci	{
202f08c3bdfSopenharmony_ci		.domain = PF_INET,
203f08c3bdfSopenharmony_ci		.type = SOCK_STREAM,
204f08c3bdfSopenharmony_ci		.iov = iov,
205f08c3bdfSopenharmony_ci		.iovcnt = 1,
206f08c3bdfSopenharmony_ci		.recv_buf = recv_buf,
207f08c3bdfSopenharmony_ci		.buflen = sizeof(recv_buf),
208f08c3bdfSopenharmony_ci		.msg = &msgdat,
209f08c3bdfSopenharmony_ci		.from = (struct sockaddr *)&from,
210f08c3bdfSopenharmony_ci		.fromlen = sizeof(from),
211f08c3bdfSopenharmony_ci		.setup = setup_large_msg_control,
212f08c3bdfSopenharmony_ci		.cleanup = cleanup_reset_all,
213f08c3bdfSopenharmony_ci		.desc = "large cmesg length",
214f08c3bdfSopenharmony_ci	},
215f08c3bdfSopenharmony_ci
216f08c3bdfSopenharmony_ci};
217f08c3bdfSopenharmony_ci
218f08c3bdfSopenharmony_cistatic void run(unsigned int n)
219f08c3bdfSopenharmony_ci{
220f08c3bdfSopenharmony_ci	struct tcase *tc = &tcases[n];
221f08c3bdfSopenharmony_ci	int ret = tc->exp_errno ? -1 : 0;
222f08c3bdfSopenharmony_ci
223f08c3bdfSopenharmony_ci	if ((tst_kvercmp(3, 17, 0) < 0)
224f08c3bdfSopenharmony_ci			&& (tc->flags & MSG_ERRQUEUE)
225f08c3bdfSopenharmony_ci			&& (tc->type & SOCK_STREAM)) {
226f08c3bdfSopenharmony_ci		tst_res(TCONF, "MSG_ERRQUEUE requires kernel >= 3.17");
227f08c3bdfSopenharmony_ci		return;
228f08c3bdfSopenharmony_ci	}
229f08c3bdfSopenharmony_ci
230f08c3bdfSopenharmony_ci	setup_all();
231f08c3bdfSopenharmony_ci	tc->setup(n);
232f08c3bdfSopenharmony_ci
233f08c3bdfSopenharmony_ci	iov[0].iov_base = tc->recv_buf;
234f08c3bdfSopenharmony_ci	iov[0].iov_len = tc->buflen;
235f08c3bdfSopenharmony_ci	msgdat.msg_name = tc->from;
236f08c3bdfSopenharmony_ci	msgdat.msg_namelen = tc->fromlen;
237f08c3bdfSopenharmony_ci	msgdat.msg_iov = tc->iov;
238f08c3bdfSopenharmony_ci	msgdat.msg_iovlen = tc->iovcnt;
239f08c3bdfSopenharmony_ci	msgdat.msg_control = control;
240f08c3bdfSopenharmony_ci	msgdat.msg_controllen = controllen;
241f08c3bdfSopenharmony_ci	msgdat.msg_flags = 0;
242f08c3bdfSopenharmony_ci
243f08c3bdfSopenharmony_ci	TEST(recvmsg(sock, tc->msg, tc->flags));
244f08c3bdfSopenharmony_ci	if (TST_RET >= 0)
245f08c3bdfSopenharmony_ci		TST_RET = 0;
246f08c3bdfSopenharmony_ci
247f08c3bdfSopenharmony_ci	if (TST_RET != ret) {
248f08c3bdfSopenharmony_ci		tst_res(TFAIL | TTERRNO, "%s: expected %d, returned %ld",
249f08c3bdfSopenharmony_ci			tc->desc, ret, TST_RET);
250f08c3bdfSopenharmony_ci	} else if (TST_ERR != tc->exp_errno) {
251f08c3bdfSopenharmony_ci		tst_res(TFAIL | TTERRNO,
252f08c3bdfSopenharmony_ci			"%s: expected %s",
253f08c3bdfSopenharmony_ci			tc->desc, tst_strerrno(tc->exp_errno));
254f08c3bdfSopenharmony_ci	} else {
255f08c3bdfSopenharmony_ci		tst_res(TPASS, "%s passed", tc->desc);
256f08c3bdfSopenharmony_ci	}
257f08c3bdfSopenharmony_ci
258f08c3bdfSopenharmony_ci	tc->cleanup(n);
259f08c3bdfSopenharmony_ci	cleanup_all();
260f08c3bdfSopenharmony_ci}
261f08c3bdfSopenharmony_ci
262f08c3bdfSopenharmony_ci
263f08c3bdfSopenharmony_cistatic void setup_all(void)
264f08c3bdfSopenharmony_ci{
265f08c3bdfSopenharmony_ci	int tfd;
266f08c3bdfSopenharmony_ci
267f08c3bdfSopenharmony_ci	sun1.sun_family = AF_UNIX;
268f08c3bdfSopenharmony_ci
269f08c3bdfSopenharmony_ci	(void)strcpy(tmpsunpath, "udsockXXXXXX");
270f08c3bdfSopenharmony_ci	tfd = mkstemp(tmpsunpath);
271f08c3bdfSopenharmony_ci	SAFE_CLOSE(tfd);
272f08c3bdfSopenharmony_ci	SAFE_UNLINK(tmpsunpath);
273f08c3bdfSopenharmony_ci	(void)strcpy(sun1.sun_path, tmpsunpath);
274f08c3bdfSopenharmony_ci	SAFE_SIGNAL(SIGPIPE, SIG_IGN);
275f08c3bdfSopenharmony_ci	pid = start_server(&sin1, &sun1);
276f08c3bdfSopenharmony_ci}
277f08c3bdfSopenharmony_ci
278f08c3bdfSopenharmony_cistatic void cleanup_all(void)
279f08c3bdfSopenharmony_ci{
280f08c3bdfSopenharmony_ci	if (pid > 0) {
281f08c3bdfSopenharmony_ci		(void)kill(pid, SIGKILL);	/* kill server */
282f08c3bdfSopenharmony_ci		wait(NULL);
283f08c3bdfSopenharmony_ci	}
284f08c3bdfSopenharmony_ci
285f08c3bdfSopenharmony_ci	if (tmpsunpath[0] != '\0')
286f08c3bdfSopenharmony_ci		(void)SAFE_UNLINK(tmpsunpath);
287f08c3bdfSopenharmony_ci}
288f08c3bdfSopenharmony_ci
289f08c3bdfSopenharmony_cistatic void setup_invalid_sock(int n)
290f08c3bdfSopenharmony_ci{
291f08c3bdfSopenharmony_ci	if (tcases[n].exp_errno == EBADF)
292f08c3bdfSopenharmony_ci		sock = 400;	/* anything not an open file */
293f08c3bdfSopenharmony_ci	else
294f08c3bdfSopenharmony_ci		sock = SAFE_OPEN("/dev/null", O_WRONLY);
295f08c3bdfSopenharmony_ci}
296f08c3bdfSopenharmony_ci
297f08c3bdfSopenharmony_cistatic void cleanup_invalid_sock(int n)
298f08c3bdfSopenharmony_ci{
299f08c3bdfSopenharmony_ci	if (tcases[n].exp_errno == EBADF)
300f08c3bdfSopenharmony_ci		sock = -1;
301f08c3bdfSopenharmony_ci	else
302f08c3bdfSopenharmony_ci		SAFE_CLOSE(sock);
303f08c3bdfSopenharmony_ci}
304f08c3bdfSopenharmony_ci
305f08c3bdfSopenharmony_cistatic void setup_valid_sock(int n)
306f08c3bdfSopenharmony_ci{
307f08c3bdfSopenharmony_ci	fd_set rdfds;
308f08c3bdfSopenharmony_ci	struct timeval timeout;
309f08c3bdfSopenharmony_ci
310f08c3bdfSopenharmony_ci	sock = SAFE_SOCKET(tcases[n].domain, tcases[n].type, tcases[n].protocol);
311f08c3bdfSopenharmony_ci
312f08c3bdfSopenharmony_ci	if (tcases[n].type == SOCK_STREAM) {
313f08c3bdfSopenharmony_ci		if (tcases[n].domain == PF_INET) {
314f08c3bdfSopenharmony_ci			SAFE_CONNECT(sock, (struct sockaddr *)&sin1, sizeof(sin1));
315f08c3bdfSopenharmony_ci			/* Wait for something to be readable, else we won't detect EFAULT on recv */
316f08c3bdfSopenharmony_ci			FD_ZERO(&rdfds);
317f08c3bdfSopenharmony_ci			FD_SET(sock, &rdfds);
318f08c3bdfSopenharmony_ci			timeout.tv_sec = 2;
319f08c3bdfSopenharmony_ci			timeout.tv_usec = 0;
320f08c3bdfSopenharmony_ci			n = select(sock + 1, &rdfds, 0, 0, &timeout);
321f08c3bdfSopenharmony_ci
322f08c3bdfSopenharmony_ci			if (n != 1 || !FD_ISSET(sock, &rdfds))
323f08c3bdfSopenharmony_ci				tst_brk(TBROK, "no message ready in %d sec", (int)timeout.tv_sec);
324f08c3bdfSopenharmony_ci
325f08c3bdfSopenharmony_ci		} else if (tcases[n].domain == PF_UNIX) {
326f08c3bdfSopenharmony_ci			SAFE_CONNECT(sock, (struct sockaddr *)&sun1, sizeof(sun1));
327f08c3bdfSopenharmony_ci		}
328f08c3bdfSopenharmony_ci	}
329f08c3bdfSopenharmony_ci}
330f08c3bdfSopenharmony_ci
331f08c3bdfSopenharmony_cistatic void setup_valid_msg_control(int n)
332f08c3bdfSopenharmony_ci{
333f08c3bdfSopenharmony_ci	setup_valid_sock(n);
334f08c3bdfSopenharmony_ci	SAFE_SEND(1, sock, "R", 1, 0);
335f08c3bdfSopenharmony_ci	control = (struct cmsghdr *)cbuf;
336f08c3bdfSopenharmony_ci	controllen = control->cmsg_len = sizeof(cbuf);
337f08c3bdfSopenharmony_ci}
338f08c3bdfSopenharmony_ci
339f08c3bdfSopenharmony_cistatic void setup_large_msg_control(int n)
340f08c3bdfSopenharmony_ci{
341f08c3bdfSopenharmony_ci	setup_valid_msg_control(n);
342f08c3bdfSopenharmony_ci	controllen = CONTROL_LEN;
343f08c3bdfSopenharmony_ci}
344f08c3bdfSopenharmony_ci
345f08c3bdfSopenharmony_cistatic void cleanup_close_sock(int n LTP_ATTRIBUTE_UNUSED)
346f08c3bdfSopenharmony_ci{
347f08c3bdfSopenharmony_ci	SAFE_CLOSE(sock);
348f08c3bdfSopenharmony_ci}
349f08c3bdfSopenharmony_ci
350f08c3bdfSopenharmony_cistatic void cleanup_reset_all(int n LTP_ATTRIBUTE_UNUSED)
351f08c3bdfSopenharmony_ci{
352f08c3bdfSopenharmony_ci	SAFE_CLOSE(sock);
353f08c3bdfSopenharmony_ci
354f08c3bdfSopenharmony_ci	control = 0;
355f08c3bdfSopenharmony_ci	controllen = 0;
356f08c3bdfSopenharmony_ci}
357f08c3bdfSopenharmony_ci
358f08c3bdfSopenharmony_cipid_t start_server(struct sockaddr_in *ssin, struct sockaddr_un *ssun)
359f08c3bdfSopenharmony_ci{
360f08c3bdfSopenharmony_ci	pid_t pid;
361f08c3bdfSopenharmony_ci	socklen_t slen = sizeof(*ssin);
362f08c3bdfSopenharmony_ci
363f08c3bdfSopenharmony_ci	ssin->sin_family = AF_INET;
364f08c3bdfSopenharmony_ci	ssin->sin_port = 0; /* pick random free port */
365f08c3bdfSopenharmony_ci	ssin->sin_addr.s_addr = INADDR_ANY;
366f08c3bdfSopenharmony_ci
367f08c3bdfSopenharmony_ci	/* set up inet socket */
368f08c3bdfSopenharmony_ci	sfd = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0);
369f08c3bdfSopenharmony_ci	SAFE_BIND(sfd, (struct sockaddr *)ssin, sizeof(*ssin));
370f08c3bdfSopenharmony_ci	SAFE_LISTEN(sfd, 10);
371f08c3bdfSopenharmony_ci	SAFE_GETSOCKNAME(sfd, (struct sockaddr *)ssin, &slen);
372f08c3bdfSopenharmony_ci
373f08c3bdfSopenharmony_ci	/* set up UNIX-domain socket */
374f08c3bdfSopenharmony_ci	ufd = SAFE_SOCKET(PF_UNIX, SOCK_STREAM, 0);
375f08c3bdfSopenharmony_ci	SAFE_BIND(ufd, (struct sockaddr *)ssun, sizeof(*ssun));
376f08c3bdfSopenharmony_ci	SAFE_LISTEN(ufd, 10);
377f08c3bdfSopenharmony_ci
378f08c3bdfSopenharmony_ci	pid = SAFE_FORK();
379f08c3bdfSopenharmony_ci	if (!pid) {
380f08c3bdfSopenharmony_ci		do_child();
381f08c3bdfSopenharmony_ci		exit(1);
382f08c3bdfSopenharmony_ci	}
383f08c3bdfSopenharmony_ci
384f08c3bdfSopenharmony_ci	SAFE_CLOSE(sfd);
385f08c3bdfSopenharmony_ci	SAFE_CLOSE(ufd);
386f08c3bdfSopenharmony_ci
387f08c3bdfSopenharmony_ci	return pid;
388f08c3bdfSopenharmony_ci}
389f08c3bdfSopenharmony_ci
390f08c3bdfSopenharmony_ci/* for permission test */
391f08c3bdfSopenharmony_cistatic void sender(int fd)
392f08c3bdfSopenharmony_ci{
393f08c3bdfSopenharmony_ci	struct msghdr mh = {};
394f08c3bdfSopenharmony_ci	struct cmsghdr *control;
395f08c3bdfSopenharmony_ci	char tmpfn[BUF_SIZE] = "";
396f08c3bdfSopenharmony_ci	char snd_cbuf[BUF_SIZE] = "";
397f08c3bdfSopenharmony_ci	int tfd;
398f08c3bdfSopenharmony_ci
399f08c3bdfSopenharmony_ci	(void)strcpy(tmpfn, "smtXXXXXX");
400f08c3bdfSopenharmony_ci	tfd = mkstemp(tmpfn);
401f08c3bdfSopenharmony_ci	if (tfd < 0)
402f08c3bdfSopenharmony_ci		return;
403f08c3bdfSopenharmony_ci
404f08c3bdfSopenharmony_ci	/* set up cmsghdr */
405f08c3bdfSopenharmony_ci	control = (struct cmsghdr *)snd_cbuf;
406f08c3bdfSopenharmony_ci	control->cmsg_len = sizeof(struct cmsghdr) + 4;
407f08c3bdfSopenharmony_ci	control->cmsg_level = SOL_SOCKET;
408f08c3bdfSopenharmony_ci	control->cmsg_type = SCM_RIGHTS;
409f08c3bdfSopenharmony_ci	*(int *)CMSG_DATA(control) = tfd;
410f08c3bdfSopenharmony_ci
411f08c3bdfSopenharmony_ci	/* set up msghdr */
412f08c3bdfSopenharmony_ci	iov[0].iov_base = MSG;
413f08c3bdfSopenharmony_ci	iov[0].iov_len = sizeof(MSG);
414f08c3bdfSopenharmony_ci	mh.msg_iov = iov;
415f08c3bdfSopenharmony_ci	mh.msg_iovlen = 1;
416f08c3bdfSopenharmony_ci	mh.msg_flags = 0;
417f08c3bdfSopenharmony_ci	mh.msg_control = control;
418f08c3bdfSopenharmony_ci	mh.msg_controllen = control->cmsg_len;
419f08c3bdfSopenharmony_ci
420f08c3bdfSopenharmony_ci	/* do it */
421f08c3bdfSopenharmony_ci	SAFE_SENDMSG(sizeof(MSG), fd, &mh, 0);
422f08c3bdfSopenharmony_ci	SAFE_CLOSE(tfd);
423f08c3bdfSopenharmony_ci	(void)SAFE_UNLINK(tmpfn);
424f08c3bdfSopenharmony_ci}
425f08c3bdfSopenharmony_ci
426f08c3bdfSopenharmony_cistatic void do_child(void)
427f08c3bdfSopenharmony_ci{
428f08c3bdfSopenharmony_ci	struct sockaddr_in fsin;
429f08c3bdfSopenharmony_ci	struct sockaddr_un fsun;
430f08c3bdfSopenharmony_ci	fd_set afds, rfds;
431f08c3bdfSopenharmony_ci	int nfds, fd;
432f08c3bdfSopenharmony_ci
433f08c3bdfSopenharmony_ci	FD_ZERO(&afds);
434f08c3bdfSopenharmony_ci	FD_SET(sfd, &afds);
435f08c3bdfSopenharmony_ci	FD_SET(ufd, &afds);
436f08c3bdfSopenharmony_ci
437f08c3bdfSopenharmony_ci	nfds = MAX(sfd + 1, ufd + 1);
438f08c3bdfSopenharmony_ci
439f08c3bdfSopenharmony_ci	/* accept connections until killed */
440f08c3bdfSopenharmony_ci	while (1) {
441f08c3bdfSopenharmony_ci		socklen_t fromlen;
442f08c3bdfSopenharmony_ci
443f08c3bdfSopenharmony_ci		memcpy(&rfds, &afds, sizeof(rfds));
444f08c3bdfSopenharmony_ci
445f08c3bdfSopenharmony_ci		if (select(nfds, &rfds, NULL, NULL,
446f08c3bdfSopenharmony_ci			   NULL) < 0) {
447f08c3bdfSopenharmony_ci			if (errno != EINTR) {
448f08c3bdfSopenharmony_ci				perror("server select");
449f08c3bdfSopenharmony_ci				exit(1);
450f08c3bdfSopenharmony_ci			}
451f08c3bdfSopenharmony_ci			continue;
452f08c3bdfSopenharmony_ci		}
453f08c3bdfSopenharmony_ci		if (FD_ISSET(sfd, &rfds)) {
454f08c3bdfSopenharmony_ci			int newfd;
455f08c3bdfSopenharmony_ci
456f08c3bdfSopenharmony_ci			fromlen = sizeof(fsin);
457f08c3bdfSopenharmony_ci			newfd = SAFE_ACCEPT(sfd, (struct sockaddr *)&fsin, &fromlen);
458f08c3bdfSopenharmony_ci			if (newfd >= 0) {
459f08c3bdfSopenharmony_ci				FD_SET(newfd, &afds);
460f08c3bdfSopenharmony_ci				nfds = MAX(nfds, newfd + 1);
461f08c3bdfSopenharmony_ci				/* send something back */
462f08c3bdfSopenharmony_ci				SAFE_SEND(1, newfd, "hi", 2, 0);
463f08c3bdfSopenharmony_ci			}
464f08c3bdfSopenharmony_ci		}
465f08c3bdfSopenharmony_ci		if (FD_ISSET(ufd, &rfds)) {
466f08c3bdfSopenharmony_ci			int newfd;
467f08c3bdfSopenharmony_ci
468f08c3bdfSopenharmony_ci			fromlen = sizeof(fsun);
469f08c3bdfSopenharmony_ci			newfd = SAFE_ACCEPT(ufd, (struct sockaddr *)&fsun, &fromlen);
470f08c3bdfSopenharmony_ci			if (newfd >= 0) {
471f08c3bdfSopenharmony_ci				FD_SET(newfd, &afds);
472f08c3bdfSopenharmony_ci				nfds = MAX(nfds, newfd + 1);
473f08c3bdfSopenharmony_ci			}
474f08c3bdfSopenharmony_ci		}
475f08c3bdfSopenharmony_ci		for (fd = 0; fd < nfds; ++fd)
476f08c3bdfSopenharmony_ci			if (fd != sfd && fd != ufd && FD_ISSET(fd, &rfds)) {
477f08c3bdfSopenharmony_ci				char rbuf[BUF_SIZE];
478f08c3bdfSopenharmony_ci
479f08c3bdfSopenharmony_ci				TEST(read(fd, rbuf, sizeof(rbuf)));
480f08c3bdfSopenharmony_ci				if (TST_RET > 0 && rbuf[0] == 'R')
481f08c3bdfSopenharmony_ci					sender(fd);
482f08c3bdfSopenharmony_ci				if (TST_RET == 0 || (TST_RET < 0 && TST_ERR != EINTR)) {
483f08c3bdfSopenharmony_ci					close(fd);
484f08c3bdfSopenharmony_ci					FD_CLR(fd, &afds);
485f08c3bdfSopenharmony_ci				}
486f08c3bdfSopenharmony_ci			}
487f08c3bdfSopenharmony_ci	}
488f08c3bdfSopenharmony_ci}
489f08c3bdfSopenharmony_ci
490f08c3bdfSopenharmony_cistatic struct tst_test test = {
491f08c3bdfSopenharmony_ci	.test = run,
492f08c3bdfSopenharmony_ci	.tcnt = ARRAY_SIZE(tcases),
493f08c3bdfSopenharmony_ci	.forks_child = 1,
494f08c3bdfSopenharmony_ci	.needs_tmpdir = 1,
495f08c3bdfSopenharmony_ci};
496