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 34static int test_getown_fcntl(int); 35static int test_getown_ioctl(int); 36static int test_gpgrp(int); 37static int test_setown_fcntl(int); 38static int test_setown_ioctl(int); 39static int test_sigio(int); 40static int test_spgrp(int); 41 42static int test_common_getown(int, int); 43static int test_common_setown(int, int); 44 45static void sigio(int); 46static void syncrecv(int, int); 47static void syncsend(int, int); 48 49static volatile sig_atomic_t nsigio; 50 51static int 52test_getown_fcntl(int fd) 53{ 54 return test_common_getown(fd, 1); 55} 56 57static int 58test_getown_ioctl(int fd) 59{ 60 return test_common_getown(fd, 0); 61} 62 63static int 64test_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 84static int 85test_setown_fcntl(int fd) 86{ 87 return test_common_setown(fd, 1); 88} 89 90static int 91test_setown_ioctl(int fd) 92{ 93 return test_common_setown(fd, 0); 94} 95 96static int 97test_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 172static int 173test_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 193static int 194test_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 232static int 233test_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 280static void 281sigio(int signo) 282{ 283 nsigio++; 284} 285 286static void 287syncrecv(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 297static void 298syncsend(int fd, int id) 299{ 300 if (write(fd, &id, sizeof(id)) == -1) 301 err(1, "%s: write", __func__); 302} 303 304int 305main(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