linux_sigaction.c revision 1.8
1/*	$NetBSD: linux_sigaction.c,v 1.8 1995/09/19 22:37:34 thorpej 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_signal.h>
52#include <compat/linux/linux_syscallargs.h>
53#include <compat/linux/linux_util.h>
54
55#define	sigemptyset(s)		bzero((s), sizeof(*(s)))
56#define	sigismember(s, n)	(*(s) & sigmask(n))
57#define	sigaddset(s, n)		(*(s) |= sigmask(n))
58
59#define	linux_sigmask(n)	(1 << ((n) - 1))
60#define	linux_sigemptyset(s)	bzero((s), sizeof(*(s)))
61#define	linux_sigismember(s, n)	(*(s) & linux_sigmask(n))
62#define	linux_sigaddset(s, n)	(*(s) |= linux_sigmask(n))
63
64int bsd_to_linux_sig[] = {
65	0,
66	LINUX_SIGHUP,
67	LINUX_SIGINT,
68	LINUX_SIGQUIT,
69	LINUX_SIGILL,
70	LINUX_SIGTRAP,
71	LINUX_SIGABRT,
72	0,
73	LINUX_SIGFPE,
74	LINUX_SIGKILL,
75	LINUX_SIGBUS,
76	LINUX_SIGSEGV,
77	0,
78	LINUX_SIGPIPE,
79	LINUX_SIGALRM,
80	LINUX_SIGTERM,
81	LINUX_SIGURG,
82	LINUX_SIGSTOP,
83	LINUX_SIGTSTP,
84	LINUX_SIGCONT,
85	LINUX_SIGCHLD,
86	LINUX_SIGTTIN,
87	LINUX_SIGTTOU,
88	LINUX_SIGIO,
89	LINUX_SIGXCPU,
90	LINUX_SIGXFSZ,
91	LINUX_SIGVTALRM,
92	LINUX_SIGPROF,
93	LINUX_SIGWINCH,
94	0,
95	LINUX_SIGUSR1,
96	LINUX_SIGUSR2,
97};
98
99int linux_to_bsd_sig[] = {
100	0,
101	SIGHUP,
102	SIGINT,
103	SIGQUIT,
104	SIGILL,
105	SIGTRAP,
106	SIGABRT,
107	SIGBUS,
108	SIGFPE,
109	SIGKILL,
110	SIGUSR1,
111	SIGSEGV,
112	SIGUSR2,
113	SIGPIPE,
114	SIGALRM,
115	SIGTERM,
116	0,
117	SIGCHLD,
118	SIGCONT,
119	SIGSTOP,
120	SIGTSTP,
121	SIGTTIN,
122	SIGTTOU,
123	SIGURG,
124	SIGXCPU,
125	SIGXFSZ,
126	SIGVTALRM,
127	SIGPROF,
128	SIGWINCH,
129	SIGIO,
130	0,
131	0,
132};
133
134/*
135 * Ok, we know that Linux and BSD signals both are just an unsigned int.
136 * Don't bother to use the sigismember() stuff for now.
137 */
138void
139linux_to_bsd_sigset(lss, bss)
140	const linux_sigset_t *lss;
141	sigset_t *bss;
142{
143	int i, newsig;
144
145	sigemptyset(bss);
146	for (i = 1; i < LINUX_NSIG; i++) {
147		if (linux_sigismember(lss, i)) {
148			newsig = linux_to_bsd_sig[i];
149			if (newsig)
150				sigaddset(bss, newsig);
151		}
152	}
153}
154
155void
156bsd_to_linux_sigset(bss, lss)
157	const sigset_t *bss;
158	linux_sigset_t *lss;
159{
160	int i, newsig;
161
162	linux_sigemptyset(lss);
163	for (i = 1; i < NSIG; i++) {
164		if (sigismember(bss, i)) {
165			newsig = bsd_to_linux_sig[i];
166			if (newsig)
167				linux_sigaddset(lss, newsig);
168		}
169	}
170}
171
172/*
173 * Convert between Linux and BSD sigaction structures. Linux has
174 * one extra field (sa_restorer) which we don't support.
175 */
176void
177linux_to_bsd_sigaction(lsa, bsa)
178	struct linux_sigaction *lsa;
179	struct sigaction *bsa;
180{
181
182	bsa->sa_handler = lsa->sa_handler;
183	linux_to_bsd_sigset(&bsa->sa_mask, &lsa->sa_mask);
184	bsa->sa_flags = 0;
185	if ((lsa->sa_flags & LINUX_SA_ONSTACK) != 0)
186		bsa->sa_flags |= SA_ONSTACK;
187	if ((lsa->sa_flags & LINUX_SA_RESTART) != 0)
188		bsa->sa_flags |= SA_RESTART;
189	if ((lsa->sa_flags & LINUX_SA_ONESHOT) != 0)
190		bsa->sa_flags |= SA_RESETHAND;
191	if ((lsa->sa_flags & LINUX_SA_NOCLDSTOP) != 0)
192		bsa->sa_flags |= SA_NOCLDSTOP;
193	if ((lsa->sa_flags & LINUX_SA_NOMASK) != 0)
194		bsa->sa_flags |= SA_NODEFER;
195}
196
197void
198bsd_to_linux_sigaction(bsa, lsa)
199	struct sigaction *bsa;
200	struct linux_sigaction *lsa;
201{
202
203	lsa->sa_handler = bsa->sa_handler;
204	bsd_to_linux_sigset(&lsa->sa_mask, &bsa->sa_mask);
205	lsa->sa_flags = 0;
206	if ((bsa->sa_flags & SA_NOCLDSTOP) != 0)
207		lsa->sa_flags |= LINUX_SA_NOCLDSTOP;
208	if ((bsa->sa_flags & SA_ONSTACK) != 0)
209		lsa->sa_flags |= LINUX_SA_ONSTACK;
210	if ((bsa->sa_flags & SA_RESTART) != 0)
211		lsa->sa_flags |= LINUX_SA_RESTART;
212	if ((bsa->sa_flags & SA_NODEFER) != 0)
213		lsa->sa_flags |= LINUX_SA_NOMASK;
214	if ((bsa->sa_flags & SA_RESETHAND) != 0)
215		lsa->sa_flags |= LINUX_SA_ONESHOT;
216	lsa->sa_restorer = NULL;
217}
218
219
220/*
221 * The Linux sigaction() system call. Do the usual conversions,
222 * and just call sigaction(). Some flags and values are silently
223 * ignored (see above).
224 */
225int
226linux_sigaction(p, v, retval)
227	register struct proc *p;
228	void *v;
229	register_t *retval;
230{
231	struct linux_sigaction_args /* {
232		syscallarg(int) signum;
233		syscallarg(struct linux_sigaction *) nsa;
234		syscallarg(struct linux_sigaction *) osa;
235	} */ *uap = v;
236	struct linux_sigaction *nlsa, *olsa, tmplsa;
237	struct sigaction *nbsa, *obsa, tmpbsa;
238	struct sigaction_args sa;
239	caddr_t sg;
240	int error;
241
242	sg = stackgap_init(p->p_emul);
243	nlsa = SCARG(uap, nsa);
244	olsa = SCARG(uap, osa);
245
246	if (olsa != NULL)
247		obsa = stackgap_alloc(&sg, sizeof(struct sigaction));
248	else
249		obsa = NULL;
250
251	if (nlsa != NULL) {
252		nbsa = stackgap_alloc(&sg, sizeof(struct sigaction));
253		if ((error = copyin(nlsa, &tmplsa, sizeof(tmplsa))) != 0)
254			return error;
255		linux_to_bsd_sigaction(&tmplsa, &tmpbsa);
256		if ((error = copyout(&tmpbsa, nbsa, sizeof(tmpbsa))) != 0)
257			return error;
258	} else
259		nbsa = NULL;
260
261	SCARG(&sa, signum) = linux_to_bsd_sig[SCARG(uap, signum)];
262	SCARG(&sa, nsa) = nbsa;
263	SCARG(&sa, osa) = obsa;
264
265	if ((error = sigaction(p, &sa, retval)) != 0)
266		return error;
267
268	if (olsa != NULL) {
269		if ((error = copyin(obsa, &tmpbsa, sizeof(tmpbsa))) != 0)
270			return error;
271		bsd_to_linux_sigaction(&tmpbsa, &tmplsa);
272		if ((error = copyout(&tmplsa, olsa, sizeof(tmplsa))) != 0)
273			return error;
274	}
275
276	return 0;
277}
278
279/*
280 * The Linux signal() system call. I think that the signal() in the C
281 * library actually calls sigaction, so I doubt this one is ever used.
282 * But hey, it can't hurt having it here. The same restrictions as for
283 * sigaction() apply.
284 */
285int
286linux_signal(p, v, retval)
287	register struct proc *p;
288	void *v;
289	register_t *retval;
290{
291	struct linux_signal_args /* {
292		syscallarg(int) sig;
293		syscallarg(linux_handler_t) handler;
294	} */ *uap = v;
295	caddr_t sg;
296	struct sigaction_args sa_args;
297	struct sigaction *osa, *nsa, tmpsa;
298	int error;
299
300	sg = stackgap_init(p->p_emul);
301	nsa = stackgap_alloc(&sg, sizeof *nsa);
302	osa = stackgap_alloc(&sg, sizeof *osa);
303
304	tmpsa.sa_handler = SCARG(uap, handler);
305	tmpsa.sa_mask = (sigset_t) 0;
306	tmpsa.sa_flags = SA_RESETHAND | SA_NODEFER;
307	if ((error = copyout(&tmpsa, nsa, sizeof tmpsa)))
308		return error;
309
310	SCARG(&sa_args, signum) = linux_to_bsd_sig[SCARG(uap, sig)];
311	SCARG(&sa_args, osa) = osa;
312	SCARG(&sa_args, nsa) = nsa;
313	if ((error = sigaction(p, &sa_args, retval)))
314		return error;
315
316	if ((error = copyin(osa, &tmpsa, sizeof *osa)))
317		return error;
318	retval[0] = (register_t) tmpsa.sa_handler;
319
320	return 0;
321}
322
323/*
324 * This is just a copy of the svr4 compat one. I feel so creative now.
325 */
326int
327linux_sigprocmask(p, v, retval)
328	register struct proc *p;
329	void *v;
330	register_t *retval;
331{
332	struct linux_sigprocmask_args /* {
333		syscallarg(int) how;
334		syscallarg(linux_sigset_t *) set;
335		syscallarg(linux_sigset_t *) oset;
336	} */ *uap = v;
337	linux_sigset_t ss;
338	sigset_t bs;
339	int error = 0;
340
341	*retval = 0;
342
343	if (SCARG(uap, oset) != NULL) {
344		/* Fix the return value first if needed */
345		bsd_to_linux_sigset(&p->p_sigmask, &ss);
346		if ((error = copyout(&ss, SCARG(uap, oset), sizeof(ss))) != 0)
347			return error;
348	}
349
350	if (SCARG(uap, set) == NULL)
351		/* Just examine */
352		return 0;
353
354	if ((error = copyin(SCARG(uap, set), &ss, sizeof(ss))) != 0)
355		return error;
356
357	linux_to_bsd_sigset(&ss, &bs);
358
359	(void) splhigh();
360
361	switch (SCARG(uap, how)) {
362	case LINUX_SIG_BLOCK:
363		p->p_sigmask |= bs & ~sigcantmask;
364		break;
365
366	case LINUX_SIG_UNBLOCK:
367		p->p_sigmask &= ~bs;
368		break;
369
370	case LINUX_SIG_SETMASK:
371		p->p_sigmask = bs & ~sigcantmask;
372		break;
373
374	default:
375		error = EINVAL;
376		break;
377	}
378
379	(void) spl0();
380
381	return error;
382}
383
384/*
385 * The functions below really make no distinction between an int
386 * and [linux_]sigset_t. This is ok for now, but it might break
387 * sometime. Then again, sigset_t is trusted to be an int everywhere
388 * else in the kernel too.
389 */
390/* ARGSUSED */
391int
392linux_siggetmask(p, uap, retval)
393	register struct proc *p;
394	void *uap;
395	register_t *retval;
396{
397
398	bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *)retval);
399	return 0;
400}
401
402/*
403 * The following three functions fiddle with a process' signal mask.
404 * Convert the signal masks because of the different signal
405 * values for Linux. The need for this is the reason why
406 * they are here, and have not been mapped directly.
407 */
408int
409linux_sigsetmask(p, v, retval)
410	register struct proc *p;
411	void *v;
412	register_t *retval;
413{
414	struct linux_sigsetmask_args /* {
415		syscallarg(linux_sigset_t) mask;
416	} */ *uap = v;
417	linux_sigset_t mask;
418	sigset_t bsdsig;
419
420	bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *)retval);
421
422	mask = SCARG(uap, mask);
423	bsd_to_linux_sigset(&mask, &bsdsig);
424
425	splhigh();
426	p->p_sigmask = bsdsig & ~sigcantmask;
427	spl0();
428
429	return 0;
430}
431
432int
433linux_sigpending(p, v, retval)
434	register struct proc *p;
435	void *v;
436	register_t *retval;
437{
438	struct linux_sigpending_args /* {
439		syscallarg(linux_sigset_t *) mask;
440	} */ *uap = v;
441	sigset_t bs;
442	linux_sigset_t ls;
443
444	bs = p->p_siglist & p->p_sigmask;
445	bsd_to_linux_sigset(&bs, &ls);
446
447	return copyout(&ls, SCARG(uap, mask), sizeof(ls));
448}
449
450int
451linux_sigsuspend(p, v, retval)
452	register struct proc *p;
453	void *v;
454	register_t *retval;
455{
456	struct linux_sigsuspend_args /* {
457		syscallarg(caddr_t) restart;
458		syscallarg(int) oldmask;
459		syscallarg(int) mask;
460	} */ *uap = v;
461	struct sigsuspend_args sa;
462
463	linux_to_bsd_sigset(&SCARG(uap, mask), &SCARG(&sa, mask));
464	return sigsuspend(p, &sa, retval);
465}
466
467/*
468 * The deprecated pause(2), which is really just an instance
469 * of sigsuspend(2).
470 */
471int
472linux_pause(p, uap, retval)
473	register struct proc *p;
474	void *uap;
475	register_t *retval;
476{
477	struct sigsuspend_args bsa;
478
479	SCARG(&bsa, mask) = p->p_sigmask;
480	return sigsuspend(p, &bsa, retval);
481}
482
483/*
484 * Once more: only a signal conversion is needed.
485 */
486int
487linux_kill(p, v, retval)
488	register struct proc *p;
489	void *v;
490	register_t *retval;
491{
492	struct linux_kill_args /* {
493		syscallarg(int) pid;
494		syscallarg(int) signum;
495	} */ *uap = v;
496	struct kill_args ka;
497
498	SCARG(&ka, pid) = SCARG(uap, pid);
499	SCARG(&ka, signum) = linux_to_bsd_sig[SCARG(uap, signum)];
500	return kill(p, &ka, retval);
501}
502