c5156c7785
of them listed in opt_global.h which is not generated while building modules outside of a kernel and such modules never match real cofigured kernel. So, we should prevent our users from building obviously defective modules. Therefore, remove the root cause of the building of modules outside of a kernel - the possibility of building modules with DEBUG or KTR flags. And remove all of DEBUG printfs as it is incomplete and in threaded programms not informative, also a half of system call does not have DEBUG printf. For debuging Linux programms we have dtrace, ktr and ktrace ability. PR: 222861 Reviewed by: trasz MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D20178
714 lines
16 KiB
C
714 lines
16 KiB
C
/*-
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* Copyright (c) 1994-1995 Søren Schmidt
|
|
* 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/lock.h>
|
|
#include <sys/mutex.h>
|
|
#include <sys/sx.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/signalvar.h>
|
|
#include <sys/syscallsubr.h>
|
|
#include <sys/sysproto.h>
|
|
|
|
#include <security/audit/audit.h>
|
|
|
|
#include "opt_compat.h"
|
|
|
|
#ifdef COMPAT_LINUX32
|
|
#include <machine/../linux32/linux.h>
|
|
#include <machine/../linux32/linux32_proto.h>
|
|
#else
|
|
#include <machine/../linux/linux.h>
|
|
#include <machine/../linux/linux_proto.h>
|
|
#endif
|
|
#include <compat/linux/linux_signal.h>
|
|
#include <compat/linux/linux_util.h>
|
|
#include <compat/linux/linux_emul.h>
|
|
#include <compat/linux/linux_misc.h>
|
|
|
|
static int linux_do_tkill(struct thread *td, struct thread *tdt,
|
|
ksiginfo_t *ksi);
|
|
static void sicode_to_lsicode(int si_code, int *lsi_code);
|
|
|
|
|
|
static void
|
|
linux_to_bsd_sigaction(l_sigaction_t *lsa, struct sigaction *bsa)
|
|
{
|
|
|
|
linux_to_bsd_sigset(&lsa->lsa_mask, &bsa->sa_mask);
|
|
bsa->sa_handler = PTRIN(lsa->lsa_handler);
|
|
bsa->sa_flags = 0;
|
|
if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP)
|
|
bsa->sa_flags |= SA_NOCLDSTOP;
|
|
if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT)
|
|
bsa->sa_flags |= SA_NOCLDWAIT;
|
|
if (lsa->lsa_flags & LINUX_SA_SIGINFO)
|
|
bsa->sa_flags |= SA_SIGINFO;
|
|
if (lsa->lsa_flags & LINUX_SA_ONSTACK)
|
|
bsa->sa_flags |= SA_ONSTACK;
|
|
if (lsa->lsa_flags & LINUX_SA_RESTART)
|
|
bsa->sa_flags |= SA_RESTART;
|
|
if (lsa->lsa_flags & LINUX_SA_ONESHOT)
|
|
bsa->sa_flags |= SA_RESETHAND;
|
|
if (lsa->lsa_flags & LINUX_SA_NOMASK)
|
|
bsa->sa_flags |= SA_NODEFER;
|
|
}
|
|
|
|
static void
|
|
bsd_to_linux_sigaction(struct sigaction *bsa, l_sigaction_t *lsa)
|
|
{
|
|
|
|
bsd_to_linux_sigset(&bsa->sa_mask, &lsa->lsa_mask);
|
|
#ifdef COMPAT_LINUX32
|
|
lsa->lsa_handler = (uintptr_t)bsa->sa_handler;
|
|
#else
|
|
lsa->lsa_handler = bsa->sa_handler;
|
|
#endif
|
|
lsa->lsa_restorer = 0; /* unsupported */
|
|
lsa->lsa_flags = 0;
|
|
if (bsa->sa_flags & SA_NOCLDSTOP)
|
|
lsa->lsa_flags |= LINUX_SA_NOCLDSTOP;
|
|
if (bsa->sa_flags & SA_NOCLDWAIT)
|
|
lsa->lsa_flags |= LINUX_SA_NOCLDWAIT;
|
|
if (bsa->sa_flags & SA_SIGINFO)
|
|
lsa->lsa_flags |= LINUX_SA_SIGINFO;
|
|
if (bsa->sa_flags & SA_ONSTACK)
|
|
lsa->lsa_flags |= LINUX_SA_ONSTACK;
|
|
if (bsa->sa_flags & SA_RESTART)
|
|
lsa->lsa_flags |= LINUX_SA_RESTART;
|
|
if (bsa->sa_flags & SA_RESETHAND)
|
|
lsa->lsa_flags |= LINUX_SA_ONESHOT;
|
|
if (bsa->sa_flags & SA_NODEFER)
|
|
lsa->lsa_flags |= LINUX_SA_NOMASK;
|
|
}
|
|
|
|
int
|
|
linux_do_sigaction(struct thread *td, int linux_sig, l_sigaction_t *linux_nsa,
|
|
l_sigaction_t *linux_osa)
|
|
{
|
|
struct sigaction act, oact, *nsa, *osa;
|
|
int error, sig;
|
|
|
|
if (!LINUX_SIG_VALID(linux_sig))
|
|
return (EINVAL);
|
|
|
|
osa = (linux_osa != NULL) ? &oact : NULL;
|
|
if (linux_nsa != NULL) {
|
|
nsa = &act;
|
|
linux_to_bsd_sigaction(linux_nsa, nsa);
|
|
} else
|
|
nsa = NULL;
|
|
sig = linux_to_bsd_signal(linux_sig);
|
|
|
|
error = kern_sigaction(td, sig, nsa, osa, 0);
|
|
if (error)
|
|
return (error);
|
|
|
|
if (linux_osa != NULL)
|
|
bsd_to_linux_sigaction(osa, linux_osa);
|
|
|
|
return (0);
|
|
}
|
|
|
|
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
|
|
int
|
|
linux_signal(struct thread *td, struct linux_signal_args *args)
|
|
{
|
|
l_sigaction_t nsa, osa;
|
|
int error;
|
|
|
|
nsa.lsa_handler = args->handler;
|
|
nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK;
|
|
LINUX_SIGEMPTYSET(nsa.lsa_mask);
|
|
|
|
error = linux_do_sigaction(td, args->sig, &nsa, &osa);
|
|
td->td_retval[0] = (int)(intptr_t)osa.lsa_handler;
|
|
|
|
return (error);
|
|
}
|
|
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
|
|
|
|
int
|
|
linux_rt_sigaction(struct thread *td, struct linux_rt_sigaction_args *args)
|
|
{
|
|
l_sigaction_t nsa, osa;
|
|
int error;
|
|
|
|
if (args->sigsetsize != sizeof(l_sigset_t))
|
|
return (EINVAL);
|
|
|
|
if (args->act != NULL) {
|
|
error = copyin(args->act, &nsa, sizeof(l_sigaction_t));
|
|
if (error)
|
|
return (error);
|
|
}
|
|
|
|
error = linux_do_sigaction(td, args->sig,
|
|
args->act ? &nsa : NULL,
|
|
args->oact ? &osa : NULL);
|
|
|
|
if (args->oact != NULL && !error) {
|
|
error = copyout(&osa, args->oact, sizeof(l_sigaction_t));
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
static int
|
|
linux_do_sigprocmask(struct thread *td, int how, l_sigset_t *new,
|
|
l_sigset_t *old)
|
|
{
|
|
sigset_t omask, nmask;
|
|
sigset_t *nmaskp;
|
|
int error;
|
|
|
|
td->td_retval[0] = 0;
|
|
|
|
switch (how) {
|
|
case LINUX_SIG_BLOCK:
|
|
how = SIG_BLOCK;
|
|
break;
|
|
case LINUX_SIG_UNBLOCK:
|
|
how = SIG_UNBLOCK;
|
|
break;
|
|
case LINUX_SIG_SETMASK:
|
|
how = SIG_SETMASK;
|
|
break;
|
|
default:
|
|
return (EINVAL);
|
|
}
|
|
if (new != NULL) {
|
|
linux_to_bsd_sigset(new, &nmask);
|
|
nmaskp = &nmask;
|
|
} else
|
|
nmaskp = NULL;
|
|
error = kern_sigprocmask(td, how, nmaskp, &omask, 0);
|
|
if (error == 0 && old != NULL)
|
|
bsd_to_linux_sigset(&omask, old);
|
|
|
|
return (error);
|
|
}
|
|
|
|
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
|
|
int
|
|
linux_sigprocmask(struct thread *td, struct linux_sigprocmask_args *args)
|
|
{
|
|
l_osigset_t mask;
|
|
l_sigset_t set, oset;
|
|
int error;
|
|
|
|
if (args->mask != NULL) {
|
|
error = copyin(args->mask, &mask, sizeof(l_osigset_t));
|
|
if (error)
|
|
return (error);
|
|
LINUX_SIGEMPTYSET(set);
|
|
set.__mask = mask;
|
|
}
|
|
|
|
error = linux_do_sigprocmask(td, args->how,
|
|
args->mask ? &set : NULL,
|
|
args->omask ? &oset : NULL);
|
|
|
|
if (args->omask != NULL && !error) {
|
|
mask = oset.__mask;
|
|
error = copyout(&mask, args->omask, sizeof(l_osigset_t));
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
|
|
|
|
int
|
|
linux_rt_sigprocmask(struct thread *td, struct linux_rt_sigprocmask_args *args)
|
|
{
|
|
l_sigset_t set, oset;
|
|
int error;
|
|
|
|
if (args->sigsetsize != sizeof(l_sigset_t))
|
|
return (EINVAL);
|
|
|
|
if (args->mask != NULL) {
|
|
error = copyin(args->mask, &set, sizeof(l_sigset_t));
|
|
if (error)
|
|
return (error);
|
|
}
|
|
|
|
error = linux_do_sigprocmask(td, args->how,
|
|
args->mask ? &set : NULL,
|
|
args->omask ? &oset : NULL);
|
|
|
|
if (args->omask != NULL && !error) {
|
|
error = copyout(&oset, args->omask, sizeof(l_sigset_t));
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
|
|
int
|
|
linux_sgetmask(struct thread *td, struct linux_sgetmask_args *args)
|
|
{
|
|
struct proc *p = td->td_proc;
|
|
l_sigset_t mask;
|
|
|
|
PROC_LOCK(p);
|
|
bsd_to_linux_sigset(&td->td_sigmask, &mask);
|
|
PROC_UNLOCK(p);
|
|
td->td_retval[0] = mask.__mask;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
linux_ssetmask(struct thread *td, struct linux_ssetmask_args *args)
|
|
{
|
|
struct proc *p = td->td_proc;
|
|
l_sigset_t lset;
|
|
sigset_t bset;
|
|
|
|
PROC_LOCK(p);
|
|
bsd_to_linux_sigset(&td->td_sigmask, &lset);
|
|
td->td_retval[0] = lset.__mask;
|
|
LINUX_SIGEMPTYSET(lset);
|
|
lset.__mask = args->mask;
|
|
linux_to_bsd_sigset(&lset, &bset);
|
|
td->td_sigmask = bset;
|
|
SIG_CANTMASK(td->td_sigmask);
|
|
signotify(td);
|
|
PROC_UNLOCK(p);
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
linux_sigpending(struct thread *td, struct linux_sigpending_args *args)
|
|
{
|
|
struct proc *p = td->td_proc;
|
|
sigset_t bset;
|
|
l_sigset_t lset;
|
|
l_osigset_t mask;
|
|
|
|
PROC_LOCK(p);
|
|
bset = p->p_siglist;
|
|
SIGSETOR(bset, td->td_siglist);
|
|
SIGSETAND(bset, td->td_sigmask);
|
|
PROC_UNLOCK(p);
|
|
bsd_to_linux_sigset(&bset, &lset);
|
|
mask = lset.__mask;
|
|
return (copyout(&mask, args->mask, sizeof(mask)));
|
|
}
|
|
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
|
|
|
|
/*
|
|
* MPSAFE
|
|
*/
|
|
int
|
|
linux_rt_sigpending(struct thread *td, struct linux_rt_sigpending_args *args)
|
|
{
|
|
struct proc *p = td->td_proc;
|
|
sigset_t bset;
|
|
l_sigset_t lset;
|
|
|
|
if (args->sigsetsize > sizeof(lset))
|
|
return (EINVAL);
|
|
/* NOT REACHED */
|
|
|
|
PROC_LOCK(p);
|
|
bset = p->p_siglist;
|
|
SIGSETOR(bset, td->td_siglist);
|
|
SIGSETAND(bset, td->td_sigmask);
|
|
PROC_UNLOCK(p);
|
|
bsd_to_linux_sigset(&bset, &lset);
|
|
return (copyout(&lset, args->set, args->sigsetsize));
|
|
}
|
|
|
|
/*
|
|
* MPSAFE
|
|
*/
|
|
int
|
|
linux_rt_sigtimedwait(struct thread *td,
|
|
struct linux_rt_sigtimedwait_args *args)
|
|
{
|
|
int error, sig;
|
|
l_timeval ltv;
|
|
struct timeval tv;
|
|
struct timespec ts, *tsa;
|
|
l_sigset_t lset;
|
|
sigset_t bset;
|
|
l_siginfo_t linfo;
|
|
ksiginfo_t info;
|
|
|
|
if (args->sigsetsize != sizeof(l_sigset_t))
|
|
return (EINVAL);
|
|
|
|
if ((error = copyin(args->mask, &lset, sizeof(lset))))
|
|
return (error);
|
|
linux_to_bsd_sigset(&lset, &bset);
|
|
|
|
tsa = NULL;
|
|
if (args->timeout) {
|
|
if ((error = copyin(args->timeout, <v, sizeof(ltv))))
|
|
return (error);
|
|
tv.tv_sec = (long)ltv.tv_sec;
|
|
tv.tv_usec = (suseconds_t)ltv.tv_usec;
|
|
if (itimerfix(&tv)) {
|
|
/*
|
|
* The timeout was invalid. Convert it to something
|
|
* valid that will act as it does under Linux.
|
|
*/
|
|
tv.tv_sec += tv.tv_usec / 1000000;
|
|
tv.tv_usec %= 1000000;
|
|
if (tv.tv_usec < 0) {
|
|
tv.tv_sec -= 1;
|
|
tv.tv_usec += 1000000;
|
|
}
|
|
if (tv.tv_sec < 0)
|
|
timevalclear(&tv);
|
|
}
|
|
TIMEVAL_TO_TIMESPEC(&tv, &ts);
|
|
tsa = &ts;
|
|
}
|
|
error = kern_sigtimedwait(td, bset, &info, tsa);
|
|
if (error)
|
|
return (error);
|
|
|
|
sig = bsd_to_linux_signal(info.ksi_signo);
|
|
|
|
if (args->ptr) {
|
|
memset(&linfo, 0, sizeof(linfo));
|
|
ksiginfo_to_lsiginfo(&info, &linfo, sig);
|
|
error = copyout(&linfo, args->ptr, sizeof(linfo));
|
|
}
|
|
if (error == 0)
|
|
td->td_retval[0] = sig;
|
|
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
linux_kill(struct thread *td, struct linux_kill_args *args)
|
|
{
|
|
struct kill_args /* {
|
|
int pid;
|
|
int signum;
|
|
} */ tmp;
|
|
|
|
/*
|
|
* Allow signal 0 as a means to check for privileges
|
|
*/
|
|
if (!LINUX_SIG_VALID(args->signum) && args->signum != 0)
|
|
return (EINVAL);
|
|
|
|
if (args->signum > 0)
|
|
tmp.signum = linux_to_bsd_signal(args->signum);
|
|
else
|
|
tmp.signum = 0;
|
|
|
|
tmp.pid = args->pid;
|
|
return (sys_kill(td, &tmp));
|
|
}
|
|
|
|
static int
|
|
linux_do_tkill(struct thread *td, struct thread *tdt, ksiginfo_t *ksi)
|
|
{
|
|
struct proc *p;
|
|
int error;
|
|
|
|
p = tdt->td_proc;
|
|
AUDIT_ARG_SIGNUM(ksi->ksi_signo);
|
|
AUDIT_ARG_PID(p->p_pid);
|
|
AUDIT_ARG_PROCESS(p);
|
|
|
|
error = p_cansignal(td, p, ksi->ksi_signo);
|
|
if (error != 0 || ksi->ksi_signo == 0)
|
|
goto out;
|
|
|
|
tdksignal(tdt, ksi->ksi_signo, ksi);
|
|
|
|
out:
|
|
PROC_UNLOCK(p);
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
linux_tgkill(struct thread *td, struct linux_tgkill_args *args)
|
|
{
|
|
struct thread *tdt;
|
|
ksiginfo_t ksi;
|
|
int sig;
|
|
|
|
if (args->pid <= 0 || args->tgid <=0)
|
|
return (EINVAL);
|
|
|
|
/*
|
|
* Allow signal 0 as a means to check for privileges
|
|
*/
|
|
if (!LINUX_SIG_VALID(args->sig) && args->sig != 0)
|
|
return (EINVAL);
|
|
|
|
if (args->sig > 0)
|
|
sig = linux_to_bsd_signal(args->sig);
|
|
else
|
|
sig = 0;
|
|
|
|
tdt = linux_tdfind(td, args->pid, args->tgid);
|
|
if (tdt == NULL)
|
|
return (ESRCH);
|
|
|
|
ksiginfo_init(&ksi);
|
|
ksi.ksi_signo = sig;
|
|
ksi.ksi_code = SI_LWP;
|
|
ksi.ksi_errno = 0;
|
|
ksi.ksi_pid = td->td_proc->p_pid;
|
|
ksi.ksi_uid = td->td_proc->p_ucred->cr_ruid;
|
|
return (linux_do_tkill(td, tdt, &ksi));
|
|
}
|
|
|
|
/*
|
|
* Deprecated since 2.5.75. Replaced by tgkill().
|
|
*/
|
|
int
|
|
linux_tkill(struct thread *td, struct linux_tkill_args *args)
|
|
{
|
|
struct thread *tdt;
|
|
ksiginfo_t ksi;
|
|
int sig;
|
|
|
|
if (args->tid <= 0)
|
|
return (EINVAL);
|
|
|
|
if (!LINUX_SIG_VALID(args->sig))
|
|
return (EINVAL);
|
|
|
|
sig = linux_to_bsd_signal(args->sig);
|
|
|
|
tdt = linux_tdfind(td, args->tid, -1);
|
|
if (tdt == NULL)
|
|
return (ESRCH);
|
|
|
|
ksiginfo_init(&ksi);
|
|
ksi.ksi_signo = sig;
|
|
ksi.ksi_code = SI_LWP;
|
|
ksi.ksi_errno = 0;
|
|
ksi.ksi_pid = td->td_proc->p_pid;
|
|
ksi.ksi_uid = td->td_proc->p_ucred->cr_ruid;
|
|
return (linux_do_tkill(td, tdt, &ksi));
|
|
}
|
|
|
|
void
|
|
ksiginfo_to_lsiginfo(const ksiginfo_t *ksi, l_siginfo_t *lsi, l_int sig)
|
|
{
|
|
|
|
siginfo_to_lsiginfo(&ksi->ksi_info, lsi, sig);
|
|
}
|
|
|
|
static void
|
|
sicode_to_lsicode(int si_code, int *lsi_code)
|
|
{
|
|
|
|
switch (si_code) {
|
|
case SI_USER:
|
|
*lsi_code = LINUX_SI_USER;
|
|
break;
|
|
case SI_KERNEL:
|
|
*lsi_code = LINUX_SI_KERNEL;
|
|
break;
|
|
case SI_QUEUE:
|
|
*lsi_code = LINUX_SI_QUEUE;
|
|
break;
|
|
case SI_TIMER:
|
|
*lsi_code = LINUX_SI_TIMER;
|
|
break;
|
|
case SI_MESGQ:
|
|
*lsi_code = LINUX_SI_MESGQ;
|
|
break;
|
|
case SI_ASYNCIO:
|
|
*lsi_code = LINUX_SI_ASYNCIO;
|
|
break;
|
|
case SI_LWP:
|
|
*lsi_code = LINUX_SI_TKILL;
|
|
break;
|
|
default:
|
|
*lsi_code = si_code;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
siginfo_to_lsiginfo(const siginfo_t *si, l_siginfo_t *lsi, l_int sig)
|
|
{
|
|
|
|
/* sig alredy converted */
|
|
lsi->lsi_signo = sig;
|
|
sicode_to_lsicode(si->si_code, &lsi->lsi_code);
|
|
|
|
switch (si->si_code) {
|
|
case SI_LWP:
|
|
lsi->lsi_pid = si->si_pid;
|
|
lsi->lsi_uid = si->si_uid;
|
|
break;
|
|
|
|
case SI_TIMER:
|
|
lsi->lsi_int = si->si_value.sival_int;
|
|
lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
|
|
lsi->lsi_tid = si->si_timerid;
|
|
break;
|
|
|
|
case SI_QUEUE:
|
|
lsi->lsi_pid = si->si_pid;
|
|
lsi->lsi_uid = si->si_uid;
|
|
lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
|
|
break;
|
|
|
|
case SI_ASYNCIO:
|
|
lsi->lsi_int = si->si_value.sival_int;
|
|
lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
|
|
break;
|
|
|
|
default:
|
|
switch (sig) {
|
|
case LINUX_SIGPOLL:
|
|
/* XXX si_fd? */
|
|
lsi->lsi_band = si->si_band;
|
|
break;
|
|
|
|
case LINUX_SIGCHLD:
|
|
lsi->lsi_errno = 0;
|
|
lsi->lsi_pid = si->si_pid;
|
|
lsi->lsi_uid = si->si_uid;
|
|
|
|
if (si->si_code == CLD_STOPPED)
|
|
lsi->lsi_status = bsd_to_linux_signal(si->si_status);
|
|
else if (si->si_code == CLD_CONTINUED)
|
|
lsi->lsi_status = bsd_to_linux_signal(SIGCONT);
|
|
else
|
|
lsi->lsi_status = si->si_status;
|
|
break;
|
|
|
|
case LINUX_SIGBUS:
|
|
case LINUX_SIGILL:
|
|
case LINUX_SIGFPE:
|
|
case LINUX_SIGSEGV:
|
|
lsi->lsi_addr = PTROUT(si->si_addr);
|
|
break;
|
|
|
|
default:
|
|
lsi->lsi_pid = si->si_pid;
|
|
lsi->lsi_uid = si->si_uid;
|
|
if (sig >= LINUX_SIGRTMIN) {
|
|
lsi->lsi_int = si->si_value.sival_int;
|
|
lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
lsiginfo_to_ksiginfo(const l_siginfo_t *lsi, ksiginfo_t *ksi, int sig)
|
|
{
|
|
|
|
ksi->ksi_signo = sig;
|
|
ksi->ksi_code = lsi->lsi_code; /* XXX. Convert. */
|
|
ksi->ksi_pid = lsi->lsi_pid;
|
|
ksi->ksi_uid = lsi->lsi_uid;
|
|
ksi->ksi_status = lsi->lsi_status;
|
|
ksi->ksi_addr = PTRIN(lsi->lsi_addr);
|
|
ksi->ksi_info.si_value.sival_int = lsi->lsi_int;
|
|
}
|
|
|
|
int
|
|
linux_rt_sigqueueinfo(struct thread *td, struct linux_rt_sigqueueinfo_args *args)
|
|
{
|
|
l_siginfo_t linfo;
|
|
struct proc *p;
|
|
ksiginfo_t ksi;
|
|
int error;
|
|
int sig;
|
|
|
|
if (!LINUX_SIG_VALID(args->sig))
|
|
return (EINVAL);
|
|
|
|
error = copyin(args->info, &linfo, sizeof(linfo));
|
|
if (error != 0)
|
|
return (error);
|
|
|
|
if (linfo.lsi_code >= 0)
|
|
return (EPERM);
|
|
|
|
sig = linux_to_bsd_signal(args->sig);
|
|
|
|
error = ESRCH;
|
|
if ((p = pfind_any(args->pid)) != NULL) {
|
|
error = p_cansignal(td, p, sig);
|
|
if (error != 0) {
|
|
PROC_UNLOCK(p);
|
|
return (error);
|
|
}
|
|
|
|
ksiginfo_init(&ksi);
|
|
lsiginfo_to_ksiginfo(&linfo, &ksi, sig);
|
|
error = tdsendsignal(p, NULL, sig, &ksi);
|
|
PROC_UNLOCK(p);
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
linux_rt_tgsigqueueinfo(struct thread *td, struct linux_rt_tgsigqueueinfo_args *args)
|
|
{
|
|
l_siginfo_t linfo;
|
|
struct thread *tds;
|
|
ksiginfo_t ksi;
|
|
int error;
|
|
int sig;
|
|
|
|
if (!LINUX_SIG_VALID(args->sig))
|
|
return (EINVAL);
|
|
|
|
error = copyin(args->uinfo, &linfo, sizeof(linfo));
|
|
if (error != 0)
|
|
return (error);
|
|
|
|
if (linfo.lsi_code >= 0)
|
|
return (EPERM);
|
|
|
|
tds = linux_tdfind(td, args->tid, args->tgid);
|
|
if (tds == NULL)
|
|
return (ESRCH);
|
|
|
|
sig = linux_to_bsd_signal(args->sig);
|
|
ksiginfo_init(&ksi);
|
|
lsiginfo_to_ksiginfo(&linfo, &ksi, sig);
|
|
return (linux_do_tkill(td, tds, &ksi));
|
|
}
|