56e656b1bec3817c1126236629e59125b7079eb5
[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 withough 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  * $DragonFly: src/sys/emulation/linux/linux_signal.c,v 1.14 2007/03/12 21:07:42 corecode Exp $
30  */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/lock.h>
35 #include <sys/proc.h>
36 #include <sys/signalvar.h>
37 #include <sys/sysproto.h>
38 #include <sys/kern_syscall.h>
39 #include <sys/thread.h>
40 #include <sys/thread2.h>
41 #include <arch_linux/linux.h>
42 #include <arch_linux/linux_proto.h>
43 #include "linux_signal.h"
44 #include "linux_util.h"
45
46 void
47 linux_to_bsd_sigset(l_sigset_t *lss, sigset_t *bss)
48 {
49         int b, l;
50
51         SIGEMPTYSET(*bss);
52         bss->__bits[0] = lss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
53         bss->__bits[1] = lss->__bits[1];
54         for (l = 1; l <= LINUX_SIGTBLSZ; l++) {
55                 if (LINUX_SIGISMEMBER(*lss, l)) {
56                         b = linux_to_bsd_signal[_SIG_IDX(l)];
57                         if (b)
58                                 SIGADDSET(*bss, b);
59                 }
60         }
61 }
62
63 void
64 bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss)
65 {
66         int b, l;
67
68         LINUX_SIGEMPTYSET(*lss);
69         lss->__bits[0] = bss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1);
70         lss->__bits[1] = bss->__bits[1];
71         for (b = 1; b <= LINUX_SIGTBLSZ; b++) {
72                 if (SIGISMEMBER(*bss, b)) {
73                         l = bsd_to_linux_signal[_SIG_IDX(b)];
74                         if (l)
75                                 LINUX_SIGADDSET(*lss, l);
76                 }
77         }
78 }
79
80 void
81 linux_to_bsd_sigaction(l_sigaction_t *lsa, struct sigaction *bsa)
82 {
83
84         linux_to_bsd_sigset(&lsa->lsa_mask, &bsa->sa_mask);
85         bsa->sa_handler = lsa->lsa_handler;
86         bsa->sa_flags = 0;
87         if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP)
88                 bsa->sa_flags |= SA_NOCLDSTOP;
89         if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT)
90                 bsa->sa_flags |= SA_NOCLDWAIT;
91         if (lsa->lsa_flags & LINUX_SA_SIGINFO)
92                 bsa->sa_flags |= SA_SIGINFO;
93         if (lsa->lsa_flags & LINUX_SA_ONSTACK)
94                 bsa->sa_flags |= SA_ONSTACK;
95         if (lsa->lsa_flags & LINUX_SA_RESTART)
96                 bsa->sa_flags |= SA_RESTART;
97         if (lsa->lsa_flags & LINUX_SA_ONESHOT)
98                 bsa->sa_flags |= SA_RESETHAND;
99         if (lsa->lsa_flags & LINUX_SA_NOMASK)
100                 bsa->sa_flags |= SA_NODEFER;
101 }
102
103 void
104 bsd_to_linux_sigaction(struct sigaction *bsa, l_sigaction_t *lsa)
105 {
106
107         bsd_to_linux_sigset(&bsa->sa_mask, &lsa->lsa_mask);
108         lsa->lsa_handler = bsa->sa_handler;
109         lsa->lsa_restorer = NULL;       /* unsupported */
110         lsa->lsa_flags = 0;
111         if (bsa->sa_flags & SA_NOCLDSTOP)
112                 lsa->lsa_flags |= LINUX_SA_NOCLDSTOP;
113         if (bsa->sa_flags & SA_NOCLDWAIT)
114                 lsa->lsa_flags |= LINUX_SA_NOCLDWAIT;
115         if (bsa->sa_flags & SA_SIGINFO)
116                 lsa->lsa_flags |= LINUX_SA_SIGINFO;
117         if (bsa->sa_flags & SA_ONSTACK)
118                 lsa->lsa_flags |= LINUX_SA_ONSTACK;
119         if (bsa->sa_flags & SA_RESTART)
120                 lsa->lsa_flags |= LINUX_SA_RESTART;
121         if (bsa->sa_flags & SA_RESETHAND)
122                 lsa->lsa_flags |= LINUX_SA_ONESHOT;
123         if (bsa->sa_flags & SA_NODEFER)
124                 lsa->lsa_flags |= LINUX_SA_NOMASK;
125 }
126
127 /*
128  * MPALMOSTSAFE
129  */
130 int
131 sys_linux_signal(struct linux_signal_args *args)
132 {
133         l_sigaction_t linux_nsa, linux_osa;
134         struct sigaction nsa, osa;
135         int error, sig;
136
137 #ifdef DEBUG
138         if (ldebug(signal))
139                 kprintf(ARGS(signal, "%d, %p"),
140                     args->sig, (void *)args->handler);
141 #endif
142         linux_nsa.lsa_handler = args->handler;
143         linux_nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK;
144         LINUX_SIGEMPTYSET(linux_nsa.lsa_mask);
145         linux_to_bsd_sigaction(&linux_nsa, &nsa);
146         if (args->sig <= LINUX_SIGTBLSZ) {
147                 sig = linux_to_bsd_signal[_SIG_IDX(args->sig)];
148         } else {
149                 sig = args->sig;
150         }
151
152         get_mplock();
153         error = kern_sigaction(sig, &nsa, &osa);
154         rel_mplock();
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         get_mplock();
193         error = kern_sigaction(sig, args->act ? &nsa : NULL,
194                                args->oact ? &osa : NULL);
195         rel_mplock();
196
197         if (error == 0 && args->oact) {
198                 bsd_to_linux_sigaction(&osa, &linux_osa);
199                 error = copyout(&linux_osa, args->oact, sizeof(linux_osa));
200         }
201
202         return (error);
203 }
204
205 static int
206 linux_to_bsd_sigprocmask(int how)
207 {
208         switch (how) {
209         case LINUX_SIG_BLOCK:
210                 return SIG_BLOCK;
211         case LINUX_SIG_UNBLOCK:
212                 return SIG_UNBLOCK;
213         case LINUX_SIG_SETMASK:
214                 return SIG_SETMASK;
215         default:
216                 return (-1);
217         }
218 }
219
220 /*
221  * MPALMOSTSAFE
222  */
223 int
224 sys_linux_sigprocmask(struct linux_sigprocmask_args *args)
225 {
226         l_osigset_t mask;
227         l_sigset_t linux_set, linux_oset;
228         sigset_t set, oset;
229         int error, how;
230
231 #ifdef DEBUG
232         if (ldebug(sigprocmask))
233                 kprintf(ARGS(sigprocmask, "%d, *, *"), args->how);
234 #endif
235
236         if (args->mask) {
237                 error = copyin(args->mask, &mask, sizeof(l_osigset_t));
238                 if (error)
239                         return (error);
240                 LINUX_SIGEMPTYSET(linux_set);
241                 linux_set.__bits[0] = mask;
242                 linux_to_bsd_sigset(&linux_set, &set);
243         }
244         how = linux_to_bsd_sigprocmask(args->how);
245
246         get_mplock();
247         error = kern_sigprocmask(how, args->mask ? &set : NULL,
248                                  args->omask ? &oset : NULL);
249         rel_mplock();
250
251         if (error == 0 && args->omask) {
252                 bsd_to_linux_sigset(&oset, &linux_oset);
253                 mask = linux_oset.__bits[0];
254                 error = copyout(&mask, args->omask, sizeof(l_osigset_t));
255         }
256         return (error);
257 }
258
259 /*
260  * MPALMOSTSAFE
261  */
262 int
263 sys_linux_rt_sigprocmask(struct linux_rt_sigprocmask_args *args)
264 {
265         l_sigset_t linux_set, linux_oset;
266         sigset_t set, oset;
267         int error, how;
268
269 #ifdef DEBUG
270         if (ldebug(rt_sigprocmask))
271                 kprintf(ARGS(rt_sigprocmask, "%d, %p, %p, %ld"),
272                     args->how, (void *)args->mask,
273                     (void *)args->omask, (long)args->sigsetsize);
274 #endif
275
276         if (args->sigsetsize != sizeof(l_sigset_t))
277                 return EINVAL;
278
279         if (args->mask) {
280                 error = copyin(args->mask, &linux_set, sizeof(l_sigset_t));
281                 if (error)
282                         return (error);
283                 linux_to_bsd_sigset(&linux_set, &set);
284         }
285         how = linux_to_bsd_sigprocmask(args->how);
286
287         get_mplock();
288         error = kern_sigprocmask(how, args->mask ? &set : NULL,
289                                  args->omask ? &oset : NULL);
290         rel_mplock();
291
292         if (error == 0 && args->omask) {
293                 bsd_to_linux_sigset(&oset, &linux_oset);
294                 error = copyout(&linux_oset, args->omask, sizeof(l_sigset_t));
295         }
296
297         return (error);
298 }
299
300 /*
301  * MPSAFE
302  */
303 int
304 sys_linux_sgetmask(struct linux_sgetmask_args *args)
305 {
306         struct lwp *lp = curthread->td_lwp;
307         l_sigset_t mask;
308
309 #ifdef DEBUG
310         if (ldebug(sgetmask))
311                 kprintf(ARGS(sgetmask, ""));
312 #endif
313
314         bsd_to_linux_sigset(&lp->lwp_sigmask, &mask);
315         args->sysmsg_result = mask.__bits[0];
316         return (0);
317 }
318
319 /*
320  * MPSAFE
321  */
322 int
323 sys_linux_ssetmask(struct linux_ssetmask_args *args)
324 {
325         struct lwp *lp = curthread->td_lwp;
326         l_sigset_t lset;
327         sigset_t bset;
328
329 #ifdef DEBUG
330         if (ldebug(ssetmask))
331                 kprintf(ARGS(ssetmask, "%08lx"), (unsigned long)args->mask);
332 #endif
333
334         bsd_to_linux_sigset(&lp->lwp_sigmask, &lset);
335         args->sysmsg_result = lset.__bits[0];
336         LINUX_SIGEMPTYSET(lset);
337         lset.__bits[0] = args->mask;
338         linux_to_bsd_sigset(&lset, &bset);
339         crit_enter();
340         lp->lwp_sigmask = bset;
341         SIG_CANTMASK(lp->lwp_sigmask);
342         crit_exit();
343         return (0);
344 }
345
346 /*
347  * MPSAFE
348  */
349 int
350 sys_linux_sigpending(struct linux_sigpending_args *args)
351 {
352         struct thread *td = curthread;
353         struct lwp *lp = td->td_lwp;
354         sigset_t set;
355         l_sigset_t linux_set;
356         l_osigset_t mask;
357         int error;
358
359 #ifdef DEBUG
360         if (ldebug(sigpending))
361                 kprintf(ARGS(sigpending, "*"));
362 #endif
363
364         error = kern_sigpending(&set);
365
366         if (error == 0) {
367                 SIGSETAND(set, lp->lwp_sigmask);
368                 bsd_to_linux_sigset(&set, &linux_set);
369                 mask = linux_set.__bits[0];
370                 error = copyout(&mask, args->mask, sizeof(mask));
371         }
372         return (error);
373 }
374
375 /*
376  * MPALMOSTSAFE
377  */
378 int
379 sys_linux_kill(struct linux_kill_args *args)
380 {
381         int error, sig;
382
383 #ifdef DEBUG
384         if (ldebug(kill))
385                 kprintf(ARGS(kill, "%d, %d"), args->pid, args->signum);
386 #endif
387
388         /*
389          * Allow signal 0 as a means to check for privileges
390          */
391         if (args->signum < 0 || args->signum > LINUX_NSIG)
392                 return EINVAL;
393
394         if (args->signum > 0 && args->signum <= LINUX_SIGTBLSZ)
395                 sig = linux_to_bsd_signal[_SIG_IDX(args->signum)];
396         else
397                 sig = args->signum;
398
399         get_mplock();
400         error = kern_kill(sig, args->pid, -1);
401         rel_mplock();
402
403         return(error);
404 }
405