1272343Sngie/* $NetBSD: t_select.c,v 1.3 2012/03/18 07:00:52 jruoho Exp $ */ 2272343Sngie 3272343Sngie/*- 4272343Sngie * Copyright (c) 2011 The NetBSD Foundation, Inc. 5272343Sngie * All rights reserved. 6272343Sngie * 7272343Sngie * This code is derived from software contributed to The NetBSD Foundatiom 8272343Sngie * by Christos Zoulas. 9272343Sngie * 10272343Sngie * Redistribution and use in source and binary forms, with or without 11272343Sngie * modification, are permitted provided that the following conditions 12272343Sngie * are met: 13272343Sngie * 1. Redistributions of source code must retain the above copyright 14272343Sngie * notice, this list of conditions and the following disclaimer. 15272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 16272343Sngie * notice, this list of conditions and the following disclaimer in the 17272343Sngie * documentation and/or other materials provided with the distribution. 18272343Sngie * 19272343Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21272343Sngie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22272343Sngie * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23272343Sngie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24272343Sngie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25272343Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26272343Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27272343Sngie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28272343Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29272343Sngie * POSSIBILITY OF SUCH DAMAGE. 30272343Sngie */ 31272343Sngie 32272343Sngie#include <assert.h> 33272343Sngie#include <sys/types.h> 34272343Sngie#include <sys/select.h> 35272343Sngie#include <sys/wait.h> 36272343Sngie#include <err.h> 37272343Sngie#include <stdio.h> 38272343Sngie#include <string.h> 39272343Sngie#include <signal.h> 40272343Sngie#include <stdlib.h> 41272343Sngie#include <unistd.h> 42272343Sngie#include <errno.h> 43272343Sngie#include <fcntl.h> 44272343Sngie 45272343Sngie#include <atf-c.h> 46272343Sngie 47272343Sngiestatic sig_atomic_t keep_going = 1; 48272343Sngie 49272343Sngiestatic void 50276478Sngie#ifdef __FreeBSD__ 51276478Sngiesig_handler(int signum __unused) 52276478Sngie#else 53272343Sngiesig_handler(int signum) 54276478Sngie#endif 55272343Sngie{ 56272343Sngie keep_going = 0; 57272343Sngie} 58272343Sngie 59272343Sngiestatic void 60276478Sngie#ifdef __FreeBSD__ 61276478Sngiesigchld(int signum __unused) 62276478Sngie#else 63272343Sngiesigchld(int signum) 64276478Sngie#endif 65272343Sngie{ 66272343Sngie} 67272343Sngie 68272343Sngiestatic char 69272343Sngiextoa(uint8_t n) 70272343Sngie{ 71272343Sngie static const char xarray[] = "0123456789abcdef"; 72272343Sngie assert(n < sizeof(xarray)); 73272343Sngie return xarray[n]; 74272343Sngie} 75272343Sngie 76272343Sngiestatic const char * 77272343Sngieprmask(const sigset_t *m, char *buf, size_t len) 78272343Sngie{ 79272343Sngie size_t j = 2; 80272343Sngie assert(len >= 3 + sizeof(*m)); 81272343Sngie buf[0] = '0'; 82272343Sngie buf[1] = 'x'; 83272343Sngie#define N(p, a) (((p) >> ((a) * 4)) & 0xf) 84272343Sngie for (size_t i = __arraycount(m->__bits); i > 0; i--) { 85272343Sngie uint32_t p = m->__bits[i - 1]; 86272343Sngie for (size_t k = sizeof(p); k > 0; k--) 87272343Sngie buf[j++] = xtoa(N(p, k - 1)); 88272343Sngie } 89272343Sngie buf[j] = '\0'; 90272343Sngie return buf; 91272343Sngie} 92272343Sngie 93272343Sngiestatic void 94272343Sngiechild(const struct timespec *ts) 95272343Sngie{ 96272343Sngie struct sigaction sa; 97272343Sngie sigset_t set, oset, nset; 98272343Sngie char obuf[sizeof(oset) + 3], nbuf[sizeof(nset) + 3]; 99272343Sngie int fd; 100272343Sngie 101272343Sngie memset(&sa, 0, sizeof(sa)); 102272343Sngie sa.sa_handler = sig_handler; 103272343Sngie if ((fd = open("/dev/null", O_RDONLY)) == -1) 104272343Sngie err(1, "open"); 105272343Sngie 106272343Sngie if (sigaction(SIGTERM, &sa, NULL) == -1) 107272343Sngie err(1, "sigaction"); 108272343Sngie 109272343Sngie sigfillset(&set); 110272343Sngie if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) 111272343Sngie err(1, "sigprocmask"); 112272343Sngie 113272343Sngie if (sigprocmask(SIG_BLOCK, NULL, &oset) == -1) 114272343Sngie err(1, "sigprocmask"); 115272343Sngie 116272343Sngie sigemptyset(&set); 117272343Sngie 118272343Sngie for (;;) { 119272343Sngie fd_set rset; 120272343Sngie FD_ZERO(&rset); 121272343Sngie FD_SET(fd, &rset); 122272343Sngie if (pselect(1, &rset, NULL, NULL, ts, &set) == -1) { 123272343Sngie if(errno == EINTR) { 124272343Sngie if (!keep_going) 125272343Sngie break; 126272343Sngie } 127272343Sngie } 128272343Sngie if (ts) 129272343Sngie break; 130272343Sngie } 131272343Sngie if (sigprocmask(SIG_BLOCK, NULL, &nset) == -1) 132272343Sngie err(1, "sigprocmask"); 133272343Sngie if (memcmp(&oset, &nset, sizeof(oset)) != 0) 134272343Sngie atf_tc_fail("pselect() masks don't match " 135272343Sngie "after timeout %s != %s", 136272343Sngie prmask(&nset, nbuf, sizeof(nbuf)), 137272343Sngie prmask(&oset, obuf, sizeof(obuf))); 138272343Sngie} 139272343Sngie 140272343SngieATF_TC(pselect_sigmask); 141272343SngieATF_TC_HEAD(pselect_sigmask, tc) 142272343Sngie{ 143272343Sngie atf_tc_set_md_var(tc, "descr", "Checks pselect's temporary mask " 144272343Sngie "setting when a signal is received (PR lib/43625)"); 145272343Sngie} 146272343Sngie 147272343SngieATF_TC_BODY(pselect_sigmask, tc) 148272343Sngie{ 149272343Sngie pid_t pid; 150272343Sngie int status; 151272343Sngie 152272343Sngie signal(SIGCHLD, sigchld); 153272343Sngie 154272343Sngie switch (pid = fork()) { 155272343Sngie case 0: 156272343Sngie child(NULL); 157272343Sngie case -1: 158272343Sngie err(1, "fork"); 159272343Sngie default: 160272343Sngie sleep(1); 161272343Sngie if (kill(pid, SIGTERM) == -1) 162272343Sngie err(1, "kill"); 163272343Sngie sleep(1); 164272343Sngie switch (waitpid(pid, &status, WNOHANG)) { 165272343Sngie case -1: 166272343Sngie err(1, "wait"); 167272343Sngie case 0: 168272343Sngie if (kill(pid, SIGKILL) == -1) 169272343Sngie err(1, "kill"); 170272343Sngie atf_tc_fail("pselect() did not receive signal"); 171272343Sngie break; 172272343Sngie default: 173272343Sngie break; 174272343Sngie } 175272343Sngie } 176272343Sngie} 177272343Sngie 178272343SngieATF_TC(pselect_timeout); 179272343SngieATF_TC_HEAD(pselect_timeout, tc) 180272343Sngie{ 181272343Sngie 182272343Sngie atf_tc_set_md_var(tc, "descr", "Checks pselect's temporary mask " 183272343Sngie "setting when a timeout occurs"); 184272343Sngie} 185272343Sngie 186272343SngieATF_TC_BODY(pselect_timeout, tc) 187272343Sngie{ 188272343Sngie pid_t pid; 189272343Sngie int status; 190272343Sngie static const struct timespec zero = { 0, 0 }; 191272343Sngie 192272343Sngie signal(SIGCHLD, sigchld); 193272343Sngie 194272343Sngie switch (pid = fork()) { 195272343Sngie case 0: 196272343Sngie child(&zero); 197272343Sngie break; 198272343Sngie case -1: 199272343Sngie err(1, "fork"); 200272343Sngie default: 201272343Sngie sleep(1); 202272343Sngie switch (waitpid(pid, &status, WNOHANG)) { 203272343Sngie case -1: 204272343Sngie err(1, "wait"); 205272343Sngie case 0: 206272343Sngie if (kill(pid, SIGKILL) == -1) 207272343Sngie err(1, "kill"); 208272343Sngie atf_tc_fail("pselect() did not receive signal"); 209272343Sngie break; 210272343Sngie default: 211272343Sngie break; 212272343Sngie } 213272343Sngie } 214272343Sngie} 215272343Sngie 216272343SngieATF_TP_ADD_TCS(tp) 217272343Sngie{ 218272343Sngie 219272343Sngie ATF_TP_ADD_TC(tp, pselect_sigmask); 220272343Sngie ATF_TP_ADD_TC(tp, pselect_timeout); 221272343Sngie 222272343Sngie return atf_no_error(); 223272343Sngie} 224