linux_signal.c revision 1.9 1 /* $NetBSD: linux_signal.c,v 1.9 1995/10/07 06:27:12 mycroft 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_signal.h>
52 #include <compat/linux/linux_syscallargs.h>
53 #include <compat/linux/linux_util.h>
54
55 #define sigemptyset(s) bzero((s), sizeof(*(s)))
56 #define sigismember(s, n) (*(s) & sigmask(n))
57 #define sigaddset(s, n) (*(s) |= sigmask(n))
58
59 #define linux_sigmask(n) (1 << ((n) - 1))
60 #define linux_sigemptyset(s) bzero((s), sizeof(*(s)))
61 #define linux_sigismember(s, n) (*(s) & linux_sigmask(n))
62 #define linux_sigaddset(s, n) (*(s) |= linux_sigmask(n))
63
64 int bsd_to_linux_sig[] = {
65 0,
66 LINUX_SIGHUP,
67 LINUX_SIGINT,
68 LINUX_SIGQUIT,
69 LINUX_SIGILL,
70 LINUX_SIGTRAP,
71 LINUX_SIGABRT,
72 0,
73 LINUX_SIGFPE,
74 LINUX_SIGKILL,
75 LINUX_SIGBUS,
76 LINUX_SIGSEGV,
77 0,
78 LINUX_SIGPIPE,
79 LINUX_SIGALRM,
80 LINUX_SIGTERM,
81 LINUX_SIGURG,
82 LINUX_SIGSTOP,
83 LINUX_SIGTSTP,
84 LINUX_SIGCONT,
85 LINUX_SIGCHLD,
86 LINUX_SIGTTIN,
87 LINUX_SIGTTOU,
88 LINUX_SIGIO,
89 LINUX_SIGXCPU,
90 LINUX_SIGXFSZ,
91 LINUX_SIGVTALRM,
92 LINUX_SIGPROF,
93 LINUX_SIGWINCH,
94 0,
95 LINUX_SIGUSR1,
96 LINUX_SIGUSR2,
97 };
98
99 int linux_to_bsd_sig[] = {
100 0,
101 SIGHUP,
102 SIGINT,
103 SIGQUIT,
104 SIGILL,
105 SIGTRAP,
106 SIGABRT,
107 SIGBUS,
108 SIGFPE,
109 SIGKILL,
110 SIGUSR1,
111 SIGSEGV,
112 SIGUSR2,
113 SIGPIPE,
114 SIGALRM,
115 SIGTERM,
116 0,
117 SIGCHLD,
118 SIGCONT,
119 SIGSTOP,
120 SIGTSTP,
121 SIGTTIN,
122 SIGTTOU,
123 SIGURG,
124 SIGXCPU,
125 SIGXFSZ,
126 SIGVTALRM,
127 SIGPROF,
128 SIGWINCH,
129 SIGIO,
130 0,
131 0,
132 };
133
134 /*
135 * Ok, we know that Linux and BSD signals both are just an unsigned int.
136 * Don't bother to use the sigismember() stuff for now.
137 */
138 void
139 linux_to_bsd_sigset(lss, bss)
140 const linux_sigset_t *lss;
141 sigset_t *bss;
142 {
143 int i, newsig;
144
145 sigemptyset(bss);
146 for (i = 1; i < LINUX_NSIG; i++) {
147 if (linux_sigismember(lss, i)) {
148 newsig = linux_to_bsd_sig[i];
149 if (newsig)
150 sigaddset(bss, newsig);
151 }
152 }
153 }
154
155 void
156 bsd_to_linux_sigset(bss, lss)
157 const sigset_t *bss;
158 linux_sigset_t *lss;
159 {
160 int i, newsig;
161
162 linux_sigemptyset(lss);
163 for (i = 1; i < NSIG; i++) {
164 if (sigismember(bss, i)) {
165 newsig = bsd_to_linux_sig[i];
166 if (newsig)
167 linux_sigaddset(lss, newsig);
168 }
169 }
170 }
171
172 /*
173 * Convert between Linux and BSD sigaction structures. Linux has
174 * one extra field (sa_restorer) which we don't support.
175 */
176 void
177 linux_to_bsd_sigaction(lsa, bsa)
178 struct linux_sigaction *lsa;
179 struct sigaction *bsa;
180 {
181
182 bsa->sa_handler = lsa->sa_handler;
183 linux_to_bsd_sigset(&bsa->sa_mask, &lsa->sa_mask);
184 bsa->sa_flags = 0;
185 if ((lsa->sa_flags & LINUX_SA_ONSTACK) != 0)
186 bsa->sa_flags |= SA_ONSTACK;
187 if ((lsa->sa_flags & LINUX_SA_RESTART) != 0)
188 bsa->sa_flags |= SA_RESTART;
189 if ((lsa->sa_flags & LINUX_SA_ONESHOT) != 0)
190 bsa->sa_flags |= SA_RESETHAND;
191 if ((lsa->sa_flags & LINUX_SA_NOCLDSTOP) != 0)
192 bsa->sa_flags |= SA_NOCLDSTOP;
193 if ((lsa->sa_flags & LINUX_SA_NOMASK) != 0)
194 bsa->sa_flags |= SA_NODEFER;
195 }
196
197 void
198 bsd_to_linux_sigaction(bsa, lsa)
199 struct sigaction *bsa;
200 struct linux_sigaction *lsa;
201 {
202
203 lsa->sa_handler = bsa->sa_handler;
204 bsd_to_linux_sigset(&lsa->sa_mask, &bsa->sa_mask);
205 lsa->sa_flags = 0;
206 if ((bsa->sa_flags & SA_NOCLDSTOP) != 0)
207 lsa->sa_flags |= LINUX_SA_NOCLDSTOP;
208 if ((bsa->sa_flags & SA_ONSTACK) != 0)
209 lsa->sa_flags |= LINUX_SA_ONSTACK;
210 if ((bsa->sa_flags & SA_RESTART) != 0)
211 lsa->sa_flags |= LINUX_SA_RESTART;
212 if ((bsa->sa_flags & SA_NODEFER) != 0)
213 lsa->sa_flags |= LINUX_SA_NOMASK;
214 if ((bsa->sa_flags & SA_RESETHAND) != 0)
215 lsa->sa_flags |= LINUX_SA_ONESHOT;
216 lsa->sa_restorer = NULL;
217 }
218
219
220 /*
221 * The Linux sigaction() system call. Do the usual conversions,
222 * and just call sigaction(). Some flags and values are silently
223 * ignored (see above).
224 */
225 int
226 linux_sys_sigaction(p, v, retval)
227 register struct proc *p;
228 void *v;
229 register_t *retval;
230 {
231 struct linux_sys_sigaction_args /* {
232 syscallarg(int) signum;
233 syscallarg(struct linux_sigaction *) nsa;
234 syscallarg(struct linux_sigaction *) osa;
235 } */ *uap = v;
236 struct linux_sigaction *nlsa, *olsa, tmplsa;
237 struct sigaction *nbsa, *obsa, tmpbsa;
238 struct sys_sigaction_args sa;
239 caddr_t sg;
240 int error;
241
242 sg = stackgap_init(p->p_emul);
243 nlsa = SCARG(uap, nsa);
244 olsa = SCARG(uap, osa);
245
246 if (olsa != NULL)
247 obsa = stackgap_alloc(&sg, sizeof(struct sigaction));
248 else
249 obsa = NULL;
250
251 if (nlsa != NULL) {
252 nbsa = stackgap_alloc(&sg, sizeof(struct sigaction));
253 if ((error = copyin(nlsa, &tmplsa, sizeof(tmplsa))) != 0)
254 return error;
255 linux_to_bsd_sigaction(&tmplsa, &tmpbsa);
256 if ((error = copyout(&tmpbsa, nbsa, sizeof(tmpbsa))) != 0)
257 return error;
258 } else
259 nbsa = NULL;
260
261 SCARG(&sa, signum) = linux_to_bsd_sig[SCARG(uap, signum)];
262 SCARG(&sa, nsa) = nbsa;
263 SCARG(&sa, osa) = obsa;
264
265 if ((error = sys_sigaction(p, &sa, retval)) != 0)
266 return error;
267
268 if (olsa != NULL) {
269 if ((error = copyin(obsa, &tmpbsa, sizeof(tmpbsa))) != 0)
270 return error;
271 bsd_to_linux_sigaction(&tmpbsa, &tmplsa);
272 if ((error = copyout(&tmplsa, olsa, sizeof(tmplsa))) != 0)
273 return error;
274 }
275
276 return 0;
277 }
278
279 /*
280 * The Linux signal() system call. I think that the signal() in the C
281 * library actually calls sigaction, so I doubt this one is ever used.
282 * But hey, it can't hurt having it here. The same restrictions as for
283 * sigaction() apply.
284 */
285 int
286 linux_sys_signal(p, v, retval)
287 register struct proc *p;
288 void *v;
289 register_t *retval;
290 {
291 struct linux_sys_signal_args /* {
292 syscallarg(int) sig;
293 syscallarg(linux_handler_t) handler;
294 } */ *uap = v;
295 caddr_t sg;
296 struct sys_sigaction_args sa_args;
297 struct sigaction *osa, *nsa, tmpsa;
298 int error;
299
300 sg = stackgap_init(p->p_emul);
301 nsa = stackgap_alloc(&sg, sizeof *nsa);
302 osa = stackgap_alloc(&sg, sizeof *osa);
303
304 tmpsa.sa_handler = SCARG(uap, handler);
305 tmpsa.sa_mask = (sigset_t) 0;
306 tmpsa.sa_flags = SA_RESETHAND | SA_NODEFER;
307 if ((error = copyout(&tmpsa, nsa, sizeof tmpsa)))
308 return error;
309
310 SCARG(&sa_args, signum) = linux_to_bsd_sig[SCARG(uap, sig)];
311 SCARG(&sa_args, osa) = osa;
312 SCARG(&sa_args, nsa) = nsa;
313 if ((error = sys_sigaction(p, &sa_args, retval)))
314 return error;
315
316 if ((error = copyin(osa, &tmpsa, sizeof *osa)))
317 return error;
318 retval[0] = (register_t) tmpsa.sa_handler;
319
320 return 0;
321 }
322
323 /*
324 * This is just a copy of the svr4 compat one. I feel so creative now.
325 */
326 int
327 linux_sys_sigprocmask(p, v, retval)
328 register struct proc *p;
329 void *v;
330 register_t *retval;
331 {
332 struct linux_sys_sigprocmask_args /* {
333 syscallarg(int) how;
334 syscallarg(linux_sigset_t *) set;
335 syscallarg(linux_sigset_t *) oset;
336 } */ *uap = v;
337 linux_sigset_t ss;
338 sigset_t bs;
339 int error = 0;
340
341 *retval = 0;
342
343 if (SCARG(uap, oset) != NULL) {
344 /* Fix the return value first if needed */
345 bsd_to_linux_sigset(&p->p_sigmask, &ss);
346 if ((error = copyout(&ss, SCARG(uap, oset), sizeof(ss))) != 0)
347 return error;
348 }
349
350 if (SCARG(uap, set) == NULL)
351 /* Just examine */
352 return 0;
353
354 if ((error = copyin(SCARG(uap, set), &ss, sizeof(ss))) != 0)
355 return error;
356
357 linux_to_bsd_sigset(&ss, &bs);
358
359 (void) splhigh();
360
361 switch (SCARG(uap, how)) {
362 case LINUX_SIG_BLOCK:
363 p->p_sigmask |= bs & ~sigcantmask;
364 break;
365
366 case LINUX_SIG_UNBLOCK:
367 p->p_sigmask &= ~bs;
368 break;
369
370 case LINUX_SIG_SETMASK:
371 p->p_sigmask = bs & ~sigcantmask;
372 break;
373
374 default:
375 error = EINVAL;
376 break;
377 }
378
379 (void) spl0();
380
381 return error;
382 }
383
384 /*
385 * The functions below really make no distinction between an int
386 * and [linux_]sigset_t. This is ok for now, but it might break
387 * sometime. Then again, sigset_t is trusted to be an int everywhere
388 * else in the kernel too.
389 */
390 /* ARGSUSED */
391 int
392 linux_sys_siggetmask(p, v, retval)
393 register struct proc *p;
394 void *v;
395 register_t *retval;
396 {
397
398 bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *)retval);
399 return 0;
400 }
401
402 /*
403 * The following three functions fiddle with a process' signal mask.
404 * Convert the signal masks because of the different signal
405 * values for Linux. The need for this is the reason why
406 * they are here, and have not been mapped directly.
407 */
408 int
409 linux_sys_sigsetmask(p, v, retval)
410 register struct proc *p;
411 void *v;
412 register_t *retval;
413 {
414 struct linux_sys_sigsetmask_args /* {
415 syscallarg(linux_sigset_t) mask;
416 } */ *uap = v;
417 linux_sigset_t mask;
418 sigset_t bsdsig;
419
420 bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *)retval);
421
422 mask = SCARG(uap, mask);
423 bsd_to_linux_sigset(&mask, &bsdsig);
424
425 splhigh();
426 p->p_sigmask = bsdsig & ~sigcantmask;
427 spl0();
428
429 return 0;
430 }
431
432 int
433 linux_sys_sigpending(p, v, retval)
434 register struct proc *p;
435 void *v;
436 register_t *retval;
437 {
438 struct linux_sys_sigpending_args /* {
439 syscallarg(linux_sigset_t *) mask;
440 } */ *uap = v;
441 sigset_t bs;
442 linux_sigset_t ls;
443
444 bs = p->p_siglist & p->p_sigmask;
445 bsd_to_linux_sigset(&bs, &ls);
446
447 return copyout(&ls, SCARG(uap, mask), sizeof(ls));
448 }
449
450 int
451 linux_sys_sigsuspend(p, v, retval)
452 register struct proc *p;
453 void *v;
454 register_t *retval;
455 {
456 struct linux_sys_sigsuspend_args /* {
457 syscallarg(caddr_t) restart;
458 syscallarg(int) oldmask;
459 syscallarg(int) mask;
460 } */ *uap = v;
461 struct sys_sigsuspend_args sa;
462
463 linux_to_bsd_sigset(&SCARG(uap, mask), &SCARG(&sa, mask));
464 return sys_sigsuspend(p, &sa, retval);
465 }
466
467 /*
468 * The deprecated pause(2), which is really just an instance
469 * of sigsuspend(2).
470 */
471 int
472 linux_sys_pause(p, v, retval)
473 register struct proc *p;
474 void *v;
475 register_t *retval;
476 {
477 struct sys_sigsuspend_args bsa;
478
479 SCARG(&bsa, mask) = p->p_sigmask;
480 return sys_sigsuspend(p, &bsa, retval);
481 }
482
483 /*
484 * Once more: only a signal conversion is needed.
485 */
486 int
487 linux_sys_kill(p, v, retval)
488 register struct proc *p;
489 void *v;
490 register_t *retval;
491 {
492 struct linux_sys_kill_args /* {
493 syscallarg(int) pid;
494 syscallarg(int) signum;
495 } */ *uap = v;
496 struct sys_kill_args ka;
497
498 SCARG(&ka, pid) = SCARG(uap, pid);
499 SCARG(&ka, signum) = linux_to_bsd_sig[SCARG(uap, signum)];
500 return sys_kill(p, &ka, retval);
501 }
502