xref: /netbsd-src/sys/compat/linux/common/linux_signal.c (revision 0d1f6a757d4cd2924400dcd163348ea2873ca3d0)
1 /*	$NetBSD: linux_signal.c,v 1.34 2002/02/18 22:24:18 christos 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 #include <sys/cdefs.h>
57 __KERNEL_RCSID(0, "$NetBSD: linux_signal.c,v 1.34 2002/02/18 22:24:18 christos Exp $");
58 
59 #define COMPAT_LINUX 1
60 
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/namei.h>
64 #include <sys/proc.h>
65 #include <sys/filedesc.h>
66 #include <sys/ioctl.h>
67 #include <sys/mount.h>
68 #include <sys/kernel.h>
69 #include <sys/signal.h>
70 #include <sys/signalvar.h>
71 #include <sys/malloc.h>
72 
73 #include <sys/syscallargs.h>
74 
75 #include <compat/linux/common/linux_types.h>
76 #include <compat/linux/common/linux_signal.h>
77 #include <compat/linux/common/linux_siginfo.h>
78 #include <compat/linux/common/linux_util.h>
79 
80 #include <compat/linux/linux_syscallargs.h>
81 
82 /* Locally used defines (in bsd<->linux conversion functions): */
83 #define	linux_sigemptyset(s)	memset((s), 0, sizeof(*(s)))
84 #define	linux_sigismember(s, n)	((s)->sig[((n) - 1) / LINUX__NSIG_BPW]	\
85 					& (1 << ((n) - 1) % LINUX__NSIG_BPW))
86 #define	linux_sigaddset(s, n)	((s)->sig[((n) - 1) / LINUX__NSIG_BPW]	\
87 					|= (1 << ((n) - 1) % LINUX__NSIG_BPW))
88 
89 /* Note: linux_to_native_sig[] is in <arch>/linux_sigarray.c */
90 const int native_to_linux_sig[NSIG] = {
91 	0,
92 	LINUX_SIGHUP,
93 	LINUX_SIGINT,
94 	LINUX_SIGQUIT,
95 	LINUX_SIGILL,
96 	LINUX_SIGTRAP,
97 	LINUX_SIGABRT,
98 	0,			/* SIGEMT */
99 	LINUX_SIGFPE,
100 	LINUX_SIGKILL,
101 	LINUX_SIGBUS,
102 	LINUX_SIGSEGV,
103 	0,			/* SIGSYS */
104 	LINUX_SIGPIPE,
105 	LINUX_SIGALRM,
106 	LINUX_SIGTERM,
107 	LINUX_SIGURG,
108 	LINUX_SIGSTOP,
109 	LINUX_SIGTSTP,
110 	LINUX_SIGCONT,
111 	LINUX_SIGCHLD,
112 	LINUX_SIGTTIN,
113 	LINUX_SIGTTOU,
114 	LINUX_SIGIO,
115 	LINUX_SIGXCPU,
116 	LINUX_SIGXFSZ,
117 	LINUX_SIGVTALRM,
118 	LINUX_SIGPROF,
119 	LINUX_SIGWINCH,
120 	0,			/* SIGINFO */
121 	LINUX_SIGUSR1,
122 	LINUX_SIGUSR2,
123 	LINUX_SIGPWR,
124 };
125 
126 /*
127  * Convert between Linux and BSD signal sets.
128  */
129 #if LINUX__NSIG_WORDS > 1
130 void
131 linux_old_extra_to_native_sigset(bss, lss, extra)
132 	sigset_t *bss;
133 	const linux_old_sigset_t *lss;
134 	const unsigned long *extra;
135 {
136 	linux_sigset_t lsnew;
137 
138 	/* convert old sigset to new sigset */
139 	linux_sigemptyset(&lsnew);
140 	lsnew.sig[0] = *lss;
141 	if (extra)
142 		memcpy(&lsnew.sig[1], extra,
143 		    sizeof(linux_sigset_t) - sizeof(linux_old_sigset_t));
144 
145 	linux_to_native_sigset(bss, &lsnew);
146 }
147 
148 void
149 native_to_linux_old_extra_sigset(lss, extra, bss)
150 	linux_old_sigset_t *lss;
151 	unsigned long *extra;
152 	const sigset_t *bss;
153 {
154 	linux_sigset_t lsnew;
155 
156 	native_to_linux_sigset(&lsnew, bss);
157 
158 	/* convert new sigset to old sigset */
159 	*lss = lsnew.sig[0];
160 	if (extra)
161 		memcpy(extra, &lsnew.sig[1],
162 		    sizeof(linux_sigset_t) - sizeof(linux_old_sigset_t));
163 }
164 #endif
165 
166 void
167 linux_to_native_sigset(bss, lss)
168 	sigset_t *bss;
169 	const linux_sigset_t *lss;
170 {
171 	int i, newsig;
172 
173 	sigemptyset(bss);
174 	for (i = 1; i < LINUX__NSIG; i++) {
175 		if (linux_sigismember(lss, i)) {
176 			newsig = linux_to_native_sig[i];
177 			if (newsig)
178 				sigaddset(bss, newsig);
179 		}
180 	}
181 }
182 
183 void
184 native_to_linux_sigset(lss, bss)
185 	linux_sigset_t *lss;
186 	const sigset_t *bss;
187 {
188 	int i, newsig;
189 
190 	linux_sigemptyset(lss);
191 	for (i = 1; i < NSIG; i++) {
192 		if (sigismember(bss, i)) {
193 			newsig = native_to_linux_sig[i];
194 			if (newsig)
195 				linux_sigaddset(lss, newsig);
196 		}
197 	}
198 }
199 
200 unsigned int
201 native_to_linux_sigflags(bsf)
202 	const int bsf;
203 {
204 	unsigned int lsf = 0;
205 	if ((bsf & SA_NOCLDSTOP) != 0)
206 		lsf |= LINUX_SA_NOCLDSTOP;
207 	if ((bsf & SA_NOCLDWAIT) != 0)
208 		lsf |= LINUX_SA_NOCLDWAIT;
209 	if ((bsf & SA_ONSTACK) != 0)
210 		lsf |= LINUX_SA_ONSTACK;
211 	if ((bsf & SA_RESTART) != 0)
212 		lsf |= LINUX_SA_RESTART;
213 	if ((bsf & SA_NODEFER) != 0)
214 		lsf |= LINUX_SA_NOMASK;
215 	if ((bsf & SA_RESETHAND) != 0)
216 		lsf |= LINUX_SA_ONESHOT;
217 	if ((bsf & SA_SIGINFO) != 0)
218 		lsf |= LINUX_SA_SIGINFO;
219 	return lsf;
220 }
221 
222 int
223 linux_to_native_sigflags(lsf)
224 	const unsigned long lsf;
225 {
226 	int bsf = 0;
227 	if ((lsf & LINUX_SA_NOCLDSTOP) != 0)
228 		bsf |= SA_NOCLDSTOP;
229 	if ((lsf & LINUX_SA_NOCLDWAIT) != 0)
230 		bsf |= SA_NOCLDWAIT;
231 	if ((lsf & LINUX_SA_ONSTACK) != 0)
232 		bsf |= SA_ONSTACK;
233 	if ((lsf & LINUX_SA_RESTART) != 0)
234 		bsf |= SA_RESTART;
235 	if ((lsf & LINUX_SA_ONESHOT) != 0)
236 		bsf |= SA_RESETHAND;
237 	if ((lsf & LINUX_SA_NOMASK) != 0)
238 		bsf |= SA_NODEFER;
239 	if ((lsf & LINUX_SA_SIGINFO) != 0)
240 		bsf |= SA_SIGINFO;
241 #ifdef DEBUG_LINUX
242 	if ((lsf & ~LINUX_SA_ALLBITS) != 0)
243 		uprintf(
244 		    "linux_old_to_native_sigflags: %lx extra bits ignored\n",
245 		    lsf);
246 #endif
247 	return bsf;
248 }
249 
250 /*
251  * Convert between Linux and BSD sigaction structures. Linux sometimes
252  * has one extra field (sa_restorer) which we don't support.
253  */
254 void
255 linux_old_to_native_sigaction(bsa, lsa)
256 	struct sigaction *bsa;
257 	const struct linux_old_sigaction *lsa;
258 {
259 	bsa->sa_handler = lsa->sa_handler;
260 	linux_old_to_native_sigset(&bsa->sa_mask, &lsa->sa_mask);
261 	bsa->sa_flags = linux_to_native_sigflags(lsa->sa_flags);
262 #ifndef __alpha__
263 /*
264  * XXX: On the alpha sa_restorer is elsewhere.
265  */
266 #ifdef DEBUG_LINUX
267 	if (lsa->sa_restorer != NULL)
268 		uprintf("linux_old_to_native_sigaction: sa_restorer ignored\n");
269 #endif
270 #endif
271 }
272 
273 void
274 native_to_linux_old_sigaction(lsa, bsa)
275 	struct linux_old_sigaction *lsa;
276 	const struct sigaction *bsa;
277 {
278 	lsa->sa_handler = bsa->sa_handler;
279 	native_to_linux_old_sigset(&lsa->sa_mask, &bsa->sa_mask);
280 	lsa->sa_flags = native_to_linux_sigflags(bsa->sa_flags);
281 #ifndef __alpha__
282 	lsa->sa_restorer = NULL;
283 #endif
284 }
285 
286 /* ...and the new sigaction conversion funcs. */
287 void
288 linux_to_native_sigaction(bsa, lsa)
289 	struct sigaction *bsa;
290 	const struct linux_sigaction *lsa;
291 {
292 	bsa->sa_handler = lsa->sa_handler;
293 	linux_to_native_sigset(&bsa->sa_mask, &lsa->sa_mask);
294 	bsa->sa_flags = linux_to_native_sigflags(lsa->sa_flags);
295 #ifndef __alpha__
296 #ifdef DEBUG_LINUX
297 	if (lsa->sa_restorer != 0)
298 		uprintf("linux_to_native_sigaction: sa_restorer ignored\n");
299 #endif
300 #endif
301 }
302 
303 void
304 native_to_linux_sigaction(lsa, bsa)
305 	struct linux_sigaction *lsa;
306 	const struct sigaction *bsa;
307 {
308 	lsa->sa_handler = bsa->sa_handler;
309 	native_to_linux_sigset(&lsa->sa_mask, &bsa->sa_mask);
310 	lsa->sa_flags = native_to_linux_sigflags(bsa->sa_flags);
311 #ifndef __alpha__
312 	lsa->sa_restorer = NULL;
313 #endif
314 }
315 
316 /* ----------------------------------------------------------------------- */
317 
318 /*
319  * The Linux sigaction() system call. Do the usual conversions,
320  * and just call sigaction(). Some flags and values are silently
321  * ignored (see above).
322  */
323 int
324 linux_sys_rt_sigaction(p, v, retval)
325 	struct proc *p;
326 	void *v;
327 	register_t *retval;
328 {
329 	struct linux_sys_rt_sigaction_args /* {
330 		syscallarg(int) signum;
331 		syscallarg(const struct linux_sigaction *) nsa;
332 		syscallarg(struct linux_sigaction *) osa;
333 		syscallarg(size_t) sigsetsize;
334 	} */ *uap = v;
335 	struct linux_sigaction nlsa, olsa;
336 	struct sigaction nbsa, obsa;
337 	int error, sig;
338 
339 	if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
340 		return (EINVAL);
341 
342 	if (SCARG(uap, nsa)) {
343 		error = copyin(SCARG(uap, nsa), &nlsa, sizeof(nlsa));
344 		if (error)
345 			return (error);
346 		linux_to_native_sigaction(&nbsa, &nlsa);
347 	}
348 	sig = SCARG(uap, signum);
349 	if (sig < 0 || sig >= LINUX__NSIG)
350 		return (EINVAL);
351 	if (sig > 0 && !linux_to_native_sig[sig]) {
352 		/* Pretend that we did something useful for unknown signals. */
353 		obsa.sa_handler = SIG_IGN;
354 		sigemptyset(&obsa.sa_mask);
355 		obsa.sa_flags = 0;
356 	} else {
357 		error = sigaction1(p, linux_to_native_sig[sig],
358 		    SCARG(uap, nsa) ? &nbsa : NULL, SCARG(uap, osa) ? &obsa : NULL);
359 		if (error)
360 			return (error);
361 	}
362 	if (SCARG(uap, osa)) {
363 		native_to_linux_sigaction(&olsa, &obsa);
364 		error = copyout(&olsa, SCARG(uap, osa), sizeof(olsa));
365 		if (error)
366 			return (error);
367 	}
368 	return (0);
369 }
370 
371 int
372 linux_sigprocmask1(p, how, set, oset)
373 	struct proc *p;
374 	int how;
375 	const linux_old_sigset_t *set;
376 	linux_old_sigset_t *oset;
377 {
378 	linux_old_sigset_t nlss, olss;
379 	sigset_t nbss, obss;
380 	int error;
381 
382 	switch (how) {
383 	case LINUX_SIG_BLOCK:
384 		how = SIG_BLOCK;
385 		break;
386 	case LINUX_SIG_UNBLOCK:
387 		how = SIG_UNBLOCK;
388 		break;
389 	case LINUX_SIG_SETMASK:
390 		how = SIG_SETMASK;
391 		break;
392 	default:
393 		return (EINVAL);
394 	}
395 
396 	if (set) {
397 		error = copyin(set, &nlss, sizeof(nlss));
398 		if (error)
399 			return (error);
400 		linux_old_to_native_sigset(&nbss, &nlss);
401 	}
402 	error = sigprocmask1(p, how,
403 	    set ? &nbss : NULL, oset ? &obss : NULL);
404 	if (error)
405 		return (error);
406 	if (oset) {
407 		native_to_linux_old_sigset(&olss, &obss);
408 		error = copyout(&olss, oset, sizeof(olss));
409 		if (error)
410 			return (error);
411 	}
412 	return (error);
413 }
414 
415 int
416 linux_sys_rt_sigprocmask(p, v, retval)
417 	struct proc *p;
418 	void *v;
419 	register_t *retval;
420 {
421 	struct linux_sys_rt_sigprocmask_args /* {
422 		syscallarg(int) how;
423 		syscallarg(const linux_sigset_t *) set;
424 		syscallarg(linux_sigset_t *) oset;
425 		syscallarg(size_t) sigsetsize;
426 	} */ *uap = v;
427 
428 	linux_sigset_t nlss, olss, *oset;
429 	const linux_sigset_t *set;
430 	sigset_t nbss, obss;
431 	int error, how;
432 
433 	if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
434 		return (EINVAL);
435 
436 	switch (SCARG(uap, how)) {
437 	case LINUX_SIG_BLOCK:
438 		how = SIG_BLOCK;
439 		break;
440 	case LINUX_SIG_UNBLOCK:
441 		how = SIG_UNBLOCK;
442 		break;
443 	case LINUX_SIG_SETMASK:
444 		how = SIG_SETMASK;
445 		break;
446 	default:
447 		return (EINVAL);
448 	}
449 
450 	set = SCARG(uap, set);
451 	oset = SCARG(uap, oset);
452 
453 	if (set) {
454 		error = copyin(set, &nlss, sizeof(nlss));
455 		if (error)
456 			return (error);
457 		linux_to_native_sigset(&nbss, &nlss);
458 	}
459 	error = sigprocmask1(p, how,
460 	    set ? &nbss : NULL, oset ? &obss : NULL);
461 	if (!error && oset) {
462 		native_to_linux_sigset(&olss, &obss);
463 		error = copyout(&olss, oset, sizeof(olss));
464 	}
465 	return (error);
466 }
467 
468 int
469 linux_sys_rt_sigpending(p, v, retval)
470 	struct proc *p;
471 	void *v;
472 	register_t *retval;
473 {
474 	struct linux_sys_rt_sigpending_args /* {
475 		syscallarg(linux_sigset_t *) set;
476 		syscallarg(size_t) sigsetsize;
477 	} */ *uap = v;
478 	sigset_t bss;
479 	linux_sigset_t lss;
480 
481 	if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
482 		return (EINVAL);
483 
484 	sigpending1(p, &bss);
485 	native_to_linux_sigset(&lss, &bss);
486 	return copyout(&lss, SCARG(uap, set), sizeof(lss));
487 }
488 
489 int
490 linux_sys_sigpending(p, v, retval)
491 	struct proc *p;
492 	void *v;
493 	register_t *retval;
494 {
495 	struct linux_sys_sigpending_args /* {
496 		syscallarg(linux_old_sigset_t *) mask;
497 	} */ *uap = v;
498 	sigset_t bss;
499 	linux_old_sigset_t lss;
500 
501 	sigpending1(p, &bss);
502 	native_to_linux_old_sigset(&lss, &bss);
503 	return copyout(&lss, SCARG(uap, set), sizeof(lss));
504 }
505 
506 int
507 linux_sys_sigsuspend(p, v, retval)
508 	struct proc *p;
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 	linux_old_sigset_t lss;
518 	sigset_t bss;
519 
520 	lss = SCARG(uap, mask);
521 	linux_old_to_native_sigset(&bss, &lss);
522 	return (sigsuspend1(p, &bss));
523 }
524 int
525 linux_sys_rt_sigsuspend(p, v, retval)
526 	struct proc *p;
527 	void *v;
528 	register_t *retval;
529 {
530 	struct linux_sys_rt_sigsuspend_args /* {
531 		syscallarg(linux_sigset_t *) unewset;
532 		syscallarg(size_t) sigsetsize;
533 	} */ *uap = v;
534 	linux_sigset_t lss;
535 	sigset_t bss;
536 	int error;
537 
538 	if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t))
539 		return (EINVAL);
540 
541 	error = copyin(SCARG(uap, unewset), &lss, sizeof(linux_sigset_t));
542 	if (error)
543 		return (error);
544 
545 	linux_to_native_sigset(&bss, &lss);
546 
547 	return (sigsuspend1(p, &bss));
548 }
549 
550 /*
551  * Once more: only a signal conversion is needed.
552  * Note: also used as sys_rt_queueinfo.  The info field is ignored.
553  */
554 int
555 linux_sys_rt_queueinfo(p, v, retval)
556 	struct proc *p;
557 	void *v;
558 	register_t *retval;
559 {
560 	/* XXX XAX This isn't this really int, int, siginfo_t *, is it? */
561 #if 0
562 	struct linux_sys_rt_queueinfo_args /* {
563 		syscallarg(int) pid;
564 		syscallarg(int) signum;
565 		syscallarg(siginfo_t *) uinfo;
566 	} */ *uap = v;
567 #endif
568 
569 	/* XXX To really implement this we need to	*/
570 	/* XXX keep a list of queued signals somewhere.	*/
571 	return (linux_sys_kill(p, v, retval));
572 }
573 
574 int
575 linux_sys_kill(p, v, retval)
576 	struct proc *p;
577 	void *v;
578 	register_t *retval;
579 {
580 	struct linux_sys_kill_args /* {
581 		syscallarg(int) pid;
582 		syscallarg(int) signum;
583 	} */ *uap = v;
584 	struct sys_kill_args ka;
585 	int sig;
586 
587 	SCARG(&ka, pid) = SCARG(uap, pid);
588 	sig = SCARG(uap, signum);
589 	if (sig < 0 || sig >= LINUX__NSIG)
590 		return (EINVAL);
591 	SCARG(&ka, signum) = linux_to_native_sig[sig];
592 	return sys_kill(p, &ka, retval);
593 }
594 
595 #ifdef LINUX_SS_ONSTACK
596 static void linux_to_native_sigaltstack __P((struct sigaltstack *,
597     const struct linux_sigaltstack *));
598 static void native_to_linux_sigaltstack __P((struct linux_sigaltstack *,
599     const struct sigaltstack *));
600 
601 static void
602 linux_to_native_sigaltstack(bss, lss)
603 	struct sigaltstack *bss;
604 	const struct linux_sigaltstack *lss;
605 {
606 	bss->ss_sp = lss->ss_sp;
607 	bss->ss_size = lss->ss_size;
608 	if (lss->ss_flags & LINUX_SS_ONSTACK)
609 	    bss->ss_flags = SS_ONSTACK;
610 	else if (lss->ss_flags & LINUX_SS_DISABLE)
611 	    bss->ss_flags = SS_DISABLE;
612 	else
613 	    bss->ss_flags = 0;
614 }
615 
616 static void
617 native_to_linux_sigaltstack(lss, bss)
618 	struct linux_sigaltstack *lss;
619 	const struct sigaltstack *bss;
620 {
621 	lss->ss_sp = bss->ss_sp;
622 	lss->ss_size = bss->ss_size;
623 	if (bss->ss_flags & SS_ONSTACK)
624 	    lss->ss_flags = LINUX_SS_ONSTACK;
625 	else if (bss->ss_flags & SS_DISABLE)
626 	    lss->ss_flags = LINUX_SS_DISABLE;
627 	else
628 	    lss->ss_flags = 0;
629 }
630 
631 int
632 linux_sys_sigaltstack(p, v, retval)
633 	struct proc *p;
634 	void *v;
635 	register_t *retval;
636 {
637 	struct linux_sys_sigaltstack_args /* {
638 		syscallarg(const struct linux_sigaltstack *) ss;
639 		syscallarg(struct linux_sigaltstack *) oss;
640 	} */ *uap = v;
641 	struct linux_sigaltstack ss;
642 	struct sigaltstack nss, oss;
643 	int error;
644 
645 	if (SCARG(uap, ss) != NULL) {
646 		if ((error = copyin(SCARG(uap, ss), &ss, sizeof(ss))) != 0)
647 			return error;
648 		linux_to_native_sigaltstack(&nss, &ss);
649 	}
650 
651 	error = sigaltstack1(p,
652 	    SCARG(uap, ss) ? &nss : NULL, SCARG(uap, oss) ? &oss : NULL);
653 	if (error)
654 		return error;
655 
656 	if (SCARG(uap, oss) != NULL) {
657 		native_to_linux_sigaltstack(&ss, &oss);
658 		if ((error = copyout(&ss, SCARG(uap, oss), sizeof(ss))) != 0)
659 			return error;
660 	}
661 	return 0;
662 }
663 #endif
664