linux_signal.c revision 1.2 1 /* $NetBSD: linux_signal.c,v 1.2 1995/03/08 15:17:49 fvdl Exp $ */
2
3 /*
4 * Copyright (c) 1995 Frank van der Linden
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed for the NetBSD Project
18 * by Frank van der Linden
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * heavily from: svr4_signal.c,v 1.7 1995/01/09 01:04:21 christos Exp
34 */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/namei.h>
39 #include <sys/proc.h>
40 #include <sys/filedesc.h>
41 #include <sys/ioctl.h>
42 #include <sys/mount.h>
43 #include <sys/kernel.h>
44 #include <sys/signal.h>
45 #include <sys/signalvar.h>
46 #include <sys/malloc.h>
47
48 #include <sys/syscallargs.h>
49
50 #include <compat/linux/linux_types.h>
51 #include <compat/linux/linux_syscallargs.h>
52 #include <compat/linux/linux_util.h>
53 #include <compat/linux/linux_signal.h>
54
55 /*
56 * Most of the stuff in this file is taken from Christos' SVR4 emul
57 * code. The things that need to be done are largely the same, so
58 * re-inventing the wheel doesn't make much sense.
59 */
60
61 /*
62 * Some boring signal conversion functions. Just a switch() for all signals;
63 * return the converted signal number, 0 if not supported.
64 */
65
66 int
67 bsd_to_linux_sig(sig)
68 int sig;
69 {
70 switch(sig) {
71 case SIGHUP:
72 return LINUX_SIGHUP;
73 case SIGINT:
74 return LINUX_SIGINT;
75 case SIGQUIT:
76 return LINUX_SIGQUIT;
77 case SIGILL:
78 return LINUX_SIGILL;
79 case SIGTRAP:
80 return LINUX_SIGTRAP;
81 case SIGABRT:
82 return LINUX_SIGABRT;
83 case SIGFPE:
84 return LINUX_SIGFPE;
85 case SIGKILL:
86 return LINUX_SIGKILL;
87 case SIGBUS:
88 return LINUX_SIGBUS;
89 case SIGSEGV:
90 return LINUX_SIGSEGV;
91 case SIGPIPE:
92 return LINUX_SIGPIPE;
93 case SIGALRM:
94 return LINUX_SIGALRM;
95 case SIGTERM:
96 return LINUX_SIGTERM;
97 case SIGURG:
98 return LINUX_SIGURG;
99 case SIGSTOP:
100 return LINUX_SIGSTOP;
101 case SIGTSTP:
102 return LINUX_SIGTSTP;
103 case SIGCONT:
104 return LINUX_SIGCONT;
105 case SIGCHLD:
106 return LINUX_SIGCHLD;
107 case SIGTTIN:
108 return LINUX_SIGTTIN;
109 case SIGTTOU:
110 return LINUX_SIGTTOU;
111 case SIGIO:
112 return LINUX_SIGIO;
113 case SIGXCPU:
114 return LINUX_SIGXCPU;
115 case SIGXFSZ:
116 return LINUX_SIGXFSZ;
117 case SIGVTALRM:
118 return LINUX_SIGVTALRM;
119 case SIGPROF:
120 return LINUX_SIGPROF;
121 case SIGWINCH:
122 return LINUX_SIGWINCH;
123 case SIGUSR1:
124 return LINUX_SIGUSR1;
125 case SIGUSR2:
126 return LINUX_SIGUSR2;
127 /* Not supported: EMT, SYS, INFO */
128 }
129 return 0;
130 }
131
132 int
133 linux_to_bsd_sig(sig)
134 int sig;
135 {
136 switch(sig) {
137 case LINUX_SIGHUP:
138 return SIGHUP;
139 case LINUX_SIGINT:
140 return SIGINT;
141 case LINUX_SIGQUIT:
142 return SIGQUIT;
143 case LINUX_SIGILL:
144 return SIGILL;
145 case LINUX_SIGTRAP:
146 return SIGTRAP;
147 case LINUX_SIGABRT:
148 return SIGABRT;
149 case LINUX_SIGBUS:
150 return SIGBUS;
151 case LINUX_SIGFPE:
152 return SIGFPE;
153 case LINUX_SIGKILL:
154 return SIGKILL;
155 case LINUX_SIGUSR1:
156 return SIGUSR1;
157 case LINUX_SIGSEGV:
158 return SIGSEGV;
159 case LINUX_SIGUSR2:
160 return SIGUSR2;
161 case LINUX_SIGPIPE:
162 return SIGPIPE;
163 case LINUX_SIGALRM:
164 return SIGALRM;
165 case LINUX_SIGTERM:
166 return SIGTERM;
167 case LINUX_SIGCHLD:
168 return SIGCHLD;
169 case LINUX_SIGCONT:
170 return SIGCONT;
171 case LINUX_SIGSTOP:
172 return SIGSTOP;
173 case LINUX_SIGTSTP:
174 return SIGTSTP;
175 case LINUX_SIGTTIN:
176 return SIGTTIN;
177 case LINUX_SIGTTOU:
178 return SIGTTOU;
179 case LINUX_SIGURG:
180 return SIGURG;
181 case LINUX_SIGXCPU:
182 return SIGXCPU;
183 case LINUX_SIGXFSZ:
184 return SIGXFSZ;
185 case LINUX_SIGVTALRM:
186 return SIGVTALRM;
187 case LINUX_SIGPROF:
188 return SIGPROF;
189 case LINUX_SIGWINCH:
190 return SIGWINCH;
191 case LINUX_SIGIO:
192 return SIGIO;
193 /* Not supported: STKFLT, PWR */
194 }
195 return 0;
196 }
197
198 /*
199 * Ok, we know that Linux and BSD signals both are just an unsigned int.
200 * Don't bother to use the sigismember() stuff for now.
201 */
202 static void
203 linux_to_bsd_sigset(lss, bss)
204 const linux_sigset_t *lss;
205 sigset_t *bss;
206 {
207 int i, newsig;
208
209 *bss = (sigset_t) 0;
210 for (i = 1; i <= LINUX_NSIG; i++) {
211 if (*lss & sigmask(i)) {
212 newsig = linux_to_bsd_sig(i);
213 if (newsig)
214 *bss |= sigmask(newsig);
215 }
216 }
217 }
218
219 void
220 bsd_to_linux_sigset(bss, lss)
221 const sigset_t *bss;
222 linux_sigset_t *lss;
223 {
224 int i, newsig;
225
226 *lss = (linux_sigset_t) 0;
227 for (i = 1; i <= NSIG; i++) {
228 if (*bss & sigmask(i)) {
229 newsig = bsd_to_linux_sig(i);
230 if (newsig)
231 *lss |= sigmask(newsig);
232 }
233 }
234 }
235
236 /*
237 * Convert between Linux and BSD sigaction structures. Linux has
238 * one extra field (sa_restorer) which we don't support. The Linux
239 * SA_ONESHOT and SA_NOMASK flags (which together form the old
240 * SysV signal behavior) are silently ignored. XXX
241 */
242 void
243 linux_to_bsd_sigaction(lsa, bsa)
244 struct linux_sigaction *lsa;
245 struct sigaction *bsa;
246 {
247 bsa->sa_handler = lsa->sa_handler;
248 linux_to_bsd_sigset(&bsa->sa_mask, &lsa->sa_mask);
249 bsa->sa_flags = 0;
250 bsa->sa_flags |= cvtto_bsd_mask(lsa->sa_flags, LINUX_SA_NOCLDSTOP,
251 SA_NOCLDSTOP);
252 bsa->sa_flags |= cvtto_bsd_mask(lsa->sa_flags, LINUX_SA_ONSTACK,
253 SA_ONSTACK);
254 bsa->sa_flags |= cvtto_bsd_mask(lsa->sa_flags, LINUX_SA_RESTART,
255 SA_RESTART);
256 }
257
258 void
259 bsd_to_linux_sigaction(bsa, lsa)
260 struct sigaction *bsa;
261 struct linux_sigaction *lsa;
262 {
263 lsa->sa_handler = bsa->sa_handler;
264 bsd_to_linux_sigset(&lsa->sa_mask, &bsa->sa_mask);
265 lsa->sa_flags = 0;
266 lsa->sa_flags |= cvtto_linux_mask(bsa->sa_flags, SA_NOCLDSTOP,
267 LINUX_SA_NOCLDSTOP);
268 lsa->sa_flags |= cvtto_linux_mask(bsa->sa_flags, SA_ONSTACK,
269 LINUX_SA_ONSTACK);
270 lsa->sa_flags |= cvtto_linux_mask(bsa->sa_flags, SA_RESTART,
271 LINUX_SA_RESTART);
272 lsa->sa_restorer = NULL;
273 }
274
275
276 /*
277 * The Linux sigaction() system call. Do the usual conversions,
278 * and just call sigaction(). Some flags and values are silently
279 * ignored (see above).
280 */
281 int
282 linux_sigaction(p, uap, retval)
283 register struct proc *p;
284 struct linux_sigaction_args /* {
285 syscallarg(int) signum;
286 syscallarg(struct linux_sigaction *) nsa;
287 syscallarg(struct linux_sigaction *) osa;
288 } */ *uap;
289 register_t *retval;
290 {
291 struct sigaction *nbsda = NULL, *obsda = NULL, tmpbsda;
292 struct linux_sigaction *nlsa, *olsa, tmplsa;
293 struct sigaction_args sa;
294 caddr_t sg;
295 int error;
296
297 sg = stackgap_init();
298 olsa = SCARG(uap, osa);
299 nlsa = SCARG(uap, nsa);
300
301 if (olsa != NULL)
302 obsda = stackgap_alloc(&sg, sizeof (struct sigaction));
303
304 if (nlsa != NULL) {
305 nbsda = stackgap_alloc(&sg, sizeof (struct sigaction));
306 if ((error = copyin(nlsa, &tmplsa, sizeof tmplsa)))
307 return error;
308 linux_to_bsd_sigaction(&tmplsa, &tmpbsda);
309 if ((error = copyout(&tmpbsda, nbsda, sizeof tmpbsda)))
310 return error;
311 }
312
313 SCARG(&sa, signum) = linux_to_bsd_sig(SCARG(uap, signum));
314 SCARG(&sa, nsa) = nbsda;
315 SCARG(&sa, osa) = obsda;
316
317 if ((error = sigaction(p, &sa, retval)))
318 return error;
319
320 if (olsa != NULL) {
321 if ((error = copyin(obsda, &tmpbsda, sizeof tmpbsda)))
322 return error;
323 bsd_to_linux_sigaction(&tmpbsda, &tmplsa);
324 if ((error = copyout(&tmplsa, olsa, sizeof tmplsa)))
325 return error;
326 }
327 return 0;
328 }
329
330 /*
331 * The Linux signal() system call. I think that the signal() in the C
332 * library actually calls sigaction, so I doubt this one is ever used.
333 * But hey, it can't hurt having it here. The same restrictions as for
334 * sigaction() apply.
335 */
336 int
337 linux_signal(p, uap, retval)
338 register struct proc *p;
339 struct linux_signal_args /* {
340 syscallarg(int) sig;
341 syscallarg(linux_handler_t) handler;
342 } */ *uap;
343 register_t *retval;
344 {
345 caddr_t sg;
346 struct sigaction_args sa_args;
347 struct sigaction *osa, *nsa, tmpsa;
348 int error;
349
350 sg = stackgap_init();
351 nsa = stackgap_alloc(&sg, sizeof *nsa);
352 osa = stackgap_alloc(&sg, sizeof *osa);
353
354 tmpsa.sa_handler = SCARG(uap, handler);
355 tmpsa.sa_mask = (sigset_t) 0;
356 tmpsa.sa_flags = 0;
357 if ((error = copyout(&tmpsa, nsa, sizeof tmpsa)))
358 return error;
359
360 SCARG(&sa_args, signum) = linux_to_bsd_sig(SCARG(uap, sig));
361 SCARG(&sa_args, osa) = osa;
362 SCARG(&sa_args, nsa) = nsa;
363 if ((error = sigaction(p, &sa_args, retval)))
364 return error;
365
366 if ((error = copyin(osa, &tmpsa, sizeof *osa)))
367 return error;
368 retval[0] = (register_t) tmpsa.sa_handler;
369
370 return 0;
371 }
372
373 /*
374 * This is just a copy of the svr4 compat one. I feel so creative now.
375 */
376 int
377 linux_sigprocmask(p, uap, retval)
378 register struct proc *p;
379 register struct linux_sigprocmask_args /* {
380 syscallarg(int) how;
381 syscallarg(linux_sigset_t *) set;
382 syscallarg(linux_sigset_t * oset;
383 } */ *uap;
384 register_t *retval;
385 {
386 linux_sigset_t ss;
387 sigset_t bs;
388 int error = 0;
389
390 *retval = 0;
391
392 if (SCARG(uap, oset) != NULL) {
393 /* Fix the return value first if needed */
394 bsd_to_linux_sigset(&p->p_sigmask, &ss);
395 if ((error = copyout(&ss, SCARG(uap, oset), sizeof(ss))) != 0)
396 return error;
397 }
398
399 if (SCARG(uap, set) == NULL)
400 /* Just examine */
401 return 0;
402
403 if ((error = copyin(SCARG(uap, set), &ss, sizeof(ss))) != 0)
404 return error;
405
406 linux_to_bsd_sigset(&ss, &bs);
407
408 (void) splhigh();
409
410 switch (SCARG(uap, how)) {
411 case LINUX_SIG_BLOCK:
412 p->p_sigmask |= bs & ~sigcantmask;
413 break;
414
415 case LINUX_SIG_UNBLOCK:
416 p->p_sigmask &= ~bs;
417 break;
418
419 case LINUX_SIG_SETMASK:
420 p->p_sigmask = bs & ~sigcantmask;
421 break;
422
423 default:
424 error = EINVAL;
425 break;
426 }
427
428 (void) spl0();
429
430 return error;
431 }
432
433 /*
434 * The functions below really make no distinction between an int
435 * and [linux_]sigset_t. This is ok for now, but it might break
436 * sometime. Then again, sigset_t is trusted to be an int everywhere
437 * else in the kernel too.
438 */
439 /* ARGSUSED */
440 int
441 linux_siggetmask(p, uap, retval)
442 struct proc *p;
443 void *uap;
444 register_t *retval;
445 {
446 bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *) retval);
447 return 0;
448 }
449
450 /*
451 * The following three functions fiddle with a process' signal mask.
452 * Convert the signal masks because of the different signal
453 * values for Linux. The need for this is the reason why
454 * they are here, and have not been mapped directly.
455 */
456 int
457 linux_sigsetmask(p, uap, retval)
458 struct proc *p;
459 struct linux_sigsetmask_args /* {
460 syscallarg(linux_sigset_t) mask;
461 } */ *uap;
462 register_t *retval;
463 {
464 linux_sigset_t mask;
465 sigset_t bsdsig;
466
467 bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *) retval);
468
469 mask = SCARG(uap, mask);
470 bsd_to_linux_sigset(&mask, &bsdsig);
471
472 splhigh();
473 p->p_sigmask = bsdsig & ~sigcantmask;
474 spl0();
475
476 return 0;
477 }
478
479 int
480 linux_sigpending(p, uap, retval)
481 struct proc *p;
482 struct linux_sigpending_args /* {
483 syscallarg(linux_sigset_t *) mask;
484 } */ *uap;
485 register_t *retval;
486 {
487 sigset_t bsdsig;
488 linux_sigset_t linuxsig;
489
490 bsdsig = p->p_siglist & p->p_sigmask;
491
492 bsd_to_linux_sigset(&bsdsig, &linuxsig);
493 return copyout(&linuxsig, SCARG(uap, mask), sizeof linuxsig);
494 }
495
496 int
497 linux_sigsuspend(p, uap, retval)
498 struct proc *p;
499 struct linux_sigsuspend_args /* {
500 syscallarg(int) mask;
501 } */ *uap;
502 register_t *retval;
503 {
504 struct sigsuspend_args ssa;
505
506 linux_to_bsd_sigset(&SCARG(uap, mask), &SCARG(&ssa, mask));
507 return sigsuspend(p, &ssa, retval);
508 }
509
510 /*
511 * Once more: only a signal conversion is needed.
512 */
513 int
514 linux_kill(p, uap, retval)
515 struct proc *p;
516 struct linux_kill_args /* {
517 syscallarg(int) pid;
518 syscallarg(int) signum;
519 } */ *uap;
520 register_t *retval;
521 {
522 SCARG(uap, signum) = linux_to_bsd_sig(SCARG(uap, signum));
523 return kill(p, (struct kill_args *) uap, retval);
524 }
525