linux_signal.c revision 70061
19313Ssos/*-
29313Ssos * Copyright (c) 1994-1995 S�ren Schmidt
39313Ssos * All rights reserved.
49313Ssos *
59313Ssos * Redistribution and use in source and binary forms, with or without
69313Ssos * modification, are permitted provided that the following conditions
79313Ssos * are met:
89313Ssos * 1. Redistributions of source code must retain the above copyright
99313Ssos *    notice, this list of conditions and the following disclaimer
109313Ssos *    in this position and unchanged.
119313Ssos * 2. Redistributions in binary form must reproduce the above copyright
129313Ssos *    notice, this list of conditions and the following disclaimer in the
139313Ssos *    documentation and/or other materials provided with the distribution.
149313Ssos * 3. The name of the author may not be used to endorse or promote products
159313Ssos *    derived from this software withough specific prior written permission
169313Ssos *
179313Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
189313Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
199313Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
209313Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
219313Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
229313Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239313Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249313Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259313Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
269313Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279313Ssos *
2850477Speter * $FreeBSD: head/sys/compat/linux/linux_signal.c 70061 2000-12-15 19:41:27Z jhb $
299313Ssos */
309313Ssos
319313Ssos#include <sys/param.h>
329313Ssos#include <sys/systm.h>
3312458Sbde#include <sys/sysproto.h>
349313Ssos#include <sys/proc.h>
359313Ssos#include <sys/signalvar.h>
369313Ssos
3764911Smarcel#include <machine/../linux/linux.h>
3868583Smarcel#include <machine/../linux/linux_proto.h>
3964911Smarcel#include <compat/linux/linux_signal.h>
4064911Smarcel#include <compat/linux/linux_util.h>
419313Ssos
4264911Smarcelvoid
4351793Smarcellinux_to_bsd_sigset(linux_sigset_t *lss, sigset_t *bss)
4451793Smarcel{
4551793Smarcel	int b, l;
469313Ssos
4751793Smarcel	SIGEMPTYSET(*bss);
4851793Smarcel	bss->__bits[0] = lss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
4951793Smarcel	bss->__bits[1] = lss->__bits[1];
5051793Smarcel	for (l = 1; l <= LINUX_SIGTBLSZ; l++) {
5151793Smarcel		if (LINUX_SIGISMEMBER(*lss, l)) {
5268201Sobrien#ifdef __alpha__
5368201Sobrien			b = _SIG_IDX(l);
5468201Sobrien#else
5551793Smarcel			b = linux_to_bsd_signal[_SIG_IDX(l)];
5668201Sobrien#endif
5751793Smarcel			if (b)
5851793Smarcel				SIGADDSET(*bss, b);
5951793Smarcel		}
6014331Speter	}
619313Ssos}
629313Ssos
6367234Sgallatinvoid
6451793Smarcelbsd_to_linux_sigset(sigset_t *bss, linux_sigset_t *lss)
6551793Smarcel{
6651793Smarcel	int b, l;
679313Ssos
6851793Smarcel	LINUX_SIGEMPTYSET(*lss);
6951793Smarcel	lss->__bits[0] = bss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
7051793Smarcel	lss->__bits[1] = bss->__bits[1];
7151793Smarcel	for (b = 1; b <= LINUX_SIGTBLSZ; b++) {
7251793Smarcel		if (SIGISMEMBER(*bss, b)) {
7368201Sobrien#if __alpha__
7468201Sobrien			l = _SIG_IDX(b);
7568201Sobrien#else
7651793Smarcel			l = bsd_to_linux_signal[_SIG_IDX(b)];
7768201Sobrien#endif
7851793Smarcel			if (l)
7951793Smarcel				LINUX_SIGADDSET(*lss, l);
8051793Smarcel		}
8114331Speter	}
829313Ssos}
839313Ssos
8414342Speterstatic void
8514331Speterlinux_to_bsd_sigaction(linux_sigaction_t *lsa, struct sigaction *bsa)
8614331Speter{
8751793Smarcel
8851793Smarcel	linux_to_bsd_sigset(&lsa->lsa_mask, &bsa->sa_mask);
8951793Smarcel	bsa->sa_handler = lsa->lsa_handler;
9051793Smarcel	bsa->sa_flags = 0;
9151793Smarcel	if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP)
9251793Smarcel		bsa->sa_flags |= SA_NOCLDSTOP;
9351793Smarcel	if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT)
9451793Smarcel		bsa->sa_flags |= SA_NOCLDWAIT;
9551793Smarcel	if (lsa->lsa_flags & LINUX_SA_SIGINFO)
9651793Smarcel		bsa->sa_flags |= SA_SIGINFO;
9751793Smarcel	if (lsa->lsa_flags & LINUX_SA_ONSTACK)
9851793Smarcel		bsa->sa_flags |= SA_ONSTACK;
9951793Smarcel	if (lsa->lsa_flags & LINUX_SA_RESTART)
10051793Smarcel		bsa->sa_flags |= SA_RESTART;
10151793Smarcel	if (lsa->lsa_flags & LINUX_SA_ONESHOT)
10251793Smarcel		bsa->sa_flags |= SA_RESETHAND;
10351793Smarcel	if (lsa->lsa_flags & LINUX_SA_NOMASK)
10451793Smarcel		bsa->sa_flags |= SA_NODEFER;
10514331Speter}
1069313Ssos
10714342Speterstatic void
10814331Speterbsd_to_linux_sigaction(struct sigaction *bsa, linux_sigaction_t *lsa)
10914331Speter{
11051793Smarcel
11151793Smarcel	bsd_to_linux_sigset(&bsa->sa_mask, &lsa->lsa_mask);
11251793Smarcel	lsa->lsa_handler = bsa->sa_handler;
11351793Smarcel	lsa->lsa_restorer = NULL;	/* unsupported */
11451793Smarcel	lsa->lsa_flags = 0;
11551793Smarcel	if (bsa->sa_flags & SA_NOCLDSTOP)
11651793Smarcel		lsa->lsa_flags |= LINUX_SA_NOCLDSTOP;
11751793Smarcel	if (bsa->sa_flags & SA_NOCLDWAIT)
11851793Smarcel		lsa->lsa_flags |= LINUX_SA_NOCLDWAIT;
11951793Smarcel	if (bsa->sa_flags & SA_SIGINFO)
12051793Smarcel		lsa->lsa_flags |= LINUX_SA_SIGINFO;
12151793Smarcel	if (bsa->sa_flags & SA_ONSTACK)
12251793Smarcel		lsa->lsa_flags |= LINUX_SA_ONSTACK;
12351793Smarcel	if (bsa->sa_flags & SA_RESTART)
12451793Smarcel		lsa->lsa_flags |= LINUX_SA_RESTART;
12551793Smarcel	if (bsa->sa_flags & SA_RESETHAND)
12651793Smarcel		lsa->lsa_flags |= LINUX_SA_ONESHOT;
12751793Smarcel	if (bsa->sa_flags & SA_NODEFER)
12851793Smarcel		lsa->lsa_flags |= LINUX_SA_NOMASK;
12914331Speter}
13014331Speter
13164911Smarcelint
13249786Smarcellinux_do_sigaction(struct proc *p, int linux_sig, linux_sigaction_t *linux_nsa,
13349786Smarcel		   linux_sigaction_t *linux_osa)
13449786Smarcel{
13553954Smarcel	struct sigaction *nsa, *osa;
13651793Smarcel	struct sigaction_args sa_args;
13751793Smarcel	int error;
13851793Smarcel	caddr_t sg = stackgap_init();
13949786Smarcel
14051793Smarcel	if (linux_sig <= 0 || linux_sig > LINUX_NSIG)
14151793Smarcel		return (EINVAL);
14249786Smarcel
14351793Smarcel	if (linux_osa != NULL)
14451793Smarcel		osa = stackgap_alloc(&sg, sizeof(struct sigaction));
14551793Smarcel	else
14651793Smarcel		osa = NULL;
14749786Smarcel
14851793Smarcel	if (linux_nsa != NULL) {
14951793Smarcel		nsa = stackgap_alloc(&sg, sizeof(struct sigaction));
15053954Smarcel		linux_to_bsd_sigaction(linux_nsa, nsa);
15151793Smarcel	}
15251793Smarcel	else
15351793Smarcel		nsa = NULL;
15449786Smarcel
15568201Sobrien#ifndef __alpha__
15651793Smarcel	if (linux_sig <= LINUX_SIGTBLSZ)
15751793Smarcel		sa_args.sig = linux_to_bsd_signal[_SIG_IDX(linux_sig)];
15851793Smarcel	else
15968201Sobrien#endif
16051793Smarcel		sa_args.sig = linux_sig;
16149786Smarcel
16251793Smarcel	sa_args.act = nsa;
16351793Smarcel	sa_args.oact = osa;
16451793Smarcel	error = sigaction(p, &sa_args);
16549786Smarcel	if (error)
16651793Smarcel		return (error);
16749786Smarcel
16853954Smarcel	if (linux_osa != NULL)
16953954Smarcel		bsd_to_linux_sigaction(osa, linux_osa);
17051793Smarcel
17151793Smarcel	return (0);
17249786Smarcel}
17349786Smarcel
17468201Sobrien
17568201Sobrien#ifndef __alpha__
1769313Ssosint
17730994Sphklinux_signal(struct proc *p, struct linux_signal_args *args)
17814331Speter{
17951793Smarcel	linux_sigaction_t nsa, osa;
18051793Smarcel	int error;
1819313Ssos
18214331Speter#ifdef DEBUG
18351793Smarcel	printf("Linux-emul(%ld): signal(%d, %p)\n",
18451793Smarcel	       (long)p->p_pid, args->sig, (void *)args->handler);
18514331Speter#endif
18649786Smarcel
18751793Smarcel	nsa.lsa_handler = args->handler;
18851793Smarcel	nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK;
18951793Smarcel	LINUX_SIGEMPTYSET(nsa.lsa_mask);
19049786Smarcel
19151793Smarcel	error = linux_do_sigaction(p, args->sig, &nsa, &osa);
19251793Smarcel	p->p_retval[0] = (int)osa.lsa_handler;
19349786Smarcel
19451793Smarcel	return (error);
19549786Smarcel}
19668201Sobrien#endif	/*!__alpha__*/
19749786Smarcel
19849786Smarcelint
19949786Smarcellinux_rt_sigaction(struct proc *p, struct linux_rt_sigaction_args *args)
20049786Smarcel{
20151793Smarcel	linux_sigaction_t nsa, osa;
20251793Smarcel	int error;
20349786Smarcel
20449786Smarcel#ifdef DEBUG
20568201Sobrien	printf("Linux-emul(%ld): rt_sigaction(%ld, %p, %p, %ld)\n",
20668201Sobrien	       (long)p->p_pid, (long)args->sig, (void *)args->act,
20768201Sobrien	       (void *)args->oact, (long)args->sigsetsize);
20849786Smarcel#endif
20949786Smarcel
21051793Smarcel	if (args->sigsetsize != sizeof(linux_sigset_t))
21151793Smarcel		return (EINVAL);
21214331Speter
21351793Smarcel	if (args->act != NULL) {
21451793Smarcel		error = copyin(args->act, &nsa, sizeof(linux_sigaction_t));
21551793Smarcel		if (error)
21651793Smarcel			return (error);
21751793Smarcel	}
21814331Speter
21951793Smarcel	error = linux_do_sigaction(p, args->sig,
22051793Smarcel				   args->act ? &nsa : NULL,
22151793Smarcel				   args->oact ? &osa : NULL);
22214331Speter
22351793Smarcel	if (args->oact != NULL && !error) {
22451793Smarcel		error = copyout(&osa, args->oact, sizeof(linux_sigaction_t));
22551793Smarcel	}
22649786Smarcel
22751793Smarcel	return (error);
22814331Speter}
22914331Speter
23049786Smarcelstatic int
23149786Smarcellinux_do_sigprocmask(struct proc *p, int how, linux_sigset_t *new,
23249786Smarcel		     linux_sigset_t *old)
23349786Smarcel{
23470061Sjhb	int error;
23551793Smarcel	sigset_t mask;
23614331Speter
23751793Smarcel	error = 0;
23851793Smarcel	p->p_retval[0] = 0;
23949786Smarcel
24070061Sjhb	PROC_LOCK(p);
24151793Smarcel	if (old != NULL)
24251793Smarcel		bsd_to_linux_sigset(&p->p_sigmask, old);
24349786Smarcel
24451793Smarcel	if (new != NULL) {
24551793Smarcel		linux_to_bsd_sigset(new, &mask);
24649786Smarcel
24751793Smarcel		switch (how) {
24851793Smarcel		case LINUX_SIG_BLOCK:
24951793Smarcel			SIGSETOR(p->p_sigmask, mask);
25051793Smarcel			SIG_CANTMASK(p->p_sigmask);
25151793Smarcel			break;
25251793Smarcel		case LINUX_SIG_UNBLOCK:
25351793Smarcel			SIGSETNAND(p->p_sigmask, mask);
25451793Smarcel			break;
25551793Smarcel		case LINUX_SIG_SETMASK:
25651793Smarcel			p->p_sigmask = mask;
25751793Smarcel			SIG_CANTMASK(p->p_sigmask);
25851793Smarcel			break;
25951793Smarcel		default:
26051793Smarcel			error = EINVAL;
26151793Smarcel			break;
26251793Smarcel		}
26349786Smarcel	}
26470061Sjhb	PROC_UNLOCK(p);
26549786Smarcel
26651793Smarcel	return (error);
26749786Smarcel}
26849786Smarcel
26968201Sobrien#ifndef __alpha__
2709313Ssosint
27130994Sphklinux_sigprocmask(struct proc *p, struct linux_sigprocmask_args *args)
2729313Ssos{
27351793Smarcel	linux_osigset_t mask;
27451793Smarcel	linux_sigset_t set, oset;
27551793Smarcel	int error;
2769313Ssos
2779313Ssos#ifdef DEBUG
27851793Smarcel	printf("Linux-emul(%d): sigprocmask(%d, *, *)\n", p->p_pid, args->how);
2799313Ssos#endif
28014331Speter
28151793Smarcel	if (args->mask != NULL) {
28251793Smarcel		error = copyin(args->mask, &mask, sizeof(linux_osigset_t));
28351793Smarcel		if (error)
28451793Smarcel			return (error);
28551793Smarcel		LINUX_SIGEMPTYSET(set);
28651793Smarcel		set.__bits[0] = mask;
28751793Smarcel	}
28814331Speter
28951793Smarcel	error = linux_do_sigprocmask(p, args->how,
29051793Smarcel				     args->mask ? &set : NULL,
29151793Smarcel				     args->omask ? &oset : NULL);
29249786Smarcel
29351793Smarcel	if (args->omask != NULL && !error) {
29451793Smarcel		mask = oset.__bits[0];
29551793Smarcel		error = copyout(&mask, args->omask, sizeof(linux_osigset_t));
29651793Smarcel	}
29749786Smarcel
29851793Smarcel	return (error);
29949786Smarcel}
30068201Sobrien#endif	/*!__alpha__*/
30149786Smarcel
30249786Smarcelint
30349786Smarcellinux_rt_sigprocmask(struct proc *p, struct linux_rt_sigprocmask_args *args)
30449786Smarcel{
30551793Smarcel	linux_sigset_t set, oset;
30651793Smarcel	int error;
30749786Smarcel
30849786Smarcel#ifdef DEBUG
30968201Sobrien	printf("Linux-emul(%ld): rt_sigprocmask(%d, %p, %p, %ld)\n",
31051793Smarcel	       (long)p->p_pid, args->how, (void *)args->mask,
31168201Sobrien	       (void *)args->omask, (long)args->sigsetsize);
31249786Smarcel#endif
31349786Smarcel
31451793Smarcel	if (args->sigsetsize != sizeof(linux_sigset_t))
31551793Smarcel		return EINVAL;
31649786Smarcel
31751793Smarcel	if (args->mask != NULL) {
31851793Smarcel		error = copyin(args->mask, &set, sizeof(linux_sigset_t));
31951793Smarcel		if (error)
32051793Smarcel			return (error);
32151793Smarcel	}
32249786Smarcel
32351793Smarcel	error = linux_do_sigprocmask(p, args->how,
32451793Smarcel				     args->mask ? &set : NULL,
32551793Smarcel				     args->omask ? &oset : NULL);
3269313Ssos
32751793Smarcel	if (args->omask != NULL && !error) {
32851793Smarcel		error = copyout(&oset, args->omask, sizeof(linux_sigset_t));
32951793Smarcel	}
33049786Smarcel
33151793Smarcel	return (error);
3329313Ssos}
3339313Ssos
33468201Sobrien#ifndef __alpha__
3359313Ssosint
33630994Sphklinux_siggetmask(struct proc *p, struct linux_siggetmask_args *args)
3379313Ssos{
33851793Smarcel	linux_sigset_t mask;
33951793Smarcel
3409313Ssos#ifdef DEBUG
34151793Smarcel	printf("Linux-emul(%d): siggetmask()\n", p->p_pid);
3429313Ssos#endif
34351793Smarcel
34470061Sjhb	PROC_LOCK(p);
34551793Smarcel	bsd_to_linux_sigset(&p->p_sigmask, &mask);
34670061Sjhb	PROC_UNLOCK(p);
34751793Smarcel	p->p_retval[0] = mask.__bits[0];
34851793Smarcel	return (0);
3499313Ssos}
3509313Ssos
3519313Ssosint
35230994Sphklinux_sigsetmask(struct proc *p, struct linux_sigsetmask_args *args)
3539313Ssos{
35451793Smarcel	linux_sigset_t lset;
35551793Smarcel	sigset_t bset;
3569313Ssos
3579313Ssos#ifdef DEBUG
35851793Smarcel	printf("Linux-emul(%ld): sigsetmask(%08lx)\n",
35951793Smarcel	       (long)p->p_pid, (unsigned long)args->mask);
3609313Ssos#endif
36114331Speter
36270061Sjhb	PROC_LOCK(p);
36351793Smarcel	bsd_to_linux_sigset(&p->p_sigmask, &lset);
36451793Smarcel	p->p_retval[0] = lset.__bits[0];
36551793Smarcel	LINUX_SIGEMPTYSET(lset);
36651793Smarcel	lset.__bits[0] = args->mask;
36751793Smarcel	linux_to_bsd_sigset(&lset, &bset);
36851793Smarcel	p->p_sigmask = bset;
36951793Smarcel	SIG_CANTMASK(p->p_sigmask);
37070061Sjhb	PROC_UNLOCK(p);
37151793Smarcel	return (0);
3729313Ssos}
3739313Ssos
3749313Ssosint
37530994Sphklinux_sigpending(struct proc *p, struct linux_sigpending_args *args)
3769313Ssos{
37751793Smarcel	sigset_t bset;
37851793Smarcel	linux_sigset_t lset;
37951793Smarcel	linux_osigset_t mask;
3809313Ssos
3819313Ssos#ifdef DEBUG
38251793Smarcel	printf("Linux-emul(%d): sigpending(*)\n", p->p_pid);
3839313Ssos#endif
38451793Smarcel
38570061Sjhb	PROC_LOCK(p);
38651793Smarcel	bset = p->p_siglist;
38751793Smarcel	SIGSETAND(bset, p->p_sigmask);
38851793Smarcel	bsd_to_linux_sigset(&bset, &lset);
38970061Sjhb	PROC_UNLOCK(p);
39051793Smarcel	mask = lset.__bits[0];
39151793Smarcel	return (copyout(&mask, args->mask, sizeof(mask)));
3929313Ssos}
39368201Sobrien#endif	/*!__alpha__*/
3949313Ssos
3959313Ssosint
39630994Sphklinux_kill(struct proc *p, struct linux_kill_args *args)
3979313Ssos{
39851793Smarcel	struct kill_args /* {
39951793Smarcel	    int pid;
40051793Smarcel	    int signum;
40151793Smarcel	} */ tmp;
4029313Ssos
4039313Ssos#ifdef DEBUG
40451793Smarcel	printf("Linux-emul(%d): kill(%d, %d)\n",
40551793Smarcel	       p->p_pid, args->pid, args->signum);
4069313Ssos#endif
40751793Smarcel
40851793Smarcel	/*
40951793Smarcel	 * Allow signal 0 as a means to check for privileges
41051793Smarcel	 */
41151793Smarcel	if (args->signum < 0 || args->signum > LINUX_NSIG)
41251793Smarcel		return EINVAL;
41351793Smarcel
41468201Sobrien#ifndef __alpha__
41551793Smarcel	if (args->signum > 0 && args->signum <= LINUX_SIGTBLSZ)
41651793Smarcel		tmp.signum = linux_to_bsd_signal[_SIG_IDX(args->signum)];
41751793Smarcel	else
41868201Sobrien#endif
41951793Smarcel		tmp.signum = args->signum;
42051793Smarcel
42151793Smarcel	tmp.pid = args->pid;
42251793Smarcel	return (kill(p, &tmp));
4239313Ssos}
424