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