xref: /netbsd-src/tests/lib/libc/sys/t_select.c (revision 2c2346570d2ce999f9439f8cef1e71b985b433f7)
1*2c234657Sriastradh /*	$NetBSD: t_select.c,v 1.5 2024/10/18 16:39:41 riastradh Exp $ */
2068fb4f1Sjruoho 
3068fb4f1Sjruoho /*-
4068fb4f1Sjruoho  * Copyright (c) 2011 The NetBSD Foundation, Inc.
5068fb4f1Sjruoho  * All rights reserved.
6068fb4f1Sjruoho  *
7068fb4f1Sjruoho  * This code is derived from software contributed to The NetBSD Foundatiom
8068fb4f1Sjruoho  * by Christos Zoulas.
9068fb4f1Sjruoho  *
10068fb4f1Sjruoho  * Redistribution and use in source and binary forms, with or without
11068fb4f1Sjruoho  * modification, are permitted provided that the following conditions
12068fb4f1Sjruoho  * are met:
13068fb4f1Sjruoho  * 1. Redistributions of source code must retain the above copyright
14068fb4f1Sjruoho  *    notice, this list of conditions and the following disclaimer.
15068fb4f1Sjruoho  * 2. Redistributions in binary form must reproduce the above copyright
16068fb4f1Sjruoho  *    notice, this list of conditions and the following disclaimer in the
17068fb4f1Sjruoho  *    documentation and/or other materials provided with the distribution.
18068fb4f1Sjruoho  *
19068fb4f1Sjruoho  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20068fb4f1Sjruoho  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21068fb4f1Sjruoho  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22068fb4f1Sjruoho  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23068fb4f1Sjruoho  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24068fb4f1Sjruoho  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25068fb4f1Sjruoho  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26068fb4f1Sjruoho  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27068fb4f1Sjruoho  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28068fb4f1Sjruoho  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29068fb4f1Sjruoho  * POSSIBILITY OF SUCH DAMAGE.
30068fb4f1Sjruoho  */
31068fb4f1Sjruoho 
32068fb4f1Sjruoho #include <sys/types.h>
33*2c234657Sriastradh 
34068fb4f1Sjruoho #include <sys/select.h>
35068fb4f1Sjruoho #include <sys/wait.h>
36*2c234657Sriastradh 
37*2c234657Sriastradh #include <assert.h>
38068fb4f1Sjruoho #include <err.h>
39068fb4f1Sjruoho #include <errno.h>
40068fb4f1Sjruoho #include <fcntl.h>
41*2c234657Sriastradh #include <signal.h>
42*2c234657Sriastradh #include <stdio.h>
43*2c234657Sriastradh #include <stdlib.h>
44*2c234657Sriastradh #include <string.h>
45*2c234657Sriastradh #include <unistd.h>
46068fb4f1Sjruoho 
47068fb4f1Sjruoho #include <atf-c.h>
48068fb4f1Sjruoho 
49068fb4f1Sjruoho static sig_atomic_t keep_going = 1;
50068fb4f1Sjruoho 
51068fb4f1Sjruoho static void
529398a6c8Schristos sig_handler(int signum __unused)
53068fb4f1Sjruoho {
54068fb4f1Sjruoho 	keep_going = 0;
55068fb4f1Sjruoho }
56068fb4f1Sjruoho 
57068fb4f1Sjruoho static void
589398a6c8Schristos sigchld(int signum __unused)
59068fb4f1Sjruoho {
60068fb4f1Sjruoho }
61068fb4f1Sjruoho 
62068fb4f1Sjruoho static char
63068fb4f1Sjruoho xtoa(uint8_t n)
64068fb4f1Sjruoho {
65068fb4f1Sjruoho 	static const char xarray[] = "0123456789abcdef";
66068fb4f1Sjruoho 	assert(n < sizeof(xarray));
67068fb4f1Sjruoho 	return xarray[n];
68068fb4f1Sjruoho }
69068fb4f1Sjruoho 
70068fb4f1Sjruoho static const char *
71068fb4f1Sjruoho prmask(const sigset_t *m, char *buf, size_t len)
72068fb4f1Sjruoho {
73068fb4f1Sjruoho 	size_t j = 2;
74068fb4f1Sjruoho 	assert(len >= 3 + sizeof(*m));
75068fb4f1Sjruoho 	buf[0] = '0';
76068fb4f1Sjruoho 	buf[1] = 'x';
77068fb4f1Sjruoho #define N(p, a)	(((p) >> ((a) * 4)) & 0xf)
78068fb4f1Sjruoho 	for (size_t i = __arraycount(m->__bits); i > 0; i--) {
79068fb4f1Sjruoho 		uint32_t p = m->__bits[i - 1];
80068fb4f1Sjruoho 		for (size_t k = sizeof(p); k > 0; k--)
81068fb4f1Sjruoho 			buf[j++] = xtoa(N(p, k - 1));
82068fb4f1Sjruoho 	}
83068fb4f1Sjruoho 	buf[j] = '\0';
84068fb4f1Sjruoho 	return buf;
85068fb4f1Sjruoho }
86068fb4f1Sjruoho 
879398a6c8Schristos static __dead void
88068fb4f1Sjruoho child(const struct timespec *ts)
89068fb4f1Sjruoho {
90068fb4f1Sjruoho 	struct sigaction sa;
91068fb4f1Sjruoho 	sigset_t set, oset, nset;
92068fb4f1Sjruoho 	char obuf[sizeof(oset) + 3], nbuf[sizeof(nset) + 3];
93068fb4f1Sjruoho 	int fd;
94068fb4f1Sjruoho 
95068fb4f1Sjruoho 	memset(&sa, 0, sizeof(sa));
96068fb4f1Sjruoho 	sa.sa_handler = sig_handler;
97068fb4f1Sjruoho 	if ((fd = open("/dev/null", O_RDONLY)) == -1)
98068fb4f1Sjruoho 		err(1, "open");
99068fb4f1Sjruoho 
100068fb4f1Sjruoho 	if (sigaction(SIGTERM, &sa, NULL) == -1)
101068fb4f1Sjruoho 		err(1, "sigaction");
102068fb4f1Sjruoho 
103068fb4f1Sjruoho 	sigfillset(&set);
104068fb4f1Sjruoho 	if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
105068fb4f1Sjruoho 		err(1, "sigprocmask");
106068fb4f1Sjruoho 
107068fb4f1Sjruoho 	if (sigprocmask(SIG_BLOCK, NULL, &oset) == -1)
108068fb4f1Sjruoho 		err(1, "sigprocmask");
109068fb4f1Sjruoho 
110068fb4f1Sjruoho 	sigemptyset(&set);
111068fb4f1Sjruoho 
112068fb4f1Sjruoho 	for (;;) {
113068fb4f1Sjruoho 		fd_set rset;
114068fb4f1Sjruoho 		FD_ZERO(&rset);
115068fb4f1Sjruoho 		FD_SET(fd, &rset);
116068fb4f1Sjruoho 		if (pselect(1, &rset, NULL, NULL, ts, &set) == -1) {
117068fb4f1Sjruoho 			if(errno == EINTR) {
118068fb4f1Sjruoho 				if (!keep_going)
119068fb4f1Sjruoho 					break;
120068fb4f1Sjruoho 			}
121068fb4f1Sjruoho 		}
122068fb4f1Sjruoho 		if (ts)
123068fb4f1Sjruoho 			break;
124068fb4f1Sjruoho 	}
125068fb4f1Sjruoho 	if (sigprocmask(SIG_BLOCK, NULL, &nset) == -1)
126068fb4f1Sjruoho 		err(1, "sigprocmask");
127068fb4f1Sjruoho 	if (memcmp(&oset, &nset, sizeof(oset)) != 0)
128068fb4f1Sjruoho 		atf_tc_fail("pselect() masks don't match "
129068fb4f1Sjruoho 		    "after timeout %s != %s",
130068fb4f1Sjruoho 		    prmask(&nset, nbuf, sizeof(nbuf)),
131068fb4f1Sjruoho 		    prmask(&oset, obuf, sizeof(obuf)));
1329398a6c8Schristos 	_exit(0);
133068fb4f1Sjruoho }
134068fb4f1Sjruoho 
135068fb4f1Sjruoho ATF_TC(pselect_sigmask);
136068fb4f1Sjruoho ATF_TC_HEAD(pselect_sigmask, tc)
137068fb4f1Sjruoho {
138068fb4f1Sjruoho 	atf_tc_set_md_var(tc, "descr", "Checks pselect's temporary mask "
1398b18a8bfSjruoho 	    "setting when a signal is received (PR lib/43625)");
140068fb4f1Sjruoho }
141068fb4f1Sjruoho 
142068fb4f1Sjruoho ATF_TC_BODY(pselect_sigmask, tc)
143068fb4f1Sjruoho {
144068fb4f1Sjruoho 	pid_t pid;
145068fb4f1Sjruoho 	int status;
146068fb4f1Sjruoho 
147068fb4f1Sjruoho 	signal(SIGCHLD, sigchld);
148068fb4f1Sjruoho 
149068fb4f1Sjruoho 	switch (pid = fork()) {
150068fb4f1Sjruoho 	case 0:
151068fb4f1Sjruoho 		child(NULL);
1529398a6c8Schristos 		/*NOTREACHED*/
153068fb4f1Sjruoho 	case -1:
154068fb4f1Sjruoho 		err(1, "fork");
155068fb4f1Sjruoho 	default:
156068fb4f1Sjruoho 		sleep(1);
157068fb4f1Sjruoho 		if (kill(pid, SIGTERM) == -1)
158068fb4f1Sjruoho 			err(1, "kill");
159068fb4f1Sjruoho 		sleep(1);
160068fb4f1Sjruoho 		switch (waitpid(pid, &status, WNOHANG)) {
161068fb4f1Sjruoho 		case -1:
162068fb4f1Sjruoho 			err(1, "wait");
163068fb4f1Sjruoho 		case 0:
164068fb4f1Sjruoho 			if (kill(pid, SIGKILL) == -1)
165068fb4f1Sjruoho 				err(1, "kill");
166068fb4f1Sjruoho 			atf_tc_fail("pselect() did not receive signal");
167068fb4f1Sjruoho 			break;
168068fb4f1Sjruoho 		default:
169068fb4f1Sjruoho 			break;
170068fb4f1Sjruoho 		}
171068fb4f1Sjruoho 	}
172068fb4f1Sjruoho }
173068fb4f1Sjruoho 
174068fb4f1Sjruoho ATF_TC(pselect_timeout);
175068fb4f1Sjruoho ATF_TC_HEAD(pselect_timeout, tc)
176068fb4f1Sjruoho {
177068fb4f1Sjruoho 
178068fb4f1Sjruoho 	atf_tc_set_md_var(tc, "descr", "Checks pselect's temporary mask "
179068fb4f1Sjruoho 	    "setting when a timeout occurs");
180068fb4f1Sjruoho }
181068fb4f1Sjruoho 
182068fb4f1Sjruoho ATF_TC_BODY(pselect_timeout, tc)
183068fb4f1Sjruoho {
184068fb4f1Sjruoho 	pid_t pid;
185068fb4f1Sjruoho 	int status;
186068fb4f1Sjruoho 	static const struct timespec zero = { 0, 0 };
187068fb4f1Sjruoho 
188068fb4f1Sjruoho 	signal(SIGCHLD, sigchld);
189068fb4f1Sjruoho 
190068fb4f1Sjruoho 	switch (pid = fork()) {
191068fb4f1Sjruoho 	case 0:
192068fb4f1Sjruoho 		child(&zero);
193068fb4f1Sjruoho 		break;
194068fb4f1Sjruoho 	case -1:
195068fb4f1Sjruoho 		err(1, "fork");
196068fb4f1Sjruoho 	default:
19750e2e69cSskrll 		sleep(1);
198068fb4f1Sjruoho 		switch (waitpid(pid, &status, WNOHANG)) {
199068fb4f1Sjruoho 		case -1:
200068fb4f1Sjruoho 			err(1, "wait");
201068fb4f1Sjruoho 		case 0:
202068fb4f1Sjruoho 			if (kill(pid, SIGKILL) == -1)
203068fb4f1Sjruoho 				err(1, "kill");
204068fb4f1Sjruoho 			atf_tc_fail("pselect() did not receive signal");
205068fb4f1Sjruoho 			break;
206068fb4f1Sjruoho 		default:
207068fb4f1Sjruoho 			break;
208068fb4f1Sjruoho 		}
209068fb4f1Sjruoho 	}
210068fb4f1Sjruoho }
211068fb4f1Sjruoho 
212*2c234657Sriastradh ATF_TC(select_badfd);
213*2c234657Sriastradh ATF_TC_HEAD(select_badfd, tc)
214*2c234657Sriastradh {
215*2c234657Sriastradh 
216*2c234657Sriastradh 	atf_tc_set_md_var(tc, "descr", "Checks select rejects bad fds");
217*2c234657Sriastradh }
218*2c234657Sriastradh 
219*2c234657Sriastradh ATF_TC_BODY(select_badfd, tc)
220*2c234657Sriastradh {
221*2c234657Sriastradh 	int fd;
222*2c234657Sriastradh 
223*2c234657Sriastradh 	for (fd = 0; fd < FD_SETSIZE; fd++) {
224*2c234657Sriastradh 		fd_set readfds;
225*2c234657Sriastradh 		int ret, error;
226*2c234657Sriastradh 
227*2c234657Sriastradh 		if (fcntl(fd, F_GETFL) != -1 || errno != EBADF)
228*2c234657Sriastradh 			continue;
229*2c234657Sriastradh 
230*2c234657Sriastradh 		FD_ZERO(&readfds);
231*2c234657Sriastradh 		FD_SET(fd, &readfds);
232*2c234657Sriastradh 		alarm(5);
233*2c234657Sriastradh 		errno = 0;
234*2c234657Sriastradh 		ret = select(fd + 1, &readfds, NULL, NULL, NULL);
235*2c234657Sriastradh 		error = errno;
236*2c234657Sriastradh 		alarm(0);
237*2c234657Sriastradh 		errno = error;
238*2c234657Sriastradh 		ATF_CHECK_ERRNO(EBADF, ret == -1);
239*2c234657Sriastradh 	}
240*2c234657Sriastradh }
241*2c234657Sriastradh 
242068fb4f1Sjruoho ATF_TP_ADD_TCS(tp)
243068fb4f1Sjruoho {
244068fb4f1Sjruoho 
245068fb4f1Sjruoho 	ATF_TP_ADD_TC(tp, pselect_sigmask);
246068fb4f1Sjruoho 	ATF_TP_ADD_TC(tp, pselect_timeout);
247*2c234657Sriastradh 	ATF_TP_ADD_TC(tp, select_badfd);
248068fb4f1Sjruoho 
249068fb4f1Sjruoho 	return atf_no_error();
250068fb4f1Sjruoho }
251