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
test_getown_fcntl(int fd)52 test_getown_fcntl(int fd)
53 {
54 return test_common_getown(fd, 1);
55 }
56
57 static int
test_getown_ioctl(int fd)58 test_getown_ioctl(int fd)
59 {
60 return test_common_getown(fd, 0);
61 }
62
63 static int
test_gpgrp(int fd)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
test_setown_fcntl(int fd)85 test_setown_fcntl(int fd)
86 {
87 return test_common_setown(fd, 1);
88 }
89
90 static int
test_setown_ioctl(int fd)91 test_setown_ioctl(int fd)
92 {
93 return test_common_setown(fd, 0);
94 }
95
96 static int
test_sigio(int fd)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
test_spgrp(int fd)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
test_common_getown(int fd,int dofcntl)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
test_common_setown(int fd,int dofcntl)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
sigio(int signo)281 sigio(int signo)
282 {
283 nsigio++;
284 }
285
286 static void
syncrecv(int fd,int id)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
syncsend(int fd,int id)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
main(int argc,char * argv[])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