summaryrefslogtreecommitdiffstats
path: root/sys/compat/linux/linux_signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat/linux/linux_signal.c')
-rw-r--r--sys/compat/linux/linux_signal.c348
1 files changed, 229 insertions, 119 deletions
diff --git a/sys/compat/linux/linux_signal.c b/sys/compat/linux/linux_signal.c
index 1c778f9..0ecf537 100644
--- a/sys/compat/linux/linux_signal.c
+++ b/sys/compat/linux/linux_signal.c
@@ -53,40 +53,12 @@ __FBSDID("$FreeBSD$");
#include <compat/linux/linux_signal.h>
#include <compat/linux/linux_util.h>
#include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_misc.h>
-void
-linux_to_bsd_sigset(l_sigset_t *lss, sigset_t *bss)
-{
- int b, l;
-
- SIGEMPTYSET(*bss);
- bss->__bits[0] = lss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
- bss->__bits[1] = lss->__bits[1];
- for (l = 1; l <= LINUX_SIGTBLSZ; l++) {
- if (LINUX_SIGISMEMBER(*lss, l)) {
- b = linux_to_bsd_signal[_SIG_IDX(l)];
- if (b)
- SIGADDSET(*bss, b);
- }
- }
-}
+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);
-void
-bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss)
-{
- int b, l;
-
- LINUX_SIGEMPTYSET(*lss);
- lss->__bits[0] = bss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
- lss->__bits[1] = bss->__bits[1];
- for (b = 1; b <= LINUX_SIGTBLSZ; b++) {
- if (SIGISMEMBER(*bss, b)) {
- l = bsd_to_linux_signal[_SIG_IDX(b)];
- if (l)
- LINUX_SIGADDSET(*lss, l);
- }
- }
-}
static void
linux_to_bsd_sigaction(l_sigaction_t *lsa, struct sigaction *bsa)
@@ -155,11 +127,7 @@ linux_do_sigaction(struct thread *td, int linux_sig, l_sigaction_t *linux_nsa,
linux_to_bsd_sigaction(linux_nsa, nsa);
} else
nsa = NULL;
-
- if (linux_sig <= LINUX_SIGTBLSZ)
- sig = linux_to_bsd_signal[_SIG_IDX(linux_sig)];
- else
- sig = linux_sig;
+ sig = linux_to_bsd_signal(linux_sig);
error = kern_sigaction(td, sig, nsa, osa, 0);
if (error)
@@ -171,7 +139,7 @@ linux_do_sigaction(struct thread *td, int linux_sig, l_sigaction_t *linux_nsa,
return (0);
}
-
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
int
linux_signal(struct thread *td, struct linux_signal_args *args)
{
@@ -193,6 +161,7 @@ linux_signal(struct thread *td, struct linux_signal_args *args)
return (error);
}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
int
linux_rt_sigaction(struct thread *td, struct linux_rt_sigaction_args *args)
@@ -262,6 +231,7 @@ linux_do_sigprocmask(struct thread *td, int how, l_sigset_t *new,
return (error);
}
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
int
linux_sigprocmask(struct thread *td, struct linux_sigprocmask_args *args)
{
@@ -279,7 +249,7 @@ linux_sigprocmask(struct thread *td, struct linux_sigprocmask_args *args)
if (error)
return (error);
LINUX_SIGEMPTYSET(set);
- set.__bits[0] = mask;
+ set.__mask = mask;
}
error = linux_do_sigprocmask(td, args->how,
@@ -287,12 +257,13 @@ linux_sigprocmask(struct thread *td, struct linux_sigprocmask_args *args)
args->omask ? &oset : NULL);
if (args->omask != NULL && !error) {
- mask = oset.__bits[0];
+ 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)
@@ -327,6 +298,7 @@ linux_rt_sigprocmask(struct thread *td, struct linux_rt_sigprocmask_args *args)
return (error);
}
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
int
linux_sgetmask(struct thread *td, struct linux_sgetmask_args *args)
{
@@ -341,7 +313,7 @@ linux_sgetmask(struct thread *td, struct linux_sgetmask_args *args)
PROC_LOCK(p);
bsd_to_linux_sigset(&td->td_sigmask, &mask);
PROC_UNLOCK(p);
- td->td_retval[0] = mask.__bits[0];
+ td->td_retval[0] = mask.__mask;
return (0);
}
@@ -359,9 +331,9 @@ linux_ssetmask(struct thread *td, struct linux_ssetmask_args *args)
PROC_LOCK(p);
bsd_to_linux_sigset(&td->td_sigmask, &lset);
- td->td_retval[0] = lset.__bits[0];
+ td->td_retval[0] = lset.__mask;
LINUX_SIGEMPTYSET(lset);
- lset.__bits[0] = args->mask;
+ lset.__mask = args->mask;
linux_to_bsd_sigset(&lset, &bset);
td->td_sigmask = bset;
SIG_CANTMASK(td->td_sigmask);
@@ -370,9 +342,6 @@ linux_ssetmask(struct thread *td, struct linux_ssetmask_args *args)
return (0);
}
-/*
- * MPSAFE
- */
int
linux_sigpending(struct thread *td, struct linux_sigpending_args *args)
{
@@ -392,9 +361,10 @@ linux_sigpending(struct thread *td, struct linux_sigpending_args *args)
SIGSETAND(bset, td->td_sigmask);
PROC_UNLOCK(p);
bsd_to_linux_sigset(&bset, &lset);
- mask = lset.__bits[0];
+ mask = lset.__mask;
return (copyout(&mask, args->mask, sizeof(mask)));
}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
/*
* MPSAFE
@@ -458,8 +428,8 @@ linux_rt_sigtimedwait(struct thread *td,
#ifdef DEBUG
if (ldebug(rt_sigtimedwait))
printf(LMSG("linux_rt_sigtimedwait: "
- "incoming timeout (%d/%d)\n"),
- ltv.tv_sec, ltv.tv_usec);
+ "incoming timeout (%jd/%jd)\n"),
+ (intmax_t)ltv.tv_sec, (intmax_t)ltv.tv_usec);
#endif
tv.tv_sec = (long)ltv.tv_sec;
tv.tv_usec = (suseconds_t)ltv.tv_usec;
@@ -495,7 +465,7 @@ linux_rt_sigtimedwait(struct thread *td,
if (error)
return (error);
- sig = BSD_TO_LINUX_SIGNAL(info.ksi_signo);
+ sig = bsd_to_linux_signal(info.ksi_signo);
if (args->ptr) {
memset(&linfo, 0, sizeof(linfo));
@@ -527,66 +497,31 @@ linux_kill(struct thread *td, struct linux_kill_args *args)
if (!LINUX_SIG_VALID(args->signum) && args->signum != 0)
return (EINVAL);
- if (args->signum > 0 && args->signum <= LINUX_SIGTBLSZ)
- tmp.signum = linux_to_bsd_signal[_SIG_IDX(args->signum)];
+ if (args->signum > 0)
+ tmp.signum = linux_to_bsd_signal(args->signum);
else
- tmp.signum = args->signum;
+ tmp.signum = 0;
tmp.pid = args->pid;
return (sys_kill(td, &tmp));
}
static int
-linux_do_tkill(struct thread *td, l_int tgid, l_int pid, l_int signum)
+linux_do_tkill(struct thread *td, struct thread *tdt, ksiginfo_t *ksi)
{
- struct proc *proc = td->td_proc;
- struct linux_emuldata *em;
struct proc *p;
- ksiginfo_t ksi;
int error;
- AUDIT_ARG_SIGNUM(signum);
- AUDIT_ARG_PID(pid);
-
- /*
- * Allow signal 0 as a means to check for privileges
- */
- if (!LINUX_SIG_VALID(signum) && signum != 0)
- return (EINVAL);
-
- if (signum > 0 && signum <= LINUX_SIGTBLSZ)
- signum = linux_to_bsd_signal[_SIG_IDX(signum)];
-
- if ((p = pfind(pid)) == NULL) {
- if ((p = zpfind(pid)) == NULL)
- return (ESRCH);
- }
-
+ 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, signum);
- if (error != 0 || signum == 0)
- goto out;
-
- error = ESRCH;
- em = em_find(p, EMUL_DONTLOCK);
- if (em == NULL) {
-#ifdef DEBUG
- printf("emuldata not found in do_tkill.\n");
-#endif
+ error = p_cansignal(td, p, ksi->ksi_signo);
+ if (error != 0 || ksi->ksi_signo == 0)
goto out;
- }
- if (tgid > 0 && em->shared->group_pid != tgid)
- goto out;
-
- ksiginfo_init(&ksi);
- ksi.ksi_signo = signum;
- ksi.ksi_code = LINUX_SI_TKILL;
- ksi.ksi_errno = 0;
- ksi.ksi_pid = proc->p_pid;
- ksi.ksi_uid = proc->p_ucred->cr_ruid;
- error = pksignal(p, ksi.ksi_signo, &ksi);
+ tdksignal(tdt, ksi->ksi_signo, ksi);
out:
PROC_UNLOCK(p);
@@ -596,20 +531,53 @@ out:
int
linux_tgkill(struct thread *td, struct linux_tgkill_args *args)
{
+ struct thread *tdt;
+ ksiginfo_t ksi;
+ int sig;
#ifdef DEBUG
if (ldebug(tgkill))
- printf(ARGS(tgkill, "%d, %d, %d"), args->tgid, args->pid, args->sig);
+ printf(ARGS(tgkill, "%d, %d, %d"),
+ args->tgid, args->pid, args->sig);
#endif
+
if (args->pid <= 0 || args->tgid <=0)
return (EINVAL);
- return (linux_do_tkill(td, args->tgid, args->pid, args->sig));
+ /*
+ * 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;
+
#ifdef DEBUG
if (ldebug(tkill))
printf(ARGS(tkill, "%i, %i"), args->tid, args->sig);
@@ -617,40 +585,182 @@ linux_tkill(struct thread *td, struct linux_tkill_args *args)
if (args->tid <= 0)
return (EINVAL);
- return (linux_do_tkill(td, 0, args->tid, args->sig));
+ 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
-ksiginfo_to_lsiginfo(ksiginfo_t *ksi, l_siginfo_t *lsi, l_int sig)
+siginfo_to_lsiginfo(const siginfo_t *si, l_siginfo_t *lsi, l_int sig)
{
+ /* sig alredy converted */
lsi->lsi_signo = sig;
- lsi->lsi_code = ksi->ksi_code;
+ sicode_to_lsicode(si->si_code, &lsi->lsi_code);
- switch (sig) {
- case LINUX_SIGPOLL:
- /* XXX si_fd? */
- lsi->lsi_band = ksi->ksi_band;
+ switch (si->si_code) {
+ case SI_LWP:
+ lsi->lsi_pid = si->si_pid;
+ lsi->lsi_uid = si->si_uid;
break;
- case LINUX_SIGCHLD:
- lsi->lsi_pid = ksi->ksi_pid;
- lsi->lsi_uid = ksi->ksi_uid;
- lsi->lsi_status = ksi->ksi_status;
+
+ 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 LINUX_SIGBUS:
- case LINUX_SIGILL:
- case LINUX_SIGFPE:
- case LINUX_SIGSEGV:
- lsi->lsi_addr = PTROUT(ksi->ksi_addr);
+
+ 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:
- /* XXX SI_TIMER etc... */
- lsi->lsi_pid = ksi->ksi_pid;
- lsi->lsi_uid = ksi->ksi_uid;
+ 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;
}
- if (sig >= LINUX_SIGRTMIN) {
- lsi->lsi_int = ksi->ksi_info.si_value.sival_int;
- lsi->lsi_ptr = PTROUT(ksi->ksi_info.si_value.sival_ptr);
+}
+
+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(args->pid)) != NULL ||
+ (p = zpfind(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);
}
OpenPOWER on IntegriCloud