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