sigio.c revision 1.3
1/* $OpenBSD: sigio.c,v 1.3 2018/11/20 19:37:10 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_getown_fcntl(int); 34static int test_getown_ioctl(int); 35static int test_gpgrp(int); 36static int test_setown_fcntl(int); 37static int test_setown_ioctl(int); 38static int test_sigio(int); 39static int test_spgrp(int); 40 41static int test_common_getown(int, int); 42static int test_common_setown(int, int); 43 44static void sigio(int); 45static void syncrecv(int, int); 46static void syncsend(int, int); 47static __dead void usage(void); 48 49static volatile sig_atomic_t nsigio; 50 51static struct { 52 const char *name; 53 int (*fn)(int); 54} tests[] = { 55 { "getown-fcntl", test_getown_fcntl }, 56 { "getown-ioctl", test_getown_ioctl }, 57 { "gpgrp", test_gpgrp }, 58 { "setown-fcntl", test_setown_fcntl }, 59 { "setown-ioctl", test_setown_ioctl }, 60 { "sigio", test_sigio }, 61 { "spgrp", test_spgrp }, 62 { NULL, NULL }, 63}; 64 65int 66main(int argc, char *argv[]) 67{ 68 int (*fn)(int) = NULL; 69 const char *dev = NULL; 70 int c, fd, i; 71 int prereq = 0; 72 73 while ((c = getopt(argc, argv, "d:p")) != -1) 74 switch (c) { 75 case 'd': 76 dev = optarg; 77 break; 78 case 'p': 79 prereq = 1; 80 break; 81 default: 82 usage(); 83 } 84 argc -= optind; 85 argv += optind; 86 if (dev == NULL || argc != 1) 87 usage(); 88 89 fd = open(dev, O_RDWR); 90 if (fd == -1) 91 err(1, "open: %s", dev); 92 if (prereq) 93 return 0; 94 95 for (i = 0; tests[i].name != NULL; i++) { 96 if (strcmp(argv[0], tests[i].name)) 97 continue; 98 99 fn = tests[i].fn; 100 break; 101 } 102 if (fn == NULL) 103 errx(1, "%s: no such test", argv[0]); 104 105 return fn(fd); 106} 107 108static int 109test_getown_fcntl(int fd) 110{ 111 return test_common_getown(fd, 1); 112} 113 114static int 115test_getown_ioctl(int fd) 116{ 117 return test_common_getown(fd, 0); 118} 119 120static int 121test_gpgrp(int fd) 122{ 123 int arg, pgrp; 124 125 if (ioctl(fd, TIOCGPGRP, &pgrp) == -1) 126 err(1, "ioctl: TIOCGPGRP"); 127 if (pgrp != 0) 128 errx(1, "ioctl: TIOCGPGRP: expected 0, got %d", pgrp); 129 130 arg = getpgrp(); 131 if (ioctl(fd, TIOCSPGRP, &arg) == -1) 132 err(1, "ioctl: TIOCSPGRP"); 133 if (ioctl(fd, TIOCGPGRP, &pgrp) == -1) 134 err(1, "ioctl: TIOCGPGRP"); 135 if (pgrp != getpgrp()) 136 errx(1, "ioctl: TIOCGPGRP: expected %d, got %d", getpgrp(), pgrp); 137 138 return 0; 139} 140 141static int 142test_setown_fcntl(int fd) 143{ 144 return test_common_setown(fd, 1); 145} 146 147static int 148test_setown_ioctl(int fd) 149{ 150 return test_common_setown(fd, 0); 151} 152 153static int 154test_sigio(int fd) 155{ 156 struct wscons_event ev; 157 int cfd[2], pfd[2]; 158 ssize_t n; 159 pid_t pid; 160 int arg, len, status; 161 162 if (pipe(cfd) == -1) 163 err(1, "pipe"); 164 if (pipe(pfd) == -1) 165 err(1, "pipe"); 166 167 arg = getpid(); 168 if (ioctl(fd, FIOSETOWN, &arg) == -1) 169 err(1, "ioctl: FIOSETOWN"); 170 171 /* Enable async IO. */ 172 arg = 1; 173 if (ioctl(fd, FIOASYNC, &arg) == -1) 174 err(1, "ioctl: FIOASYNC"); 175 176 pid = fork(); 177 if (pid == -1) 178 err(1, "fork"); 179 if (pid == 0) { 180 close(cfd[1]); 181 close(pfd[0]); 182 183 syncsend(pfd[1], 1); 184 syncrecv(cfd[0], 2); 185 186 memset(&ev, 0, sizeof(ev)); 187 if (ioctl(fd, WSMUXIO_INJECTEVENT, &ev) == -1) 188 err(1, "ioctl: WSMUXIO_INJECTEVENT"); 189 190 close(cfd[0]); 191 close(pfd[1]); 192 _exit(0); 193 } 194 close(cfd[0]); 195 close(pfd[1]); 196 197 syncrecv(pfd[0], 1); 198 199 if (signal(SIGIO, sigio) == SIG_ERR) 200 err(1, "signal"); 201 202 syncsend(cfd[1], 2); 203 204 if (waitpid(pid, &status, 0) == -1) 205 err(1, "waitpid"); 206 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 207 errx(1, "child exited %d", WEXITSTATUS(status)); 208 if (WIFSIGNALED(status)) 209 errx(1, "child killed by signal %d", WTERMSIG(status)); 210 211 if (nsigio != 1) 212 errx(1, "expected SIGIO to be received once, got %d", nsigio); 213 214 len = sizeof(ev); 215 n = read(fd, &ev, len); 216 if (n == -1) 217 err(1, "read"); 218 if (n != len) 219 errx(1, "read: expected %d bytes, got %ld", len, n); 220 221 /* Disable async IO. */ 222 arg = 0; 223 if (ioctl(fd, FIOASYNC, &arg) == -1) 224 err(1, "ioctl: FIOASYNC"); 225 226 return 0; 227} 228 229static int 230test_spgrp(int fd) 231{ 232 int arg; 233 234 /* The process group must be able to receive SIGIO. */ 235 arg = getpgrp(); 236 if (ioctl(fd, TIOCSPGRP, &arg) == -1) 237 errx(1, "ioctl: TIOCSPGRP"); 238 239 /* Bogus process groups must be rejected. */ 240 arg = -getpgrp(); 241 if (ioctl(fd, TIOCSPGRP, &arg) != -1) 242 errx(1, "ioctl: TIOCSPGRP: %d accepted", arg); 243 arg = 1000000; 244 if (ioctl(fd, TIOCSPGRP, &arg) != -1) 245 errx(1, "ioctl: TIOCSPGRP: %d accepted", arg); 246 247 return 0; 248} 249 250static int 251test_common_getown(int fd, int dofcntl) 252{ 253 int arg, pgrp; 254 255 if (dofcntl) { 256 pgrp = fcntl(fd, F_GETOWN); 257 if (pgrp == -1) 258 err(1, "fcntl: F_GETOWN"); 259 if (pgrp != 0) 260 errx(1, "fcntl: F_GETOWN: expected 0, got %d", pgrp); 261 } else { 262 if (ioctl(fd, FIOGETOWN, &pgrp) == -1) 263 err(1, "ioctl: FIOGETOWN"); 264 if (pgrp != 0) 265 errx(1, "ioctl: FIOGETOWN: expected 0, got %d", pgrp); 266 } 267 268 arg = getpid(); 269 if (ioctl(fd, FIOSETOWN, &arg) == -1) 270 err(1, "ioctl: FIOSETOWN"); 271 if (dofcntl) { 272 pgrp = fcntl(fd, F_GETOWN); 273 if (pgrp == -1) 274 err(1, "fcntl: F_GETOWN"); 275 if (pgrp != -getpgrp()) 276 errx(1, "fcntl: F_GETOWN: expected %d, got %d", 277 -getpgrp(), pgrp); 278 } else { 279 if (ioctl(fd, FIOGETOWN, &pgrp) == -1) 280 err(1, "ioctl: FIOGETOWN"); 281 if (pgrp != -getpgrp()) 282 errx(1, "ioctl: FIOGETOWN: expected %d, got %d", 283 -getpgrp(), pgrp); 284 } 285 286 return 0; 287} 288 289static int 290test_common_setown(int fd, int dofcntl) 291{ 292 int arg; 293 294 /* The process must be able to receive SIGIO. */ 295 arg = getpid(); 296 if (dofcntl) { 297 if (fcntl(fd, F_SETOWN, arg) == -1) 298 errx(1, "fcntl: F_SETOWN: process rejected"); 299 } else { 300 if (ioctl(fd, FIOSETOWN, &arg) == -1) 301 errx(1, "ioctl: FIOSETOWN: process rejected"); 302 } 303 304 /* The process group must be able to receive SIGIO. */ 305 arg = -getpgrp(); 306 if (dofcntl) { 307 if (fcntl(fd, F_SETOWN, arg) == -1) 308 errx(1, "fcntl: F_SETOWN: process group rejected"); 309 } else { 310 if (ioctl(fd, FIOSETOWN, &arg) == -1) 311 errx(1, "ioctl: FIOSETOWN: process group rejected"); 312 } 313 314 /* A bogus process must be rejected. */ 315 arg = 1000000; 316 if (dofcntl) { 317 if (fcntl(fd, F_SETOWN, arg) != -1) 318 errx(1, "fcntl: F_SETOWN: bogus process accepted"); 319 } else { 320 if (ioctl(fd, FIOSETOWN, &arg) != -1) 321 errx(1, "ioctl: FIOSETOWN: bogus process accepted"); 322 } 323 324 /* A bogus process group must be rejected. */ 325 arg = -1000000; 326 if (dofcntl) { 327 if (fcntl(fd, F_SETOWN, arg) != -1) 328 errx(1, "fcntl: F_SETOWN: bogus process group accepted"); 329 } else { 330 if (ioctl(fd, FIOSETOWN, &arg) != -1) 331 errx(1, "ioctl: FIOSETOWN: bogus process group accepted"); 332 } 333 334 return 0; 335} 336 337static void 338sigio(int signo) 339{ 340 nsigio++; 341} 342 343static void 344syncrecv(int fd, int id) 345{ 346 int r; 347 348 if (read(fd, &r, sizeof(r)) == -1) 349 err(1, "%s: read", __func__); 350 if (r != id) 351 errx(1, "%s: expected %d, got %d", __func__, id, r); 352} 353 354static void 355syncsend(int fd, int id) 356{ 357 if (write(fd, &id, sizeof(id)) == -1) 358 err(1, "%s: write", __func__); 359} 360 361static __dead void 362usage(void) 363{ 364 fprintf(stderr, "usage: sigio [-p] -d device test\n"); 365 exit(1); 366} 367