linux_signal.c revision 72543
1/*-
2 * Copyright (c) 1994-1995 S�ren Schmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software withough specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $FreeBSD: head/sys/compat/linux/linux_signal.c 72543 2001-02-16 16:40:43Z jlemon $
29 */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/sysproto.h>
34#include <sys/proc.h>
35#include <sys/signalvar.h>
36
37#include <machine/../linux/linux.h>
38#include <machine/../linux/linux_proto.h>
39#include <compat/linux/linux_signal.h>
40#include <compat/linux/linux_util.h>
41
42void
43linux_to_bsd_sigset(linux_sigset_t *lss, sigset_t *bss)
44{
45	int b, l;
46
47	SIGEMPTYSET(*bss);
48	bss->__bits[0] = lss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
49	bss->__bits[1] = lss->__bits[1];
50	for (l = 1; l <= LINUX_SIGTBLSZ; l++) {
51		if (LINUX_SIGISMEMBER(*lss, l)) {
52#ifdef __alpha__
53			b = _SIG_IDX(l);
54#else
55			b = linux_to_bsd_signal[_SIG_IDX(l)];
56#endif
57			if (b)
58				SIGADDSET(*bss, b);
59		}
60	}
61}
62
63void
64bsd_to_linux_sigset(sigset_t *bss, linux_sigset_t *lss)
65{
66	int b, l;
67
68	LINUX_SIGEMPTYSET(*lss);
69	lss->__bits[0] = bss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
70	lss->__bits[1] = bss->__bits[1];
71	for (b = 1; b <= LINUX_SIGTBLSZ; b++) {
72		if (SIGISMEMBER(*bss, b)) {
73#if __alpha__
74			l = _SIG_IDX(b);
75#else
76			l = bsd_to_linux_signal[_SIG_IDX(b)];
77#endif
78			if (l)
79				LINUX_SIGADDSET(*lss, l);
80		}
81	}
82}
83
84static void
85linux_to_bsd_sigaction(linux_sigaction_t *lsa, struct sigaction *bsa)
86{
87
88	linux_to_bsd_sigset(&lsa->lsa_mask, &bsa->sa_mask);
89	bsa->sa_handler = lsa->lsa_handler;
90	bsa->sa_flags = 0;
91	if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP)
92		bsa->sa_flags |= SA_NOCLDSTOP;
93	if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT)
94		bsa->sa_flags |= SA_NOCLDWAIT;
95	if (lsa->lsa_flags & LINUX_SA_SIGINFO)
96		bsa->sa_flags |= SA_SIGINFO;
97	if (lsa->lsa_flags & LINUX_SA_ONSTACK)
98		bsa->sa_flags |= SA_ONSTACK;
99	if (lsa->lsa_flags & LINUX_SA_RESTART)
100		bsa->sa_flags |= SA_RESTART;
101	if (lsa->lsa_flags & LINUX_SA_ONESHOT)
102		bsa->sa_flags |= SA_RESETHAND;
103	if (lsa->lsa_flags & LINUX_SA_NOMASK)
104		bsa->sa_flags |= SA_NODEFER;
105}
106
107static void
108bsd_to_linux_sigaction(struct sigaction *bsa, linux_sigaction_t *lsa)
109{
110
111	bsd_to_linux_sigset(&bsa->sa_mask, &lsa->lsa_mask);
112	lsa->lsa_handler = bsa->sa_handler;
113	lsa->lsa_restorer = NULL;	/* unsupported */
114	lsa->lsa_flags = 0;
115	if (bsa->sa_flags & SA_NOCLDSTOP)
116		lsa->lsa_flags |= LINUX_SA_NOCLDSTOP;
117	if (bsa->sa_flags & SA_NOCLDWAIT)
118		lsa->lsa_flags |= LINUX_SA_NOCLDWAIT;
119	if (bsa->sa_flags & SA_SIGINFO)
120		lsa->lsa_flags |= LINUX_SA_SIGINFO;
121	if (bsa->sa_flags & SA_ONSTACK)
122		lsa->lsa_flags |= LINUX_SA_ONSTACK;
123	if (bsa->sa_flags & SA_RESTART)
124		lsa->lsa_flags |= LINUX_SA_RESTART;
125	if (bsa->sa_flags & SA_RESETHAND)
126		lsa->lsa_flags |= LINUX_SA_ONESHOT;
127	if (bsa->sa_flags & SA_NODEFER)
128		lsa->lsa_flags |= LINUX_SA_NOMASK;
129}
130
131int
132linux_do_sigaction(struct proc *p, int linux_sig, linux_sigaction_t *linux_nsa,
133		   linux_sigaction_t *linux_osa)
134{
135	struct sigaction *nsa, *osa;
136	struct sigaction_args sa_args;
137	int error;
138	caddr_t sg = stackgap_init();
139
140	if (linux_sig <= 0 || linux_sig > LINUX_NSIG)
141		return (EINVAL);
142
143	if (linux_osa != NULL)
144		osa = stackgap_alloc(&sg, sizeof(struct sigaction));
145	else
146		osa = NULL;
147
148	if (linux_nsa != NULL) {
149		nsa = stackgap_alloc(&sg, sizeof(struct sigaction));
150		linux_to_bsd_sigaction(linux_nsa, nsa);
151	}
152	else
153		nsa = NULL;
154
155#ifndef __alpha__
156	if (linux_sig <= LINUX_SIGTBLSZ)
157		sa_args.sig = linux_to_bsd_signal[_SIG_IDX(linux_sig)];
158	else
159#endif
160		sa_args.sig = linux_sig;
161
162	sa_args.act = nsa;
163	sa_args.oact = osa;
164	error = sigaction(p, &sa_args);
165	if (error)
166		return (error);
167
168	if (linux_osa != NULL)
169		bsd_to_linux_sigaction(osa, linux_osa);
170
171	return (0);
172}
173
174
175#ifndef __alpha__
176int
177linux_signal(struct proc *p, struct linux_signal_args *args)
178{
179	linux_sigaction_t nsa, osa;
180	int error;
181
182#ifdef DEBUG
183	if (ldebug(signal))
184		printf(ARGS(signal, "%d, %p"),
185		    args->sig, (void *)args->handler);
186#endif
187
188	nsa.lsa_handler = args->handler;
189	nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK;
190	LINUX_SIGEMPTYSET(nsa.lsa_mask);
191
192	error = linux_do_sigaction(p, args->sig, &nsa, &osa);
193	p->p_retval[0] = (int)osa.lsa_handler;
194
195	return (error);
196}
197#endif	/*!__alpha__*/
198
199int
200linux_rt_sigaction(struct proc *p, struct linux_rt_sigaction_args *args)
201{
202	linux_sigaction_t nsa, osa;
203	int error;
204
205#ifdef DEBUG
206	if (ldebug(rt_sigaction))
207		printf(ARGS(rt_sigaction, "%ld, %p, %p, %ld"),
208		    (long)args->sig, (void *)args->act,
209		    (void *)args->oact, (long)args->sigsetsize);
210#endif
211
212	if (args->sigsetsize != sizeof(linux_sigset_t))
213		return (EINVAL);
214
215	if (args->act != NULL) {
216		error = copyin(args->act, &nsa, sizeof(linux_sigaction_t));
217		if (error)
218			return (error);
219	}
220
221	error = linux_do_sigaction(p, args->sig,
222				   args->act ? &nsa : NULL,
223				   args->oact ? &osa : NULL);
224
225	if (args->oact != NULL && !error) {
226		error = copyout(&osa, args->oact, sizeof(linux_sigaction_t));
227	}
228
229	return (error);
230}
231
232static int
233linux_do_sigprocmask(struct proc *p, int how, linux_sigset_t *new,
234		     linux_sigset_t *old)
235{
236	int error;
237	sigset_t mask;
238
239	error = 0;
240	p->p_retval[0] = 0;
241
242	PROC_LOCK(p);
243	if (old != NULL)
244		bsd_to_linux_sigset(&p->p_sigmask, old);
245
246	if (new != NULL) {
247		linux_to_bsd_sigset(new, &mask);
248
249		switch (how) {
250		case LINUX_SIG_BLOCK:
251			SIGSETOR(p->p_sigmask, mask);
252			SIG_CANTMASK(p->p_sigmask);
253			break;
254		case LINUX_SIG_UNBLOCK:
255			SIGSETNAND(p->p_sigmask, mask);
256			break;
257		case LINUX_SIG_SETMASK:
258			p->p_sigmask = mask;
259			SIG_CANTMASK(p->p_sigmask);
260			break;
261		default:
262			error = EINVAL;
263			break;
264		}
265	}
266	PROC_UNLOCK(p);
267
268	return (error);
269}
270
271#ifndef __alpha__
272int
273linux_sigprocmask(struct proc *p, struct linux_sigprocmask_args *args)
274{
275	linux_osigset_t mask;
276	linux_sigset_t set, oset;
277	int error;
278
279#ifdef DEBUG
280	if (ldebug(sigprocmask))
281		printf(ARGS(sigprocmask, "%d, *, *"), args->how);
282#endif
283
284	if (args->mask != NULL) {
285		error = copyin(args->mask, &mask, sizeof(linux_osigset_t));
286		if (error)
287			return (error);
288		LINUX_SIGEMPTYSET(set);
289		set.__bits[0] = mask;
290	}
291
292	error = linux_do_sigprocmask(p, args->how,
293				     args->mask ? &set : NULL,
294				     args->omask ? &oset : NULL);
295
296	if (args->omask != NULL && !error) {
297		mask = oset.__bits[0];
298		error = copyout(&mask, args->omask, sizeof(linux_osigset_t));
299	}
300
301	return (error);
302}
303#endif	/*!__alpha__*/
304
305int
306linux_rt_sigprocmask(struct proc *p, struct linux_rt_sigprocmask_args *args)
307{
308	linux_sigset_t set, oset;
309	int error;
310
311#ifdef DEBUG
312	if (ldebug(rt_sigprocmask))
313		printf(ARGS(rt_sigprocmask, "%d, %p, %p, %ld"),
314		    args->how, (void *)args->mask,
315		    (void *)args->omask, (long)args->sigsetsize);
316#endif
317
318	if (args->sigsetsize != sizeof(linux_sigset_t))
319		return EINVAL;
320
321	if (args->mask != NULL) {
322		error = copyin(args->mask, &set, sizeof(linux_sigset_t));
323		if (error)
324			return (error);
325	}
326
327	error = linux_do_sigprocmask(p, args->how,
328				     args->mask ? &set : NULL,
329				     args->omask ? &oset : NULL);
330
331	if (args->omask != NULL && !error) {
332		error = copyout(&oset, args->omask, sizeof(linux_sigset_t));
333	}
334
335	return (error);
336}
337
338#ifndef __alpha__
339int
340linux_siggetmask(struct proc *p, struct linux_siggetmask_args *args)
341{
342	linux_sigset_t mask;
343
344#ifdef DEBUG
345	if (ldebug(siggetmask))
346		printf(ARGS(siggetmask, ""));
347#endif
348
349	PROC_LOCK(p);
350	bsd_to_linux_sigset(&p->p_sigmask, &mask);
351	PROC_UNLOCK(p);
352	p->p_retval[0] = mask.__bits[0];
353	return (0);
354}
355
356int
357linux_sigsetmask(struct proc *p, struct linux_sigsetmask_args *args)
358{
359	linux_sigset_t lset;
360	sigset_t bset;
361
362#ifdef DEBUG
363	if (ldebug(sigsetmask))
364		printf(ARGS(sigsetmask, "%08lx"), (unsigned long)args->mask);
365#endif
366
367	PROC_LOCK(p);
368	bsd_to_linux_sigset(&p->p_sigmask, &lset);
369	p->p_retval[0] = lset.__bits[0];
370	LINUX_SIGEMPTYSET(lset);
371	lset.__bits[0] = args->mask;
372	linux_to_bsd_sigset(&lset, &bset);
373	p->p_sigmask = bset;
374	SIG_CANTMASK(p->p_sigmask);
375	PROC_UNLOCK(p);
376	return (0);
377}
378
379int
380linux_sigpending(struct proc *p, struct linux_sigpending_args *args)
381{
382	sigset_t bset;
383	linux_sigset_t lset;
384	linux_osigset_t mask;
385
386#ifdef DEBUG
387	if (ldebug(sigpending))
388		printf(ARGS(sigpending, "*"));
389#endif
390
391	PROC_LOCK(p);
392	bset = p->p_siglist;
393	SIGSETAND(bset, p->p_sigmask);
394	bsd_to_linux_sigset(&bset, &lset);
395	PROC_UNLOCK(p);
396	mask = lset.__bits[0];
397	return (copyout(&mask, args->mask, sizeof(mask)));
398}
399#endif	/*!__alpha__*/
400
401int
402linux_kill(struct proc *p, struct linux_kill_args *args)
403{
404	struct kill_args /* {
405	    int pid;
406	    int signum;
407	} */ tmp;
408
409#ifdef DEBUG
410	if (ldebug(kill))
411		printf(ARGS(kill, "%d, %d"), args->pid, args->signum);
412#endif
413
414	/*
415	 * Allow signal 0 as a means to check for privileges
416	 */
417	if (args->signum < 0 || args->signum > LINUX_NSIG)
418		return EINVAL;
419
420#ifndef __alpha__
421	if (args->signum > 0 && args->signum <= LINUX_SIGTBLSZ)
422		tmp.signum = linux_to_bsd_signal[_SIG_IDX(args->signum)];
423	else
424#endif
425		tmp.signum = args->signum;
426
427	tmp.pid = args->pid;
428	return (kill(p, &tmp));
429}
430