linux_signal.c revision 49786
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 *
2849786Smarcel *  $Id: linux_signal.c,v 1.16 1999/07/06 06:54:00 cracauer Exp $
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
379313Ssos#include <i386/linux/linux.h>
3814331Speter#include <i386/linux/linux_proto.h>
3914331Speter#include <i386/linux/linux_util.h>
409313Ssos
419313Ssosstatic sigset_t
4214331Speterlinux_to_bsd_sigset(linux_sigset_t mask) {
4314331Speter    int b, l;
449313Ssos    sigset_t new = 0;
459313Ssos
4640203Sjdp    for (l = 1; l < LINUX_NSIG; l++) {
4714331Speter	if (mask & (1 << (l - 1))) {
4814331Speter	    if ((b = linux_to_bsd_signal[l]))
4914331Speter		new |= (1 << (b - 1));
5014331Speter	}
5114331Speter    }
529313Ssos    return new;
539313Ssos}
549313Ssos
559313Ssosstatic linux_sigset_t
5614331Speterbsd_to_linux_sigset(sigset_t mask) {
5714331Speter    int b, l;
589313Ssos    sigset_t new = 0;
599313Ssos
6040203Sjdp    for (b = 1; b < NSIG; b++) {
6114331Speter	if (mask & (1 << (b - 1))) {
6214331Speter	    if ((l = bsd_to_linux_signal[b]))
6314331Speter		new |= (1 << (l - 1));
6414331Speter	}
6514331Speter    }
669313Ssos    return new;
679313Ssos}
689313Ssos
6914342Speterstatic void
7014331Speterlinux_to_bsd_sigaction(linux_sigaction_t *lsa, struct sigaction *bsa)
7114331Speter{
7248620Scracauer    bsa->sa_mask = linux_to_bsd_sigset(lsa->lsa_mask);
7348620Scracauer    bsa->sa_handler = lsa->lsa_handler;
7414331Speter    bsa->sa_flags = 0;
7548620Scracauer    if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP)
7614331Speter	bsa->sa_flags |= SA_NOCLDSTOP;
7749786Smarcel    if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT)
7849786Smarcel	bsa->sa_flags |= SA_NOCLDWAIT;
7949786Smarcel    if (lsa->lsa_flags & LINUX_SA_SIGINFO)
8049786Smarcel	bsa->sa_flags |= SA_SIGINFO;
8148620Scracauer    if (lsa->lsa_flags & LINUX_SA_ONSTACK)
8214331Speter	bsa->sa_flags |= SA_ONSTACK;
8348620Scracauer    if (lsa->lsa_flags & LINUX_SA_RESTART)
8414331Speter	bsa->sa_flags |= SA_RESTART;
8548620Scracauer    if (lsa->lsa_flags & LINUX_SA_ONESHOT)
8614331Speter	bsa->sa_flags |= SA_RESETHAND;
8748620Scracauer    if (lsa->lsa_flags & LINUX_SA_NOMASK)
8814331Speter	bsa->sa_flags |= SA_NODEFER;
8914331Speter}
909313Ssos
9114342Speterstatic void
9214331Speterbsd_to_linux_sigaction(struct sigaction *bsa, linux_sigaction_t *lsa)
9314331Speter{
9448620Scracauer    lsa->lsa_handler = bsa->sa_handler;
9548620Scracauer    lsa->lsa_restorer = NULL;	/* unsupported */
9648620Scracauer    lsa->lsa_mask = bsd_to_linux_sigset(bsa->sa_mask);
9748620Scracauer    lsa->lsa_flags = 0;
9814331Speter    if (bsa->sa_flags & SA_NOCLDSTOP)
9948620Scracauer	lsa->lsa_flags |= LINUX_SA_NOCLDSTOP;
10049786Smarcel    if (bsa->sa_flags & SA_NOCLDWAIT)
10149786Smarcel	lsa->lsa_flags |= LINUX_SA_NOCLDWAIT;
10249786Smarcel    if (bsa->sa_flags & SA_SIGINFO)
10349786Smarcel	lsa->lsa_flags |= LINUX_SA_SIGINFO;
10414331Speter    if (bsa->sa_flags & SA_ONSTACK)
10548620Scracauer	lsa->lsa_flags |= LINUX_SA_ONSTACK;
10614331Speter    if (bsa->sa_flags & SA_RESTART)
10748620Scracauer	lsa->lsa_flags |= LINUX_SA_RESTART;
10814331Speter    if (bsa->sa_flags & SA_RESETHAND)
10948620Scracauer	lsa->lsa_flags |= LINUX_SA_ONESHOT;
11014331Speter    if (bsa->sa_flags & SA_NODEFER)
11148620Scracauer	lsa->lsa_flags |= LINUX_SA_NOMASK;
11214331Speter}
11314331Speter
11449786Smarcelstatic int
11549786Smarcellinux_do_sigaction(struct proc *p, int linux_sig, linux_sigaction_t *linux_nsa,
11649786Smarcel		   linux_sigaction_t *linux_osa)
11749786Smarcel{
11849786Smarcel    struct sigaction *nsa, *osa, sa;
11949786Smarcel    struct sigaction_args sa_args;
12049786Smarcel    int error;
12149786Smarcel    caddr_t sg = stackgap_init();
12249786Smarcel
12349786Smarcel    if (linux_sig <= 0 || linux_sig >= LINUX_NSIG)
12449786Smarcel	return EINVAL;
12549786Smarcel
12649786Smarcel    if (linux_osa)
12749786Smarcel	osa = stackgap_alloc(&sg, sizeof(struct sigaction));
12849786Smarcel    else
12949786Smarcel	osa = NULL;
13049786Smarcel
13149786Smarcel    if (linux_nsa) {
13249786Smarcel	nsa = stackgap_alloc(&sg, sizeof(struct sigaction));
13349786Smarcel	linux_to_bsd_sigaction(linux_nsa, &sa);
13449786Smarcel	error = copyout(&sa, nsa, sizeof(struct sigaction));
13549786Smarcel	if (error)
13649786Smarcel	    return error;
13749786Smarcel    }
13849786Smarcel    else
13949786Smarcel	nsa = NULL;
14049786Smarcel
14149786Smarcel    sa_args.signum = linux_to_bsd_signal[linux_sig];
14249786Smarcel    sa_args.nsa = nsa;
14349786Smarcel    sa_args.osa = osa;
14449786Smarcel    error = sigaction(p, &sa_args);
14549786Smarcel    if (error)
14649786Smarcel	return error;
14749786Smarcel
14849786Smarcel    if (linux_osa) {
14949786Smarcel	error = copyin(osa, &sa, sizeof(struct sigaction));
15049786Smarcel	if (error)
15149786Smarcel	    return error;
15249786Smarcel	bsd_to_linux_sigaction(&sa, linux_osa);
15349786Smarcel    }
15449786Smarcel
15549786Smarcel    return 0;
15649786Smarcel}
15749786Smarcel
1589313Ssosint
15930994Sphklinux_sigaction(struct proc *p, struct linux_sigaction_args *args)
1609313Ssos{
16149786Smarcel    linux_sigaction_t nsa, osa;
1629313Ssos    int error;
16349786Smarcel
1649313Ssos#ifdef DEBUG
16537950Sbde    printf("Linux-emul(%ld): sigaction(%d, %p, %p)\n",
16649786Smarcel	   (long)p->p_pid, args->sig, (void *)args->nsa, (void *)args->osa);
1679313Ssos#endif
1689313Ssos
1699313Ssos    if (args->nsa) {
17049786Smarcel	error = copyin(args->nsa, &nsa, sizeof(linux_sigaction_t));
17146571Speter	if (error)
1729313Ssos	    return error;
1739313Ssos    }
17449786Smarcel
17549786Smarcel    error = linux_do_sigaction(p, args->sig,
17649786Smarcel			       args->nsa ? &nsa : NULL,
17749786Smarcel			       args->osa ? &osa : NULL);
17846571Speter    if (error)
1799313Ssos	return error;
1809313Ssos
1819313Ssos    if (args->osa) {
18249786Smarcel	error = copyout(&osa, args->osa, sizeof(linux_sigaction_t));
18346571Speter	if (error)
1849313Ssos	    return error;
1859313Ssos    }
18649786Smarcel
1879313Ssos    return 0;
1889313Ssos}
1899313Ssos
19014331Speterint
19130994Sphklinux_signal(struct proc *p, struct linux_signal_args *args)
19214331Speter{
19349786Smarcel    linux_sigaction_t nsa, osa;
19414331Speter    int error;
1959313Ssos
19614331Speter#ifdef DEBUG
19737950Sbde    printf("Linux-emul(%ld): signal(%d, %p)\n",
19849786Smarcel	   (long)p->p_pid, args->sig, (void *)args->handler);
19914331Speter#endif
20049786Smarcel
20149786Smarcel    nsa.lsa_handler = args->handler;
20249786Smarcel    nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK;
20349786Smarcel    nsa.lsa_mask = NULL;
20449786Smarcel
20549786Smarcel    error = linux_do_sigaction(p, args->sig, &nsa, &osa);
20649786Smarcel
20749786Smarcel    p->p_retval[0] = (int)osa.lsa_handler;
20849786Smarcel
20949786Smarcel    return 0;
21049786Smarcel}
21149786Smarcel
21249786Smarcelint
21349786Smarcellinux_rt_sigaction(struct proc *p, struct linux_rt_sigaction_args *args)
21449786Smarcel{
21549786Smarcel    linux_sigaction_t nsa, osa;
21649786Smarcel    linux_new_sigaction_t new_sa;
21749786Smarcel    int error;
21849786Smarcel
21949786Smarcel#ifdef DEBUG
22049786Smarcel    printf("Linux-emul(%ld): rt_sigaction(%d, %p, %p, %d)\n",
22149786Smarcel	   (long)p->p_pid, args->sig, (void *)args->act,
22249786Smarcel	   (void *)args->oact, args->sigsetsize);
22349786Smarcel#endif
22449786Smarcel
22549786Smarcel    if (args->sigsetsize != sizeof(linux_new_sigset_t))
22640203Sjdp	return EINVAL;
22714331Speter
22849786Smarcel#ifdef DEBUG
22949786Smarcel    if (args->sig >= LINUX_NSIG) {
23049786Smarcel	printf("LINUX(%ld): rt_sigaction: 64-bit signal (%d)\n",
23149786Smarcel	       (long)p->p_pid, args->sig);
23249786Smarcel    }
23349786Smarcel#endif
23414331Speter
23549786Smarcel    if (args->act) {
23649786Smarcel	error = copyin(args->act, &new_sa, sizeof(linux_new_sigaction_t));
23749786Smarcel	if (error)
23849786Smarcel	    return error;
23914331Speter
24049786Smarcel	nsa.lsa_handler = new_sa.lsa_handler;
24149786Smarcel	nsa.lsa_mask = new_sa.lsa_mask.sig[0];
24249786Smarcel	nsa.lsa_flags = new_sa.lsa_flags;
24349786Smarcel	nsa.lsa_restorer = new_sa.lsa_restorer;
24449786Smarcel
24549786Smarcel#ifdef DEBUG
24649786Smarcel	if (new_sa.lsa_mask.sig[1] != 0)
24749786Smarcel	    printf("LINUX(%ld): rt_sigaction: sig[1] = 0x%08lx\n",
24849786Smarcel		   (long)p->p_pid, new_sa.lsa_mask.sig[1]);
24949786Smarcel#endif
25049786Smarcel    }
25149786Smarcel
25249786Smarcel    error = linux_do_sigaction(p, args->sig,
25349786Smarcel			       args->act ? &nsa : NULL,
25449786Smarcel			       args->oact ? &osa : NULL);
25549786Smarcel    if (error)
25614331Speter	return error;
25714331Speter
25849786Smarcel    if (args->oact) {
25949786Smarcel	new_sa.lsa_handler = osa.lsa_handler;
26049786Smarcel	new_sa.lsa_flags = osa.lsa_flags;
26149786Smarcel	new_sa.lsa_restorer = osa.lsa_restorer;
26249786Smarcel	new_sa.lsa_mask.sig[0] = osa.lsa_mask;
26349786Smarcel	new_sa.lsa_mask.sig[1] = 0;
26449786Smarcel	error = copyout(&osa, args->oact, sizeof(linux_new_sigaction_t));
26549786Smarcel	if (error)
26649786Smarcel	    return error;
26749786Smarcel    }
26814331Speter
26914331Speter    return 0;
27014331Speter}
27114331Speter
27249786Smarcelstatic int
27349786Smarcellinux_do_sigprocmask(struct proc *p, int how, linux_sigset_t *new,
27449786Smarcel		     linux_sigset_t *old)
27549786Smarcel{
27649786Smarcel    int error = 0, s;
27749786Smarcel    sigset_t mask;
27814331Speter
27949786Smarcel    p->p_retval[0] = 0;
28049786Smarcel
28149786Smarcel    if (old != NULL)
28249786Smarcel	*old = bsd_to_linux_sigset(p->p_sigmask);
28349786Smarcel
28449786Smarcel    if (new != NULL) {
28549786Smarcel	mask = linux_to_bsd_sigset(*new);
28649786Smarcel
28749786Smarcel	s = splhigh();
28849786Smarcel
28949786Smarcel	switch (how) {
29049786Smarcel	case LINUX_SIG_BLOCK:
29149786Smarcel	    p->p_sigmask |= (mask & ~sigcantmask);
29249786Smarcel	    break;
29349786Smarcel	case LINUX_SIG_UNBLOCK:
29449786Smarcel	    p->p_sigmask &= ~mask;
29549786Smarcel	    break;
29649786Smarcel	case LINUX_SIG_SETMASK:
29749786Smarcel	    p->p_sigmask = (mask & ~sigcantmask);
29849786Smarcel	    break;
29949786Smarcel	default:
30049786Smarcel	    error = EINVAL;
30149786Smarcel	    break;
30249786Smarcel	}
30349786Smarcel
30449786Smarcel	splx(s);
30549786Smarcel    }
30649786Smarcel
30749786Smarcel    return error;
30849786Smarcel}
30949786Smarcel
3109313Ssosint
31130994Sphklinux_sigprocmask(struct proc *p, struct linux_sigprocmask_args *args)
3129313Ssos{
31349786Smarcel    linux_sigset_t mask;
31449786Smarcel    linux_sigset_t omask;
31549786Smarcel    int error;
3169313Ssos
3179313Ssos#ifdef DEBUG
3189313Ssos    printf("Linux-emul(%d): sigprocmask(%d, *, *)\n", p->p_pid, args->how);
3199313Ssos#endif
32014331Speter
32149786Smarcel    if (args->mask != NULL) {
32249786Smarcel	error = copyin(args->mask, &mask, sizeof(linux_sigset_t));
32349786Smarcel	if (error)
32449786Smarcel	    return error;
32549786Smarcel    }
32614331Speter
32749786Smarcel    error = linux_do_sigprocmask(p, args->how,
32849786Smarcel				 args->mask ? &mask : NULL,
32949786Smarcel				 args->omask ? &omask : NULL);
33049786Smarcel
33149786Smarcel    if (!error && args->omask != NULL) {
33249786Smarcel	error = copyout(&omask, args->omask, sizeof(linux_sigset_t));
33349786Smarcel    }
33449786Smarcel
33549786Smarcel    return error;
33649786Smarcel}
33749786Smarcel
33849786Smarcelint
33949786Smarcellinux_rt_sigprocmask(struct proc *p, struct linux_rt_sigprocmask_args *args)
34049786Smarcel{
34149786Smarcel    linux_new_sigset_t new_mask;
34249786Smarcel    linux_sigset_t old_mask;
34349786Smarcel    int error;
34449786Smarcel
34549786Smarcel#ifdef DEBUG
34649786Smarcel    printf("Linux-emul(%ld): rt_sigprocmask(%d, %p, %p, %d)\n",
34749786Smarcel	   (long)p->p_pid, args->how, (void *)args->mask,
34849786Smarcel	   (void *)args->omask, args->sigsetsize);
34949786Smarcel#endif
35049786Smarcel
35149786Smarcel    if (args->sigsetsize != sizeof(linux_new_sigset_t))
35249786Smarcel	return EINVAL;
35349786Smarcel
35449786Smarcel    if (args->mask != NULL) {
35549786Smarcel	error = copyin(args->mask, &new_mask, sizeof(linux_new_sigset_t));
35646571Speter	if (error)
3579313Ssos	    return error;
35849786Smarcel
35949786Smarcel#ifdef DEBUG
36049786Smarcel	if (new_mask.sig[1] != 0)
36149786Smarcel	    printf("LINUX(%ld): rt_sigprocmask: sig[1] = 0x%08lx\n",
36249786Smarcel		   (long)p->p_pid, new_mask.sig[1]);
36349786Smarcel#endif
3649313Ssos    }
3659313Ssos
36649786Smarcel    error = linux_do_sigprocmask(p, args->how,
36749786Smarcel				 args->mask ? new_mask.sig : NULL,
36849786Smarcel				 args->omask ? &old_mask : NULL);
36949786Smarcel
37049786Smarcel    if (!error && args->omask != NULL) {
37149786Smarcel	new_mask.sig[0] = old_mask;
37249786Smarcel	error = copyout(&new_mask, args->omask, sizeof(linux_new_sigset_t));
3739313Ssos    }
37449786Smarcel
3759313Ssos    return error;
3769313Ssos}
3779313Ssos
3789313Ssosint
37930994Sphklinux_siggetmask(struct proc *p, struct linux_siggetmask_args *args)
3809313Ssos{
3819313Ssos#ifdef DEBUG
3829313Ssos    printf("Linux-emul(%d): siggetmask()\n", p->p_pid);
3839313Ssos#endif
38430994Sphk    p->p_retval[0] = bsd_to_linux_sigset(p->p_sigmask);
3859313Ssos    return 0;
3869313Ssos}
3879313Ssos
3889313Ssosint
38930994Sphklinux_sigsetmask(struct proc *p, struct linux_sigsetmask_args *args)
3909313Ssos{
3919313Ssos    int s;
39214331Speter    sigset_t mask;
3939313Ssos
3949313Ssos#ifdef DEBUG
39538344Sbde    printf("Linux-emul(%ld): sigsetmask(%08lx)\n",
39638344Sbde	(long)p->p_pid, (unsigned long)args->mask);
3979313Ssos#endif
39830994Sphk    p->p_retval[0] = bsd_to_linux_sigset(p->p_sigmask);
39914331Speter
40014331Speter    mask = linux_to_bsd_sigset(args->mask);
4019313Ssos    s = splhigh();
40214331Speter    p->p_sigmask = mask & ~sigcantmask;
4039313Ssos    splx(s);
4049313Ssos    return 0;
4059313Ssos}
4069313Ssos
4079313Ssosint
40830994Sphklinux_sigpending(struct proc *p, struct linux_sigpending_args *args)
4099313Ssos{
4109313Ssos    linux_sigset_t linux_sig;
4119313Ssos
4129313Ssos#ifdef DEBUG
4139313Ssos    printf("Linux-emul(%d): sigpending(*)\n", p->p_pid);
4149313Ssos#endif
41514331Speter    linux_sig = bsd_to_linux_sigset(p->p_siglist & p->p_sigmask);
4169313Ssos    return copyout(&linux_sig, args->mask, sizeof(linux_sig));
4179313Ssos}
4189313Ssos
41914381Speter/*
42014381Speter * Linux has two extra args, restart and oldmask.  We dont use these,
42114381Speter * but it seems that "restart" is actually a context pointer that
42214381Speter * enables the signal to happen with a different register set.
42314381Speter */
4249313Ssosint
42530994Sphklinux_sigsuspend(struct proc *p, struct linux_sigsuspend_args *args)
4269313Ssos{
42714331Speter    struct sigsuspend_args tmp;
4289313Ssos
4299313Ssos#ifdef DEBUG
43038344Sbde    printf("Linux-emul(%ld): sigsuspend(%08lx)\n",
43138344Sbde	(long)p->p_pid, (unsigned long)args->mask);
4329313Ssos#endif
43314331Speter    tmp.mask = linux_to_bsd_sigset(args->mask);
43430994Sphk    return sigsuspend(p, &tmp);
4359313Ssos}
4369313Ssos
43714331Speterint
43830994Sphklinux_pause(struct proc *p, struct linux_pause_args *args)
43914331Speter{
44014331Speter    struct sigsuspend_args tmp;
4419313Ssos
44214331Speter#ifdef DEBUG
44314331Speter    printf("Linux-emul(%d): pause()\n", p->p_pid);
44414331Speter#endif
44514331Speter    tmp.mask = p->p_sigmask;
44630994Sphk    return sigsuspend(p, &tmp);
44714331Speter}
44814331Speter
4499313Ssosint
45030994Sphklinux_kill(struct proc *p, struct linux_kill_args *args)
4519313Ssos{
45212858Speter    struct kill_args /* {
4539313Ssos	int pid;
4549313Ssos	int signum;
45512858Speter    } */ tmp;
4569313Ssos
4579313Ssos#ifdef DEBUG
4589313Ssos    printf("Linux-emul(%d): kill(%d, %d)\n",
4599313Ssos	   p->p_pid, args->pid, args->signum);
4609313Ssos#endif
46141986Ssos    if (args->signum < 0 || args->signum >= LINUX_NSIG)
46240203Sjdp	return EINVAL;
4639313Ssos    tmp.pid = args->pid;
4649313Ssos    tmp.signum = linux_to_bsd_signal[args->signum];
46530994Sphk    return kill(p, &tmp);
4669313Ssos}
467