linux_signal.c revision 1.15 1 /* $NetBSD: linux_signal.c,v 1.15 1998/10/03 20:17:43 christos Exp $ */
2
3 /*
4 * Copyright (c) 1998 Eric Haszlakiewicz
5 * Copyright (c) 1995 Frank van der Linden
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed for the NetBSD Project
19 * by Frank van der Linden
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 * heavily from: svr4_signal.c,v 1.7 1995/01/09 01:04:21 christos Exp
35 */
36
37 /*
38 * Functions in multiarch:
39 * linux_sys_signal : linux_sig_notalpha.c
40 * linux_sys_siggetmask : linux_sig_notalpha.c
41 * linux_sys_sigsetmask : linux_sig_notalpha.c
42 * linux_sys_pause : linux_sig_notalpha.c
43 * linux_sys_sigaction : linux_sigaction.c
44 *
45 */
46
47 /*
48 * Unimplemented:
49 * linux_sys_rt_sigtimedwait : sigsuspend w/timeout.
50 */
51
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/namei.h>
55 #include <sys/proc.h>
56 #include <sys/filedesc.h>
57 #include <sys/ioctl.h>
58 #include <sys/mount.h>
59 #include <sys/kernel.h>
60 #include <sys/signal.h>
61 #include <sys/signalvar.h>
62 #include <sys/malloc.h>
63
64 #include <sys/syscallargs.h>
65
66 #include <compat/linux/common/linux_types.h>
67 #include <compat/linux/common/linux_signal.h>
68 #include <compat/linux/common/linux_util.h>
69
70 #include <compat/linux/linux_syscallargs.h>
71
72 /* Locally used defines (in bsd<->linux conversion functions): */
73 /* XXX XAX rename to linux_old. Add stuff for new type linux_sigset_t
74 handle _NSIG_WORDS > 1 */
75 #define linux_sigmask(n) (1 << ((n) - 1))
76 #define linux_sigemptyset(s) memset((s), 0, sizeof(*(s)))
77 #define linux_sigismember(s, n) (*(s) & linux_sigmask(n))
78 #define linux_sigaddset(s, n) (*(s) |= linux_sigmask(n))
79
80 /* Note: linux_to_native_sig[] is in <arch>/linux_sigarray.c */
81 int native_to_linux_sig[NSIG] = {
82 0,
83 LINUX_SIGHUP,
84 LINUX_SIGINT,
85 LINUX_SIGQUIT,
86 LINUX_SIGILL,
87 LINUX_SIGTRAP,
88 LINUX_SIGABRT,
89 0, /* SIGEMT */
90 LINUX_SIGFPE,
91 LINUX_SIGKILL,
92 LINUX_SIGBUS,
93 LINUX_SIGSEGV,
94 0, /* SIGSEGV */
95 LINUX_SIGPIPE,
96 LINUX_SIGALRM,
97 LINUX_SIGTERM,
98 LINUX_SIGURG,
99 LINUX_SIGSTOP,
100 LINUX_SIGTSTP,
101 LINUX_SIGCONT,
102 LINUX_SIGCHLD,
103 LINUX_SIGTTIN,
104 LINUX_SIGTTOU,
105 LINUX_SIGIO,
106 LINUX_SIGXCPU,
107 LINUX_SIGXFSZ,
108 LINUX_SIGVTALRM,
109 LINUX_SIGPROF,
110 LINUX_SIGWINCH,
111 0, /* SIGINFO */
112 LINUX_SIGUSR1,
113 LINUX_SIGUSR2,
114 LINUX_SIGPWR,
115 };
116
117 /*
118 * Ok, we know that Linux and BSD signals both are just an unsigned int.
119 * Don't bother to use the sigismember() stuff for now.
120 */
121 void
122 linux_old_to_native_sigset(lss, bss)
123 const linux_old_sigset_t *lss;
124 sigset_t *bss;
125 {
126 int i, newsig;
127
128 sigemptyset(bss);
129 for (i = 1; i < LINUX_NSIG; i++) {
130 if (linux_sigismember(lss, i)) {
131 newsig = linux_to_native_sig[i];
132 if (newsig)
133 sigaddset(bss, newsig);
134 }
135 }
136 }
137
138 void
139 native_to_linux_old_sigset(bss, lss)
140 const sigset_t *bss;
141 linux_old_sigset_t *lss;
142 {
143 int i, newsig;
144
145 linux_sigemptyset(lss);
146 for (i = 1; i < NSIG; i++) {
147 if (sigismember(bss, i)) {
148 newsig = native_to_linux_sig[i];
149 if (newsig)
150 linux_sigaddset(lss, newsig);
151 }
152 }
153 }
154
155 /*
156 * Convert between Linux and BSD sigaction structures. Linux sometimes
157 * has one extra field (sa_restorer) which we don't support.
158 */
159 void
160 linux_old_to_native_sigaction(lsa, bsa)
161 struct linux_old_sigaction *lsa;
162 struct sigaction *bsa;
163 {
164
165 bsa->sa_handler = lsa->sa_handler;
166 linux_old_to_native_sigset(&lsa->sa_mask, &bsa->sa_mask);
167 bsa->sa_flags = 0;
168 if ((lsa->sa_flags & LINUX_SA_NOCLDSTOP) != 0)
169 bsa->sa_flags |= SA_NOCLDSTOP;
170 if ((lsa->sa_flags & LINUX_SA_ONSTACK) != 0)
171 bsa->sa_flags |= SA_ONSTACK;
172 if ((lsa->sa_flags & LINUX_SA_RESTART) != 0)
173 bsa->sa_flags |= SA_RESTART;
174 if ((lsa->sa_flags & LINUX_SA_ONESHOT) != 0)
175 bsa->sa_flags |= SA_RESETHAND;
176 if ((lsa->sa_flags & LINUX_SA_NOMASK) != 0)
177 bsa->sa_flags |= SA_NODEFER;
178 if ((lsa->sa_flags & LINUX_SA_SIGINFO) != 0)
179 bsa->sa_flags |= SA_SIGINFO;
180 #ifdef DEBUG
181 if ((lsa->sa_flags & ~LINUX_SA_ALLBITS) != 0)
182 /*XXX*/ printf("linux_old_to_native_sigaction: extra bits ignored\n");
183 if (lsa->sa_restorer != 0)
184 /*XXX*/ printf("linux_old_to_native_sigaction: sa_restorer ignored\n");
185 #endif
186 }
187
188 void
189 native_to_linux_old_sigaction(bsa, lsa)
190 struct sigaction *bsa;
191 struct linux_old_sigaction *lsa;
192 {
193
194 /* Clear sa_flags and sa_restorer (if it exists) */
195 bzero(lsa, sizeof(struct linux_old_sigaction));
196
197 /* ...and fill in the mask and flags */
198 native_to_linux_old_sigset(&bsa->sa_mask, &lsa->sa_mask);
199 if ((bsa->sa_flags & SA_NOCLDSTOP) != 0)
200 lsa->sa_flags |= LINUX_SA_NOCLDSTOP;
201 if ((bsa->sa_flags & SA_ONSTACK) != 0)
202 lsa->sa_flags |= LINUX_SA_ONSTACK;
203 if ((bsa->sa_flags & SA_RESTART) != 0)
204 lsa->sa_flags |= LINUX_SA_RESTART;
205 if ((bsa->sa_flags & SA_NODEFER) != 0)
206 lsa->sa_flags |= LINUX_SA_NOMASK;
207 if ((bsa->sa_flags & SA_RESETHAND) != 0)
208 lsa->sa_flags |= LINUX_SA_ONESHOT;
209 if ((bsa->sa_flags & SA_SIGINFO) != 0)
210 lsa->sa_flags |= LINUX_SA_SIGINFO;
211 lsa->sa_handler = bsa->sa_handler;
212 }
213
214 /* ...and the new sigaction conversion funcs. */
215 void
216 linux_to_native_sigaction(lsa, bsa)
217 struct linux_sigaction *lsa;
218 struct sigaction *bsa;
219 {
220
221 bsa->sa_handler = lsa->sa_handler;
222 linux_to_native_sigset(&lsa->sa_mask, &bsa->sa_mask);
223 bsa->sa_flags = 0;
224 if ((lsa->sa_flags & LINUX_SA_NOCLDSTOP) != 0)
225 bsa->sa_flags |= SA_NOCLDSTOP;
226 if ((lsa->sa_flags & LINUX_SA_ONSTACK) != 0)
227 bsa->sa_flags |= SA_ONSTACK;
228 if ((lsa->sa_flags & LINUX_SA_RESTART) != 0)
229 bsa->sa_flags |= SA_RESTART;
230 if ((lsa->sa_flags & LINUX_SA_ONESHOT) != 0)
231 bsa->sa_flags |= SA_RESETHAND;
232 if ((lsa->sa_flags & LINUX_SA_NOMASK) != 0)
233 bsa->sa_flags |= SA_NODEFER;
234 if ((lsa->sa_flags & LINUX_SA_SIGINFO) != 0)
235 bsa->sa_flags |= SA_SIGINFO;
236 #ifdef DEBUG
237 if ((lsa->sa_flags & ~LINUX_SA_ALLBITS) != 0)
238 /*XXX*/ printf("linux_to_native_sigaction: extra bits ignored\n");
239 if (lsa->sa_restorer != 0)
240 /*XXX*/ printf("linux_to_native_sigaction: sa_restorer ignored\n");
241 #endif
242 }
243
244 void
245 native_to_linux_sigaction(bsa, lsa)
246 struct sigaction *bsa;
247 struct linux_sigaction *lsa;
248 {
249
250 /* Clear sa_flags and sa_restorer (if it exists) */
251 bzero(lsa, sizeof(struct linux_sigaction));
252
253 /* ...and fill in the mask and flags */
254 native_to_linux_sigset(&bsa->sa_mask, &lsa->sa_mask);
255 if ((bsa->sa_flags & SA_NOCLDSTOP) != 0)
256 lsa->sa_flags |= LINUX_SA_NOCLDSTOP;
257 if ((bsa->sa_flags & SA_ONSTACK) != 0)
258 lsa->sa_flags |= LINUX_SA_ONSTACK;
259 if ((bsa->sa_flags & SA_RESTART) != 0)
260 lsa->sa_flags |= LINUX_SA_RESTART;
261 if ((bsa->sa_flags & SA_NODEFER) != 0)
262 lsa->sa_flags |= LINUX_SA_NOMASK;
263 if ((bsa->sa_flags & SA_RESETHAND) != 0)
264 lsa->sa_flags |= LINUX_SA_ONESHOT;
265 if ((bsa->sa_flags & SA_SIGINFO) != 0)
266 lsa->sa_flags |= LINUX_SA_SIGINFO;
267 lsa->sa_handler = bsa->sa_handler;
268 }
269
270 /* ----------------------------------------------------------------------- */
271
272 /*
273 * The Linux sigaction() system call. Do the usual conversions,
274 * and just call sigaction(). Some flags and values are silently
275 * ignored (see above).
276 */
277 int
278 linux_sys_rt_sigaction(p, v, retval)
279 register struct proc *p;
280 void *v;
281 register_t *retval;
282 {
283 struct linux_sys_rt_sigaction_args /* {
284 syscallarg(int) signum;
285 syscallarg(const struct linux_sigaction *) nsa;
286 syscallarg(struct linux_sigaction *) osa;
287 syscallarg(size_t) sigsetsize;
288 } */ *uap = v;
289 struct linux_sigaction nlsa, olsa;
290 struct sigaction nbsa, obsa;
291 int error;
292
293 /* XXX XAX linux_sigset_t or struct linux_sigaction here? */
294 if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
295 return (EINVAL);
296
297 if (SCARG(uap, nsa)) {
298 error = copyin(SCARG(uap, nsa), &nlsa, sizeof(nlsa));
299 if (error)
300 return (error);
301 linux_to_native_sigaction(&nlsa, &nbsa);
302 }
303 error = sigaction1(p, linux_to_native_sig[SCARG(uap, signum)],
304 SCARG(uap, nsa) ? &nbsa : 0, SCARG(uap, osa) ? &obsa : 0);
305 if (error)
306 return (error);
307 if (SCARG(uap, osa)) {
308 native_to_linux_sigaction(&obsa, &olsa);
309 error = copyout(&olsa, SCARG(uap, osa), sizeof(olsa));
310 if (error)
311 return (error);
312 }
313 return (0);
314 }
315
316 int
317 linux_sys_rt_sigprocmask(p, v, retval)
318 register struct proc *p;
319 void *v;
320 register_t *retval;
321 {
322 /* Use non-rt function: sigsetsize is ignored. */
323 /* Assume sizeof(linux_sigset_t) == sizeof(linux_old_sigset_t) */
324 return(linux_sys_sigprocmask(p, v, retval));
325 }
326
327
328 int
329 linux_sys_sigprocmask(p, v, retval)
330 register struct proc *p;
331 void *v;
332 register_t *retval;
333 {
334 struct linux_sys_sigprocmask_args /* {
335 syscallarg(int) how;
336 syscallarg(const linux_old_sigset_t *) set;
337 syscallarg(linux_old_sigset_t *) oset;
338 } */ *uap = v;
339 linux_old_sigset_t nlss, olss;
340 sigset_t nbss, obss;
341 int how;
342 int error;
343
344 switch (SCARG(uap, how)) {
345 case LINUX_SIG_BLOCK:
346 how = SIG_BLOCK;
347 break;
348 case LINUX_SIG_UNBLOCK:
349 how = SIG_UNBLOCK;
350 break;
351 case LINUX_SIG_SETMASK:
352 how = SIG_SETMASK;
353 break;
354 default:
355 return (EINVAL);
356 }
357
358 if (SCARG(uap, set)) {
359 error = copyin(SCARG(uap, set), &nlss, sizeof(nlss));
360 if (error)
361 return (error);
362 linux_old_to_native_sigset(&nlss, &nbss);
363 }
364 error = sigprocmask1(p, how,
365 SCARG(uap, set) ? &nbss : 0, SCARG(uap, oset) ? &obss : 0);
366 if (error)
367 return (error);
368 if (SCARG(uap, oset)) {
369 native_to_linux_old_sigset(&obss, &olss);
370 error = copyout(&olss, SCARG(uap, oset), sizeof(olss));
371 if (error)
372 return (error);
373 }
374 return (error);
375 }
376
377 int
378 linux_sys_rt_sigpending(p, v, retval)
379 register struct proc *p;
380 void *v;
381 register_t *retval;
382 {
383 struct linux_sys_rt_sigpending_args /* {
384 syscallarg(linux_sigset_t *) set;
385 syscallarg(size_t) sigsetsize;
386 } */ *uap = v;
387 sigset_t bss;
388 linux_sigset_t lss;
389
390 if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
391 return (EINVAL);
392
393 sigpending1(p, &bss);
394 native_to_linux_sigset(&bss, &lss);
395 return copyout(&lss, SCARG(uap, set), sizeof(lss));
396 }
397 int
398 linux_sys_sigpending(p, v, retval)
399 register struct proc *p;
400 void *v;
401 register_t *retval;
402 {
403 struct linux_sys_sigpending_args /* {
404 syscallarg(linux_old_sigset_t *) mask;
405 } */ *uap = v;
406 sigset_t bss;
407 linux_old_sigset_t lss;
408
409 sigpending1(p, &bss);
410 native_to_linux_old_sigset(&bss, &lss);
411 return copyout(&lss, SCARG(uap, set), sizeof(lss));
412 }
413
414 int
415 linux_sys_sigsuspend(p, v, retval)
416 register struct proc *p;
417 void *v;
418 register_t *retval;
419 {
420 struct linux_sys_sigsuspend_args /* {
421 syscallarg(caddr_t) restart;
422 syscallarg(int) oldmask;
423 syscallarg(int) mask;
424 } */ *uap = v;
425 linux_old_sigset_t lss;
426 sigset_t bss;
427
428 lss = SCARG(uap, mask);
429 linux_old_to_native_sigset(&lss, &bss);
430 return (sigsuspend1(p, &bss));
431 }
432 int
433 linux_sys_rt_sigsuspend(p, v, retval)
434 register struct proc *p;
435 void *v;
436 register_t *retval;
437 {
438 struct linux_sys_rt_sigsuspend_args /* {
439 syscallarg(linux_sigset_t *) unewset;
440 syscallarg(size_t) sigsetsize;
441 } */ *uap = v;
442 linux_sigset_t lss;
443 sigset_t bss;
444 int error;
445
446 if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
447 return (EINVAL);
448
449 error = copyin(SCARG(uap, unewset), &lss, sizeof(linux_sigset_t));
450 if (error)
451 return (error);
452
453 linux_to_native_sigset(&lss, &bss);
454
455 return (sigsuspend1(p, &bss));
456 }
457
458 /*
459 * Once more: only a signal conversion is needed.
460 * Note: also used as sys_rt_queueinfo. The info field is ignored.
461 */
462 int
463 linux_sys_rt_queueinfo(p, v, retval)
464 register struct proc *p;
465 void *v;
466 register_t *retval;
467 {
468 /* XXX XAX This isn't this really int, int, siginfo_t *, is it? */
469 #if 0
470 struct linux_sys_rt_queueinfo_args /* {
471 syscallarg(int) pid;
472 syscallarg(int) signum;
473 syscallarg(siginfo_t *) uinfo;
474 } */ *uap = v;
475 #endif
476
477 /* XXX To really implement this we need to */
478 /* XXX keep a list of queued signals somewhere. */
479 return (linux_sys_kill(p, v, retval));
480 }
481
482 int
483 linux_sys_kill(p, v, retval)
484 register struct proc *p;
485 void *v;
486 register_t *retval;
487 {
488 struct linux_sys_kill_args /* {
489 syscallarg(int) pid;
490 syscallarg(int) signum;
491 } */ *uap = v;
492 struct sys_kill_args ka;
493
494 SCARG(&ka, pid) = SCARG(uap, pid);
495 SCARG(&ka, signum) = linux_to_native_sig[SCARG(uap, signum)];
496 return sys_kill(p, &ka, retval);
497 }
498