linux_signal.c revision 1.13 1 /* $NetBSD: linux_signal.c,v 1.13 1998/09/29 14:15:49 tv 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 linux_sigmask(n) (1 << ((n) - 1))
56 #define linux_sigemptyset(s) memset((s), 0, sizeof(*(s)))
57 #define linux_sigismember(s, n) (*(s) & linux_sigmask(n))
58 #define linux_sigaddset(s, n) (*(s) |= linux_sigmask(n))
59
60 int native_to_linux_sig[NSIG] = {
61 0,
62 LINUX_SIGHUP,
63 LINUX_SIGINT,
64 LINUX_SIGQUIT,
65 LINUX_SIGILL,
66 LINUX_SIGTRAP,
67 LINUX_SIGABRT,
68 0, /* SIGEMT */
69 LINUX_SIGFPE,
70 LINUX_SIGKILL,
71 LINUX_SIGBUS,
72 LINUX_SIGSEGV,
73 0, /* SIGSEGV */
74 LINUX_SIGPIPE,
75 LINUX_SIGALRM,
76 LINUX_SIGTERM,
77 LINUX_SIGURG,
78 LINUX_SIGSTOP,
79 LINUX_SIGTSTP,
80 LINUX_SIGCONT,
81 LINUX_SIGCHLD,
82 LINUX_SIGTTIN,
83 LINUX_SIGTTOU,
84 LINUX_SIGIO,
85 LINUX_SIGXCPU,
86 LINUX_SIGXFSZ,
87 LINUX_SIGVTALRM,
88 LINUX_SIGPROF,
89 LINUX_SIGWINCH,
90 0, /* SIGINFO */
91 LINUX_SIGUSR1,
92 LINUX_SIGUSR2,
93 LINUX_SIGPWR,
94 };
95
96 int linux_to_native_sig[LINUX_NSIG] = {
97 0,
98 SIGHUP,
99 SIGINT,
100 SIGQUIT,
101 SIGILL,
102 SIGTRAP,
103 SIGABRT,
104 SIGBUS,
105 SIGFPE,
106 SIGKILL,
107 SIGUSR1,
108 SIGSEGV,
109 SIGUSR2,
110 SIGPIPE,
111 SIGALRM,
112 SIGTERM,
113 0, /* SIGSTKFLT */
114 SIGCHLD,
115 SIGCONT,
116 SIGSTOP,
117 SIGTSTP,
118 SIGTTIN,
119 SIGTTOU,
120 SIGURG,
121 SIGXCPU,
122 SIGXFSZ,
123 SIGVTALRM,
124 SIGPROF,
125 SIGWINCH,
126 SIGIO,
127 SIGPWR,
128 0, /* SIGUNUSED */
129 };
130
131 /* linux_signal.c */
132 void linux_to_native_sigaction __P((struct linux_sigaction *, struct sigaction *));
133 void native_to_linux_sigaction __P((struct sigaction *, struct linux_sigaction *));
134
135 void
136 linux_to_native_sigset(lss, bss)
137 const linux_sigset_t *lss;
138 sigset_t *bss;
139 {
140 int i, newsig;
141
142 sigemptyset(bss);
143 for (i = 1; i < LINUX_NSIG; i++) {
144 if (linux_sigismember(lss, i)) {
145 newsig = linux_to_native_sig[i];
146 if (newsig)
147 sigaddset(bss, newsig);
148 }
149 }
150 }
151
152 void
153 native_to_linux_sigset(bss, lss)
154 const sigset_t *bss;
155 linux_sigset_t *lss;
156 {
157 int i, newsig;
158
159 linux_sigemptyset(lss);
160 for (i = 1; i < NSIG; i++) {
161 if (sigismember(bss, i)) {
162 newsig = native_to_linux_sig[i];
163 if (newsig)
164 linux_sigaddset(lss, newsig);
165 }
166 }
167 }
168
169 /*
170 * Convert between Linux and BSD sigaction structures. Linux has
171 * one extra field (sa_restorer) which we don't support.
172 */
173 void
174 linux_to_native_sigaction(lsa, bsa)
175 struct linux_sigaction *lsa;
176 struct sigaction *bsa;
177 {
178
179 bsa->sa_handler = lsa->sa_handler;
180 linux_to_native_sigset(&lsa->sa_mask, &bsa->sa_mask);
181 bsa->sa_flags = 0;
182 if ((lsa->sa_flags & LINUX_SA_NOCLDSTOP) != 0)
183 bsa->sa_flags |= SA_NOCLDSTOP;
184 if ((lsa->sa_flags & LINUX_SA_ONSTACK) != 0)
185 bsa->sa_flags |= SA_ONSTACK;
186 if ((lsa->sa_flags & LINUX_SA_RESTART) != 0)
187 bsa->sa_flags |= SA_RESTART;
188 if ((lsa->sa_flags & LINUX_SA_ONESHOT) != 0)
189 bsa->sa_flags |= SA_RESETHAND;
190 if ((lsa->sa_flags & LINUX_SA_NOMASK) != 0)
191 bsa->sa_flags |= SA_NODEFER;
192 #ifdef DEBUG
193 if ((lsa->sa_flags & ~LINUX_SA_ALLBITS) != 0)
194 /*XXX*/ printf("linux_to_native_sigaction: extra bits ignored\n");
195 if (lsa->sa_restorer != 0)
196 /*XXX*/ printf("linux_to_native_sigaction: sa_restorer ignored\n");
197 #endif
198 }
199
200 void
201 native_to_linux_sigaction(bsa, lsa)
202 struct sigaction *bsa;
203 struct linux_sigaction *lsa;
204 {
205
206 lsa->sa_handler = bsa->sa_handler;
207 native_to_linux_sigset(&bsa->sa_mask, &lsa->sa_mask);
208 lsa->sa_flags = 0;
209 if ((bsa->sa_flags & SA_NOCLDSTOP) != 0)
210 lsa->sa_flags |= LINUX_SA_NOCLDSTOP;
211 if ((bsa->sa_flags & SA_ONSTACK) != 0)
212 lsa->sa_flags |= LINUX_SA_ONSTACK;
213 if ((bsa->sa_flags & SA_RESTART) != 0)
214 lsa->sa_flags |= LINUX_SA_RESTART;
215 if ((bsa->sa_flags & SA_NODEFER) != 0)
216 lsa->sa_flags |= LINUX_SA_NOMASK;
217 if ((bsa->sa_flags & SA_RESETHAND) != 0)
218 lsa->sa_flags |= LINUX_SA_ONESHOT;
219 lsa->sa_restorer = NULL;
220 }
221
222
223 /*
224 * The Linux sigaction() system call. Do the usual conversions,
225 * and just call sigaction(). Some flags and values are silently
226 * ignored (see above).
227 */
228 int
229 linux_sys_sigaction(p, v, retval)
230 register struct proc *p;
231 void *v;
232 register_t *retval;
233 {
234 struct linux_sys_sigaction_args /* {
235 syscallarg(int) signum;
236 syscallarg(const struct linux_sigaction *) nsa;
237 syscallarg(struct linux_sigaction *) osa;
238 } */ *uap = v;
239 struct linux_sigaction nlsa, olsa;
240 struct sigaction nbsa, obsa;
241 int error;
242
243 if (SCARG(uap, nsa)) {
244 error = copyin(SCARG(uap, nsa), &nlsa, sizeof(nlsa));
245 if (error)
246 return (error);
247 linux_to_native_sigaction(&nlsa, &nbsa);
248 }
249 error = sigaction1(p, linux_to_native_sig[SCARG(uap, signum)],
250 SCARG(uap, nsa) ? &nbsa : 0, SCARG(uap, osa) ? &obsa : 0);
251 if (error)
252 return (error);
253 if (SCARG(uap, osa)) {
254 native_to_linux_sigaction(&obsa, &olsa);
255 error = copyout(&olsa, SCARG(uap, osa), sizeof(olsa));
256 if (error)
257 return (error);
258 }
259 return (0);
260 }
261
262 /*
263 * The Linux signal() system call. I think that the signal() in the C
264 * library actually calls sigaction, so I doubt this one is ever used.
265 * But hey, it can't hurt having it here. The same restrictions as for
266 * sigaction() apply.
267 */
268 int
269 linux_sys_signal(p, v, retval)
270 register struct proc *p;
271 void *v;
272 register_t *retval;
273 {
274 struct linux_sys_signal_args /* {
275 syscallarg(int) sig;
276 syscallarg(linux_handler_t) handler;
277 } */ *uap = v;
278 struct sigaction nbsa, obsa;
279 int error;
280
281 nbsa.sa_handler = SCARG(uap, handler);
282 sigemptyset(&nbsa.sa_mask);
283 nbsa.sa_flags = SA_RESETHAND | SA_NODEFER;
284 error = sigaction1(p, linux_to_native_sig[SCARG(uap, sig)],
285 &nbsa, &obsa);
286 if (error)
287 return (error);
288 *retval = (int)obsa.sa_handler;
289 return (0);
290 }
291
292 int
293 linux_sys_sigprocmask(p, v, retval)
294 register struct proc *p;
295 void *v;
296 register_t *retval;
297 {
298 struct linux_sys_sigprocmask_args /* {
299 syscallarg(int) how;
300 syscallarg(const linux_sigset_t *) set;
301 syscallarg(linux_sigset_t *) oset;
302 } */ *uap = v;
303 linux_sigset_t nlss, olss;
304 sigset_t nbss, obss;
305 int how;
306 int error;
307
308 switch (SCARG(uap, how)) {
309 case LINUX_SIG_BLOCK:
310 how = SIG_BLOCK;
311 break;
312 case LINUX_SIG_UNBLOCK:
313 how = SIG_UNBLOCK;
314 break;
315 case LINUX_SIG_SETMASK:
316 how = SIG_SETMASK;
317 break;
318 default:
319 return (EINVAL);
320 }
321
322 if (SCARG(uap, set)) {
323 error = copyin(SCARG(uap, set), &nlss, sizeof(nlss));
324 if (error)
325 return (error);
326 linux_to_native_sigset(&nlss, &nbss);
327 }
328 error = sigprocmask1(p, how,
329 SCARG(uap, set) ? &nbss : 0, SCARG(uap, oset) ? &obss : 0);
330 if (error)
331 return (error);
332 if (SCARG(uap, oset)) {
333 native_to_linux_sigset(&obss, &olss);
334 error = copyout(&olss, SCARG(uap, oset), sizeof(olss));
335 if (error)
336 return (error);
337 }
338 return (error);
339 }
340
341 /* ARGSUSED */
342 int
343 linux_sys_siggetmask(p, v, retval)
344 register struct proc *p;
345 void *v;
346 register_t *retval;
347 {
348 sigset_t bss;
349 linux_sigset_t lss;
350 int error;
351
352 error = sigprocmask1(p, SIG_SETMASK, 0, &bss);
353 if (error)
354 return (error);
355 native_to_linux_sigset(&bss, &lss);
356 *retval = lss;
357 return (0);
358 }
359
360 /*
361 * The following three functions fiddle with a process' signal mask.
362 * Convert the signal masks because of the different signal
363 * values for Linux. The need for this is the reason why
364 * they are here, and have not been mapped directly.
365 */
366 int
367 linux_sys_sigsetmask(p, v, retval)
368 register struct proc *p;
369 void *v;
370 register_t *retval;
371 {
372 struct linux_sys_sigsetmask_args /* {
373 syscallarg(linux_sigset_t) mask;
374 } */ *uap = v;
375 sigset_t nbss, obss;
376 linux_sigset_t nlss, olss;
377 int error;
378
379 nlss = SCARG(uap, mask);
380 linux_to_native_sigset(&nlss, &nbss);
381 error = sigprocmask1(p, SIG_SETMASK, &nbss, &obss);
382 if (error)
383 return (error);
384 native_to_linux_sigset(&obss, &olss);
385 *retval = olss;
386 return (0);
387 }
388
389 int
390 linux_sys_sigpending(p, v, retval)
391 register struct proc *p;
392 void *v;
393 register_t *retval;
394 {
395 struct linux_sys_sigpending_args /* {
396 syscallarg(linux_sigset_t *) set;
397 } */ *uap = v;
398 sigset_t bss;
399 linux_sigset_t lss;
400
401 sigpending1(p, &bss);
402 native_to_linux_sigset(&bss, &lss);
403 return copyout(&lss, SCARG(uap, set), sizeof(lss));
404 }
405
406 int
407 linux_sys_sigsuspend(p, v, retval)
408 register struct proc *p;
409 void *v;
410 register_t *retval;
411 {
412 struct linux_sys_sigsuspend_args /* {
413 syscallarg(caddr_t) restart;
414 syscallarg(int) oldmask;
415 syscallarg(int) mask;
416 } */ *uap = v;
417 linux_sigset_t lss;
418 sigset_t bss;
419
420 lss = SCARG(uap, mask);
421 linux_to_native_sigset(&lss, &bss);
422 return (sigsuspend1(p, &bss));
423 }
424
425 /*
426 * The deprecated pause(2), which is really just an instance
427 * of sigsuspend(2).
428 */
429 int
430 linux_sys_pause(p, v, retval)
431 register struct proc *p;
432 void *v;
433 register_t *retval;
434 {
435
436 return (sigsuspend1(p, 0));
437 }
438
439 /*
440 * Once more: only a signal conversion is needed.
441 */
442 int
443 linux_sys_kill(p, v, retval)
444 register struct proc *p;
445 void *v;
446 register_t *retval;
447 {
448 struct linux_sys_kill_args /* {
449 syscallarg(int) pid;
450 syscallarg(int) signum;
451 } */ *uap = v;
452 struct sys_kill_args ka;
453
454 SCARG(&ka, pid) = SCARG(uap, pid);
455 SCARG(&ka, signum) = linux_to_native_sig[SCARG(uap, signum)];
456 return sys_kill(p, &ka, retval);
457 }
458