NetBSD/sys/compat/hpux/hpux_sig.c
thorpej 011d4d5f44 Add kernel support for having userland provide the signal trampoline:
* struct sigacts gets a new sigact_sigdesc structure, which has the
  sigaction and the trampoline/version.  Version 0 means "legacy kernel
  provided trampoline".  Other versions are coordinated with machine-
  dependent code in libc.
* sigaction1() grows two more arguments -- the trampoline pointer and
  the trampoline version.
* A new __sigaction_sigtramp() system call is provided to register a
  trampoline along with a signal handler.
* The handler is no longer passed to sensig() functions.  Instead,
  sendsig() looks up the handler by peeking in the sigacts for the
  process getting the signal (since it has to look in there for the
  trampoline anyway).
* Native sendsig() functions now select the appropriate trampoline and
  its arguments based on the trampoline version in the sigacts.

Changes to libc to use the new facility will be checked in later.  Kernel
version not bumped; we will ride the 1.6C bump made recently.
2002-07-04 23:32:02 +00:00

444 lines
11 KiB
C

/* $NetBSD: hpux_sig.c,v 1.23 2002/07/04 23:32:09 thorpej Exp $ */
/*
* Copyright (c) 1988 University of Utah.
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
* Science Department.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* from: Utah $Hdr: hpux_sig.c 1.4 92/01/20$
*
* @(#)hpux_sig.c 8.2 (Berkeley) 9/23/93
*/
/*
* Signal related HPUX compatibility routines
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: hpux_sig.c,v 1.23 2002/07/04 23:32:09 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/syscallargs.h>
#include <compat/hpux/hpux.h>
#include <compat/hpux/hpux_sig.h>
#include <compat/hpux/hpux_syscallargs.h>
extern const unsigned char native_to_hpux_signo[];
extern const unsigned char hpux_to_native_signo[];
/*
* XXX: In addition to mapping the signal number we also have
* to see if the "old" style signal mechinism is needed.
* If so, we set the OUSIG flag. This is not really correct
* as under HP-UX "old" style handling can be set on a per
* signal basis and we are setting it for all signals in one
* swell foop. I suspect we can get away with this since I
* doubt any program of interest mixes the two semantics.
*/
int
hpux_sys_sigvec(p, v, retval)
struct proc *p;
void *v;
register_t *retval;
{
struct hpux_sys_sigvec_args *uap = v;
struct sigvec nsv, osv;
struct sigaction nsa, osa;
int sig, error;
/* XXX */
extern void compat_43_sigvec_to_sigaction
__P((const struct sigvec *, struct sigaction *));
extern void compat_43_sigaction_to_sigvec
__P((const struct sigaction *, struct sigvec *));
/*
* XXX We don't handle HPUXSV_RESET!
*/
sig = hpuxtobsdsig(SCARG(uap, signo));
if (sig <= 0 || sig >= NSIG || sig == SIGKILL || sig == SIGSTOP)
return (EINVAL);
if (SCARG(uap, nsv)) {
error = copyin(SCARG(uap, nsv), &nsv, sizeof(nsv));
if (error)
return (error);
compat_43_sigvec_to_sigaction(&nsv, &nsa);
}
error = sigaction1(p, sig,
SCARG(uap, nsv) ? &nsa : NULL,
SCARG(uap, osv) ? &osa : NULL,
NULL, 0);
if (error)
return (error);
if (SCARG(uap, osv)) {
compat_43_sigaction_to_sigvec(&osa, &osv);
error = copyout(&osv, SCARG(uap, osv), sizeof(osv));
if (error)
return (error);
}
return (0);
}
int
hpux_sys_sigblock(p, v, retval)
struct proc *p;
void *v;
register_t *retval;
{
struct hpux_sys_sigblock_args *uap = v;
sigset_t nmask;
(void) splsched();
bsdtohpuxmask(&p->p_sigctx.ps_sigmask, (int *)retval);
hpuxtobsdmask(SCARG(uap, mask), &nmask);
sigplusset(&nmask, &p->p_sigctx.ps_sigmask);
sigminusset(&sigcantmask, &p->p_sigctx.ps_sigmask);
(void) spl0();
return (0);
}
int
hpux_sys_sigsetmask(p, v, retval)
struct proc *p;
void *v;
register_t *retval;
{
struct hpux_sys_sigsetmask_args *uap = v;
(void) splsched();
bsdtohpuxmask(&p->p_sigctx.ps_sigmask, (int *)retval);
hpuxtobsdmask(SCARG(uap, mask), &p->p_sigctx.ps_sigmask);
sigminusset(&sigcantmask, &p->p_sigctx.ps_sigmask);
(void) spl0();
return (0);
}
int
hpux_sys_sigpause(p, v, retval)
struct proc *p;
void *v;
register_t *retval;
{
struct hpux_sys_sigpause_args *uap = v;
sigset_t mask;
hpuxtobsdmask(SCARG(uap, mask), &mask);
return (sigsuspend1(p, &mask));
}
/* not totally correct, but close enuf' */
int
hpux_sys_kill(p, v, retval)
struct proc *p;
void *v;
register_t *retval;
{
struct hpux_sys_kill_args *uap = v;
if (SCARG(uap, signo)) {
SCARG(uap, signo) = hpuxtobsdsig(SCARG(uap, signo));
if (SCARG(uap, signo) == 0)
SCARG(uap, signo) = NSIG;
}
return (sys_kill(p, uap, retval));
}
/*
* The following (sigprocmask, sigpending, sigsuspend, sigaction are
* POSIX calls. Under BSD, the library routine dereferences the sigset_t
* pointers before traping. Not so under HP-UX.
*/
/*
* Manipulate signal mask.
* Note that we receive new mask, not pointer,
* and return old mask as return value;
* the library stub does the rest.
*
* XXX We don't handle all HP-UX signals!
*/
int
hpux_sys_sigprocmask(p, v, retval)
struct proc *p;
void *v;
register_t *retval;
{
struct hpux_sys_sigprocmask_args *uap = v;
int error = 0;
hpux_sigset_t sigset;
sigset_t mask;
/*
* Copy out old mask first to ensure no errors.
* (proc sigmask should not be changed if call fails for any reason)
*/
if (SCARG(uap, oset)) {
memset((caddr_t)&sigset, 0, sizeof(sigset));
bsdtohpuxmask(&p->p_sigctx.ps_sigmask, &sigset.sigset[0]);
error = copyout(&sigset, SCARG(uap, oset), sizeof(sigset));
if (error)
return (error);
}
if (SCARG(uap, set)) {
error = copyin(SCARG(uap, set), &sigset, sizeof(sigset));
if (error)
return (error);
hpuxtobsdmask(sigset.sigset[0], &mask);
(void) splsched();
switch (SCARG(uap, how)) {
case HPUXSIG_BLOCK:
sigplusset(&mask, &p->p_sigctx.ps_sigmask);
sigminusset(&sigcantmask, &p->p_sigctx.ps_sigmask);
break;
case HPUXSIG_UNBLOCK:
sigminusset(&mask, &p->p_sigctx.ps_sigmask);
break;
case HPUXSIG_SETMASK:
p->p_sigctx.ps_sigmask = mask;
sigminusset(&sigcantmask, &p->p_sigctx.ps_sigmask);
break;
default:
error = EINVAL;
break;
}
(void) spl0();
}
return (error);
}
int
hpux_sys_sigpending(p, v, retval)
struct proc *p;
void *v;
register_t *retval;
{
struct hpux_sys_sigpending_args *uap = v;
hpux_sigset_t sigset;
bsdtohpuxmask(&p->p_sigctx.ps_siglist, &sigset.sigset[0]);
return (copyout(&sigset, SCARG(uap, set), sizeof(sigset)));
}
int
hpux_sys_sigsuspend(p, v, retval)
struct proc *p;
void *v;
register_t *retval;
{
struct hpux_sys_sigsuspend_args *uap = v;
hpux_sigset_t sigset;
sigset_t mask;
int error;
error = copyin(SCARG(uap, set), &sigset, sizeof(sigset));
if (error)
return (error);
hpuxtobsdmask(sigset.sigset[0], &mask);
return (sigsuspend1(p, &mask));
}
int
hpux_sys_sigaction(p, v, retval)
struct proc *p;
void *v;
register_t *retval;
{
struct hpux_sys_sigaction_args *uap = v;
struct hpux_sigaction action;
struct hpux_sigaction *sa;
struct sigaction *bsa;
int sig, error;
sig = hpuxtobsdsig(SCARG(uap, signo));
if (sig <= 0 || sig >= NSIG || sig == SIGKILL || sig == SIGSTOP)
return (EINVAL);
bsa = &SIGACTION(p, sig);
sa = &action;
if (SCARG(uap, osa)) {
sa->sa_handler = bsa->sa_handler;
memset((caddr_t)&sa->sa_mask, 0, sizeof(sa->sa_mask));
bsdtohpuxmask(&bsa->sa_mask, &sa->sa_mask.sigset[0]);
sa->sa_flags = 0;
if (bsa->sa_flags & SA_ONSTACK)
sa->sa_flags |= HPUXSA_ONSTACK;
if (bsa->sa_flags & SA_RESETHAND)
sa->sa_flags |= HPUXSA_RESETHAND;
if (bsa->sa_flags & SA_NOCLDSTOP)
sa->sa_flags |= HPUXSA_NOCLDSTOP;
error = copyout(sa, SCARG(uap, osa), sizeof (action));
if (error)
return (error);
}
if (SCARG(uap, nsa)) {
struct sigaction act;
error = copyin(SCARG(uap, nsa), sa, sizeof(action));
if (error)
return (error);
if (sig == SIGCONT && sa->sa_handler == SIG_IGN)
return (EINVAL);
act.sa_handler = sa->sa_handler;
hpuxtobsdmask(sa->sa_mask.sigset[0], &act.sa_mask);
act.sa_flags = SA_RESTART;
if (sa->sa_flags & HPUXSA_ONSTACK)
act.sa_flags |= SA_ONSTACK;
if (sa->sa_flags & HPUXSA_RESETHAND)
act.sa_flags |= SA_RESETHAND;
if (sa->sa_flags & HPUXSA_NOCLDSTOP)
act.sa_flags |= SA_NOCLDSTOP;
error = sigaction1(p, sig, &act, NULL, NULL, 0);
if (error)
return (error);
}
return (0);
}
int
hpux_sys_ssig_6x(p, v, retval)
struct proc *p;
void *v;
register_t *retval;
{
struct hpux_sys_ssig_6x_args /* {
syscallarg(int) signo;
syscallarg(sig_t) fun;
} */ *uap = v;
int a;
struct sigaction vec;
struct sigaction *sa = &vec;
memset(sa, 0, sizeof(*sa));
a = hpuxtobsdsig(SCARG(uap, signo));
sa->sa_handler = SCARG(uap, fun);
/*
* Kill processes trying to use job control facilities
* (this'll help us find any vestiges of the old stuff).
*/
if ((a &~ 0377) ||
(sa->sa_handler != SIG_DFL && sa->sa_handler != SIG_IGN &&
((int)sa->sa_handler) & 1)) {
psignal(p, SIGSYS);
return (0);
}
if (a <= 0 || a >= NSIG || a == SIGKILL || a == SIGSTOP ||
(a == SIGCONT && sa->sa_handler == SIG_IGN))
return (EINVAL);
sigemptyset(&sa->sa_mask);
sa->sa_flags = 0;
*retval = (register_t)SIGACTION(p, a).sa_handler;
sigaction1(p, a, sa, NULL, NULL, 0);
#if 0
p->p_flag |= SOUSIG; /* mark as simulating old stuff */
#endif
return (0);
}
/* signal numbers: convert from HPUX to BSD */
int
hpuxtobsdsig(sig)
int sig;
{
if (sig < 0 || sig >= NSIG)
return(0);
return hpux_to_native_signo[sig];
}
/* signal numbers: convert from BSD to HPUX */
int
bsdtohpuxsig(sig)
int sig;
{
if (sig < 0 || sig >= NSIG)
return(0);
return native_to_hpux_signo[sig];
}
/* signal masks: convert from HPUX to BSD (not pretty or fast) */
void
hpuxtobsdmask(hpuxmask, bsdmask)
int hpuxmask;
sigset_t *bsdmask;
{
int sig, nsig;
sigemptyset(bsdmask);
for (sig = 1; sig < NSIG; sig++) {
if ((hpuxmask & (1 << sig)) != 0 &&
(nsig = hpuxtobsdsig(sig)) != 0)
sigaddset(bsdmask, sig);
}
}
void
bsdtohpuxmask(bsdmask, hpuxmask)
const sigset_t *bsdmask;
int *hpuxmask;
{
int sig, nsig;
*hpuxmask = 0;
for (sig = 1; sig < NSIG; sig++) {
if (sigismember(bsdmask, sig) &&
(nsig = bsdtohpuxsig(sig)) != 0)
*hpuxmask |= (1 << sig);
}
}