freebsd-dev/sys/compat/linux/linux.c
Dmitry Chagin 4ab7403bbd Rework signal code to allow using it by other modules, like linprocfs:
1. Linux sigset always 64 bit on all platforms. In order to move Linux
sigset code to the linux_common module define it as 64 bit int. Move
Linux sigset manipulation routines to the MI path.

2. Move Linux signal number definitions to the MI path. In general, they
are the same on all platforms except for a few signals.

3. Map Linux RT signals to the FreeBSD RT signals and hide signal conversion
tables to avoid conversion errors.

4. Emulate Linux SIGPWR signal via FreeBSD SIGRTMIN signal which is outside
of allowed on Linux signal numbers.

PR:		197216
2015-05-24 17:47:20 +00:00

206 lines
5.1 KiB
C

/*-
* Copyright (c) 2015 Dmitry Chagin
* 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.
*
* THIS SOFTWARE IS PROVIDED BY 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/signalvar.h>
#include <compat/linux/linux.h>
static int bsd_to_linux_sigtbl[LINUX_SIGTBLSZ] = {
LINUX_SIGHUP, /* SIGHUP */
LINUX_SIGINT, /* SIGINT */
LINUX_SIGQUIT, /* SIGQUIT */
LINUX_SIGILL, /* SIGILL */
LINUX_SIGTRAP, /* SIGTRAP */
LINUX_SIGABRT, /* SIGABRT */
0, /* SIGEMT */
LINUX_SIGFPE, /* SIGFPE */
LINUX_SIGKILL, /* SIGKILL */
LINUX_SIGBUS, /* SIGBUS */
LINUX_SIGSEGV, /* SIGSEGV */
LINUX_SIGSYS, /* SIGSYS */
LINUX_SIGPIPE, /* SIGPIPE */
LINUX_SIGALRM, /* SIGALRM */
LINUX_SIGTERM, /* SIGTERM */
LINUX_SIGURG, /* SIGURG */
LINUX_SIGSTOP, /* SIGSTOP */
LINUX_SIGTSTP, /* SIGTSTP */
LINUX_SIGCONT, /* SIGCONT */
LINUX_SIGCHLD, /* SIGCHLD */
LINUX_SIGTTIN, /* SIGTTIN */
LINUX_SIGTTOU, /* SIGTTOU */
LINUX_SIGIO, /* SIGIO */
LINUX_SIGXCPU, /* SIGXCPU */
LINUX_SIGXFSZ, /* SIGXFSZ */
LINUX_SIGVTALRM,/* SIGVTALRM */
LINUX_SIGPROF, /* SIGPROF */
LINUX_SIGWINCH, /* SIGWINCH */
0, /* SIGINFO */
LINUX_SIGUSR1, /* SIGUSR1 */
LINUX_SIGUSR2 /* SIGUSR2 */
};
static int linux_to_bsd_sigtbl[LINUX_SIGTBLSZ] = {
SIGHUP, /* LINUX_SIGHUP */
SIGINT, /* LINUX_SIGINT */
SIGQUIT, /* LINUX_SIGQUIT */
SIGILL, /* LINUX_SIGILL */
SIGTRAP, /* LINUX_SIGTRAP */
SIGABRT, /* LINUX_SIGABRT */
SIGBUS, /* LINUX_SIGBUS */
SIGFPE, /* LINUX_SIGFPE */
SIGKILL, /* LINUX_SIGKILL */
SIGUSR1, /* LINUX_SIGUSR1 */
SIGSEGV, /* LINUX_SIGSEGV */
SIGUSR2, /* LINUX_SIGUSR2 */
SIGPIPE, /* LINUX_SIGPIPE */
SIGALRM, /* LINUX_SIGALRM */
SIGTERM, /* LINUX_SIGTERM */
SIGBUS, /* LINUX_SIGSTKFLT */
SIGCHLD, /* LINUX_SIGCHLD */
SIGCONT, /* LINUX_SIGCONT */
SIGSTOP, /* LINUX_SIGSTOP */
SIGTSTP, /* LINUX_SIGTSTP */
SIGTTIN, /* LINUX_SIGTTIN */
SIGTTOU, /* LINUX_SIGTTOU */
SIGURG, /* LINUX_SIGURG */
SIGXCPU, /* LINUX_SIGXCPU */
SIGXFSZ, /* LINUX_SIGXFSZ */
SIGVTALRM, /* LINUX_SIGVTALARM */
SIGPROF, /* LINUX_SIGPROF */
SIGWINCH, /* LINUX_SIGWINCH */
SIGIO, /* LINUX_SIGIO */
/*
* FreeBSD does not have SIGPWR signal, map Linux SIGPWR signal
* to the first unused FreeBSD signal number. Since Linux supports
* signals from 1 to 64 we are ok here as our SIGRTMIN = 65.
*/
SIGRTMIN, /* LINUX_SIGPWR */
SIGSYS /* LINUX_SIGSYS */
};
/*
* Map Linux RT signals to the FreeBSD RT signals.
*/
static inline int
linux_to_bsd_rt_signal(int sig)
{
return (SIGRTMIN + 1 + sig - LINUX_SIGRTMIN);
}
static inline int
bsd_to_linux_rt_signal(int sig)
{
return (sig - SIGRTMIN - 1 + LINUX_SIGRTMIN);
}
int
linux_to_bsd_signal(int sig)
{
KASSERT(sig > 0 && sig <= LINUX_SIGRTMAX, ("Invalid Linux signal\n"));
if (sig < LINUX_SIGRTMIN)
return (linux_to_bsd_sigtbl[_SIG_IDX(sig)]);
return (linux_to_bsd_rt_signal(sig));
}
int
bsd_to_linux_signal(int sig)
{
if (sig <= LINUX_SIGTBLSZ)
return (bsd_to_linux_sigtbl[_SIG_IDX(sig)]);
if (sig == SIGRTMIN)
return (LINUX_SIGPWR);
return (bsd_to_linux_rt_signal(sig));
}
int
linux_to_bsd_sigaltstack(int lsa)
{
int bsa = 0;
if (lsa & LINUX_SS_DISABLE)
bsa |= SS_DISABLE;
/*
* Linux ignores SS_ONSTACK flag for ss
* parameter while FreeBSD prohibits it.
*/
return (bsa);
}
int
bsd_to_linux_sigaltstack(int bsa)
{
int lsa = 0;
if (bsa & SS_DISABLE)
lsa |= LINUX_SS_DISABLE;
if (bsa & SS_ONSTACK)
lsa |= LINUX_SS_ONSTACK;
return (lsa);
}
void
linux_to_bsd_sigset(l_sigset_t *lss, sigset_t *bss)
{
int b, l;
SIGEMPTYSET(*bss);
for (l = 1; l <= LINUX_SIGRTMAX; l++) {
if (LINUX_SIGISMEMBER(*lss, l)) {
b = linux_to_bsd_signal(l);
if (b)
SIGADDSET(*bss, b);
}
}
}
void
bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss)
{
int b, l;
LINUX_SIGEMPTYSET(*lss);
for (b = 1; b <= SIGRTMAX; b++) {
if (SIGISMEMBER(*bss, b)) {
l = bsd_to_linux_signal(b);
if (l)
LINUX_SIGADDSET(*lss, l);
}
}
}