linux_signal.c revision 1.7 1 /* $NetBSD: linux_signal.c,v 1.7 1995/08/14 01:12:15 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_sigaction(p, uap, retval)
227 register struct proc *p;
228 struct linux_sigaction_args /* {
229 syscallarg(int) signum;
230 syscallarg(struct linux_sigaction *) nsa;
231 syscallarg(struct linux_sigaction *) osa;
232 } */ *uap;
233 register_t *retval;
234 {
235 struct linux_sigaction *nlsa, *olsa, tmplsa;
236 struct sigaction *nbsa, *obsa, tmpbsa;
237 struct sigaction_args sa;
238 caddr_t sg;
239 int error;
240
241 sg = stackgap_init(p->p_emul);
242 nlsa = SCARG(uap, nsa);
243 olsa = SCARG(uap, osa);
244
245 if (olsa != NULL)
246 obsa = stackgap_alloc(&sg, sizeof(struct sigaction));
247 else
248 obsa = NULL;
249
250 if (nlsa != NULL) {
251 nbsa = stackgap_alloc(&sg, sizeof(struct sigaction));
252 if ((error = copyin(nlsa, &tmplsa, sizeof(tmplsa))) != 0)
253 return error;
254 linux_to_bsd_sigaction(&tmplsa, &tmpbsa);
255 if ((error = copyout(&tmpbsa, nbsa, sizeof(tmpbsa))) != 0)
256 return error;
257 } else
258 nbsa = NULL;
259
260 SCARG(&sa, signum) = linux_to_bsd_sig[SCARG(uap, signum)];
261 SCARG(&sa, nsa) = nbsa;
262 SCARG(&sa, osa) = obsa;
263
264 if ((error = sigaction(p, &sa, retval)) != 0)
265 return error;
266
267 if (olsa != NULL) {
268 if ((error = copyin(obsa, &tmpbsa, sizeof(tmpbsa))) != 0)
269 return error;
270 bsd_to_linux_sigaction(&tmpbsa, &tmplsa);
271 if ((error = copyout(&tmplsa, olsa, sizeof(tmplsa))) != 0)
272 return error;
273 }
274
275 return 0;
276 }
277
278 /*
279 * The Linux signal() system call. I think that the signal() in the C
280 * library actually calls sigaction, so I doubt this one is ever used.
281 * But hey, it can't hurt having it here. The same restrictions as for
282 * sigaction() apply.
283 */
284 int
285 linux_signal(p, uap, retval)
286 register struct proc *p;
287 struct linux_signal_args /* {
288 syscallarg(int) sig;
289 syscallarg(linux_handler_t) handler;
290 } */ *uap;
291 register_t *retval;
292 {
293 caddr_t sg;
294 struct sigaction_args sa_args;
295 struct sigaction *osa, *nsa, tmpsa;
296 int error;
297
298 sg = stackgap_init(p->p_emul);
299 nsa = stackgap_alloc(&sg, sizeof *nsa);
300 osa = stackgap_alloc(&sg, sizeof *osa);
301
302 tmpsa.sa_handler = SCARG(uap, handler);
303 tmpsa.sa_mask = (sigset_t) 0;
304 tmpsa.sa_flags = SA_RESETHAND | SA_NODEFER;
305 if ((error = copyout(&tmpsa, nsa, sizeof tmpsa)))
306 return error;
307
308 SCARG(&sa_args, signum) = linux_to_bsd_sig[SCARG(uap, sig)];
309 SCARG(&sa_args, osa) = osa;
310 SCARG(&sa_args, nsa) = nsa;
311 if ((error = sigaction(p, &sa_args, retval)))
312 return error;
313
314 if ((error = copyin(osa, &tmpsa, sizeof *osa)))
315 return error;
316 retval[0] = (register_t) tmpsa.sa_handler;
317
318 return 0;
319 }
320
321 /*
322 * This is just a copy of the svr4 compat one. I feel so creative now.
323 */
324 int
325 linux_sigprocmask(p, uap, retval)
326 register struct proc *p;
327 struct linux_sigprocmask_args /* {
328 syscallarg(int) how;
329 syscallarg(linux_sigset_t *) set;
330 syscallarg(linux_sigset_t *) oset;
331 } */ *uap;
332 register_t *retval;
333 {
334 linux_sigset_t ss;
335 sigset_t bs;
336 int error = 0;
337
338 *retval = 0;
339
340 if (SCARG(uap, oset) != NULL) {
341 /* Fix the return value first if needed */
342 bsd_to_linux_sigset(&p->p_sigmask, &ss);
343 if ((error = copyout(&ss, SCARG(uap, oset), sizeof(ss))) != 0)
344 return error;
345 }
346
347 if (SCARG(uap, set) == NULL)
348 /* Just examine */
349 return 0;
350
351 if ((error = copyin(SCARG(uap, set), &ss, sizeof(ss))) != 0)
352 return error;
353
354 linux_to_bsd_sigset(&ss, &bs);
355
356 (void) splhigh();
357
358 switch (SCARG(uap, how)) {
359 case LINUX_SIG_BLOCK:
360 p->p_sigmask |= bs & ~sigcantmask;
361 break;
362
363 case LINUX_SIG_UNBLOCK:
364 p->p_sigmask &= ~bs;
365 break;
366
367 case LINUX_SIG_SETMASK:
368 p->p_sigmask = bs & ~sigcantmask;
369 break;
370
371 default:
372 error = EINVAL;
373 break;
374 }
375
376 (void) spl0();
377
378 return error;
379 }
380
381 /*
382 * The functions below really make no distinction between an int
383 * and [linux_]sigset_t. This is ok for now, but it might break
384 * sometime. Then again, sigset_t is trusted to be an int everywhere
385 * else in the kernel too.
386 */
387 /* ARGSUSED */
388 int
389 linux_siggetmask(p, uap, retval)
390 register struct proc *p;
391 void *uap;
392 register_t *retval;
393 {
394
395 bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *)retval);
396 return 0;
397 }
398
399 /*
400 * The following three functions fiddle with a process' signal mask.
401 * Convert the signal masks because of the different signal
402 * values for Linux. The need for this is the reason why
403 * they are here, and have not been mapped directly.
404 */
405 int
406 linux_sigsetmask(p, uap, retval)
407 register struct proc *p;
408 struct linux_sigsetmask_args /* {
409 syscallarg(linux_sigset_t) mask;
410 } */ *uap;
411 register_t *retval;
412 {
413 linux_sigset_t mask;
414 sigset_t bsdsig;
415
416 bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *)retval);
417
418 mask = SCARG(uap, mask);
419 bsd_to_linux_sigset(&mask, &bsdsig);
420
421 splhigh();
422 p->p_sigmask = bsdsig & ~sigcantmask;
423 spl0();
424
425 return 0;
426 }
427
428 int
429 linux_sigpending(p, uap, retval)
430 register struct proc *p;
431 struct linux_sigpending_args /* {
432 syscallarg(linux_sigset_t *) mask;
433 } */ *uap;
434 register_t *retval;
435 {
436 sigset_t bs;
437 linux_sigset_t ls;
438
439 bs = p->p_siglist & p->p_sigmask;
440 bsd_to_linux_sigset(&bs, &ls);
441
442 return copyout(&ls, SCARG(uap, mask), sizeof(ls));
443 }
444
445 int
446 linux_sigsuspend(p, uap, retval)
447 register struct proc *p;
448 struct linux_sigsuspend_args /* {
449 syscallarg(caddr_t) restart;
450 syscallarg(int) oldmask;
451 syscallarg(int) mask;
452 } */ *uap;
453 register_t *retval;
454 {
455 struct sigsuspend_args sa;
456
457 linux_to_bsd_sigset(&SCARG(uap, mask), &SCARG(&sa, mask));
458 return sigsuspend(p, &sa, retval);
459 }
460
461 /*
462 * The deprecated pause(2), which is really just an instance
463 * of sigsuspend(2).
464 */
465 int
466 linux_pause(p, uap, retval)
467 register struct proc *p;
468 void *uap;
469 register_t *retval;
470 {
471 struct sigsuspend_args bsa;
472
473 SCARG(&bsa, mask) = p->p_sigmask;
474 return sigsuspend(p, &bsa, retval);
475 }
476
477 /*
478 * Once more: only a signal conversion is needed.
479 */
480 int
481 linux_kill(p, uap, retval)
482 register struct proc *p;
483 struct linux_kill_args /* {
484 syscallarg(int) pid;
485 syscallarg(int) signum;
486 } */ *uap;
487 register_t *retval;
488 {
489 struct kill_args ka;
490
491 SCARG(&ka, pid) = SCARG(uap, pid);
492 SCARG(&ka, signum) = linux_to_bsd_sig[SCARG(uap, signum)];
493 return kill(p, &ka, retval);
494 }
495