linux_sigaction.c revision 1.12
1/*	$NetBSD: linux_sigaction.c,v 1.12 1998/09/11 12:50:09 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	linux_sigmask(n)	(1 << ((n) - 1))
56#define	linux_sigemptyset(s)	memset((s), 0, sizeof(*(s)))
57#define	linux_sigismember(s, n)	(*(s) & linux_sigmask(n))
58#define	linux_sigaddset(s, n)	(*(s) |= linux_sigmask(n))
59
60int native_to_linux_sig[NSIG] = {
61	0,
62	LINUX_SIGHUP,
63	LINUX_SIGINT,
64	LINUX_SIGQUIT,
65	LINUX_SIGILL,
66	LINUX_SIGTRAP,
67	LINUX_SIGABRT,
68	0,			/* SIGEMT */
69	LINUX_SIGFPE,
70	LINUX_SIGKILL,
71	LINUX_SIGBUS,
72	LINUX_SIGSEGV,
73	0,			/* SIGSEGV */
74	LINUX_SIGPIPE,
75	LINUX_SIGALRM,
76	LINUX_SIGTERM,
77	LINUX_SIGURG,
78	LINUX_SIGSTOP,
79	LINUX_SIGTSTP,
80	LINUX_SIGCONT,
81	LINUX_SIGCHLD,
82	LINUX_SIGTTIN,
83	LINUX_SIGTTOU,
84	LINUX_SIGIO,
85	LINUX_SIGXCPU,
86	LINUX_SIGXFSZ,
87	LINUX_SIGVTALRM,
88	LINUX_SIGPROF,
89	LINUX_SIGWINCH,
90	0,			/* SIGINFO */
91	LINUX_SIGUSR1,
92	LINUX_SIGUSR2,
93	LINUX_SIGPWR,
94};
95
96int linux_to_native_sig[LINUX_NSIG] = {
97	0,
98	SIGHUP,
99	SIGINT,
100	SIGQUIT,
101	SIGILL,
102	SIGTRAP,
103	SIGABRT,
104	SIGBUS,
105	SIGFPE,
106	SIGKILL,
107	SIGUSR1,
108	SIGSEGV,
109	SIGUSR2,
110	SIGPIPE,
111	SIGALRM,
112	SIGTERM,
113	0,			/* SIGSTKFLT */
114	SIGCHLD,
115	SIGCONT,
116	SIGSTOP,
117	SIGTSTP,
118	SIGTTIN,
119	SIGTTOU,
120	SIGURG,
121	SIGXCPU,
122	SIGXFSZ,
123	SIGVTALRM,
124	SIGPROF,
125	SIGWINCH,
126	SIGIO,
127	SIGPWR,
128	0,			/* SIGUNUSED */
129};
130
131/* linux_signal.c */
132void linux_to_native_sigaction __P((struct linux_sigaction *, struct sigaction *));
133void native_to_linux_sigaction __P((struct sigaction *, struct linux_sigaction *));
134
135void
136linux_to_native_sigset(lss, bss)
137	const linux_sigset_t *lss;
138	sigset_t *bss;
139{
140	int i, newsig;
141
142	sigemptyset(bss);
143	for (i = 1; i < LINUX_NSIG; i++) {
144		if (linux_sigismember(lss, i)) {
145			newsig = linux_to_native_sig[i];
146			if (newsig)
147				sigaddset(bss, newsig);
148		}
149	}
150}
151
152void
153native_to_linux_sigset(bss, lss)
154	const sigset_t *bss;
155	linux_sigset_t *lss;
156{
157	int i, newsig;
158
159	linux_sigemptyset(lss);
160	for (i = 1; i < NSIG; i++) {
161		if (sigismember(bss, i)) {
162			newsig = native_to_linux_sig[i];
163			if (newsig)
164				linux_sigaddset(lss, newsig);
165		}
166	}
167}
168
169/*
170 * Convert between Linux and BSD sigaction structures. Linux has
171 * one extra field (sa_restorer) which we don't support.
172 */
173void
174linux_to_native_sigaction(lsa, bsa)
175	struct linux_sigaction *lsa;
176	struct sigaction *bsa;
177{
178
179	bsa->sa_handler = lsa->sa_handler;
180	linux_to_native_sigset(&lsa->sa_mask, &bsa->sa_mask);
181	bsa->sa_flags = 0;
182	if ((lsa->sa_flags & LINUX_SA_NOCLDSTOP) != 0)
183		bsa->sa_flags |= SA_NOCLDSTOP;
184	if ((lsa->sa_flags & LINUX_SA_ONSTACK) != 0)
185		bsa->sa_flags |= SA_ONSTACK;
186	if ((lsa->sa_flags & LINUX_SA_RESTART) != 0)
187		bsa->sa_flags |= SA_RESTART;
188	if ((lsa->sa_flags & LINUX_SA_ONESHOT) != 0)
189		bsa->sa_flags |= SA_RESETHAND;
190	if ((lsa->sa_flags & LINUX_SA_NOMASK) != 0)
191		bsa->sa_flags |= SA_NODEFER;
192	if ((lsa->sa_flags & ~LINUX_SA_ALLBITS) != 0)
193/*XXX*/		printf("linux_to_native_sigaction: extra bits ignored\n");
194	if (lsa->sa_restorer != 0)
195/*XXX*/		printf("linux_to_native_sigaction: sa_restorer ignored\n");
196}
197
198void
199native_to_linux_sigaction(bsa, lsa)
200	struct sigaction *bsa;
201	struct linux_sigaction *lsa;
202{
203
204	lsa->sa_handler = bsa->sa_handler;
205	native_to_linux_sigset(&bsa->sa_mask, &lsa->sa_mask);
206	lsa->sa_flags = 0;
207	if ((bsa->sa_flags & SA_NOCLDSTOP) != 0)
208		lsa->sa_flags |= LINUX_SA_NOCLDSTOP;
209	if ((bsa->sa_flags & SA_ONSTACK) != 0)
210		lsa->sa_flags |= LINUX_SA_ONSTACK;
211	if ((bsa->sa_flags & SA_RESTART) != 0)
212		lsa->sa_flags |= LINUX_SA_RESTART;
213	if ((bsa->sa_flags & SA_NODEFER) != 0)
214		lsa->sa_flags |= LINUX_SA_NOMASK;
215	if ((bsa->sa_flags & SA_RESETHAND) != 0)
216		lsa->sa_flags |= LINUX_SA_ONESHOT;
217	lsa->sa_restorer = NULL;
218}
219
220
221/*
222 * The Linux sigaction() system call. Do the usual conversions,
223 * and just call sigaction(). Some flags and values are silently
224 * ignored (see above).
225 */
226int
227linux_sys_sigaction(p, v, retval)
228	register struct proc *p;
229	void *v;
230	register_t *retval;
231{
232	struct linux_sys_sigaction_args /* {
233		syscallarg(int) signum;
234		syscallarg(const struct linux_sigaction *) nsa;
235		syscallarg(struct linux_sigaction *) osa;
236	} */ *uap = v;
237	struct linux_sigaction nlsa, olsa;
238	struct sigaction nbsa, obsa;
239	int error;
240
241	if (SCARG(uap, nsa)) {
242		error = copyin(SCARG(uap, nsa), &nlsa, sizeof(nlsa));
243		if (error)
244			return (error);
245		linux_to_native_sigaction(&nlsa, &nbsa);
246	}
247	error = sigaction1(p, linux_to_native_sig[SCARG(uap, signum)],
248	    SCARG(uap, nsa) ? &nbsa : 0, SCARG(uap, osa) ? &obsa : 0);
249	if (error)
250		return (error);
251	if (SCARG(uap, osa)) {
252		native_to_linux_sigaction(&obsa, &olsa);
253		error = copyout(&olsa, SCARG(uap, osa), sizeof(olsa));
254		if (error)
255			return (error);
256	}
257	return (0);
258}
259
260/*
261 * The Linux signal() system call. I think that the signal() in the C
262 * library actually calls sigaction, so I doubt this one is ever used.
263 * But hey, it can't hurt having it here. The same restrictions as for
264 * sigaction() apply.
265 */
266int
267linux_sys_signal(p, v, retval)
268	register struct proc *p;
269	void *v;
270	register_t *retval;
271{
272	struct linux_sys_signal_args /* {
273		syscallarg(int) sig;
274		syscallarg(linux_handler_t) handler;
275	} */ *uap = v;
276	struct sigaction nbsa, obsa;
277	int error;
278
279	nbsa.sa_handler = SCARG(uap, handler);
280	sigemptyset(&nbsa.sa_mask);
281	nbsa.sa_flags = SA_RESETHAND | SA_NODEFER;
282	error = sigaction1(p, linux_to_native_sig[SCARG(uap, sig)],
283	    &nbsa, &obsa);
284	if (error)
285		return (error);
286	*retval = (int)obsa.sa_handler;
287	return (0);
288}
289
290int
291linux_sys_sigprocmask(p, v, retval)
292	register struct proc *p;
293	void *v;
294	register_t *retval;
295{
296	struct linux_sys_sigprocmask_args /* {
297		syscallarg(int) how;
298		syscallarg(const linux_sigset_t *) set;
299		syscallarg(linux_sigset_t *) oset;
300	} */ *uap = v;
301	linux_sigset_t nlss, olss;
302	sigset_t nbss, obss;
303	int how;
304	int error;
305
306	switch (SCARG(uap, how)) {
307	case LINUX_SIG_BLOCK:
308		how = SIG_BLOCK;
309		break;
310	case LINUX_SIG_UNBLOCK:
311		how = SIG_UNBLOCK;
312		break;
313	case LINUX_SIG_SETMASK:
314		how = SIG_SETMASK;
315		break;
316	default:
317		return (EINVAL);
318	}
319
320	if (SCARG(uap, set)) {
321		error = copyin(SCARG(uap, set), &nlss, sizeof(nlss));
322		if (error)
323			return (error);
324		linux_to_native_sigset(&nlss, &nbss);
325	}
326	error = sigprocmask1(p, how,
327	    SCARG(uap, set) ? &nbss : 0, SCARG(uap, oset) ? &obss : 0);
328	if (error)
329		return (error);
330	if (SCARG(uap, oset)) {
331		native_to_linux_sigset(&obss, &olss);
332		error = copyout(&olss, SCARG(uap, oset), sizeof(olss));
333		if (error)
334			return (error);
335	}
336	return (error);
337}
338
339/* ARGSUSED */
340int
341linux_sys_siggetmask(p, v, retval)
342	register struct proc *p;
343	void *v;
344	register_t *retval;
345{
346	sigset_t bss;
347	linux_sigset_t lss;
348	int error;
349
350	error = sigprocmask1(p, SIG_SETMASK, 0, &bss);
351	if (error)
352		return (error);
353	native_to_linux_sigset(&bss, &lss);
354	*retval = lss;
355	return (0);
356}
357
358/*
359 * The following three functions fiddle with a process' signal mask.
360 * Convert the signal masks because of the different signal
361 * values for Linux. The need for this is the reason why
362 * they are here, and have not been mapped directly.
363 */
364int
365linux_sys_sigsetmask(p, v, retval)
366	register struct proc *p;
367	void *v;
368	register_t *retval;
369{
370	struct linux_sys_sigsetmask_args /* {
371		syscallarg(linux_sigset_t) mask;
372	} */ *uap = v;
373	sigset_t nbss, obss;
374	linux_sigset_t nlss, olss;
375	int error;
376
377	nlss = SCARG(uap, mask);
378	linux_to_native_sigset(&nlss, &nbss);
379	error = sigprocmask1(p, SIG_SETMASK, &nbss, &obss);
380	if (error)
381		return (error);
382	native_to_linux_sigset(&obss, &olss);
383	*retval = olss;
384	return (0);
385}
386
387int
388linux_sys_sigpending(p, v, retval)
389	register struct proc *p;
390	void *v;
391	register_t *retval;
392{
393	struct linux_sys_sigpending_args /* {
394		syscallarg(linux_sigset_t *) set;
395	} */ *uap = v;
396	sigset_t bss;
397	linux_sigset_t lss;
398
399	sigpending1(p, &bss);
400	native_to_linux_sigset(&bss, &lss);
401	return copyout(&lss, SCARG(uap, set), sizeof(lss));
402}
403
404int
405linux_sys_sigsuspend(p, v, retval)
406	register struct proc *p;
407	void *v;
408	register_t *retval;
409{
410	struct linux_sys_sigsuspend_args /* {
411		syscallarg(caddr_t) restart;
412		syscallarg(int) oldmask;
413		syscallarg(int) mask;
414	} */ *uap = v;
415	linux_sigset_t lss;
416	sigset_t bss;
417
418	lss = SCARG(uap, mask);
419	linux_to_native_sigset(&lss, &bss);
420	return (sigsuspend1(p, &bss));
421}
422
423/*
424 * The deprecated pause(2), which is really just an instance
425 * of sigsuspend(2).
426 */
427int
428linux_sys_pause(p, v, retval)
429	register struct proc *p;
430	void *v;
431	register_t *retval;
432{
433
434	return (sigsuspend1(p, 0));
435}
436
437/*
438 * Once more: only a signal conversion is needed.
439 */
440int
441linux_sys_kill(p, v, retval)
442	register struct proc *p;
443	void *v;
444	register_t *retval;
445{
446	struct linux_sys_kill_args /* {
447		syscallarg(int) pid;
448		syscallarg(int) signum;
449	} */ *uap = v;
450	struct sys_kill_args ka;
451
452	SCARG(&ka, pid) = SCARG(uap, pid);
453	SCARG(&ka, signum) = linux_to_native_sig[SCARG(uap, signum)];
454	return sys_kill(p, &ka, retval);
455}
456