linux_signal.c revision 293540
1/*-
2 * Copyright (c) 1994-1995 S��ren Schmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_signal.c 293540 2016-01-09 16:29:51Z dchagin $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/lock.h>
35#include <sys/mutex.h>
36#include <sys/sx.h>
37#include <sys/proc.h>
38#include <sys/signalvar.h>
39#include <sys/syscallsubr.h>
40#include <sys/sysproto.h>
41
42#include <security/audit/audit.h>
43
44#include "opt_compat.h"
45
46#ifdef COMPAT_LINUX32
47#include <machine/../linux32/linux.h>
48#include <machine/../linux32/linux32_proto.h>
49#else
50#include <machine/../linux/linux.h>
51#include <machine/../linux/linux_proto.h>
52#endif
53#include <compat/linux/linux_signal.h>
54#include <compat/linux/linux_util.h>
55#include <compat/linux/linux_emul.h>
56#include <compat/linux/linux_misc.h>
57
58static int	linux_do_tkill(struct thread *td, struct thread *tdt,
59		    ksiginfo_t *ksi);
60static void	sicode_to_lsicode(int si_code, int *lsi_code);
61
62
63#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
64void
65linux_to_bsd_sigset(l_sigset_t *lss, sigset_t *bss)
66{
67	int b, l;
68
69	SIGEMPTYSET(*bss);
70	bss->__bits[0] = lss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
71	bss->__bits[1] = lss->__bits[1];
72	for (l = 1; l <= LINUX_SIGTBLSZ; l++) {
73		if (LINUX_SIGISMEMBER(*lss, l)) {
74			b = linux_to_bsd_signal[_SIG_IDX(l)];
75			if (b)
76				SIGADDSET(*bss, b);
77		}
78	}
79}
80
81void
82bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss)
83{
84	int b, l;
85
86	LINUX_SIGEMPTYSET(*lss);
87	lss->__bits[0] = bss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
88	lss->__bits[1] = bss->__bits[1];
89	for (b = 1; b <= LINUX_SIGTBLSZ; b++) {
90		if (SIGISMEMBER(*bss, b)) {
91			l = bsd_to_linux_signal[_SIG_IDX(b)];
92			if (l)
93				LINUX_SIGADDSET(*lss, l);
94		}
95	}
96}
97#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
98
99static void
100linux_to_bsd_sigaction(l_sigaction_t *lsa, struct sigaction *bsa)
101{
102
103	linux_to_bsd_sigset(&lsa->lsa_mask, &bsa->sa_mask);
104	bsa->sa_handler = PTRIN(lsa->lsa_handler);
105	bsa->sa_flags = 0;
106	if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP)
107		bsa->sa_flags |= SA_NOCLDSTOP;
108	if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT)
109		bsa->sa_flags |= SA_NOCLDWAIT;
110	if (lsa->lsa_flags & LINUX_SA_SIGINFO)
111		bsa->sa_flags |= SA_SIGINFO;
112	if (lsa->lsa_flags & LINUX_SA_ONSTACK)
113		bsa->sa_flags |= SA_ONSTACK;
114	if (lsa->lsa_flags & LINUX_SA_RESTART)
115		bsa->sa_flags |= SA_RESTART;
116	if (lsa->lsa_flags & LINUX_SA_ONESHOT)
117		bsa->sa_flags |= SA_RESETHAND;
118	if (lsa->lsa_flags & LINUX_SA_NOMASK)
119		bsa->sa_flags |= SA_NODEFER;
120}
121
122static void
123bsd_to_linux_sigaction(struct sigaction *bsa, l_sigaction_t *lsa)
124{
125
126	bsd_to_linux_sigset(&bsa->sa_mask, &lsa->lsa_mask);
127#ifdef COMPAT_LINUX32
128	lsa->lsa_handler = (uintptr_t)bsa->sa_handler;
129#else
130	lsa->lsa_handler = bsa->sa_handler;
131#endif
132	lsa->lsa_restorer = 0;		/* unsupported */
133	lsa->lsa_flags = 0;
134	if (bsa->sa_flags & SA_NOCLDSTOP)
135		lsa->lsa_flags |= LINUX_SA_NOCLDSTOP;
136	if (bsa->sa_flags & SA_NOCLDWAIT)
137		lsa->lsa_flags |= LINUX_SA_NOCLDWAIT;
138	if (bsa->sa_flags & SA_SIGINFO)
139		lsa->lsa_flags |= LINUX_SA_SIGINFO;
140	if (bsa->sa_flags & SA_ONSTACK)
141		lsa->lsa_flags |= LINUX_SA_ONSTACK;
142	if (bsa->sa_flags & SA_RESTART)
143		lsa->lsa_flags |= LINUX_SA_RESTART;
144	if (bsa->sa_flags & SA_RESETHAND)
145		lsa->lsa_flags |= LINUX_SA_ONESHOT;
146	if (bsa->sa_flags & SA_NODEFER)
147		lsa->lsa_flags |= LINUX_SA_NOMASK;
148}
149
150int
151linux_do_sigaction(struct thread *td, int linux_sig, l_sigaction_t *linux_nsa,
152		   l_sigaction_t *linux_osa)
153{
154	struct sigaction act, oact, *nsa, *osa;
155	int error, sig;
156
157	if (!LINUX_SIG_VALID(linux_sig))
158		return (EINVAL);
159
160	osa = (linux_osa != NULL) ? &oact : NULL;
161	if (linux_nsa != NULL) {
162		nsa = &act;
163		linux_to_bsd_sigaction(linux_nsa, nsa);
164	} else
165		nsa = NULL;
166
167	if (linux_sig <= LINUX_SIGTBLSZ)
168		sig = linux_to_bsd_signal[_SIG_IDX(linux_sig)];
169	else
170		sig = linux_sig;
171
172	error = kern_sigaction(td, sig, nsa, osa, 0);
173	if (error)
174		return (error);
175
176	if (linux_osa != NULL)
177		bsd_to_linux_sigaction(osa, linux_osa);
178
179	return (0);
180}
181
182#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
183int
184linux_signal(struct thread *td, struct linux_signal_args *args)
185{
186	l_sigaction_t nsa, osa;
187	int error;
188
189#ifdef DEBUG
190	if (ldebug(signal))
191		printf(ARGS(signal, "%d, %p"),
192		    args->sig, (void *)(uintptr_t)args->handler);
193#endif
194
195	nsa.lsa_handler = args->handler;
196	nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK;
197	LINUX_SIGEMPTYSET(nsa.lsa_mask);
198
199	error = linux_do_sigaction(td, args->sig, &nsa, &osa);
200	td->td_retval[0] = (int)(intptr_t)osa.lsa_handler;
201
202	return (error);
203}
204#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
205
206int
207linux_rt_sigaction(struct thread *td, struct linux_rt_sigaction_args *args)
208{
209	l_sigaction_t nsa, osa;
210	int error;
211
212#ifdef DEBUG
213	if (ldebug(rt_sigaction))
214		printf(ARGS(rt_sigaction, "%ld, %p, %p, %ld"),
215		    (long)args->sig, (void *)args->act,
216		    (void *)args->oact, (long)args->sigsetsize);
217#endif
218
219	if (args->sigsetsize != sizeof(l_sigset_t))
220		return (EINVAL);
221
222	if (args->act != NULL) {
223		error = copyin(args->act, &nsa, sizeof(l_sigaction_t));
224		if (error)
225			return (error);
226	}
227
228	error = linux_do_sigaction(td, args->sig,
229				   args->act ? &nsa : NULL,
230				   args->oact ? &osa : NULL);
231
232	if (args->oact != NULL && !error) {
233		error = copyout(&osa, args->oact, sizeof(l_sigaction_t));
234	}
235
236	return (error);
237}
238
239static int
240linux_do_sigprocmask(struct thread *td, int how, l_sigset_t *new,
241		     l_sigset_t *old)
242{
243	sigset_t omask, nmask;
244	sigset_t *nmaskp;
245	int error;
246
247	td->td_retval[0] = 0;
248
249	switch (how) {
250	case LINUX_SIG_BLOCK:
251		how = SIG_BLOCK;
252		break;
253	case LINUX_SIG_UNBLOCK:
254		how = SIG_UNBLOCK;
255		break;
256	case LINUX_SIG_SETMASK:
257		how = SIG_SETMASK;
258		break;
259	default:
260		return (EINVAL);
261	}
262	if (new != NULL) {
263		linux_to_bsd_sigset(new, &nmask);
264		nmaskp = &nmask;
265	} else
266		nmaskp = NULL;
267	error = kern_sigprocmask(td, how, nmaskp, &omask, 0);
268	if (error == 0 && old != NULL)
269		bsd_to_linux_sigset(&omask, old);
270
271	return (error);
272}
273
274#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
275int
276linux_sigprocmask(struct thread *td, struct linux_sigprocmask_args *args)
277{
278	l_osigset_t mask;
279	l_sigset_t set, oset;
280	int error;
281
282#ifdef DEBUG
283	if (ldebug(sigprocmask))
284		printf(ARGS(sigprocmask, "%d, *, *"), args->how);
285#endif
286
287	if (args->mask != NULL) {
288		error = copyin(args->mask, &mask, sizeof(l_osigset_t));
289		if (error)
290			return (error);
291		LINUX_SIGEMPTYSET(set);
292		set.__bits[0] = mask;
293	}
294
295	error = linux_do_sigprocmask(td, args->how,
296				     args->mask ? &set : NULL,
297				     args->omask ? &oset : NULL);
298
299	if (args->omask != NULL && !error) {
300		mask = oset.__bits[0];
301		error = copyout(&mask, args->omask, sizeof(l_osigset_t));
302	}
303
304	return (error);
305}
306#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
307
308int
309linux_rt_sigprocmask(struct thread *td, struct linux_rt_sigprocmask_args *args)
310{
311	l_sigset_t set, oset;
312	int error;
313
314#ifdef DEBUG
315	if (ldebug(rt_sigprocmask))
316		printf(ARGS(rt_sigprocmask, "%d, %p, %p, %ld"),
317		    args->how, (void *)args->mask,
318		    (void *)args->omask, (long)args->sigsetsize);
319#endif
320
321	if (args->sigsetsize != sizeof(l_sigset_t))
322		return EINVAL;
323
324	if (args->mask != NULL) {
325		error = copyin(args->mask, &set, sizeof(l_sigset_t));
326		if (error)
327			return (error);
328	}
329
330	error = linux_do_sigprocmask(td, args->how,
331				     args->mask ? &set : NULL,
332				     args->omask ? &oset : NULL);
333
334	if (args->omask != NULL && !error) {
335		error = copyout(&oset, args->omask, sizeof(l_sigset_t));
336	}
337
338	return (error);
339}
340
341#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
342int
343linux_sgetmask(struct thread *td, struct linux_sgetmask_args *args)
344{
345	struct proc *p = td->td_proc;
346	l_sigset_t mask;
347
348#ifdef DEBUG
349	if (ldebug(sgetmask))
350		printf(ARGS(sgetmask, ""));
351#endif
352
353	PROC_LOCK(p);
354	bsd_to_linux_sigset(&td->td_sigmask, &mask);
355	PROC_UNLOCK(p);
356	td->td_retval[0] = mask.__bits[0];
357	return (0);
358}
359
360int
361linux_ssetmask(struct thread *td, struct linux_ssetmask_args *args)
362{
363	struct proc *p = td->td_proc;
364	l_sigset_t lset;
365	sigset_t bset;
366
367#ifdef DEBUG
368	if (ldebug(ssetmask))
369		printf(ARGS(ssetmask, "%08lx"), (unsigned long)args->mask);
370#endif
371
372	PROC_LOCK(p);
373	bsd_to_linux_sigset(&td->td_sigmask, &lset);
374	td->td_retval[0] = lset.__bits[0];
375	LINUX_SIGEMPTYSET(lset);
376	lset.__bits[0] = args->mask;
377	linux_to_bsd_sigset(&lset, &bset);
378	td->td_sigmask = bset;
379	SIG_CANTMASK(td->td_sigmask);
380	signotify(td);
381	PROC_UNLOCK(p);
382	return (0);
383}
384
385int
386linux_sigpending(struct thread *td, struct linux_sigpending_args *args)
387{
388	struct proc *p = td->td_proc;
389	sigset_t bset;
390	l_sigset_t lset;
391	l_osigset_t mask;
392
393#ifdef DEBUG
394	if (ldebug(sigpending))
395		printf(ARGS(sigpending, "*"));
396#endif
397
398	PROC_LOCK(p);
399	bset = p->p_siglist;
400	SIGSETOR(bset, td->td_siglist);
401	SIGSETAND(bset, td->td_sigmask);
402	PROC_UNLOCK(p);
403	bsd_to_linux_sigset(&bset, &lset);
404	mask = lset.__bits[0];
405	return (copyout(&mask, args->mask, sizeof(mask)));
406}
407#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
408
409/*
410 * MPSAFE
411 */
412int
413linux_rt_sigpending(struct thread *td, struct linux_rt_sigpending_args *args)
414{
415	struct proc *p = td->td_proc;
416	sigset_t bset;
417	l_sigset_t lset;
418
419	if (args->sigsetsize > sizeof(lset))
420		return EINVAL;
421		/* NOT REACHED */
422
423#ifdef DEBUG
424	if (ldebug(rt_sigpending))
425		printf(ARGS(rt_sigpending, "*"));
426#endif
427
428	PROC_LOCK(p);
429	bset = p->p_siglist;
430	SIGSETOR(bset, td->td_siglist);
431	SIGSETAND(bset, td->td_sigmask);
432	PROC_UNLOCK(p);
433	bsd_to_linux_sigset(&bset, &lset);
434	return (copyout(&lset, args->set, args->sigsetsize));
435}
436
437/*
438 * MPSAFE
439 */
440int
441linux_rt_sigtimedwait(struct thread *td,
442	struct linux_rt_sigtimedwait_args *args)
443{
444	int error, sig;
445	l_timeval ltv;
446	struct timeval tv;
447	struct timespec ts, *tsa;
448	l_sigset_t lset;
449	sigset_t bset;
450	l_siginfo_t linfo;
451	ksiginfo_t info;
452
453#ifdef DEBUG
454	if (ldebug(rt_sigtimedwait))
455		printf(ARGS(rt_sigtimedwait, "*"));
456#endif
457	if (args->sigsetsize != sizeof(l_sigset_t))
458		return (EINVAL);
459
460	if ((error = copyin(args->mask, &lset, sizeof(lset))))
461		return (error);
462	linux_to_bsd_sigset(&lset, &bset);
463
464	tsa = NULL;
465	if (args->timeout) {
466		if ((error = copyin(args->timeout, &ltv, sizeof(ltv))))
467			return (error);
468#ifdef DEBUG
469		if (ldebug(rt_sigtimedwait))
470			printf(LMSG("linux_rt_sigtimedwait: "
471			    "incoming timeout (%jd/%jd)\n"),
472			    (intmax_t)ltv.tv_sec, (intmax_t)ltv.tv_usec);
473#endif
474		tv.tv_sec = (long)ltv.tv_sec;
475		tv.tv_usec = (suseconds_t)ltv.tv_usec;
476		if (itimerfix(&tv)) {
477			/*
478			 * The timeout was invalid. Convert it to something
479			 * valid that will act as it does under Linux.
480			 */
481			tv.tv_sec += tv.tv_usec / 1000000;
482			tv.tv_usec %= 1000000;
483			if (tv.tv_usec < 0) {
484				tv.tv_sec -= 1;
485				tv.tv_usec += 1000000;
486			}
487			if (tv.tv_sec < 0)
488				timevalclear(&tv);
489#ifdef DEBUG
490			if (ldebug(rt_sigtimedwait))
491				printf(LMSG("linux_rt_sigtimedwait: "
492				    "converted timeout (%jd/%ld)\n"),
493				    (intmax_t)tv.tv_sec, tv.tv_usec);
494#endif
495		}
496		TIMEVAL_TO_TIMESPEC(&tv, &ts);
497		tsa = &ts;
498	}
499	error = kern_sigtimedwait(td, bset, &info, tsa);
500#ifdef DEBUG
501	if (ldebug(rt_sigtimedwait))
502		printf(LMSG("linux_rt_sigtimedwait: "
503		    "sigtimedwait returning (%d)\n"), error);
504#endif
505	if (error)
506		return (error);
507
508	sig = BSD_TO_LINUX_SIGNAL(info.ksi_signo);
509
510	if (args->ptr) {
511		memset(&linfo, 0, sizeof(linfo));
512		ksiginfo_to_lsiginfo(&info, &linfo, sig);
513		error = copyout(&linfo, args->ptr, sizeof(linfo));
514	}
515	if (error == 0)
516		td->td_retval[0] = sig;
517
518	return (error);
519}
520
521int
522linux_kill(struct thread *td, struct linux_kill_args *args)
523{
524	struct kill_args /* {
525	    int pid;
526	    int signum;
527	} */ tmp;
528
529#ifdef DEBUG
530	if (ldebug(kill))
531		printf(ARGS(kill, "%d, %d"), args->pid, args->signum);
532#endif
533
534	/*
535	 * Allow signal 0 as a means to check for privileges
536	 */
537	if (!LINUX_SIG_VALID(args->signum) && args->signum != 0)
538		return (EINVAL);
539
540	if (args->signum > 0 && args->signum <= LINUX_SIGTBLSZ)
541		tmp.signum = linux_to_bsd_signal[_SIG_IDX(args->signum)];
542	else
543		tmp.signum = args->signum;
544
545	tmp.pid = args->pid;
546	return (sys_kill(td, &tmp));
547}
548
549static int
550linux_do_tkill(struct thread *td, struct thread *tdt, ksiginfo_t *ksi)
551{
552	struct proc *p;
553	int error;
554
555	p = tdt->td_proc;
556	AUDIT_ARG_SIGNUM(ksi->ksi_signo);
557	AUDIT_ARG_PID(p->p_pid);
558	AUDIT_ARG_PROCESS(p);
559
560	error = p_cansignal(td, p, ksi->ksi_signo);
561	if (error != 0 || ksi->ksi_signo == 0)
562		goto out;
563
564	tdksignal(tdt, ksi->ksi_signo, ksi);
565
566out:
567	PROC_UNLOCK(p);
568	return (error);
569}
570
571int
572linux_tgkill(struct thread *td, struct linux_tgkill_args *args)
573{
574	struct thread *tdt;
575	ksiginfo_t ksi;
576	int sig;
577
578#ifdef DEBUG
579	if (ldebug(tgkill))
580		printf(ARGS(tgkill, "%d, %d, %d"),
581		    args->tgid, args->pid, args->sig);
582#endif
583
584	if (args->pid <= 0 || args->tgid <=0)
585		return (EINVAL);
586
587	/*
588	 * Allow signal 0 as a means to check for privileges
589	 */
590	if (!LINUX_SIG_VALID(args->sig) && args->sig != 0)
591		return (EINVAL);
592
593	if (args->sig > 0 && args->sig <= LINUX_SIGTBLSZ)
594		sig = linux_to_bsd_signal[_SIG_IDX(args->sig)];
595	else
596		sig = args->sig;
597
598	tdt = linux_tdfind(td, args->pid, args->tgid);
599	if (tdt == NULL)
600		return (ESRCH);
601
602	ksiginfo_init(&ksi);
603	ksi.ksi_signo = sig;
604	ksi.ksi_code = SI_LWP;
605	ksi.ksi_errno = 0;
606	ksi.ksi_pid = td->td_proc->p_pid;
607	ksi.ksi_uid = td->td_proc->p_ucred->cr_ruid;
608	return (linux_do_tkill(td, tdt, &ksi));
609}
610
611/*
612 * Deprecated since 2.5.75. Replaced by tgkill().
613 */
614int
615linux_tkill(struct thread *td, struct linux_tkill_args *args)
616{
617	struct thread *tdt;
618	ksiginfo_t ksi;
619	int sig;
620
621#ifdef DEBUG
622	if (ldebug(tkill))
623		printf(ARGS(tkill, "%i, %i"), args->tid, args->sig);
624#endif
625	if (args->tid <= 0)
626		return (EINVAL);
627
628	if (!LINUX_SIG_VALID(args->sig))
629		return (EINVAL);
630
631
632	sig = BSD_TO_LINUX_SIGNAL(args->sig);
633
634	tdt = linux_tdfind(td, args->tid, -1);
635	if (tdt == NULL)
636		return (ESRCH);
637
638	ksiginfo_init(&ksi);
639	ksi.ksi_signo = sig;
640	ksi.ksi_code = SI_LWP;
641	ksi.ksi_errno = 0;
642	ksi.ksi_pid = td->td_proc->p_pid;
643	ksi.ksi_uid = td->td_proc->p_ucred->cr_ruid;
644	return (linux_do_tkill(td, tdt, &ksi));
645}
646
647void
648ksiginfo_to_lsiginfo(const ksiginfo_t *ksi, l_siginfo_t *lsi, l_int sig)
649{
650
651	siginfo_to_lsiginfo(&ksi->ksi_info, lsi, sig);
652}
653
654static void
655sicode_to_lsicode(int si_code, int *lsi_code)
656{
657
658	switch (si_code) {
659	case SI_USER:
660		*lsi_code = LINUX_SI_USER;
661		break;
662	case SI_KERNEL:
663		*lsi_code = LINUX_SI_KERNEL;
664		break;
665	case SI_QUEUE:
666		*lsi_code = LINUX_SI_QUEUE;
667		break;
668	case SI_TIMER:
669		*lsi_code = LINUX_SI_TIMER;
670		break;
671	case SI_MESGQ:
672		*lsi_code = LINUX_SI_MESGQ;
673		break;
674	case SI_ASYNCIO:
675		*lsi_code = LINUX_SI_ASYNCIO;
676		break;
677	case SI_LWP:
678		*lsi_code = LINUX_SI_TKILL;
679		break;
680	default:
681		*lsi_code = si_code;
682		break;
683	}
684}
685
686void
687siginfo_to_lsiginfo(const siginfo_t *si, l_siginfo_t *lsi, l_int sig)
688{
689
690	/* sig alredy converted */
691	lsi->lsi_signo = sig;
692	sicode_to_lsicode(si->si_code, &lsi->lsi_code);
693
694	switch (si->si_code) {
695	case SI_LWP:
696		lsi->lsi_pid = si->si_pid;
697		lsi->lsi_uid = si->si_uid;
698		break;
699
700	case SI_TIMER:
701		lsi->lsi_int = si->si_value.sival_int;
702		lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
703		lsi->lsi_tid = si->si_timerid;
704		break;
705
706	case SI_QUEUE:
707		lsi->lsi_pid = si->si_pid;
708		lsi->lsi_uid = si->si_uid;
709		lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
710		break;
711
712	case SI_ASYNCIO:
713		lsi->lsi_int = si->si_value.sival_int;
714		lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
715		break;
716
717	default:
718		switch (sig) {
719		case LINUX_SIGPOLL:
720			/* XXX si_fd? */
721			lsi->lsi_band = si->si_band;
722			break;
723
724		case LINUX_SIGCHLD:
725			lsi->lsi_errno = 0;
726			lsi->lsi_pid = si->si_pid;
727			lsi->lsi_uid = si->si_uid;
728
729			if (si->si_code == CLD_STOPPED)
730				lsi->lsi_status = BSD_TO_LINUX_SIGNAL(si->si_status);
731			else if (si->si_code == CLD_CONTINUED)
732				lsi->lsi_status = BSD_TO_LINUX_SIGNAL(SIGCONT);
733			else
734				lsi->lsi_status = si->si_status;
735			break;
736
737		case LINUX_SIGBUS:
738		case LINUX_SIGILL:
739		case LINUX_SIGFPE:
740		case LINUX_SIGSEGV:
741			lsi->lsi_addr = PTROUT(si->si_addr);
742			break;
743
744		default:
745			lsi->lsi_pid = si->si_pid;
746			lsi->lsi_uid = si->si_uid;
747			if (sig >= LINUX_SIGRTMIN) {
748				lsi->lsi_int = si->si_value.sival_int;
749				lsi->lsi_ptr = PTROUT(si->si_value.sival_ptr);
750			}
751			break;
752		}
753		break;
754	}
755}
756
757void
758lsiginfo_to_ksiginfo(const l_siginfo_t *lsi, ksiginfo_t *ksi, int sig)
759{
760
761	ksi->ksi_signo = sig;
762	ksi->ksi_code = lsi->lsi_code;	/* XXX. Convert. */
763	ksi->ksi_pid = lsi->lsi_pid;
764	ksi->ksi_uid = lsi->lsi_uid;
765	ksi->ksi_status = lsi->lsi_status;
766	ksi->ksi_addr = PTRIN(lsi->lsi_addr);
767	ksi->ksi_info.si_value.sival_int = lsi->lsi_int;
768}
769
770int
771linux_rt_sigqueueinfo(struct thread *td, struct linux_rt_sigqueueinfo_args *args)
772{
773	l_siginfo_t linfo;
774	struct proc *p;
775	ksiginfo_t ksi;
776	int error;
777	int sig;
778
779	if (!LINUX_SIG_VALID(args->sig))
780		return (EINVAL);
781
782	error = copyin(args->info, &linfo, sizeof(linfo));
783	if (error != 0)
784		return (error);
785
786	if (linfo.lsi_code >= 0)
787		return (EPERM);
788
789	sig = BSD_TO_LINUX_SIGNAL(args->sig);
790
791	error = ESRCH;
792	if ((p = pfind(args->pid)) != NULL ||
793	    (p = zpfind(args->pid)) != NULL) {
794		error = p_cansignal(td, p, sig);
795		if (error != 0) {
796			PROC_UNLOCK(p);
797			return (error);
798		}
799
800		ksiginfo_init(&ksi);
801		lsiginfo_to_ksiginfo(&linfo, &ksi, sig);
802		error = tdsendsignal(p, NULL, sig, &ksi);
803		PROC_UNLOCK(p);
804	}
805
806	return (error);
807}
808