linux_sigaction.c revision 1.1
1/*	$NetBSD: linux_sigaction.c,v 1.1 1995/02/28 23:25:12 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
66int
67bsd_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
132int
133linux_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 */
202static void
203linux_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
219void
220bsd_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 */
242void
243linux_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
258void
259bsd_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 */
281int
282linux_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 */
336int
337linux_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 */
376int
377linux_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 */
440int
441linux_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 */
456int
457linux_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
479int
480linux_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
496int
497linux_sigsuspend(p, uap, retval)
498	struct proc *p;
499	struct linux_sigsuspend_args /* {
500		syscallarg(int) mask;
501	} */ *uap;
502	register_t *retval;
503{
504	struct sigsuspend_args ssa;
505
506	linux_to_bsd_sigset(&SCARG(uap, mask), &SCARG(&ssa, mask));
507	return sigsuspend(p, &ssa, retval);
508}
509
510/*
511 * Once more: only a signal conversion is needed.
512 */
513int
514linux_kill(p, uap, retval)
515	struct proc *p;
516	struct linux_kill_args /* {
517		syscallarg(int) pid;
518		syscallarg(int) signum;
519	} */ *uap;
520	register_t *retval;
521{
522	SCARG(uap, signum) = linux_to_bsd_sig(SCARG(uap, signum));
523	return kill(p, (struct kill_args *) uap, retval);
524}
525