xref: /openbsd/regress/sys/dev/wscons/sigio.c (revision 36b1b8b4)
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