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