/*-
* Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved.
*
* 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 Emmanuel Dreyfus
* 4. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR 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 AUTHOR 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.
*/
extern const int native_to_linux32_signo[];
extern const int linux32_to_native_signo[];
#ifdef DEBUG_LINUX
#define DPRINTF(a) uprintf a
#else
#define DPRINTF(a)
#endif
void
linux32_to_native_sigset(sigset_t *bss, const linux32_sigset_t *lss)
{
int i, newsig;
sigemptyset(bss);
for (i = 1; i < LINUX32__NSIG; i++) {
if (linux32_sigismember(lss, i)) {
newsig = linux32_to_native_signo[i];
if (newsig)
sigaddset(bss, newsig);
}
}
}
void
native_to_linux32_sigset(linux32_sigset_t *lss, const sigset_t *bss)
{
int i, newsig;
linux32_sigemptyset(lss);
for (i = 1; i < NSIG; i++) {
if (sigismember(bss, i)) {
newsig = native_to_linux32_signo[i];
if (newsig)
linux32_sigaddset(lss, newsig);
}
}
}
sig = SCARG(uap, signum);
/*
* XXX: Linux has 33 realtime signals, the go binary wants to
* reset all of them; nothing else uses the last RT signal, so for
* now ignore it.
*/
if (sig == LINUX__NSIG) {
uprintf("%s: setting signal %d ignored\n", __func__, sig);
sig--; /* back to 63 which is ignored */
}
if (sig < 0 || sig >= LINUX32__NSIG) {
DPRINTF(("rt_sigaction: Bad signal number %d %d\n",
sig, LINUX32__NSIG));
return EINVAL;
}
if (sig > 0 && !linux32_to_native_signo[sig]) {
/* unknown signal... */
os.sa_handler = SIG_IGN;
sigemptyset(&os.sa_mask);
os.sa_flags = 0;
} else {
if ((error = sigaction1(l,
linux32_to_native_signo[sig],
SCARG_P32(uap, nsa) ? &ns : NULL,
SCARG_P32(uap, osa) ? &os : NULL,
tramp, vers)) != 0) {
DPRINTF(("rt_sigaction: sigaction %d\n", error));
return error;
}
}
if (SCARG_P32(uap, osa) != NULL) {
native_to_linux32_sigaction(&ols32, &os);
if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t))
return EINVAL;
switch (SCARG(uap, how)) {
case LINUX32_SIG_BLOCK:
how = SIG_BLOCK;
break;
case LINUX32_SIG_UNBLOCK:
how = SIG_UNBLOCK;
break;
case LINUX32_SIG_SETMASK:
how = SIG_SETMASK;
break;
default:
return EINVAL;
break;
}
if (SCARG_P32(uap, set) != NULL) {
if ((error = copyin(SCARG_P32(uap, set),
&nls32, sizeof(nls32))) != 0)
return error;
linux32_to_native_sigset(&ns, &nls32);
}
error = copyin(SCARG_P32(uap, uinfo), &info, sizeof(info));
if (error)
return error;
if (info.lsi_code >= 0)
return EPERM;
/* XXX To really implement this we need to */
/* XXX keep a list of queued signals somewhere. */
return linux32_sys_kill(l, (const void *)uap, retval);
}
int
native_to_linux32_si_code(int code)
{
int si_codes[] = {
LINUX32_SI_USER, LINUX32_SI_QUEUE, LINUX32_SI_TIMER,
LINUX32_SI_ASYNCIO, LINUX32_SI_MESGQ, LINUX32_SI_TKILL /* SI_LWP */
};
if (code <= 0 && -code < __arraycount(si_codes))
return si_codes[-code];
return code;
}
int
native_to_linux32_si_status(int code, int status)
{
int sts;
switch (code) {
case CLD_CONTINUED:
sts = LINUX_SIGCONT;
break;
case CLD_EXITED:
sts = WEXITSTATUS(status);
break;
case CLD_STOPPED:
case CLD_TRAPPED:
case CLD_DUMPED:
case CLD_KILLED:
default:
sts = native_to_linux32_signo[WTERMSIG(status)];
break;
}