#include <sys/types.h>
#include <sys/brand.h>
#include <sys/errno.h>
#include <sys/sysconfig.h>
#include <sys/ucontext.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <strings.h>
#include <signal.h>
#include <s10_brand.h>
#include <brand_misc.h>
#include <s10_misc.h>
#include <s10_signal.h>
s10_sighandler_t s10_handlers[S10_NSIG - 1];
static int
native_sigrtmin()
{
static int sigrtmin;
sysret_t rval;
if (sigrtmin)
return (sigrtmin);
sigrtmin = __systemcall(&rval, SYS_sysconfig + 1024, _CONFIG_SIGRT_MIN)?
_SIGRTMIN : (int)rval.sys_rval1;
return (sigrtmin);
}
static int
native_sigrtmax()
{
static int sigrtmax;
sysret_t rval;
if (sigrtmax)
return (sigrtmax);
sigrtmax = __systemcall(&rval, SYS_sysconfig + 1024, _CONFIG_SIGRT_MAX)?
_SIGRTMAX : (int)rval.sys_rval1;
return (sigrtmax);
}
#define NATIVE_SIGRTMIN (native_sigrtmin())
#define NATIVE_SIGRTMAX (native_sigrtmax())
#define MAXBITNO (NBPW*8)
#define SIGWORD(n) ((n-1)/MAXBITNO)
#define BITMASK(n) (1L<<((n-1)%MAXBITNO))
#define SIGADDSET(sigset, sig) \
((sigset)->__sigbits[SIGWORD(sig)] |= BITMASK(sig))
#define SIGISMEMBER(sigset, sig) \
(((sigset)->__sigbits[SIGWORD(sig)] & BITMASK(sig)) != 0)
static int
s10sig_to_native(int sig)
{
if (sig <= SIGJVM2)
return (sig);
if (sig < S10_SIGRTMIN)
return (-1);
if (sig > S10_MAXSIG)
return (-1);
sig -= S10_SIGRTMIN;
if (sig > (NATIVE_SIGRTMAX - NATIVE_SIGRTMIN))
return (-1);
return (NATIVE_SIGRTMIN + sig);
}
int
s10sigset_to_native(const sigset_t *s10_set, sigset_t *native_set)
{
int sig;
int nativesig;
sigset_t srcset, newset;
if (brand_uucopy(s10_set, &srcset, sizeof (sigset_t)) != 0)
return (EFAULT);
(void) sigemptyset(&newset);
newset.__sigbits[0] = srcset.__sigbits[0];
for (sig = 33; sig <= SIGJVM2; sig++)
if (SIGISMEMBER(&srcset, sig))
SIGADDSET(&newset, sig);
for (sig = S10_SIGRTMIN; sig <= S10_SIGRTMAX; sig++) {
if (SIGISMEMBER(&srcset, sig) &&
(nativesig = s10sig_to_native(sig)) > 0)
SIGADDSET(&newset, nativesig);
}
if (brand_uucopy(&newset, native_set, sizeof (sigset_t)) != 0)
return (EFAULT);
return (0);
}
int
nativesig_to_s10(int sig)
{
if (sig <= SIGJVM2)
return (sig);
if (sig < NATIVE_SIGRTMIN)
return (-1);
sig -= NATIVE_SIGRTMIN;
if (sig > (S10_SIGRTMAX - S10_SIGRTMIN))
return (-1);
return (S10_SIGRTMIN + sig);
}
int
nativesigset_to_s10(const sigset_t *native_set, sigset_t *s10_set)
{
int sig;
int s10sig;
sigset_t srcset, newset;
if (brand_uucopy(native_set, &srcset, sizeof (sigset_t)) != 0)
return (EFAULT);
(void) sigemptyset(&newset);
newset.__sigbits[0] = srcset.__sigbits[0];
for (sig = 33; sig <= SIGJVM2; sig++)
if (SIGISMEMBER(&srcset, sig))
SIGADDSET(&newset, sig);
for (sig = NATIVE_SIGRTMIN; sig <= NATIVE_SIGRTMAX; sig++) {
if (SIGISMEMBER(&srcset, sig) &&
(s10sig = nativesig_to_s10(sig)) > 0)
SIGADDSET(&newset, s10sig);
}
if (brand_uucopy(&newset, s10_set, sizeof (sigset_t)) != 0)
return (EFAULT);
return (0);
}
static void
s10_sigacthandler(int sig, siginfo_t *sip, void *uvp)
{
int s10_sig;
ucontext_t *ucp;
s10_sig = nativesig_to_s10(sig);
if (s10_sig <= 0)
brand_abort(sig, "Received an impossible signal");
if (sip != NULL) {
if (sip->si_signo != sig)
brand_abort(sig, "Received an impossible siginfo");
sip->si_signo = s10_sig;
}
if ((ucp = uvp) != NULL &&
(ucp->uc_flags & UC_SIGMASK))
(void) nativesigset_to_s10(&ucp->uc_sigmask, &ucp->uc_sigmask);
s10_handlers[s10_sig - 1](s10_sig, sip, uvp);
}
int
s10_lwp_sigmask(sysret_t *rval, int how, uint_t bits0, uint_t bits1)
{
sigset_t s10_blockset;
sigset_t native_blockset;
int err;
s10_blockset.__sigbits[0] = bits0;
s10_blockset.__sigbits[1] = bits1;
s10_blockset.__sigbits[2] = 0;
s10_blockset.__sigbits[3] = 0;
(void) s10sigset_to_native(&s10_blockset, &native_blockset);
err = __systemcall(rval, SYS_lwp_sigmask + 1024,
how,
native_blockset.__sigbits[0],
native_blockset.__sigbits[1],
native_blockset.__sigbits[2],
native_blockset.__sigbits[3]);
if (err != 0)
return (err);
native_blockset.__sigbits[0] = (int)rval->sys_rval1;
native_blockset.__sigbits[1] = (int)rval->sys_rval2;
native_blockset.__sigbits[2] = 0;
native_blockset.__sigbits[3] = 0;
(void) nativesigset_to_s10(&native_blockset, &s10_blockset);
rval->sys_rval1 = s10_blockset.__sigbits[0];
rval->sys_rval2 = s10_blockset.__sigbits[1];
return (0);
}
int
s10_sigprocmask(sysret_t *rval, int how, const sigset_t *set, sigset_t *oset)
{
sigset_t sigset_set, sigset_oset;
sigset_t *set_ptr, *oset_ptr;
int err;
oset_ptr = (oset == NULL) ? NULL : &sigset_oset;
set_ptr = (set == NULL) ? NULL : &sigset_set;
if (set_ptr != NULL &&
(err = s10sigset_to_native(set, set_ptr)) != 0)
return (err);
if ((err = __systemcall(rval, SYS_sigprocmask + 1024,
how, set_ptr, oset_ptr)) != 0)
return (err);
if (oset_ptr != NULL &&
(err = nativesigset_to_s10(oset_ptr, oset)) != 0)
return (err);
return (0);
}
int
s10_sigsuspend(sysret_t *rval, const sigset_t *set)
{
sigset_t sigset_set;
int err;
if ((err = s10sigset_to_native(set, &sigset_set)) != 0) {
(void) B_TRUSS_POINT_1(rval, SYS_sigsuspend, err, set);
return (err);
}
return (__systemcall(rval, SYS_sigsuspend + 1024, &sigset_set));
}
int
s10_sigaction(sysret_t *rval,
int sig, const struct sigaction *act, struct sigaction *oact)
{
struct sigaction sigact, osigact;
struct sigaction *sigactp, *osigactp;
int err, nativesig;
void (*handler)();
if ((nativesig = s10sig_to_native(sig)) < 0) {
(void) B_TRUSS_POINT_3(rval, SYS_sigaction, EINVAL,
sig, act, oact);
return (EINVAL);
}
if (act == NULL) {
sigactp = NULL;
} else {
sigactp = &sigact;
if (brand_uucopy(act, sigactp, sizeof (struct sigaction)) != 0)
return (EFAULT);
if ((err = s10sigset_to_native(&sigactp->sa_mask,
&sigactp->sa_mask)) != 0) {
(void) B_TRUSS_POINT_3(rval, SYS_sigaction, err,
sig, act, oact);
return (err);
}
}
osigactp = ((oact == NULL) ? NULL : &osigact);
if (sigactp != NULL) {
handler = sigactp->sa_handler;
if (handler != SIG_DFL && handler != SIG_IGN)
sigactp->sa_sigaction = s10_sigacthandler;
}
if ((err = __systemcall(rval, SYS_sigaction + 1024,
nativesig, sigactp, osigactp)) != 0)
return (err);
if (osigactp != NULL) {
err = nativesigset_to_s10(&osigactp->sa_mask,
&osigactp->sa_mask);
if (osigactp->sa_sigaction == s10_sigacthandler)
osigactp->sa_sigaction = s10_handlers[sig - 1];
if (err == 0 && brand_uucopy(osigactp, oact,
sizeof (struct sigaction)) != 0)
err = EFAULT;
}
if (sigactp != NULL &&
handler != SIG_DFL && handler != SIG_IGN)
s10_handlers[sig - 1] = handler;
return (err);
}
int
s10_sigpending(sysret_t *rval, int flag, sigset_t *set)
{
sigset_t sigset_set;
int err;
if ((err = __systemcall(rval, SYS_sigpending + 1024,
flag, &sigset_set)) != 0)
return (err);
if ((err = nativesigset_to_s10(&sigset_set, set)) != 0)
return (err);
return (0);
}
int
s10_sigsendsys(sysret_t *rval, procset_t *psp, int sig)
{
int nativesig;
if ((nativesig = s10sig_to_native(sig)) < 0) {
(void) B_TRUSS_POINT_2(rval, SYS_sigsendsys, EINVAL,
psp, sig);
return (EINVAL);
}
return (__systemcall(rval, SYS_sigsendsys + 1024, psp, nativesig));
}
static int
wstat(int code, int status)
{
int stat = (status & 0377);
switch (code) {
case CLD_EXITED:
stat <<= 8;
break;
case CLD_DUMPED:
stat |= WCOREFLG;
break;
case CLD_KILLED:
break;
case CLD_TRAPPED:
case CLD_STOPPED:
stat <<= 8;
stat |= WSTOPFLG;
break;
case CLD_CONTINUED:
stat = WCONTFLG;
break;
}
return (stat);
}
int
s10_wait(sysret_t *rval)
{
int err;
siginfo_t info;
err = s10_waitid(rval, P_ALL, 0, &info, WEXITED | WTRAPPED);
if (err != 0)
return (err);
rval->sys_rval1 = info.si_pid;
rval->sys_rval2 = wstat(info.si_code, info.si_status);
return (0);
}
int
s10_waitid(sysret_t *rval,
idtype_t idtype, id_t id, siginfo_t *infop, int options)
{
int err, sig;
err = __systemcall(rval, SYS_waitid + 1024, idtype, id, infop, options);
if (err != 0)
return (err);
if (infop->si_signo == SIGCLD && infop->si_code != CLD_EXITED &&
(sig = nativesig_to_s10(infop->si_status)) > 0)
infop->si_status = sig;
return (0);
}
int
s10_sigtimedwait(sysret_t *rval,
const sigset_t *set, siginfo_t *info, const timespec_t *timeout)
{
sigset_t sigset_set;
int err, sig;
if ((err = s10sigset_to_native(set, &sigset_set)) != 0) {
(void) B_TRUSS_POINT_3(rval, SYS_sigtimedwait, err,
set, info, timeout);
return (err);
}
if ((err = __systemcall(rval, SYS_sigtimedwait + 1024,
&sigset_set, info, timeout)) != 0)
return (err);
if (info != NULL) {
if ((sig = nativesig_to_s10(info->si_signo)) > 0)
info->si_signo = sig;
}
if ((sig = nativesig_to_s10((int)rval->sys_rval1)) > 0)
rval->sys_rval1 = sig;
return (0);
}
int
s10_sigqueue(sysret_t *rval, pid_t pid, int signo, void *value, int si_code)
{
int nativesig;
if ((nativesig = s10sig_to_native(signo)) < 0) {
(void) B_TRUSS_POINT_4(rval, SYS_sigqueue, EINVAL,
pid, signo, value, si_code);
return (EINVAL);
}
if (pid == 1)
pid = zone_init_pid;
return (__systemcall(rval, SYS_sigqueue + 1024,
pid, nativesig, value, si_code, 0));
}
int
s10_signotify(sysret_t *rval,
int cmd, siginfo_t *siginfo, signotify_id_t *sn_id)
{
siginfo_t *infop, info;
infop = siginfo;
if (cmd == SN_PROC) {
int nativesig;
if (brand_uucopy(infop, &info, sizeof (siginfo_t)) != 0)
return (EFAULT);
if ((nativesig = s10sig_to_native(info.si_signo)) < 0) {
(void) B_TRUSS_POINT_3(rval, SYS_signotify, EINVAL,
cmd, siginfo, sn_id);
return (EINVAL);
}
info.si_signo = nativesig;
infop = &info;
}
return (__systemcall(rval, SYS_signotify + 1024, cmd, infop, sn_id));
}
int
s10_kill(sysret_t *rval, pid_t pid, int sig)
{
int nativesig;
if ((nativesig = s10sig_to_native(sig)) < 0) {
(void) B_TRUSS_POINT_2(rval, SYS_kill, EINVAL, pid, sig);
return (EINVAL);
}
if (pid == 1)
pid = zone_init_pid;
return (__systemcall(rval, SYS_kill + 1024, pid, nativesig));
}
int
s10_lwp_create(sysret_t *rval, ucontext_t *ucp, int flags, id_t *new_lwp)
{
ucontext_t s10_uc;
if (brand_uucopy(ucp, &s10_uc, sizeof (ucontext_t)) != 0)
return (EFAULT);
if (s10_uc.uc_flags & UC_SIGMASK)
(void) s10sigset_to_native(&s10_uc.uc_sigmask,
&s10_uc.uc_sigmask);
return (__systemcall(rval, SYS_lwp_create + 1024,
&s10_uc, flags, new_lwp));
}
int
s10_lwp_kill(sysret_t *rval, id_t lwpid, int sig)
{
int nativesig;
if ((nativesig = s10sig_to_native(sig)) < 0) {
(void) B_TRUSS_POINT_2(rval, SYS_lwp_kill, EINVAL,
lwpid, sig);
return (EINVAL);
}
return (__systemcall(rval, SYS_lwp_kill + 1024, lwpid, nativesig));
}