xref: /netbsd-src/sys/compat/linux/arch/i386/linux_sigarray.c (revision 1f2744e6e4915c9da2a3f980279398c4cf7d5e6d)
1 /*	$NetBSD: linux_sigarray.c,v 1.3 1995/03/10 22:55:04 fvdl Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Frank van der Linden
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed for the NetBSD Project
18  *      by Frank van der Linden
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * heavily from: svr4_signal.c,v 1.7 1995/01/09 01:04:21 christos Exp
34  */
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/namei.h>
39 #include <sys/proc.h>
40 #include <sys/filedesc.h>
41 #include <sys/ioctl.h>
42 #include <sys/mount.h>
43 #include <sys/kernel.h>
44 #include <sys/signal.h>
45 #include <sys/signalvar.h>
46 #include <sys/malloc.h>
47 
48 #include <sys/syscallargs.h>
49 
50 #include <compat/linux/linux_types.h>
51 #include <compat/linux/linux_syscallargs.h>
52 #include <compat/linux/linux_util.h>
53 #include <compat/linux/linux_signal.h>
54 
55 /*
56  * Most of ths stuff in this file is taken from Christos' SVR4 emul
57  * code. The things that need to be done are largely the same, so
58  * re-inventing the wheel doesn't make much sense.
59  */
60 
61 /*
62  * Some boring signal conversion functions. Just a switch() for all signals;
63  * return the converted signal number, 0 if not supported.
64  */
65 
66 int
67 bsd_to_linux_sig(sig)
68 	int sig;
69 {
70 	switch(sig) {
71 	case SIGHUP:
72 		return LINUX_SIGHUP;
73 	case SIGINT:
74 		return LINUX_SIGINT;
75 	case SIGQUIT:
76 		return LINUX_SIGQUIT;
77 	case SIGILL:
78 		return LINUX_SIGILL;
79 	case SIGTRAP:
80 		return LINUX_SIGTRAP;
81 	case SIGABRT:
82 		return LINUX_SIGABRT;
83 	case SIGFPE:
84 		return LINUX_SIGFPE;
85 	case SIGKILL:
86 		return LINUX_SIGKILL;
87 	case SIGBUS:
88 		return LINUX_SIGBUS;
89 	case SIGSEGV:
90 		return LINUX_SIGSEGV;
91 	case SIGPIPE:
92 		return LINUX_SIGPIPE;
93 	case SIGALRM:
94 		return LINUX_SIGALRM;
95 	case SIGTERM:
96 		return LINUX_SIGTERM;
97 	case SIGURG:
98 		return LINUX_SIGURG;
99 	case SIGSTOP:
100 		return LINUX_SIGSTOP;
101 	case SIGTSTP:
102 		return LINUX_SIGTSTP;
103 	case SIGCONT:
104 		return LINUX_SIGCONT;
105 	case SIGCHLD:
106 		return LINUX_SIGCHLD;
107 	case SIGTTIN:
108 		return LINUX_SIGTTIN;
109 	case SIGTTOU:
110 		return LINUX_SIGTTOU;
111 	case SIGIO:
112 		return LINUX_SIGIO;
113 	case SIGXCPU:
114 		return LINUX_SIGXCPU;
115 	case SIGXFSZ:
116 		return LINUX_SIGXFSZ;
117 	case SIGVTALRM:
118 		return LINUX_SIGVTALRM;
119 	case SIGPROF:
120 		return LINUX_SIGPROF;
121 	case SIGWINCH:
122 		return LINUX_SIGWINCH;
123 	case SIGUSR1:
124 		return LINUX_SIGUSR1;
125 	case SIGUSR2:
126 		return LINUX_SIGUSR2;
127 	/* Not supported: EMT, SYS, INFO */
128 	}
129 	return 0;
130 }
131 
132 int
133 linux_to_bsd_sig(sig)
134 	int sig;
135 {
136 	switch(sig) {
137 	case LINUX_SIGHUP:
138 		return SIGHUP;
139 	case LINUX_SIGINT:
140 		return SIGINT;
141 	case LINUX_SIGQUIT:
142 		return SIGQUIT;
143 	case LINUX_SIGILL:
144 		return SIGILL;
145 	case LINUX_SIGTRAP:
146 		return SIGTRAP;
147 	case LINUX_SIGABRT:
148 		return SIGABRT;
149 	case LINUX_SIGBUS:
150 		return SIGBUS;
151 	case LINUX_SIGFPE:
152 		return SIGFPE;
153 	case LINUX_SIGKILL:
154 		return SIGKILL;
155 	case LINUX_SIGUSR1:
156 		return SIGUSR1;
157 	case LINUX_SIGSEGV:
158 		return SIGSEGV;
159 	case LINUX_SIGUSR2:
160 		return SIGUSR2;
161 	case LINUX_SIGPIPE:
162 		return SIGPIPE;
163 	case LINUX_SIGALRM:
164 		return SIGALRM;
165 	case LINUX_SIGTERM:
166 		return SIGTERM;
167 	case LINUX_SIGCHLD:
168 		return SIGCHLD;
169 	case LINUX_SIGCONT:
170 		return SIGCONT;
171 	case LINUX_SIGSTOP:
172 		return SIGSTOP;
173 	case LINUX_SIGTSTP:
174 		return SIGTSTP;
175 	case LINUX_SIGTTIN:
176 		return SIGTTIN;
177 	case LINUX_SIGTTOU:
178 		return SIGTTOU;
179 	case LINUX_SIGURG:
180 		return SIGURG;
181 	case LINUX_SIGXCPU:
182 		return SIGXCPU;
183 	case LINUX_SIGXFSZ:
184 		return SIGXFSZ;
185 	case LINUX_SIGVTALRM:
186 		return SIGVTALRM;
187 	case LINUX_SIGPROF:
188 		return SIGPROF;
189 	case LINUX_SIGWINCH:
190 		return SIGWINCH;
191 	case LINUX_SIGIO:
192 		return SIGIO;
193 	/* Not supported: STKFLT, PWR */
194 	}
195 	return 0;
196 }
197 
198 /*
199  * Ok, we know that Linux and BSD signals both are just an unsigned int.
200  * Don't bother to use the sigismember() stuff for now.
201  */
202 static void
203 linux_to_bsd_sigset(lss, bss)
204 	const linux_sigset_t *lss;
205 	sigset_t *bss;
206 {
207 	int i, newsig;
208 
209 	*bss = (sigset_t) 0;
210 	for (i = 1; i <= LINUX_NSIG; i++) {
211 		if (*lss & sigmask(i)) {
212 			newsig = linux_to_bsd_sig(i);
213 			if (newsig)
214 				*bss |= sigmask(newsig);
215 		}
216 	}
217 }
218 
219 void
220 bsd_to_linux_sigset(bss, lss)
221 	const sigset_t *bss;
222 	linux_sigset_t *lss;
223 {
224 	int i, newsig;
225 
226 	*lss = (linux_sigset_t) 0;
227 	for (i = 1; i <= NSIG; i++) {
228 		if (*bss & sigmask(i)) {
229 			newsig = bsd_to_linux_sig(i);
230 			if (newsig)
231 				*lss |= sigmask(newsig);
232 		}
233 	}
234 }
235 
236 /*
237  * Convert between Linux and BSD sigaction structures. Linux has
238  * one extra field (sa_restorer) which we don't support. The Linux
239  * SA_ONESHOT and SA_NOMASK flags (which together form the old
240  * SysV signal behavior) are silently ignored. XXX
241  */
242 void
243 linux_to_bsd_sigaction(lsa, bsa)
244 	struct linux_sigaction *lsa;
245 	struct sigaction *bsa;
246 {
247 	bsa->sa_handler = lsa->sa_handler;
248 	linux_to_bsd_sigset(&bsa->sa_mask, &lsa->sa_mask);
249 	bsa->sa_flags = 0;
250 	bsa->sa_flags |= cvtto_bsd_mask(lsa->sa_flags, LINUX_SA_NOCLDSTOP,
251 	    SA_NOCLDSTOP);
252 	bsa->sa_flags |= cvtto_bsd_mask(lsa->sa_flags, LINUX_SA_ONSTACK,
253 	    SA_ONSTACK);
254 	bsa->sa_flags |= cvtto_bsd_mask(lsa->sa_flags, LINUX_SA_RESTART,
255 	    SA_RESTART);
256 }
257 
258 void
259 bsd_to_linux_sigaction(bsa, lsa)
260 	struct sigaction *bsa;
261 	struct linux_sigaction *lsa;
262 {
263 	lsa->sa_handler = bsa->sa_handler;
264 	bsd_to_linux_sigset(&lsa->sa_mask, &bsa->sa_mask);
265 	lsa->sa_flags = 0;
266 	lsa->sa_flags |= cvtto_linux_mask(bsa->sa_flags, SA_NOCLDSTOP,
267 	    LINUX_SA_NOCLDSTOP);
268 	lsa->sa_flags |= cvtto_linux_mask(bsa->sa_flags, SA_ONSTACK,
269 	    LINUX_SA_ONSTACK);
270 	lsa->sa_flags |= cvtto_linux_mask(bsa->sa_flags, SA_RESTART,
271 	    LINUX_SA_RESTART);
272 	lsa->sa_restorer = NULL;
273 }
274 
275 
276 /*
277  * The Linux sigaction() system call. Do the usual conversions,
278  * and just call sigaction(). Some flags and values are silently
279  * ignored (see above).
280  */
281 int
282 linux_sigaction(p, uap, retval)
283 	register struct proc *p;
284 	struct linux_sigaction_args /* {
285 		syscallarg(int) signum;
286 		syscallarg(struct linux_sigaction *) nsa;
287 		syscallarg(struct linux_sigaction *) osa;
288 	} */ *uap;
289 	register_t *retval;
290 {
291 	struct sigaction *nbsda = NULL, *obsda = NULL, tmpbsda;
292 	struct linux_sigaction *nlsa, *olsa, tmplsa;
293 	struct sigaction_args sa;
294 	caddr_t sg;
295 	int error;
296 
297 	sg = stackgap_init();
298 	olsa = SCARG(uap, osa);
299 	nlsa = SCARG(uap, nsa);
300 
301 	if (olsa != NULL)
302 		obsda = stackgap_alloc(&sg, sizeof (struct sigaction));
303 
304 	if (nlsa != NULL) {
305 		nbsda = stackgap_alloc(&sg, sizeof (struct sigaction));
306 		if ((error = copyin(nlsa, &tmplsa, sizeof tmplsa)))
307 			return error;
308 		linux_to_bsd_sigaction(&tmplsa, &tmpbsda);
309 		if ((error = copyout(&tmpbsda, nbsda, sizeof tmpbsda)))
310 			return error;
311 	}
312 
313 	SCARG(&sa, signum) = linux_to_bsd_sig(SCARG(uap, signum));
314 	SCARG(&sa, nsa) = nbsda;
315 	SCARG(&sa, osa) = obsda;
316 
317 	if ((error = sigaction(p, &sa, retval)))
318 		return error;
319 
320 	if (olsa != NULL) {
321 		if ((error = copyin(obsda, &tmpbsda, sizeof tmpbsda)))
322 			return error;
323 		bsd_to_linux_sigaction(&tmpbsda, &tmplsa);
324 		if ((error = copyout(&tmplsa, olsa, sizeof tmplsa)))
325 			return error;
326 	}
327 	return 0;
328 }
329 
330 /*
331  * The Linux signal() system call. I think that the signal() in the C
332  * library actually calls sigaction, so I doubt this one is ever used.
333  * But hey, it can't hurt having it here. The same restrictions as for
334  * sigaction() apply.
335  */
336 int
337 linux_signal(p, uap, retval)
338 	register struct proc *p;
339 	struct linux_signal_args /* {
340 		syscallarg(int) sig;
341 		syscallarg(linux_handler_t) handler;
342 	} */ *uap;
343 	register_t *retval;
344 {
345 	caddr_t sg;
346 	struct sigaction_args sa_args;
347 	struct sigaction *osa, *nsa, tmpsa;
348 	int error;
349 
350 	sg = stackgap_init();
351 	nsa = stackgap_alloc(&sg, sizeof *nsa);
352 	osa = stackgap_alloc(&sg, sizeof *osa);
353 
354 	tmpsa.sa_handler = SCARG(uap, handler);
355 	tmpsa.sa_mask = (sigset_t) 0;
356 	tmpsa.sa_flags = 0;
357 	if ((error = copyout(&tmpsa, nsa, sizeof tmpsa)))
358 		return error;
359 
360 	SCARG(&sa_args, signum) = linux_to_bsd_sig(SCARG(uap, sig));
361 	SCARG(&sa_args, osa) = osa;
362 	SCARG(&sa_args, nsa) = nsa;
363 	if ((error = sigaction(p, &sa_args, retval)))
364 		return error;
365 
366 	if ((error = copyin(osa, &tmpsa, sizeof *osa)))
367 		return error;
368 	retval[0] = (register_t) tmpsa.sa_handler;
369 
370 	return 0;
371 }
372 
373 /*
374  * This is just a copy of the svr4 compat one. I feel so creative now.
375  */
376 int
377 linux_sigprocmask(p, uap, retval)
378 	register struct proc *p;
379 	register struct linux_sigprocmask_args /* {
380 		syscallarg(int) how;
381 		syscallarg(linux_sigset_t *) set;
382 		syscallarg(linux_sigset_t * oset;
383 	} */ *uap;
384 	register_t *retval;
385 {
386 	linux_sigset_t ss;
387 	sigset_t bs;
388 	int error = 0;
389 
390 	*retval = 0;
391 
392 	if (SCARG(uap, oset) != NULL) {
393 		/* Fix the return value first if needed */
394 		bsd_to_linux_sigset(&p->p_sigmask, &ss);
395 		if ((error = copyout(&ss, SCARG(uap, oset), sizeof(ss))) != 0)
396 			return error;
397 	}
398 
399 	if (SCARG(uap, set) == NULL)
400 		/* Just examine */
401 		return 0;
402 
403 	if ((error = copyin(SCARG(uap, set), &ss, sizeof(ss))) != 0)
404 		return error;
405 
406 	linux_to_bsd_sigset(&ss, &bs);
407 
408 	(void) splhigh();
409 
410 	switch (SCARG(uap, how)) {
411 	case LINUX_SIG_BLOCK:
412 		p->p_sigmask |= bs & ~sigcantmask;
413 		break;
414 
415 	case LINUX_SIG_UNBLOCK:
416 		p->p_sigmask &= ~bs;
417 		break;
418 
419 	case LINUX_SIG_SETMASK:
420 		p->p_sigmask = bs & ~sigcantmask;
421 		break;
422 
423 	default:
424 		error = EINVAL;
425 		break;
426 	}
427 
428 	(void) spl0();
429 
430 	return error;
431 }
432 
433 /*
434  * The functions below really make no distinction between an int
435  * and [linux_]sigset_t. This is ok for now, but it might break
436  * sometime. Then again, sigset_t is trusted to be an int everywhere
437  * else in the kernel too.
438  */
439 /* ARGSUSED */
440 int
441 linux_siggetmask(p, uap, retval)
442 	struct proc *p;
443 	void *uap;
444 	register_t *retval;
445 {
446 	bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *) retval);
447 	return 0;
448 }
449 
450 /*
451  * The following three functions fiddle with a process' signal mask.
452  * Convert the signal masks because of the different signal
453  * values for Linux. The need for this is the reason why
454  * they are here, and have not been mapped directly.
455  */
456 int
457 linux_sigsetmask(p, uap, retval)
458 	struct proc *p;
459 	struct linux_sigsetmask_args /* {
460 		syscallarg(linux_sigset_t) mask;
461 	} */ *uap;
462 	register_t *retval;
463 {
464 	linux_sigset_t mask;
465 	sigset_t bsdsig;
466 
467 	bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *) retval);
468 
469 	mask = SCARG(uap, mask);
470 	bsd_to_linux_sigset(&mask, &bsdsig);
471 
472 	splhigh();
473 	p->p_sigmask = bsdsig & ~sigcantmask;
474 	spl0();
475 
476 	return 0;
477 }
478 
479 int
480 linux_sigpending(p, uap, retval)
481 	struct proc *p;
482 	struct linux_sigpending_args /* {
483 		syscallarg(linux_sigset_t *) mask;
484 	} */ *uap;
485 	register_t *retval;
486 {
487 	sigset_t bsdsig;
488 	linux_sigset_t linuxsig;
489 
490 	bsdsig = p->p_siglist & p->p_sigmask;
491 
492 	bsd_to_linux_sigset(&bsdsig, &linuxsig);
493 	return copyout(&linuxsig, SCARG(uap, mask), sizeof linuxsig);
494 }
495 
496 int
497 linux_sigsuspend(p, uap, retval)
498 	struct proc *p;
499 	struct linux_sigsuspend_args /* {
500 		syscallarg(caddr_t) restart;
501 		syscallarg(int) oldmask;
502 		syscallarg(int) mask;
503 	} */ *uap;
504 	register_t *retval;
505 {
506 	struct sigsuspend_args ssa;
507 
508 	linux_to_bsd_sigset(&SCARG(uap, mask), &SCARG(&ssa, mask));
509 	return sigsuspend(p, &ssa, retval);
510 }
511 
512 /*
513  * The deprecated pause(2), which is really just an instance
514  * of sigsuspend(2).
515  */
516 int
517 linux_pause(p, uap, retval)
518 	struct proc *p;
519 	void *uap;
520 	register_t *retval;
521 {
522 	struct sigsuspend_args bsa;
523 
524 	SCARG(&bsa, mask) = p->p_sigmask;
525 	return sigsuspend(p, &bsa, retval);
526 }
527 
528 /*
529  * Once more: only a signal conversion is needed.
530  */
531 int
532 linux_kill(p, uap, retval)
533 	struct proc *p;
534 	struct linux_kill_args /* {
535 		syscallarg(int) pid;
536 		syscallarg(int) signum;
537 	} */ *uap;
538 	register_t *retval;
539 {
540 	SCARG(uap, signum) = linux_to_bsd_sig(SCARG(uap, signum));
541 	return kill(p, (struct kill_args *) uap, retval);
542 }
543