linux_signal.c revision 1.31.2.1 1 /* $NetBSD: linux_signal.c,v 1.31.2.1 2001/03/05 22:49:28 nathanw Exp $ */
2 /*-
3 * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Frank van der Linden and Eric Haszlakiewicz.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the NetBSD
20 * Foundation, Inc. and its contributors.
21 * 4. Neither the name of The NetBSD Foundation nor the names of its
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37 /*
38 * heavily from: svr4_signal.c,v 1.7 1995/01/09 01:04:21 christos Exp
39 */
40
41 /*
42 * Functions in multiarch:
43 * linux_sys_signal : linux_sig_notalpha.c
44 * linux_sys_siggetmask : linux_sig_notalpha.c
45 * linux_sys_sigsetmask : linux_sig_notalpha.c
46 * linux_sys_pause : linux_sig_notalpha.c
47 * linux_sys_sigaction : linux_sigaction.c
48 *
49 */
50
51 /*
52 * Unimplemented:
53 * linux_sys_rt_sigtimedwait : sigsuspend w/timeout.
54 */
55
56 #define COMPAT_LINUX 1
57
58 #include <sys/param.h>
59 #include <sys/systm.h>
60 #include <sys/namei.h>
61 #include <sys/lwp.h>
62 #include <sys/proc.h>
63 #include <sys/filedesc.h>
64 #include <sys/ioctl.h>
65 #include <sys/mount.h>
66 #include <sys/kernel.h>
67 #include <sys/signal.h>
68 #include <sys/signalvar.h>
69 #include <sys/malloc.h>
70
71 #include <sys/syscallargs.h>
72
73 #include <compat/linux/common/linux_types.h>
74 #include <compat/linux/common/linux_signal.h>
75 #include <compat/linux/common/linux_siginfo.h>
76 #include <compat/linux/common/linux_util.h>
77
78 #include <compat/linux/linux_syscallargs.h>
79
80 /* Locally used defines (in bsd<->linux conversion functions): */
81 #define linux_sigemptyset(s) memset((s), 0, sizeof(*(s)))
82 #define linux_sigismember(s, n) ((s)->sig[((n) - 1) / LINUX__NSIG_BPW] \
83 & (1 << ((n) - 1) % LINUX__NSIG_BPW))
84 #define linux_sigaddset(s, n) ((s)->sig[((n) - 1) / LINUX__NSIG_BPW] \
85 |= (1 << ((n) - 1) % LINUX__NSIG_BPW))
86
87 /* Note: linux_to_native_sig[] is in <arch>/linux_sigarray.c */
88 const int native_to_linux_sig[NSIG] = {
89 0,
90 LINUX_SIGHUP,
91 LINUX_SIGINT,
92 LINUX_SIGQUIT,
93 LINUX_SIGILL,
94 LINUX_SIGTRAP,
95 LINUX_SIGABRT,
96 0, /* SIGEMT */
97 LINUX_SIGFPE,
98 LINUX_SIGKILL,
99 LINUX_SIGBUS,
100 LINUX_SIGSEGV,
101 0, /* SIGSYS */
102 LINUX_SIGPIPE,
103 LINUX_SIGALRM,
104 LINUX_SIGTERM,
105 LINUX_SIGURG,
106 LINUX_SIGSTOP,
107 LINUX_SIGTSTP,
108 LINUX_SIGCONT,
109 LINUX_SIGCHLD,
110 LINUX_SIGTTIN,
111 LINUX_SIGTTOU,
112 LINUX_SIGIO,
113 LINUX_SIGXCPU,
114 LINUX_SIGXFSZ,
115 LINUX_SIGVTALRM,
116 LINUX_SIGPROF,
117 LINUX_SIGWINCH,
118 0, /* SIGINFO */
119 LINUX_SIGUSR1,
120 LINUX_SIGUSR2,
121 LINUX_SIGPWR,
122 };
123
124 /*
125 * Convert between Linux and BSD signal sets.
126 */
127 #if LINUX__NSIG_WORDS > 1
128 void
129 linux_old_extra_to_native_sigset(lss, extra, bss)
130 const linux_old_sigset_t *lss;
131 const unsigned long *extra;
132 sigset_t *bss;
133 {
134 linux_sigset_t lsnew;
135
136 /* convert old sigset to new sigset */
137 linux_sigemptyset(&lsnew);
138 lsnew.sig[0] = *lss;
139 if (extra)
140 bcopy(extra, &lsnew.sig[1],
141 sizeof(linux_sigset_t) - sizeof(linux_old_sigset_t));
142
143 linux_to_native_sigset(&lsnew, bss);
144 }
145
146 void
147 native_to_linux_old_extra_sigset(bss, lss, extra)
148 const sigset_t *bss;
149 linux_old_sigset_t *lss;
150 unsigned long *extra;
151 {
152 linux_sigset_t lsnew;
153
154 native_to_linux_sigset(bss, &lsnew);
155
156 /* convert new sigset to old sigset */
157 *lss = lsnew.sig[0];
158 if (extra)
159 bcopy(&lsnew.sig[1], extra,
160 sizeof(linux_sigset_t) - sizeof(linux_old_sigset_t));
161 }
162 #endif
163
164 void
165 linux_to_native_sigset(lss, bss)
166 const linux_sigset_t *lss;
167 sigset_t *bss;
168 {
169 int i, newsig;
170
171 sigemptyset(bss);
172 for (i = 1; i < LINUX__NSIG; i++) {
173 if (linux_sigismember(lss, i)) {
174 newsig = linux_to_native_sig[i];
175 if (newsig)
176 sigaddset(bss, newsig);
177 }
178 }
179 }
180
181 void
182 native_to_linux_sigset(bss, lss)
183 const sigset_t *bss;
184 linux_sigset_t *lss;
185 {
186 int i, newsig;
187
188 linux_sigemptyset(lss);
189 for (i = 1; i < NSIG; i++) {
190 if (sigismember(bss, i)) {
191 newsig = native_to_linux_sig[i];
192 if (newsig)
193 linux_sigaddset(lss, newsig);
194 }
195 }
196 }
197
198 /*
199 * Convert between Linux and BSD sigaction structures. Linux sometimes
200 * has one extra field (sa_restorer) which we don't support.
201 */
202 void
203 linux_old_to_native_sigaction(lsa, bsa)
204 struct linux_old_sigaction *lsa;
205 struct sigaction *bsa;
206 {
207
208 bsa->sa_handler = lsa->sa_handler;
209 linux_old_to_native_sigset(&lsa->sa_mask, &bsa->sa_mask);
210 bsa->sa_flags = 0;
211 if ((lsa->sa_flags & LINUX_SA_NOCLDSTOP) != 0)
212 bsa->sa_flags |= SA_NOCLDSTOP;
213 if ((lsa->sa_flags & LINUX_SA_ONSTACK) != 0)
214 bsa->sa_flags |= SA_ONSTACK;
215 if ((lsa->sa_flags & LINUX_SA_RESTART) != 0)
216 bsa->sa_flags |= SA_RESTART;
217 if ((lsa->sa_flags & LINUX_SA_ONESHOT) != 0)
218 bsa->sa_flags |= SA_RESETHAND;
219 if ((lsa->sa_flags & LINUX_SA_NOMASK) != 0)
220 bsa->sa_flags |= SA_NODEFER;
221 if ((lsa->sa_flags & LINUX_SA_SIGINFO) != 0)
222 bsa->sa_flags |= SA_SIGINFO;
223 #ifdef DEBUG_LINUX
224 if ((lsa->sa_flags & ~LINUX_SA_ALLBITS) != 0)
225 /*XXX*/ printf("linux_old_to_native_sigaction: extra bits ignored\n");
226 if (lsa->sa_restorer != 0)
227 /*XXX*/ printf("linux_old_to_native_sigaction: sa_restorer ignored\n");
228 #endif
229 }
230
231 void
232 native_to_linux_old_sigaction(bsa, lsa)
233 struct sigaction *bsa;
234 struct linux_old_sigaction *lsa;
235 {
236
237 /* Clear sa_flags and sa_restorer (if it exists) */
238 bzero(lsa, sizeof(struct linux_old_sigaction));
239
240 /* ...and fill in the mask and flags */
241 native_to_linux_old_sigset(&bsa->sa_mask, &lsa->sa_mask);
242 if ((bsa->sa_flags & SA_NOCLDSTOP) != 0)
243 lsa->sa_flags |= LINUX_SA_NOCLDSTOP;
244 if ((bsa->sa_flags & SA_ONSTACK) != 0)
245 lsa->sa_flags |= LINUX_SA_ONSTACK;
246 if ((bsa->sa_flags & SA_RESTART) != 0)
247 lsa->sa_flags |= LINUX_SA_RESTART;
248 if ((bsa->sa_flags & SA_NODEFER) != 0)
249 lsa->sa_flags |= LINUX_SA_NOMASK;
250 if ((bsa->sa_flags & SA_RESETHAND) != 0)
251 lsa->sa_flags |= LINUX_SA_ONESHOT;
252 if ((bsa->sa_flags & SA_SIGINFO) != 0)
253 lsa->sa_flags |= LINUX_SA_SIGINFO;
254 lsa->sa_handler = bsa->sa_handler;
255 }
256
257 /* ...and the new sigaction conversion funcs. */
258 void
259 linux_to_native_sigaction(lsa, bsa)
260 struct linux_sigaction *lsa;
261 struct sigaction *bsa;
262 {
263
264 bsa->sa_handler = lsa->sa_handler;
265 linux_to_native_sigset(&lsa->sa_mask, &bsa->sa_mask);
266 bsa->sa_flags = 0;
267 if ((lsa->sa_flags & LINUX_SA_NOCLDSTOP) != 0)
268 bsa->sa_flags |= SA_NOCLDSTOP;
269 if ((lsa->sa_flags & LINUX_SA_ONSTACK) != 0)
270 bsa->sa_flags |= SA_ONSTACK;
271 if ((lsa->sa_flags & LINUX_SA_RESTART) != 0)
272 bsa->sa_flags |= SA_RESTART;
273 if ((lsa->sa_flags & LINUX_SA_ONESHOT) != 0)
274 bsa->sa_flags |= SA_RESETHAND;
275 if ((lsa->sa_flags & LINUX_SA_NOMASK) != 0)
276 bsa->sa_flags |= SA_NODEFER;
277 if ((lsa->sa_flags & LINUX_SA_SIGINFO) != 0)
278 bsa->sa_flags |= SA_SIGINFO;
279 #ifdef DEBUG_LINUX
280 if ((lsa->sa_flags & ~LINUX_SA_ALLBITS) != 0)
281 /*XXX*/ printf("linux_to_native_sigaction: extra bits ignored\n");
282 if (lsa->sa_restorer != 0)
283 /*XXX*/ printf("linux_to_native_sigaction: sa_restorer ignored\n");
284 #endif
285 }
286
287 void
288 native_to_linux_sigaction(bsa, lsa)
289 struct sigaction *bsa;
290 struct linux_sigaction *lsa;
291 {
292
293 /* Clear sa_flags and sa_restorer (if it exists) */
294 bzero(lsa, sizeof(struct linux_sigaction));
295
296 /* ...and fill in the mask and flags */
297 native_to_linux_sigset(&bsa->sa_mask, &lsa->sa_mask);
298 if ((bsa->sa_flags & SA_NOCLDSTOP) != 0)
299 lsa->sa_flags |= LINUX_SA_NOCLDSTOP;
300 if ((bsa->sa_flags & SA_ONSTACK) != 0)
301 lsa->sa_flags |= LINUX_SA_ONSTACK;
302 if ((bsa->sa_flags & SA_RESTART) != 0)
303 lsa->sa_flags |= LINUX_SA_RESTART;
304 if ((bsa->sa_flags & SA_NODEFER) != 0)
305 lsa->sa_flags |= LINUX_SA_NOMASK;
306 if ((bsa->sa_flags & SA_RESETHAND) != 0)
307 lsa->sa_flags |= LINUX_SA_ONESHOT;
308 if ((bsa->sa_flags & SA_SIGINFO) != 0)
309 lsa->sa_flags |= LINUX_SA_SIGINFO;
310 lsa->sa_handler = bsa->sa_handler;
311 }
312
313 /* ----------------------------------------------------------------------- */
314
315 /*
316 * The Linux sigaction() system call. Do the usual conversions,
317 * and just call sigaction(). Some flags and values are silently
318 * ignored (see above).
319 */
320 int
321 linux_sys_rt_sigaction(l, v, retval)
322 struct lwp *l;
323 void *v;
324 register_t *retval;
325 {
326 struct linux_sys_rt_sigaction_args /* {
327 syscallarg(int) signum;
328 syscallarg(const struct linux_sigaction *) nsa;
329 syscallarg(struct linux_sigaction *) osa;
330 syscallarg(size_t) sigsetsize;
331 } */ *uap = v;
332 struct proc *p = l->l_proc;
333 struct linux_sigaction nlsa, olsa;
334 struct sigaction nbsa, obsa;
335 int error, sig;
336
337 if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
338 return (EINVAL);
339
340 if (SCARG(uap, nsa)) {
341 error = copyin(SCARG(uap, nsa), &nlsa, sizeof(nlsa));
342 if (error)
343 return (error);
344 linux_to_native_sigaction(&nlsa, &nbsa);
345 }
346 sig = SCARG(uap, signum);
347 if (sig < 0 || sig >= LINUX__NSIG)
348 return (EINVAL);
349 if (sig > 0 && !linux_to_native_sig[sig]) {
350 /* Pretend that we did something useful for unknown signals. */
351 obsa.sa_handler = SIG_IGN;
352 sigemptyset(&obsa.sa_mask);
353 obsa.sa_flags = 0;
354 } else {
355 error = sigaction1(p, linux_to_native_sig[sig],
356 SCARG(uap, nsa) ? &nbsa : NULL, SCARG(uap, osa) ? &obsa : NULL);
357 if (error)
358 return (error);
359 }
360 if (SCARG(uap, osa)) {
361 native_to_linux_sigaction(&obsa, &olsa);
362 error = copyout(&olsa, SCARG(uap, osa), sizeof(olsa));
363 if (error)
364 return (error);
365 }
366 return (0);
367 }
368
369 int
370 linux_sigprocmask1(p, how, set, oset)
371 struct proc *p;
372 int how;
373 const linux_old_sigset_t *set;
374 linux_old_sigset_t *oset;
375 {
376 linux_old_sigset_t nlss, olss;
377 sigset_t nbss, obss;
378 int error;
379
380 switch (how) {
381 case LINUX_SIG_BLOCK:
382 how = SIG_BLOCK;
383 break;
384 case LINUX_SIG_UNBLOCK:
385 how = SIG_UNBLOCK;
386 break;
387 case LINUX_SIG_SETMASK:
388 how = SIG_SETMASK;
389 break;
390 default:
391 return (EINVAL);
392 }
393
394 if (set) {
395 error = copyin(set, &nlss, sizeof(nlss));
396 if (error)
397 return (error);
398 linux_old_to_native_sigset(&nlss, &nbss);
399 }
400 error = sigprocmask1(p, how,
401 set ? &nbss : NULL, oset ? &obss : NULL);
402 if (error)
403 return (error);
404 if (oset) {
405 native_to_linux_old_sigset(&obss, &olss);
406 error = copyout(&olss, oset, sizeof(olss));
407 if (error)
408 return (error);
409 }
410 return (error);
411 }
412
413 int
414 linux_sys_rt_sigprocmask(l, v, retval)
415 struct lwp *l;
416 void *v;
417 register_t *retval;
418 {
419 struct linux_sys_rt_sigprocmask_args /* {
420 syscallarg(int) how;
421 syscallarg(const linux_sigset_t *) set;
422 syscallarg(linux_sigset_t *) oset;
423 syscallarg(size_t) sigsetsize;
424 } */ *uap = v;
425 struct proc *p = l->l_proc;
426 linux_sigset_t nlss, olss, *oset;
427 const linux_sigset_t *set;
428 sigset_t nbss, obss;
429 int error, how;
430
431 if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
432 return (EINVAL);
433
434 switch (SCARG(uap, how)) {
435 case LINUX_SIG_BLOCK:
436 how = SIG_BLOCK;
437 break;
438 case LINUX_SIG_UNBLOCK:
439 how = SIG_UNBLOCK;
440 break;
441 case LINUX_SIG_SETMASK:
442 how = SIG_SETMASK;
443 break;
444 default:
445 return (EINVAL);
446 }
447
448 set = SCARG(uap, set);
449 oset = SCARG(uap, oset);
450
451 if (set) {
452 error = copyin(set, &nlss, sizeof(nlss));
453 if (error)
454 return (error);
455 linux_to_native_sigset(&nlss, &nbss);
456 }
457 error = sigprocmask1(p, how,
458 set ? &nbss : NULL, oset ? &obss : NULL);
459 if (!error && oset) {
460 native_to_linux_sigset(&obss, &olss);
461 error = copyout(&olss, oset, sizeof(olss));
462 }
463 return (error);
464 }
465
466 int
467 linux_sys_rt_sigpending(l, v, retval)
468 struct lwp *l;
469 void *v;
470 register_t *retval;
471 {
472 struct linux_sys_rt_sigpending_args /* {
473 syscallarg(linux_sigset_t *) set;
474 syscallarg(size_t) sigsetsize;
475 } */ *uap = v;
476 struct proc *p = l->l_proc;
477 sigset_t bss;
478 linux_sigset_t lss;
479
480 if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
481 return (EINVAL);
482
483 sigpending1(p, &bss);
484 native_to_linux_sigset(&bss, &lss);
485 return copyout(&lss, SCARG(uap, set), sizeof(lss));
486 }
487
488 int
489 linux_sys_sigpending(l, v, retval)
490 struct lwp *l;
491 void *v;
492 register_t *retval;
493 {
494 struct linux_sys_sigpending_args /* {
495 syscallarg(linux_old_sigset_t *) mask;
496 } */ *uap = v;
497 struct proc *p = l->l_proc;
498 sigset_t bss;
499 linux_old_sigset_t lss;
500
501 sigpending1(p, &bss);
502 native_to_linux_old_sigset(&bss, &lss);
503 return copyout(&lss, SCARG(uap, set), sizeof(lss));
504 }
505
506 int
507 linux_sys_sigsuspend(l, v, retval)
508 struct lwp *l;
509 void *v;
510 register_t *retval;
511 {
512 struct linux_sys_sigsuspend_args /* {
513 syscallarg(caddr_t) restart;
514 syscallarg(int) oldmask;
515 syscallarg(int) mask;
516 } */ *uap = v;
517 struct proc *p = l->l_proc;
518 linux_old_sigset_t lss;
519 sigset_t bss;
520
521 lss = SCARG(uap, mask);
522 linux_old_to_native_sigset(&lss, &bss);
523 return (sigsuspend1(p, &bss));
524 }
525 int
526 linux_sys_rt_sigsuspend(l, v, retval)
527 struct lwp *l;
528 void *v;
529 register_t *retval;
530 {
531 struct linux_sys_rt_sigsuspend_args /* {
532 syscallarg(linux_sigset_t *) unewset;
533 syscallarg(size_t) sigsetsize;
534 } */ *uap = v;
535 struct proc *p = l->l_proc;
536 linux_sigset_t lss;
537 sigset_t bss;
538 int error;
539
540 if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
541 return (EINVAL);
542
543 error = copyin(SCARG(uap, unewset), &lss, sizeof(linux_sigset_t));
544 if (error)
545 return (error);
546
547 linux_to_native_sigset(&lss, &bss);
548
549 return (sigsuspend1(p, &bss));
550 }
551
552 /*
553 * Once more: only a signal conversion is needed.
554 * Note: also used as sys_rt_queueinfo. The info field is ignored.
555 */
556 int
557 linux_sys_rt_queueinfo(l, v, retval)
558 struct lwp *l;
559 void *v;
560 register_t *retval;
561 {
562 /* XXX XAX This isn't this really int, int, siginfo_t *, is it? */
563 #if 0
564 struct linux_sys_rt_queueinfo_args /* {
565 syscallarg(int) pid;
566 syscallarg(int) signum;
567 syscallarg(siginfo_t *) uinfo;
568 } */ *uap = v;
569 #endif
570
571 /* XXX To really implement this we need to */
572 /* XXX keep a list of queued signals somewhere. */
573 return (linux_sys_kill(l, v, retval));
574 }
575
576 int
577 linux_sys_kill(l, v, retval)
578 struct lwp *l;
579 void *v;
580 register_t *retval;
581 {
582 struct linux_sys_kill_args /* {
583 syscallarg(int) pid;
584 syscallarg(int) signum;
585 } */ *uap = v;
586
587 struct sys_kill_args ka;
588 int sig;
589
590 SCARG(&ka, pid) = SCARG(uap, pid);
591 sig = SCARG(uap, signum);
592 if (sig < 0 || sig >= LINUX__NSIG)
593 return (EINVAL);
594 SCARG(&ka, signum) = linux_to_native_sig[sig];
595 return sys_kill(l, &ka, retval);
596 }
597
598 #ifdef LINUX_SS_ONSTACK
599 static void linux_to_native_sigaltstack __P((struct sigaltstack *,
600 const struct linux_sigaltstack *));
601 static void native_to_linux_sigaltstack __P((struct linux_sigaltstack *,
602 const struct sigaltstack *));
603
604 static void
605 linux_to_native_sigaltstack(bss, lss)
606 struct sigaltstack *bss;
607 const struct linux_sigaltstack *lss;
608 {
609 bss->ss_sp = lss->ss_sp;
610 bss->ss_size = lss->ss_size;
611 if (lss->ss_flags & LINUX_SS_ONSTACK)
612 bss->ss_flags = SS_ONSTACK;
613 else if (lss->ss_flags & LINUX_SS_DISABLE)
614 bss->ss_flags = SS_DISABLE;
615 else
616 bss->ss_flags = 0;
617 }
618
619 static void
620 native_to_linux_sigaltstack(lss, bss)
621 struct linux_sigaltstack *lss;
622 const struct sigaltstack *bss;
623 {
624 lss->ss_sp = bss->ss_sp;
625 lss->ss_size = bss->ss_size;
626 if (bss->ss_flags & SS_ONSTACK)
627 lss->ss_flags = LINUX_SS_ONSTACK;
628 else if (bss->ss_flags & SS_DISABLE)
629 lss->ss_flags = LINUX_SS_DISABLE;
630 else
631 lss->ss_flags = 0;
632 }
633
634 int
635 linux_sys_sigaltstack(l, v, retval)
636 struct lwp *l;
637 void *v;
638 register_t *retval;
639 {
640 struct linux_sys_sigaltstack_args /* {
641 syscallarg(const struct linux_sigaltstack *) ss;
642 syscallarg(struct linux_sigaltstack *) oss;
643 } */ *uap = v;
644 struct proc *p = l->l_proc;
645 struct linux_sigaltstack ss;
646 struct sigaltstack nss, oss;
647 int error;
648
649 if (SCARG(uap, ss) != NULL) {
650 if ((error = copyin(SCARG(uap, ss), &ss, sizeof(ss))) != 0)
651 return error;
652 linux_to_native_sigaltstack(&nss, &ss);
653 }
654
655 error = sigaltstack1(p,
656 SCARG(uap, ss) ? &nss : NULL, SCARG(uap, oss) ? &oss : NULL);
657 if (error)
658 return error;
659
660 if (SCARG(uap, oss) != NULL) {
661 native_to_linux_sigaltstack(&ss, &oss);
662 if ((error = copyout(&ss, SCARG(uap, oss), sizeof(ss))) != 0)
663 return error;
664 }
665 return 0;
666 }
667 #endif
668