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