linux_sigaction.c revision 1.7
1/*	$NetBSD: linux_sigaction.c,v 1.7 1995/08/14 01:12:15 mycroft 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, uap, retval)
227	register struct proc *p;
228	struct linux_sigaction_args /* {
229		syscallarg(int) signum;
230		syscallarg(struct linux_sigaction *) nsa;
231		syscallarg(struct linux_sigaction *) osa;
232	} */ *uap;
233	register_t *retval;
234{
235	struct linux_sigaction *nlsa, *olsa, tmplsa;
236	struct sigaction *nbsa, *obsa, tmpbsa;
237	struct sigaction_args sa;
238	caddr_t sg;
239	int error;
240
241	sg = stackgap_init(p->p_emul);
242	nlsa = SCARG(uap, nsa);
243	olsa = SCARG(uap, osa);
244
245	if (olsa != NULL)
246		obsa = stackgap_alloc(&sg, sizeof(struct sigaction));
247	else
248		obsa = NULL;
249
250	if (nlsa != NULL) {
251		nbsa = stackgap_alloc(&sg, sizeof(struct sigaction));
252		if ((error = copyin(nlsa, &tmplsa, sizeof(tmplsa))) != 0)
253			return error;
254		linux_to_bsd_sigaction(&tmplsa, &tmpbsa);
255		if ((error = copyout(&tmpbsa, nbsa, sizeof(tmpbsa))) != 0)
256			return error;
257	} else
258		nbsa = NULL;
259
260	SCARG(&sa, signum) = linux_to_bsd_sig[SCARG(uap, signum)];
261	SCARG(&sa, nsa) = nbsa;
262	SCARG(&sa, osa) = obsa;
263
264	if ((error = sigaction(p, &sa, retval)) != 0)
265		return error;
266
267	if (olsa != NULL) {
268		if ((error = copyin(obsa, &tmpbsa, sizeof(tmpbsa))) != 0)
269			return error;
270		bsd_to_linux_sigaction(&tmpbsa, &tmplsa);
271		if ((error = copyout(&tmplsa, olsa, sizeof(tmplsa))) != 0)
272			return error;
273	}
274
275	return 0;
276}
277
278/*
279 * The Linux signal() system call. I think that the signal() in the C
280 * library actually calls sigaction, so I doubt this one is ever used.
281 * But hey, it can't hurt having it here. The same restrictions as for
282 * sigaction() apply.
283 */
284int
285linux_signal(p, uap, retval)
286	register struct proc *p;
287	struct linux_signal_args /* {
288		syscallarg(int) sig;
289		syscallarg(linux_handler_t) handler;
290	} */ *uap;
291	register_t *retval;
292{
293	caddr_t sg;
294	struct sigaction_args sa_args;
295	struct sigaction *osa, *nsa, tmpsa;
296	int error;
297
298	sg = stackgap_init(p->p_emul);
299	nsa = stackgap_alloc(&sg, sizeof *nsa);
300	osa = stackgap_alloc(&sg, sizeof *osa);
301
302	tmpsa.sa_handler = SCARG(uap, handler);
303	tmpsa.sa_mask = (sigset_t) 0;
304	tmpsa.sa_flags = SA_RESETHAND | SA_NODEFER;
305	if ((error = copyout(&tmpsa, nsa, sizeof tmpsa)))
306		return error;
307
308	SCARG(&sa_args, signum) = linux_to_bsd_sig[SCARG(uap, sig)];
309	SCARG(&sa_args, osa) = osa;
310	SCARG(&sa_args, nsa) = nsa;
311	if ((error = sigaction(p, &sa_args, retval)))
312		return error;
313
314	if ((error = copyin(osa, &tmpsa, sizeof *osa)))
315		return error;
316	retval[0] = (register_t) tmpsa.sa_handler;
317
318	return 0;
319}
320
321/*
322 * This is just a copy of the svr4 compat one. I feel so creative now.
323 */
324int
325linux_sigprocmask(p, uap, retval)
326	register struct proc *p;
327	struct linux_sigprocmask_args /* {
328		syscallarg(int) how;
329		syscallarg(linux_sigset_t *) set;
330		syscallarg(linux_sigset_t *) oset;
331	} */ *uap;
332	register_t *retval;
333{
334	linux_sigset_t ss;
335	sigset_t bs;
336	int error = 0;
337
338	*retval = 0;
339
340	if (SCARG(uap, oset) != NULL) {
341		/* Fix the return value first if needed */
342		bsd_to_linux_sigset(&p->p_sigmask, &ss);
343		if ((error = copyout(&ss, SCARG(uap, oset), sizeof(ss))) != 0)
344			return error;
345	}
346
347	if (SCARG(uap, set) == NULL)
348		/* Just examine */
349		return 0;
350
351	if ((error = copyin(SCARG(uap, set), &ss, sizeof(ss))) != 0)
352		return error;
353
354	linux_to_bsd_sigset(&ss, &bs);
355
356	(void) splhigh();
357
358	switch (SCARG(uap, how)) {
359	case LINUX_SIG_BLOCK:
360		p->p_sigmask |= bs & ~sigcantmask;
361		break;
362
363	case LINUX_SIG_UNBLOCK:
364		p->p_sigmask &= ~bs;
365		break;
366
367	case LINUX_SIG_SETMASK:
368		p->p_sigmask = bs & ~sigcantmask;
369		break;
370
371	default:
372		error = EINVAL;
373		break;
374	}
375
376	(void) spl0();
377
378	return error;
379}
380
381/*
382 * The functions below really make no distinction between an int
383 * and [linux_]sigset_t. This is ok for now, but it might break
384 * sometime. Then again, sigset_t is trusted to be an int everywhere
385 * else in the kernel too.
386 */
387/* ARGSUSED */
388int
389linux_siggetmask(p, uap, retval)
390	register struct proc *p;
391	void *uap;
392	register_t *retval;
393{
394
395	bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *)retval);
396	return 0;
397}
398
399/*
400 * The following three functions fiddle with a process' signal mask.
401 * Convert the signal masks because of the different signal
402 * values for Linux. The need for this is the reason why
403 * they are here, and have not been mapped directly.
404 */
405int
406linux_sigsetmask(p, uap, retval)
407	register struct proc *p;
408	struct linux_sigsetmask_args /* {
409		syscallarg(linux_sigset_t) mask;
410	} */ *uap;
411	register_t *retval;
412{
413	linux_sigset_t mask;
414	sigset_t bsdsig;
415
416	bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *)retval);
417
418	mask = SCARG(uap, mask);
419	bsd_to_linux_sigset(&mask, &bsdsig);
420
421	splhigh();
422	p->p_sigmask = bsdsig & ~sigcantmask;
423	spl0();
424
425	return 0;
426}
427
428int
429linux_sigpending(p, uap, retval)
430	register struct proc *p;
431	struct linux_sigpending_args /* {
432		syscallarg(linux_sigset_t *) mask;
433	} */ *uap;
434	register_t *retval;
435{
436	sigset_t bs;
437	linux_sigset_t ls;
438
439	bs = p->p_siglist & p->p_sigmask;
440	bsd_to_linux_sigset(&bs, &ls);
441
442	return copyout(&ls, SCARG(uap, mask), sizeof(ls));
443}
444
445int
446linux_sigsuspend(p, uap, retval)
447	register struct proc *p;
448	struct linux_sigsuspend_args /* {
449		syscallarg(caddr_t) restart;
450		syscallarg(int) oldmask;
451		syscallarg(int) mask;
452	} */ *uap;
453	register_t *retval;
454{
455	struct sigsuspend_args sa;
456
457	linux_to_bsd_sigset(&SCARG(uap, mask), &SCARG(&sa, mask));
458	return sigsuspend(p, &sa, retval);
459}
460
461/*
462 * The deprecated pause(2), which is really just an instance
463 * of sigsuspend(2).
464 */
465int
466linux_pause(p, uap, retval)
467	register struct proc *p;
468	void *uap;
469	register_t *retval;
470{
471	struct sigsuspend_args bsa;
472
473	SCARG(&bsa, mask) = p->p_sigmask;
474	return sigsuspend(p, &bsa, retval);
475}
476
477/*
478 * Once more: only a signal conversion is needed.
479 */
480int
481linux_kill(p, uap, retval)
482	register struct proc *p;
483	struct linux_kill_args /* {
484		syscallarg(int) pid;
485		syscallarg(int) signum;
486	} */ *uap;
487	register_t *retval;
488{
489	struct kill_args ka;
490
491	SCARG(&ka, pid) = SCARG(uap, pid);
492	SCARG(&ka, signum) = linux_to_bsd_sig[SCARG(uap, signum)];
493	return kill(p, &ka, retval);
494}
495