linux_signal.c revision 1.12 1 /* $NetBSD: linux_signal.c,v 1.12 1998/09/11 12:50:09 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 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 if ((lsa->sa_flags & ~LINUX_SA_ALLBITS) != 0)
193 /*XXX*/ printf("linux_to_native_sigaction: extra bits ignored\n");
194 if (lsa->sa_restorer != 0)
195 /*XXX*/ printf("linux_to_native_sigaction: sa_restorer ignored\n");
196 }
197
198 void
199 native_to_linux_sigaction(bsa, lsa)
200 struct sigaction *bsa;
201 struct linux_sigaction *lsa;
202 {
203
204 lsa->sa_handler = bsa->sa_handler;
205 native_to_linux_sigset(&bsa->sa_mask, &lsa->sa_mask);
206 lsa->sa_flags = 0;
207 if ((bsa->sa_flags & SA_NOCLDSTOP) != 0)
208 lsa->sa_flags |= LINUX_SA_NOCLDSTOP;
209 if ((bsa->sa_flags & SA_ONSTACK) != 0)
210 lsa->sa_flags |= LINUX_SA_ONSTACK;
211 if ((bsa->sa_flags & SA_RESTART) != 0)
212 lsa->sa_flags |= LINUX_SA_RESTART;
213 if ((bsa->sa_flags & SA_NODEFER) != 0)
214 lsa->sa_flags |= LINUX_SA_NOMASK;
215 if ((bsa->sa_flags & SA_RESETHAND) != 0)
216 lsa->sa_flags |= LINUX_SA_ONESHOT;
217 lsa->sa_restorer = NULL;
218 }
219
220
221 /*
222 * The Linux sigaction() system call. Do the usual conversions,
223 * and just call sigaction(). Some flags and values are silently
224 * ignored (see above).
225 */
226 int
227 linux_sys_sigaction(p, v, retval)
228 register struct proc *p;
229 void *v;
230 register_t *retval;
231 {
232 struct linux_sys_sigaction_args /* {
233 syscallarg(int) signum;
234 syscallarg(const struct linux_sigaction *) nsa;
235 syscallarg(struct linux_sigaction *) osa;
236 } */ *uap = v;
237 struct linux_sigaction nlsa, olsa;
238 struct sigaction nbsa, obsa;
239 int error;
240
241 if (SCARG(uap, nsa)) {
242 error = copyin(SCARG(uap, nsa), &nlsa, sizeof(nlsa));
243 if (error)
244 return (error);
245 linux_to_native_sigaction(&nlsa, &nbsa);
246 }
247 error = sigaction1(p, linux_to_native_sig[SCARG(uap, signum)],
248 SCARG(uap, nsa) ? &nbsa : 0, SCARG(uap, osa) ? &obsa : 0);
249 if (error)
250 return (error);
251 if (SCARG(uap, osa)) {
252 native_to_linux_sigaction(&obsa, &olsa);
253 error = copyout(&olsa, SCARG(uap, osa), sizeof(olsa));
254 if (error)
255 return (error);
256 }
257 return (0);
258 }
259
260 /*
261 * The Linux signal() system call. I think that the signal() in the C
262 * library actually calls sigaction, so I doubt this one is ever used.
263 * But hey, it can't hurt having it here. The same restrictions as for
264 * sigaction() apply.
265 */
266 int
267 linux_sys_signal(p, v, retval)
268 register struct proc *p;
269 void *v;
270 register_t *retval;
271 {
272 struct linux_sys_signal_args /* {
273 syscallarg(int) sig;
274 syscallarg(linux_handler_t) handler;
275 } */ *uap = v;
276 struct sigaction nbsa, obsa;
277 int error;
278
279 nbsa.sa_handler = SCARG(uap, handler);
280 sigemptyset(&nbsa.sa_mask);
281 nbsa.sa_flags = SA_RESETHAND | SA_NODEFER;
282 error = sigaction1(p, linux_to_native_sig[SCARG(uap, sig)],
283 &nbsa, &obsa);
284 if (error)
285 return (error);
286 *retval = (int)obsa.sa_handler;
287 return (0);
288 }
289
290 int
291 linux_sys_sigprocmask(p, v, retval)
292 register struct proc *p;
293 void *v;
294 register_t *retval;
295 {
296 struct linux_sys_sigprocmask_args /* {
297 syscallarg(int) how;
298 syscallarg(const linux_sigset_t *) set;
299 syscallarg(linux_sigset_t *) oset;
300 } */ *uap = v;
301 linux_sigset_t nlss, olss;
302 sigset_t nbss, obss;
303 int how;
304 int error;
305
306 switch (SCARG(uap, how)) {
307 case LINUX_SIG_BLOCK:
308 how = SIG_BLOCK;
309 break;
310 case LINUX_SIG_UNBLOCK:
311 how = SIG_UNBLOCK;
312 break;
313 case LINUX_SIG_SETMASK:
314 how = SIG_SETMASK;
315 break;
316 default:
317 return (EINVAL);
318 }
319
320 if (SCARG(uap, set)) {
321 error = copyin(SCARG(uap, set), &nlss, sizeof(nlss));
322 if (error)
323 return (error);
324 linux_to_native_sigset(&nlss, &nbss);
325 }
326 error = sigprocmask1(p, how,
327 SCARG(uap, set) ? &nbss : 0, SCARG(uap, oset) ? &obss : 0);
328 if (error)
329 return (error);
330 if (SCARG(uap, oset)) {
331 native_to_linux_sigset(&obss, &olss);
332 error = copyout(&olss, SCARG(uap, oset), sizeof(olss));
333 if (error)
334 return (error);
335 }
336 return (error);
337 }
338
339 /* ARGSUSED */
340 int
341 linux_sys_siggetmask(p, v, retval)
342 register struct proc *p;
343 void *v;
344 register_t *retval;
345 {
346 sigset_t bss;
347 linux_sigset_t lss;
348 int error;
349
350 error = sigprocmask1(p, SIG_SETMASK, 0, &bss);
351 if (error)
352 return (error);
353 native_to_linux_sigset(&bss, &lss);
354 *retval = lss;
355 return (0);
356 }
357
358 /*
359 * The following three functions fiddle with a process' signal mask.
360 * Convert the signal masks because of the different signal
361 * values for Linux. The need for this is the reason why
362 * they are here, and have not been mapped directly.
363 */
364 int
365 linux_sys_sigsetmask(p, v, retval)
366 register struct proc *p;
367 void *v;
368 register_t *retval;
369 {
370 struct linux_sys_sigsetmask_args /* {
371 syscallarg(linux_sigset_t) mask;
372 } */ *uap = v;
373 sigset_t nbss, obss;
374 linux_sigset_t nlss, olss;
375 int error;
376
377 nlss = SCARG(uap, mask);
378 linux_to_native_sigset(&nlss, &nbss);
379 error = sigprocmask1(p, SIG_SETMASK, &nbss, &obss);
380 if (error)
381 return (error);
382 native_to_linux_sigset(&obss, &olss);
383 *retval = olss;
384 return (0);
385 }
386
387 int
388 linux_sys_sigpending(p, v, retval)
389 register struct proc *p;
390 void *v;
391 register_t *retval;
392 {
393 struct linux_sys_sigpending_args /* {
394 syscallarg(linux_sigset_t *) set;
395 } */ *uap = v;
396 sigset_t bss;
397 linux_sigset_t lss;
398
399 sigpending1(p, &bss);
400 native_to_linux_sigset(&bss, &lss);
401 return copyout(&lss, SCARG(uap, set), sizeof(lss));
402 }
403
404 int
405 linux_sys_sigsuspend(p, v, retval)
406 register struct proc *p;
407 void *v;
408 register_t *retval;
409 {
410 struct linux_sys_sigsuspend_args /* {
411 syscallarg(caddr_t) restart;
412 syscallarg(int) oldmask;
413 syscallarg(int) mask;
414 } */ *uap = v;
415 linux_sigset_t lss;
416 sigset_t bss;
417
418 lss = SCARG(uap, mask);
419 linux_to_native_sigset(&lss, &bss);
420 return (sigsuspend1(p, &bss));
421 }
422
423 /*
424 * The deprecated pause(2), which is really just an instance
425 * of sigsuspend(2).
426 */
427 int
428 linux_sys_pause(p, v, retval)
429 register struct proc *p;
430 void *v;
431 register_t *retval;
432 {
433
434 return (sigsuspend1(p, 0));
435 }
436
437 /*
438 * Once more: only a signal conversion is needed.
439 */
440 int
441 linux_sys_kill(p, v, retval)
442 register struct proc *p;
443 void *v;
444 register_t *retval;
445 {
446 struct linux_sys_kill_args /* {
447 syscallarg(int) pid;
448 syscallarg(int) signum;
449 } */ *uap = v;
450 struct sys_kill_args ka;
451
452 SCARG(&ka, pid) = SCARG(uap, pid);
453 SCARG(&ka, signum) = linux_to_native_sig[SCARG(uap, signum)];
454 return sys_kill(p, &ka, retval);
455 }
456