1b4ddc26b64ef5d789b2ee4b49da25f0c244730d
[dragonfly.git] / sys / emulation / linux / linux_signal.c
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  * $FreeBSD: src/sys/compat/linux/linux_signal.c,v 1.23.2.3 2001/11/05 19:08:23 marcel Exp $
29  */
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/lock.h>
34 #include <sys/proc.h>
35 #include <sys/signalvar.h>
36 #include <sys/sysproto.h>
37 #include <sys/kern_syscall.h>
38 #include <sys/thread.h>
39
40 #include <sys/thread2.h>
41
42 #include <arch_linux/linux.h>
43 #include <arch_linux/linux_proto.h>
44 #include "linux_emuldata.h"
45 #include "linux_signal.h"
46 #include "linux_util.h"
47
48 void
49 linux_to_bsd_sigset(l_sigset_t *lss, sigset_t *bss)
50 {
51         int b, l;
52
53         SIGEMPTYSET(*bss);
54         bss->__bits[0] = lss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
55         bss->__bits[1] = lss->__bits[1];
56         for (l = 1; l <= LINUX_SIGTBLSZ; l++) {
57                 if (LINUX_SIGISMEMBER(*lss, l)) {
58                         b = linux_to_bsd_signal[_SIG_IDX(l)];
59                         if (b)
60                                 SIGADDSET(*bss, b);
61                 }
62         }
63 }
64
65 void
66 bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss)
67 {
68         int b, l;
69
70         LINUX_SIGEMPTYSET(*lss);
71         lss->__bits[0] = bss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
72         lss->__bits[1] = bss->__bits[1];
73         for (b = 1; b <= LINUX_SIGTBLSZ; b++) {
74                 if (SIGISMEMBER(*bss, b)) {
75                         l = bsd_to_linux_signal[_SIG_IDX(b)];
76                         if (l)
77                                 LINUX_SIGADDSET(*lss, l);
78                 }
79         }
80 }
81
82 void
83 linux_to_bsd_sigaction(l_sigaction_t *lsa, struct sigaction *bsa)
84 {
85
86         linux_to_bsd_sigset(&lsa->lsa_mask, &bsa->sa_mask);
87         bsa->sa_handler = lsa->lsa_handler;
88         bsa->sa_flags = 0;
89         if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP)
90                 bsa->sa_flags |= SA_NOCLDSTOP;
91         if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT)
92                 bsa->sa_flags |= SA_NOCLDWAIT;
93         if (lsa->lsa_flags & LINUX_SA_SIGINFO)
94                 bsa->sa_flags |= SA_SIGINFO;
95         if (lsa->lsa_flags & LINUX_SA_ONSTACK)
96                 bsa->sa_flags |= SA_ONSTACK;
97         if (lsa->lsa_flags & LINUX_SA_RESTART)
98                 bsa->sa_flags |= SA_RESTART;
99         if (lsa->lsa_flags & LINUX_SA_ONESHOT)
100                 bsa->sa_flags |= SA_RESETHAND;
101         if (lsa->lsa_flags & LINUX_SA_NOMASK)
102                 bsa->sa_flags |= SA_NODEFER;
103 }
104
105 void
106 bsd_to_linux_sigaction(struct sigaction *bsa, l_sigaction_t *lsa)
107 {
108
109         bsd_to_linux_sigset(&bsa->sa_mask, &lsa->lsa_mask);
110         lsa->lsa_handler = bsa->sa_handler;
111         lsa->lsa_restorer = NULL;       /* unsupported */
112         lsa->lsa_flags = 0;
113         if (bsa->sa_flags & SA_NOCLDSTOP)
114                 lsa->lsa_flags |= LINUX_SA_NOCLDSTOP;
115         if (bsa->sa_flags & SA_NOCLDWAIT)
116                 lsa->lsa_flags |= LINUX_SA_NOCLDWAIT;
117         if (bsa->sa_flags & SA_SIGINFO)
118                 lsa->lsa_flags |= LINUX_SA_SIGINFO;
119         if (bsa->sa_flags & SA_ONSTACK)
120                 lsa->lsa_flags |= LINUX_SA_ONSTACK;
121         if (bsa->sa_flags & SA_RESTART)
122                 lsa->lsa_flags |= LINUX_SA_RESTART;
123         if (bsa->sa_flags & SA_RESETHAND)
124                 lsa->lsa_flags |= LINUX_SA_ONESHOT;
125         if (bsa->sa_flags & SA_NODEFER)
126                 lsa->lsa_flags |= LINUX_SA_NOMASK;
127 }
128
129 /*
130  * MPALMOSTSAFE
131  */
132 int
133 sys_linux_signal(struct linux_signal_args *args)
134 {
135         l_sigaction_t linux_nsa, linux_osa;
136         struct sigaction nsa, osa;
137         int error, sig;
138
139 #ifdef DEBUG
140         if (ldebug(signal))
141                 kprintf(ARGS(signal, "%d, %p"),
142                     args->sig, (void *)args->handler);
143 #endif
144         linux_nsa.lsa_handler = args->handler;
145         linux_nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK;
146         LINUX_SIGEMPTYSET(linux_nsa.lsa_mask);
147         linux_to_bsd_sigaction(&linux_nsa, &nsa);
148         if (args->sig <= LINUX_SIGTBLSZ) {
149                 sig = linux_to_bsd_signal[_SIG_IDX(args->sig)];
150         } else {
151                 sig = args->sig;
152         }
153
154         error = kern_sigaction(sig, &nsa, &osa);
155
156         bsd_to_linux_sigaction(&osa, &linux_osa);
157         args->sysmsg_result = (int) linux_osa.lsa_handler;
158         return (error);
159 }
160
161 /*
162  * MPALMOSTSAFE
163  */
164 int
165 sys_linux_rt_sigaction(struct linux_rt_sigaction_args *args)
166 {
167         l_sigaction_t linux_nsa, linux_osa;
168         struct sigaction nsa, osa;
169         int error, sig;
170
171 #ifdef DEBUG
172         if (ldebug(rt_sigaction))
173                 kprintf(ARGS(rt_sigaction, "%ld, %p, %p, %ld"),
174                     (long)args->sig, (void *)args->act,
175                     (void *)args->oact, (long)args->sigsetsize);
176 #endif
177         if (args->sigsetsize != sizeof(l_sigset_t))
178                 return (EINVAL);
179
180         if (args->act) {
181                 error = copyin(args->act, &linux_nsa, sizeof(linux_nsa));
182                 if (error)
183                         return (error);
184                 linux_to_bsd_sigaction(&linux_nsa, &nsa);
185         }
186         if (args->sig <= LINUX_SIGTBLSZ) {
187                 sig = linux_to_bsd_signal[_SIG_IDX(args->sig)];
188         } else {
189                 sig = args->sig;
190         }
191
192         error = kern_sigaction(sig, args->act ? &nsa : NULL,
193                                args->oact ? &osa : NULL);
194
195         if (error == 0 && args->oact) {
196                 bsd_to_linux_sigaction(&osa, &linux_osa);
197                 error = copyout(&linux_osa, args->oact, sizeof(linux_osa));
198         }
199
200         return (error);
201 }
202
203 static int
204 linux_to_bsd_sigprocmask(int how)
205 {
206         switch (how) {
207         case LINUX_SIG_BLOCK:
208                 return SIG_BLOCK;
209         case LINUX_SIG_UNBLOCK:
210                 return SIG_UNBLOCK;
211         case LINUX_SIG_SETMASK:
212                 return SIG_SETMASK;
213         default:
214                 return (-1);
215         }
216 }
217
218 /*
219  * MPALMOSTSAFE
220  */
221 int
222 sys_linux_sigprocmask(struct linux_sigprocmask_args *args)
223 {
224         l_osigset_t mask;
225         l_sigset_t linux_set, linux_oset;
226         sigset_t set, oset;
227         int error, how;
228
229 #ifdef DEBUG
230         if (ldebug(sigprocmask))
231                 kprintf(ARGS(sigprocmask, "%d, *, *"), args->how);
232 #endif
233
234         if (args->mask) {
235                 error = copyin(args->mask, &mask, sizeof(l_osigset_t));
236                 if (error)
237                         return (error);
238                 LINUX_SIGEMPTYSET(linux_set);
239                 linux_set.__bits[0] = mask;
240                 linux_to_bsd_sigset(&linux_set, &set);
241         }
242         how = linux_to_bsd_sigprocmask(args->how);
243
244         error = kern_sigprocmask(how, args->mask ? &set : NULL,
245                                  args->omask ? &oset : NULL);
246
247         if (error == 0 && args->omask) {
248                 bsd_to_linux_sigset(&oset, &linux_oset);
249                 mask = linux_oset.__bits[0];
250                 error = copyout(&mask, args->omask, sizeof(l_osigset_t));
251         }
252         return (error);
253 }
254
255 /*
256  * MPALMOSTSAFE
257  */
258 int
259 sys_linux_rt_sigprocmask(struct linux_rt_sigprocmask_args *args)
260 {
261         l_sigset_t linux_set, linux_oset;
262         sigset_t set, oset;
263         int error, how;
264
265 #ifdef DEBUG
266         if (ldebug(rt_sigprocmask))
267                 kprintf(ARGS(rt_sigprocmask, "%d, %p, %p, %ld"),
268                     args->how, (void *)args->mask,
269                     (void *)args->omask, (long)args->sigsetsize);
270 #endif
271
272         if (args->sigsetsize != sizeof(l_sigset_t))
273                 return EINVAL;
274
275         if (args->mask) {
276                 error = copyin(args->mask, &linux_set, sizeof(l_sigset_t));
277                 if (error)
278                         return (error);
279                 linux_to_bsd_sigset(&linux_set, &set);
280         }
281         how = linux_to_bsd_sigprocmask(args->how);
282
283         error = kern_sigprocmask(how, args->mask ? &set : NULL,
284                                  args->omask ? &oset : NULL);
285
286         if (error == 0 && args->omask) {
287                 bsd_to_linux_sigset(&oset, &linux_oset);
288                 error = copyout(&linux_oset, args->omask, sizeof(l_sigset_t));
289         }
290
291         return (error);
292 }
293
294 /*
295  * MPSAFE
296  */
297 int
298 sys_linux_sgetmask(struct linux_sgetmask_args *args)
299 {
300         struct lwp *lp = curthread->td_lwp;
301         l_sigset_t mask;
302
303 #ifdef DEBUG
304         if (ldebug(sgetmask))
305                 kprintf(ARGS(sgetmask, ""));
306 #endif
307
308         bsd_to_linux_sigset(&lp->lwp_sigmask, &mask);
309         args->sysmsg_result = mask.__bits[0];
310         return (0);
311 }
312
313 /*
314  * MPSAFE
315  */
316 int
317 sys_linux_ssetmask(struct linux_ssetmask_args *args)
318 {
319         struct lwp *lp = curthread->td_lwp;
320         l_sigset_t lset;
321         sigset_t bset;
322
323 #ifdef DEBUG
324         if (ldebug(ssetmask))
325                 kprintf(ARGS(ssetmask, "%08lx"), (unsigned long)args->mask);
326 #endif
327
328         bsd_to_linux_sigset(&lp->lwp_sigmask, &lset);
329         args->sysmsg_result = lset.__bits[0];
330         LINUX_SIGEMPTYSET(lset);
331         lset.__bits[0] = args->mask;
332         linux_to_bsd_sigset(&lset, &bset);
333         crit_enter();
334         lp->lwp_sigmask = bset;
335         SIG_CANTMASK(lp->lwp_sigmask);
336         crit_exit();
337         return (0);
338 }
339
340 /*
341  * MPSAFE
342  */
343 int
344 sys_linux_sigpending(struct linux_sigpending_args *args)
345 {
346         struct thread *td = curthread;
347         struct lwp *lp = td->td_lwp;
348         sigset_t set;
349         l_sigset_t linux_set;
350         l_osigset_t mask;
351         int error;
352
353 #ifdef DEBUG
354         if (ldebug(sigpending))
355                 kprintf(ARGS(sigpending, "*"));
356 #endif
357
358         error = kern_sigpending(&set);
359
360         if (error == 0) {
361                 SIGSETAND(set, lp->lwp_sigmask);
362                 bsd_to_linux_sigset(&set, &linux_set);
363                 mask = linux_set.__bits[0];
364                 error = copyout(&mask, args->mask, sizeof(mask));
365         }
366         return (error);
367 }
368
369 int
370 sys_linux_kill(struct linux_kill_args *args)
371 {
372         int error, sig;
373
374 #ifdef DEBUG
375         if (ldebug(kill))
376                 kprintf(ARGS(kill, "%d, %d"), args->pid, args->signum);
377 #endif
378         /*
379          * Allow signal 0 as a means to check for privileges
380          */
381         if (args->signum < 0 || args->signum > LINUX_NSIG)
382                 return EINVAL;
383
384         if (args->signum > 0 && args->signum <= LINUX_SIGTBLSZ)
385                 sig = linux_to_bsd_signal[_SIG_IDX(args->signum)];
386         else
387                 sig = args->signum;
388
389         error = kern_kill(sig, args->pid, -1);
390
391         return(error);
392 }
393
394
395 static int
396 linux_do_tkill(l_int tgid, l_int pid, l_int sig)
397 {
398         struct linux_emuldata *em;
399         struct proc *p;
400         int error = 0;
401
402         /*
403          * Allow signal 0 as a means to check for privileges
404          */
405         if (sig < 0 || sig > LINUX_NSIG)
406                 return (EINVAL);
407
408         if (sig > 0 && sig <= LINUX_SIGTBLSZ)
409                 sig = linux_to_bsd_signal[_SIG_IDX(sig)];
410
411         lwkt_gettoken(&proc_token);
412         if ((p = pfind(pid)) == NULL) {
413                 if ((p = zpfind(pid)) == NULL) {
414                         error = ESRCH;
415                         goto done2;
416                 }
417         }
418         PHOLD(p);
419
420         EMUL_LOCK();
421         em = emuldata_get(p);
422
423         if (em == NULL) {
424                 EMUL_UNLOCK();
425                 error = ESRCH;
426                 goto done1;
427         }
428
429         if (tgid > 0 && em->s->group_pid != tgid) {
430                 EMUL_UNLOCK();
431                 error = ESRCH;
432                 goto done1;
433         }
434         EMUL_UNLOCK();
435
436         error = kern_kill(sig, pid, -1);
437
438 done1:
439         PRELE(p);
440 done2:
441         lwkt_reltoken(&proc_token);
442
443         return (error);
444 }
445
446 int
447 sys_linux_tgkill(struct linux_tgkill_args *args)
448 {
449
450 #ifdef DEBUG
451         if (ldebug(tgkill))
452                 kprintf(ARGS(tgkill, "%d, %d, %d"), args->tgid, args->pid, args->sig);
453 #endif
454         if (args->pid <= 0 || args->tgid <= 0)
455                 return (EINVAL);
456
457         return (linux_do_tkill(args->tgid, args->pid, args->sig));
458 }
459
460 int
461 sys_linux_tkill(struct linux_tkill_args *args)
462 {
463 #ifdef DEBUG
464         if (ldebug(tkill))
465                 kprintf(ARGS(tkill, "%i, %i"), args->tid, args->sig);
466 #endif
467         if (args->tid <= 0)
468                 return (EINVAL);
469
470         return (linux_do_tkill(0, args->tid, args->sig));
471 }
472