sigio.c revision 1.2
1/* $OpenBSD: sigio.c,v 1.2 2018/11/20 18:49:42 anton Exp $ */ 2 3/* 4 * Copyright (c) 2018 Anton Lindqvist <anton@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/ioctl.h> 20#include <sys/time.h> 21#include <sys/wait.h> 22 23#include <dev/wscons/wsconsio.h> 24 25#include <err.h> 26#include <fcntl.h> 27#include <signal.h> 28#include <stdio.h> 29#include <stdlib.h> 30#include <string.h> 31#include <unistd.h> 32 33static int test_setown_fcntl(int); 34static int test_setown_ioctl(int); 35static int test_sigio(int); 36static int test_spgrp(int); 37 38static int test_common_setown(int, int); 39 40static void sigio(int); 41static void syncrecv(int, int); 42static void syncsend(int, int); 43static __dead void usage(void); 44 45static volatile sig_atomic_t nsigio; 46 47static struct { 48 const char *name; 49 int (*fn)(int); 50} tests[] = { 51 { "setown-fcntl", test_setown_fcntl }, 52 { "setown-ioctl", test_setown_ioctl }, 53 { "sigio", test_sigio }, 54 { "spgrp", test_spgrp }, 55 { NULL, NULL }, 56}; 57 58int 59main(int argc, char *argv[]) 60{ 61 int (*fn)(int) = NULL; 62 const char *dev = NULL; 63 int c, fd, i; 64 int prereq = 0; 65 66 while ((c = getopt(argc, argv, "d:p")) != -1) 67 switch (c) { 68 case 'd': 69 dev = optarg; 70 break; 71 case 'p': 72 prereq = 1; 73 break; 74 default: 75 usage(); 76 } 77 argc -= optind; 78 argv += optind; 79 if (dev == NULL || argc != 1) 80 usage(); 81 82 fd = open(dev, O_RDWR); 83 if (fd == -1) 84 err(1, "open: %s", dev); 85 if (prereq) 86 return 0; 87 88 for (i = 0; tests[i].name != NULL; i++) { 89 if (strcmp(argv[0], tests[i].name)) 90 continue; 91 92 fn = tests[i].fn; 93 break; 94 } 95 if (fn == NULL) 96 errx(1, "%s: no such test", argv[0]); 97 98 return fn(fd); 99} 100 101static int 102test_setown_fcntl(int fd) 103{ 104 return test_common_setown(fd, 1); 105} 106 107static int 108test_setown_ioctl(int fd) 109{ 110 return test_common_setown(fd, 0); 111} 112 113static int 114test_sigio(int fd) 115{ 116 struct wscons_event ev; 117 int cfd[2], pfd[2]; 118 ssize_t n; 119 pid_t pid; 120 int arg, len, status; 121 122 if (pipe(cfd) == -1) 123 err(1, "pipe"); 124 if (pipe(pfd) == -1) 125 err(1, "pipe"); 126 127 arg = getpid(); 128 if (ioctl(fd, FIOSETOWN, &arg) == -1) 129 err(1, "ioctl: FIOSETOWN"); 130 131 /* Enable async IO. */ 132 arg = 1; 133 if (ioctl(fd, FIOASYNC, &arg) == -1) 134 err(1, "ioctl: FIOASYNC"); 135 136 pid = fork(); 137 if (pid == -1) 138 err(1, "fork"); 139 if (pid == 0) { 140 close(cfd[1]); 141 close(pfd[0]); 142 143 syncsend(pfd[1], 1); 144 syncrecv(cfd[0], 2); 145 146 memset(&ev, 0, sizeof(ev)); 147 if (ioctl(fd, WSMUXIO_INJECTEVENT, &ev) == -1) 148 err(1, "ioctl: WSMUXIO_INJECTEVENT"); 149 150 close(cfd[0]); 151 close(pfd[1]); 152 _exit(0); 153 } 154 close(cfd[0]); 155 close(pfd[1]); 156 157 syncrecv(pfd[0], 1); 158 159 if (signal(SIGIO, sigio) == SIG_ERR) 160 err(1, "signal"); 161 162 syncsend(cfd[1], 2); 163 164 if (waitpid(pid, &status, 0) == -1) 165 err(1, "waitpid"); 166 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 167 errx(1, "child exited %d", WEXITSTATUS(status)); 168 if (WIFSIGNALED(status)) 169 errx(1, "child killed by signal %d", WTERMSIG(status)); 170 171 if (nsigio != 1) 172 errx(1, "expected SIGIO to be received once, got %d", nsigio); 173 174 len = sizeof(ev); 175 n = read(fd, &ev, len); 176 if (n == -1) 177 err(1, "read"); 178 if (n != len) 179 errx(1, "read: expected %d bytes, got %ld", len, n); 180 181 /* Disable async IO. */ 182 arg = 0; 183 if (ioctl(fd, FIOASYNC, &arg) == -1) 184 err(1, "ioctl: FIOASYNC"); 185 186 return 0; 187} 188 189static int 190test_spgrp(int fd) 191{ 192 int arg; 193 194 /* The process group must be able to receive SIGIO. */ 195 arg = getpgrp(); 196 if (ioctl(fd, TIOCSPGRP, &arg) == -1) 197 errx(1, "ioctl: TIOCSPGRP"); 198 199 /* Bogus process groups must be rejected. */ 200 arg = -getpgrp(); 201 if (ioctl(fd, TIOCSPGRP, &arg) != -1) 202 errx(1, "ioctl: TIOCSPGRP: %d accepted", arg); 203 arg = 1000000; 204 if (ioctl(fd, TIOCSPGRP, &arg) != -1) 205 errx(1, "ioctl: TIOCSPGRP: %d accepted", arg); 206 207 return 0; 208} 209 210static int 211test_common_setown(int fd, int dofcntl) 212{ 213 int arg; 214 215 /* The process must be able to receive SIGIO. */ 216 arg = getpid(); 217 if (dofcntl) { 218 if (fcntl(fd, F_SETOWN, arg) == -1) 219 errx(1, "fcntl: F_SETOWN: process rejected"); 220 } else { 221 if (ioctl(fd, FIOSETOWN, &arg) == -1) 222 errx(1, "ioctl: FIOSETOWN: process rejected"); 223 } 224 225 /* The process group must be able to receive SIGIO. */ 226 arg = -getpgrp(); 227 if (dofcntl) { 228 if (fcntl(fd, F_SETOWN, arg) == -1) 229 errx(1, "fcntl: F_SETOWN: process group rejected"); 230 } else { 231 if (ioctl(fd, FIOSETOWN, &arg) == -1) 232 errx(1, "ioctl: FIOSETOWN: process group rejected"); 233 } 234 235 /* A bogus process must be rejected. */ 236 arg = 1000000; 237 if (dofcntl) { 238 if (fcntl(fd, F_SETOWN, arg) != -1) 239 errx(1, "fcntl: F_SETOWN: bogus process accepted"); 240 } else { 241 if (ioctl(fd, FIOSETOWN, &arg) != -1) 242 errx(1, "ioctl: FIOSETOWN: bogus process accepted"); 243 } 244 245 /* A bogus process group must be rejected. */ 246 arg = -1000000; 247 if (dofcntl) { 248 if (fcntl(fd, F_SETOWN, arg) != -1) 249 errx(1, "fcntl: F_SETOWN: bogus process group accepted"); 250 } else { 251 if (ioctl(fd, FIOSETOWN, &arg) != -1) 252 errx(1, "ioctl: FIOSETOWN: bogus process group accepted"); 253 } 254 255 return 0; 256} 257 258static void 259sigio(int signo) 260{ 261 nsigio++; 262} 263 264static void 265syncrecv(int fd, int id) 266{ 267 int r; 268 269 if (read(fd, &r, sizeof(r)) == -1) 270 err(1, "%s: read", __func__); 271 if (r != id) 272 errx(1, "%s: expected %d, got %d", __func__, id, r); 273} 274 275static void 276syncsend(int fd, int id) 277{ 278 if (write(fd, &id, sizeof(id)) == -1) 279 err(1, "%s: write", __func__); 280} 281 282static __dead void 283usage(void) 284{ 285 fprintf(stderr, "usage: sigio [-p] -d device test\n"); 286 exit(1); 287} 288