xref: /freebsd/sys/compat/freebsd32/freebsd32_misc.c (revision 7660b554bc59a07be0431c17e0e33815818baa69)
1 /*-
2  * Copyright (c) 2002 Doug Rabson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include "opt_compat.h"
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35 #include <sys/exec.h>
36 #include <sys/fcntl.h>
37 #include <sys/filedesc.h>
38 #include <sys/imgact.h>
39 #include <sys/kernel.h>
40 #include <sys/lock.h>
41 #include <sys/malloc.h>
42 #include <sys/file.h>		/* Must come after sys/malloc.h */
43 #include <sys/mman.h>
44 #include <sys/module.h>
45 #include <sys/mount.h>
46 #include <sys/mutex.h>
47 #include <sys/namei.h>
48 #include <sys/param.h>
49 #include <sys/proc.h>
50 #include <sys/reboot.h>
51 #include <sys/resource.h>
52 #include <sys/resourcevar.h>
53 #include <sys/selinfo.h>
54 #include <sys/pipe.h>		/* Must come after sys/selinfo.h */
55 #include <sys/signal.h>
56 #include <sys/signalvar.h>
57 #include <sys/socket.h>
58 #include <sys/socketvar.h>
59 #include <sys/stat.h>
60 #include <sys/syscallsubr.h>
61 #include <sys/sysctl.h>
62 #include <sys/sysent.h>
63 #include <sys/sysproto.h>
64 #include <sys/systm.h>
65 #include <sys/unistd.h>
66 #include <sys/user.h>
67 #include <sys/utsname.h>
68 #include <sys/vnode.h>
69 
70 #include <vm/vm.h>
71 #include <vm/vm_kern.h>
72 #include <vm/vm_param.h>
73 #include <vm/pmap.h>
74 #include <vm/vm_map.h>
75 #include <vm/vm_object.h>
76 #include <vm/vm_extern.h>
77 
78 #include <compat/freebsd32/freebsd32_util.h>
79 #include <compat/freebsd32/freebsd32.h>
80 #include <compat/freebsd32/freebsd32_proto.h>
81 
82 /*
83  * [ taken from the linux emulator ]
84  * Search an alternate path before passing pathname arguments on
85  * to system calls. Useful for keeping a separate 'emulation tree'.
86  *
87  * If cflag is set, we check if an attempt can be made to create
88  * the named file, i.e. we check if the directory it should
89  * be in exists.
90  */
91 int
92 freebsd32_emul_find(td, sgp, prefix, path, pbuf, cflag)
93 	struct thread	*td;
94 	caddr_t		*sgp;		/* Pointer to stackgap memory */
95 	const char	*prefix;
96 	char		*path;
97 	char		**pbuf;
98 	int		cflag;
99 {
100 	int			error;
101 	size_t			len, sz;
102 	char			*buf, *cp, *ptr;
103 	struct ucred		*ucred;
104 	struct nameidata	nd;
105 	struct nameidata	ndroot;
106 	struct vattr		vat;
107 	struct vattr		vatroot;
108 
109 	buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
110 	*pbuf = path;
111 
112 	for (ptr = buf; (*ptr = *prefix) != '\0'; ptr++, prefix++)
113 		continue;
114 
115 	sz = MAXPATHLEN - (ptr - buf);
116 
117 	/*
118 	 * If sgp is not given then the path is already in kernel space
119 	 */
120 	if (sgp == NULL)
121 		error = copystr(path, ptr, sz, &len);
122 	else
123 		error = copyinstr(path, ptr, sz, &len);
124 
125 	if (error) {
126 		free(buf, M_TEMP);
127 		return error;
128 	}
129 
130 	if (*ptr != '/') {
131 		free(buf, M_TEMP);
132 		return EINVAL;
133 	}
134 
135 	/*
136 	 *  We know that there is a / somewhere in this pathname.
137 	 *  Search backwards for it, to find the file's parent dir
138 	 *  to see if it exists in the alternate tree. If it does,
139 	 *  and we want to create a file (cflag is set). We don't
140 	 *  need to worry about the root comparison in this case.
141 	 */
142 
143 	if (cflag) {
144 		for (cp = &ptr[len] - 1; *cp != '/'; cp--)
145 			;
146 		*cp = '\0';
147 
148 		NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td);
149 
150 		if ((error = namei(&nd)) != 0) {
151 			free(buf, M_TEMP);
152 			return error;
153 		}
154 
155 		*cp = '/';
156 	} else {
157 		NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td);
158 
159 		if ((error = namei(&nd)) != 0) {
160 			free(buf, M_TEMP);
161 			return error;
162 		}
163 
164 		/*
165 		 * We now compare the vnode of the freebsd32_root to the one
166 		 * vnode asked. If they resolve to be the same, then we
167 		 * ignore the match so that the real root gets used.
168 		 * This avoids the problem of traversing "../.." to find the
169 		 * root directory and never finding it, because "/" resolves
170 		 * to the emulation root directory. This is expensive :-(
171 		 */
172 		NDINIT(&ndroot, LOOKUP, FOLLOW, UIO_SYSSPACE,
173 		    freebsd32_emul_path, td);
174 
175 		if ((error = namei(&ndroot)) != 0) {
176 			/* Cannot happen! */
177 			free(buf, M_TEMP);
178 			vrele(nd.ni_vp);
179 			return error;
180 		}
181 
182 		ucred = td->td_ucred;
183 		if ((error = VOP_GETATTR(nd.ni_vp, &vat, ucred, td)) != 0) {
184 			goto bad;
185 		}
186 
187 		if ((error = VOP_GETATTR(ndroot.ni_vp, &vatroot, ucred,
188 		    td)) != 0) {
189 			goto bad;
190 		}
191 
192 		if (vat.va_fsid == vatroot.va_fsid &&
193 		    vat.va_fileid == vatroot.va_fileid) {
194 			error = ENOENT;
195 			goto bad;
196 		}
197 
198 	}
199 	if (sgp == NULL)
200 		*pbuf = buf;
201 	else {
202 		sz = &ptr[len] - buf;
203 		*pbuf = stackgap_alloc(sgp, sz + 1);
204 		error = copyout(buf, *pbuf, sz);
205 		free(buf, M_TEMP);
206 	}
207 
208 	vrele(nd.ni_vp);
209 	if (!cflag)
210 		vrele(ndroot.ni_vp);
211 
212 	return error;
213 
214 bad:
215 	vrele(ndroot.ni_vp);
216 	vrele(nd.ni_vp);
217 	free(buf, M_TEMP);
218 	return error;
219 }
220 
221 int
222 freebsd32_open(struct thread *td, struct freebsd32_open_args *uap)
223 {
224 	caddr_t sg;
225 
226 	sg = stackgap_init();
227 	CHECKALTEXIST(td, &sg, uap->path);
228 
229 	return open(td, (struct open_args *) uap);
230 }
231 
232 int
233 freebsd32_wait4(struct thread *td, struct freebsd32_wait4_args *uap)
234 {
235 	int error;
236 	caddr_t sg;
237 	struct rusage32 *rusage32, ru32;
238 	struct rusage *rusage = NULL, ru;
239 
240 	rusage32 = uap->rusage;
241 	if (rusage32) {
242 		sg = stackgap_init();
243 		rusage = stackgap_alloc(&sg, sizeof(struct rusage));
244 		uap->rusage = (struct rusage32 *)rusage;
245 	}
246 	error = wait4(td, (struct wait_args *)uap);
247 	if (error)
248 		return (error);
249 	if (rusage32 && (error = copyin(rusage, &ru, sizeof(ru)) == 0)) {
250 		TV_CP(ru, ru32, ru_utime);
251 		TV_CP(ru, ru32, ru_stime);
252 		CP(ru, ru32, ru_maxrss);
253 		CP(ru, ru32, ru_ixrss);
254 		CP(ru, ru32, ru_idrss);
255 		CP(ru, ru32, ru_isrss);
256 		CP(ru, ru32, ru_minflt);
257 		CP(ru, ru32, ru_majflt);
258 		CP(ru, ru32, ru_nswap);
259 		CP(ru, ru32, ru_inblock);
260 		CP(ru, ru32, ru_oublock);
261 		CP(ru, ru32, ru_msgsnd);
262 		CP(ru, ru32, ru_msgrcv);
263 		CP(ru, ru32, ru_nsignals);
264 		CP(ru, ru32, ru_nvcsw);
265 		CP(ru, ru32, ru_nivcsw);
266 		error = copyout(&ru32, rusage32, sizeof(ru32));
267 	}
268 	return (error);
269 }
270 
271 static void
272 copy_statfs(struct statfs *in, struct statfs32 *out)
273 {
274 	CP(*in, *out, f_bsize);
275 	CP(*in, *out, f_iosize);
276 	CP(*in, *out, f_blocks);
277 	CP(*in, *out, f_bfree);
278 	CP(*in, *out, f_bavail);
279 	CP(*in, *out, f_files);
280 	CP(*in, *out, f_ffree);
281 	CP(*in, *out, f_fsid);
282 	CP(*in, *out, f_owner);
283 	CP(*in, *out, f_type);
284 	CP(*in, *out, f_flags);
285 	CP(*in, *out, f_flags);
286 	CP(*in, *out, f_syncwrites);
287 	CP(*in, *out, f_asyncwrites);
288 	bcopy(in->f_fstypename,
289 	      out->f_fstypename, MFSNAMELEN);
290 	bcopy(in->f_mntonname,
291 	      out->f_mntonname, MNAMELEN);
292 	CP(*in, *out, f_syncreads);
293 	CP(*in, *out, f_asyncreads);
294 	bcopy(in->f_mntfromname,
295 	      out->f_mntfromname, MNAMELEN);
296 }
297 
298 int
299 freebsd32_getfsstat(struct thread *td, struct freebsd32_getfsstat_args *uap)
300 {
301 	int error;
302 	caddr_t sg;
303 	struct statfs32 *sp32, stat32;
304 	struct statfs *sp = NULL, stat;
305 	int maxcount, count, i;
306 
307 	sp32 = uap->buf;
308 	maxcount = uap->bufsize / sizeof(struct statfs32);
309 
310 	if (sp32) {
311 		sg = stackgap_init();
312 		sp = stackgap_alloc(&sg, sizeof(struct statfs) * maxcount);
313 		uap->buf = (struct statfs32 *)sp;
314 	}
315 	error = getfsstat(td, (struct getfsstat_args *) uap);
316 	if (sp32 && !error) {
317 		count = td->td_retval[0];
318 		for (i = 0; i < count; i++) {
319 			error = copyin(&sp[i], &stat, sizeof(stat));
320 			if (error)
321 				return (error);
322 			copy_statfs(&stat, &stat32);
323 			error = copyout(&stat32, &sp32[i], sizeof(stat32));
324 			if (error)
325 				return (error);
326 		}
327 	}
328 	return (error);
329 }
330 
331 int
332 freebsd32_access(struct thread *td, struct freebsd32_access_args *uap)
333 {
334 	caddr_t sg;
335 
336 	sg = stackgap_init();
337 	CHECKALTEXIST(td, &sg, uap->path);
338 
339 	return access(td, (struct access_args *)uap);
340 }
341 
342 int
343 freebsd32_chflags(struct thread *td, struct freebsd32_chflags_args *uap)
344 {
345 	caddr_t sg;
346 
347 	sg = stackgap_init();
348 	CHECKALTEXIST(td, &sg, uap->path);
349 
350 	return chflags(td, (struct chflags_args *)uap);
351 }
352 
353 struct sigaltstack32 {
354 	u_int32_t	ss_sp;
355 	u_int32_t	ss_size;
356 	int		ss_flags;
357 };
358 
359 int
360 freebsd32_sigaltstack(struct thread *td,
361 		      struct freebsd32_sigaltstack_args *uap)
362 {
363 	struct sigaltstack32 s32;
364 	struct sigaltstack ss, oss, *ssp;
365 	int error;
366 
367 	if (uap->ss != NULL) {
368 		error = copyin(uap->ss, &s32, sizeof(s32));
369 		if (error)
370 			return (error);
371 		PTRIN_CP(s32, ss, ss_sp);
372 		CP(s32, ss, ss_size);
373 		CP(s32, ss, ss_flags);
374 		ssp = &ss;
375 	} else
376 		ssp = NULL;
377 	error = kern_sigaltstack(td, ssp, &oss);
378 	if (error == 0 && uap->oss != NULL) {
379 		PTROUT_CP(oss, s32, ss_sp);
380 		CP(oss, s32, ss_size);
381 		CP(oss, s32, ss_flags);
382 		error = copyout(&s32, uap->oss, sizeof(s32));
383 	}
384 	return (error);
385 }
386 
387 int
388 freebsd32_execve(struct thread *td, struct freebsd32_execve_args *uap)
389 {
390 	int error;
391 	caddr_t sg;
392 	struct execve_args ap;
393 	u_int32_t *p32, arg;
394 	char **p;
395 	int count;
396 
397 	sg = stackgap_init();
398 	CHECKALTEXIST(td, &sg, uap->fname);
399 	ap.fname = uap->fname;
400 
401 	if (uap->argv) {
402 		count = 0;
403 		p32 = uap->argv;
404 		do {
405 			error = copyin(p32++, &arg, sizeof(arg));
406 			if (error)
407 				return error;
408 			count++;
409 		} while (arg != 0);
410 		p = stackgap_alloc(&sg, count * sizeof(char *));
411 		ap.argv = p;
412 		p32 = uap->argv;
413 		do {
414 			error = copyin(p32++, &arg, sizeof(arg));
415 			if (error)
416 				return error;
417 			*p++ = PTRIN(arg);
418 		} while (arg != 0);
419 	}
420 	if (uap->envv) {
421 		count = 0;
422 		p32 = uap->envv;
423 		do {
424 			error = copyin(p32++, &arg, sizeof(arg));
425 			if (error)
426 				return error;
427 			count++;
428 		} while (arg != 0);
429 		p = stackgap_alloc(&sg, count * sizeof(char *));
430 		ap.envv = p;
431 		p32 = uap->envv;
432 		do {
433 			error = copyin(p32++, &arg, sizeof(arg));
434 			if (error)
435 				return error;
436 			*p++ = PTRIN(arg);
437 		} while (arg != 0);
438 	}
439 
440 	return execve(td, &ap);
441 }
442 
443 #ifdef __ia64__
444 static int
445 freebsd32_mmap_partial(struct thread *td, vm_offset_t start, vm_offset_t end,
446 		       int prot, int fd, off_t pos)
447 {
448 	vm_map_t map;
449 	vm_map_entry_t entry;
450 	int rv;
451 
452 	map = &td->td_proc->p_vmspace->vm_map;
453 	if (fd != -1)
454 		prot |= VM_PROT_WRITE;
455 
456 	if (vm_map_lookup_entry(map, start, &entry)) {
457 		if ((entry->protection & prot) != prot) {
458 			rv = vm_map_protect(map,
459 					    trunc_page(start),
460 					    round_page(end),
461 					    entry->protection | prot,
462 					    FALSE);
463 			if (rv != KERN_SUCCESS)
464 				return (EINVAL);
465 		}
466 	} else {
467 		vm_offset_t addr = trunc_page(start);
468 		rv = vm_map_find(map, 0, 0,
469 				 &addr, PAGE_SIZE, FALSE, prot,
470 				 VM_PROT_ALL, 0);
471 		if (rv != KERN_SUCCESS)
472 			return (EINVAL);
473 	}
474 
475 	if (fd != -1) {
476 		struct pread_args r;
477 		r.fd = fd;
478 		r.buf = (void *) start;
479 		r.nbyte = end - start;
480 		r.offset = pos;
481 		return (pread(td, &r));
482 	} else {
483 		while (start < end) {
484 			subyte((void *) start, 0);
485 			start++;
486 		}
487 		return (0);
488 	}
489 }
490 #endif
491 
492 int
493 freebsd32_mmap(struct thread *td, struct freebsd32_mmap_args *uap)
494 {
495 	struct mmap_args ap;
496 	vm_offset_t addr = (vm_offset_t) uap->addr;
497 	vm_size_t len	 = uap->len;
498 	int prot	 = uap->prot;
499 	int flags	 = uap->flags;
500 	int fd		 = uap->fd;
501 	off_t pos	 = (uap->poslo
502 			    | ((off_t)uap->poshi << 32));
503 #ifdef __ia64__
504 	vm_size_t pageoff;
505 	int error;
506 
507 	/*
508 	 * Attempt to handle page size hassles.
509 	 */
510 	pageoff = (pos & PAGE_MASK);
511 	if (flags & MAP_FIXED) {
512 		vm_offset_t start, end;
513 		start = addr;
514 		end = addr + len;
515 
516 		if (start != trunc_page(start)) {
517 			error = freebsd32_mmap_partial(td, start,
518 						       round_page(start), prot,
519 						       fd, pos);
520 			if (fd != -1)
521 				pos += round_page(start) - start;
522 			start = round_page(start);
523 		}
524 		if (end != round_page(end)) {
525 			vm_offset_t t = trunc_page(end);
526 			error = freebsd32_mmap_partial(td, t, end,
527 						  prot, fd,
528 						  pos + t - start);
529 			end = trunc_page(end);
530 		}
531 		if (end > start && fd != -1 && (pos & PAGE_MASK)) {
532 			/*
533 			 * We can't map this region at all. The specified
534 			 * address doesn't have the same alignment as the file
535 			 * position. Fake the mapping by simply reading the
536 			 * entire region into memory. First we need to make
537 			 * sure the region exists.
538 			 */
539 			vm_map_t map;
540 			struct pread_args r;
541 			int rv;
542 
543 			prot |= VM_PROT_WRITE;
544 			map = &td->td_proc->p_vmspace->vm_map;
545 			rv = vm_map_remove(map, start, end);
546 			if (rv != KERN_SUCCESS)
547 				return (EINVAL);
548 			rv = vm_map_find(map, 0, 0,
549 					 &start, end - start, FALSE,
550 					 prot, VM_PROT_ALL, 0);
551 			if (rv != KERN_SUCCESS)
552 				return (EINVAL);
553 			r.fd = fd;
554 			r.buf = (void *) start;
555 			r.nbyte = end - start;
556 			r.offset = pos;
557 			error = pread(td, &r);
558 			if (error)
559 				return (error);
560 
561 			td->td_retval[0] = addr;
562 			return (0);
563 		}
564 		if (end == start) {
565 			/*
566 			 * After dealing with the ragged ends, there
567 			 * might be none left.
568 			 */
569 			td->td_retval[0] = addr;
570 			return (0);
571 		}
572 		addr = start;
573 		len = end - start;
574 	}
575 #endif
576 
577 	ap.addr = (void *) addr;
578 	ap.len = len;
579 	ap.prot = prot;
580 	ap.flags = flags;
581 	ap.fd = fd;
582 	ap.pos = pos;
583 
584 	return (mmap(td, &ap));
585 }
586 
587 struct itimerval32 {
588 	struct timeval32 it_interval;
589 	struct timeval32 it_value;
590 };
591 
592 int
593 freebsd32_setitimer(struct thread *td, struct freebsd32_setitimer_args *uap)
594 {
595 	int error;
596 	caddr_t sg;
597 	struct itimerval32 *p32, *op32, s32;
598 	struct itimerval *p = NULL, *op = NULL, s;
599 
600 	p32 = uap->itv;
601 	if (p32) {
602 		sg = stackgap_init();
603 		p = stackgap_alloc(&sg, sizeof(struct itimerval));
604 		uap->itv = (struct itimerval32 *)p;
605 		error = copyin(p32, &s32, sizeof(s32));
606 		if (error)
607 			return (error);
608 		TV_CP(s32, s, it_interval);
609 		TV_CP(s32, s, it_value);
610 		error = copyout(&s, p, sizeof(s));
611 		if (error)
612 			return (error);
613 	}
614 	op32 = uap->oitv;
615 	if (op32) {
616 		sg = stackgap_init();
617 		op = stackgap_alloc(&sg, sizeof(struct itimerval));
618 		uap->oitv = (struct itimerval32 *)op;
619 	}
620 	error = setitimer(td, (struct setitimer_args *) uap);
621 	if (error)
622 		return (error);
623 	if (op32) {
624 		error = copyin(op, &s, sizeof(s));
625 		if (error)
626 			return (error);
627 		TV_CP(s, s32, it_interval);
628 		TV_CP(s, s32, it_value);
629 		error = copyout(&s32, op32, sizeof(s32));
630 	}
631 	return (error);
632 }
633 
634 int
635 freebsd32_select(struct thread *td, struct freebsd32_select_args *uap)
636 {
637 	int error;
638 	caddr_t sg;
639 	struct timeval32 *p32, s32;
640 	struct timeval *p = NULL, s;
641 
642 	p32 = uap->tv;
643 	if (p32) {
644 		sg = stackgap_init();
645 		p = stackgap_alloc(&sg, sizeof(struct timeval));
646 		uap->tv = (struct timeval32 *)p;
647 		error = copyin(p32, &s32, sizeof(s32));
648 		if (error)
649 			return (error);
650 		CP(s32, s, tv_sec);
651 		CP(s32, s, tv_usec);
652 		error = copyout(&s, p, sizeof(s));
653 		if (error)
654 			return (error);
655 	}
656 	/*
657 	 * XXX big-endian needs to convert the fd_sets too.
658 	 */
659 	return (select(td, (struct select_args *) uap));
660 }
661 
662 struct kevent32 {
663 	u_int32_t	ident;		/* identifier for this event */
664 	short		filter;		/* filter for event */
665 	u_short		flags;
666 	u_int		fflags;
667 	int32_t		data;
668 	u_int32_t	udata;		/* opaque user data identifier */
669 };
670 
671 int
672 freebsd32_kevent(struct thread *td, struct freebsd32_kevent_args *uap)
673 {
674 	int error;
675 	caddr_t sg;
676 	struct timespec32 ts32;
677 	struct timespec ts;
678 	struct kevent32 ks32;
679 	struct kevent *ks;
680 	struct kevent_args a;
681 	int i;
682 
683 	sg = stackgap_init();
684 
685 	a.fd = uap->fd;
686 	a.changelist = uap->changelist;
687 	a.nchanges = uap->nchanges;
688 	a.eventlist = uap->eventlist;
689 	a.nevents = uap->nevents;
690 	a.timeout = NULL;
691 
692 	if (uap->timeout) {
693 		a.timeout = stackgap_alloc(&sg, sizeof(struct timespec));
694 		error = copyin(uap->timeout, &ts32, sizeof(ts32));
695 		if (error)
696 			return (error);
697 		CP(ts32, ts, tv_sec);
698 		CP(ts32, ts, tv_nsec);
699 		error = copyout(&ts, (void *)(uintptr_t)a.timeout, sizeof(ts));
700 		if (error)
701 			return (error);
702 	}
703 	if (uap->changelist) {
704 		a.changelist = (struct kevent *)stackgap_alloc(&sg,
705 		    uap->nchanges * sizeof(struct kevent));
706 		for (i = 0; i < uap->nchanges; i++) {
707 			error = copyin(&uap->changelist[i], &ks32,
708 			    sizeof(ks32));
709 			if (error)
710 				return (error);
711 			ks = (struct kevent *)(uintptr_t)&a.changelist[i];
712 			CP(ks32, *ks, ident);
713 			CP(ks32, *ks, filter);
714 			CP(ks32, *ks, flags);
715 			CP(ks32, *ks, fflags);
716 			CP(ks32, *ks, data);
717 			PTRIN_CP(ks32, *ks, udata);
718 		}
719 	}
720 	if (uap->eventlist) {
721 		a.eventlist = stackgap_alloc(&sg,
722 		    uap->nevents * sizeof(struct kevent));
723 	}
724 	error = kevent(td, &a);
725 	if (uap->eventlist && error > 0) {
726 		for (i = 0; i < error; i++) {
727 			ks = &a.eventlist[i];
728 			CP(*ks, ks32, ident);
729 			CP(*ks, ks32, filter);
730 			CP(*ks, ks32, flags);
731 			CP(*ks, ks32, fflags);
732 			CP(*ks, ks32, data);
733 			PTROUT_CP(*ks, ks32, udata);
734 			error = copyout(&ks32, &uap->eventlist[i],
735 			    sizeof(ks32));
736 			if (error)
737 				return (error);
738 		}
739 	}
740 	return error;
741 }
742 
743 int
744 freebsd32_gettimeofday(struct thread *td,
745 		       struct freebsd32_gettimeofday_args *uap)
746 {
747 	int error;
748 	caddr_t sg;
749 	struct timeval32 *p32, s32;
750 	struct timeval *p = NULL, s;
751 
752 	p32 = uap->tp;
753 	if (p32) {
754 		sg = stackgap_init();
755 		p = stackgap_alloc(&sg, sizeof(struct timeval));
756 		uap->tp = (struct timeval32 *)p;
757 	}
758 	error = gettimeofday(td, (struct gettimeofday_args *) uap);
759 	if (error)
760 		return (error);
761 	if (p32) {
762 		error = copyin(p, &s, sizeof(s));
763 		if (error)
764 			return (error);
765 		CP(s, s32, tv_sec);
766 		CP(s, s32, tv_usec);
767 		error = copyout(&s32, p32, sizeof(s32));
768 		if (error)
769 			return (error);
770 	}
771 	return (error);
772 }
773 
774 int
775 freebsd32_getrusage(struct thread *td, struct freebsd32_getrusage_args *uap)
776 {
777 	int error;
778 	caddr_t sg;
779 	struct rusage32 *p32, s32;
780 	struct rusage *p = NULL, s;
781 
782 	p32 = uap->rusage;
783 	if (p32) {
784 		sg = stackgap_init();
785 		p = stackgap_alloc(&sg, sizeof(struct rusage));
786 		uap->rusage = (struct rusage32 *)p;
787 	}
788 	error = getrusage(td, (struct getrusage_args *) uap);
789 	if (error)
790 		return (error);
791 	if (p32) {
792 		error = copyin(p, &s, sizeof(s));
793 		if (error)
794 			return (error);
795 		TV_CP(s, s32, ru_utime);
796 		TV_CP(s, s32, ru_stime);
797 		CP(s, s32, ru_maxrss);
798 		CP(s, s32, ru_ixrss);
799 		CP(s, s32, ru_idrss);
800 		CP(s, s32, ru_isrss);
801 		CP(s, s32, ru_minflt);
802 		CP(s, s32, ru_majflt);
803 		CP(s, s32, ru_nswap);
804 		CP(s, s32, ru_inblock);
805 		CP(s, s32, ru_oublock);
806 		CP(s, s32, ru_msgsnd);
807 		CP(s, s32, ru_msgrcv);
808 		CP(s, s32, ru_nsignals);
809 		CP(s, s32, ru_nvcsw);
810 		CP(s, s32, ru_nivcsw);
811 		error = copyout(&s32, p32, sizeof(s32));
812 	}
813 	return (error);
814 }
815 
816 struct iovec32 {
817 	u_int32_t iov_base;
818 	int	iov_len;
819 };
820 #define	STACKGAPLEN	400
821 
822 int
823 freebsd32_readv(struct thread *td, struct freebsd32_readv_args *uap)
824 {
825 	int error, osize, nsize, i;
826 	caddr_t sg;
827 	struct readv_args /* {
828 		syscallarg(int) fd;
829 		syscallarg(struct iovec *) iovp;
830 		syscallarg(u_int) iovcnt;
831 	} */ a;
832 	struct iovec32 *oio;
833 	struct iovec *nio;
834 
835 	sg = stackgap_init();
836 
837 	if (uap->iovcnt > (STACKGAPLEN / sizeof (struct iovec)))
838 		return (EINVAL);
839 
840 	osize = uap->iovcnt * sizeof (struct iovec32);
841 	nsize = uap->iovcnt * sizeof (struct iovec);
842 
843 	oio = malloc(osize, M_TEMP, M_WAITOK);
844 	nio = malloc(nsize, M_TEMP, M_WAITOK);
845 
846 	error = 0;
847 	if ((error = copyin(uap->iovp, oio, osize)))
848 		goto punt;
849 	for (i = 0; i < uap->iovcnt; i++) {
850 		nio[i].iov_base = PTRIN(oio[i].iov_base);
851 		nio[i].iov_len = oio[i].iov_len;
852 	}
853 
854 	a.fd = uap->fd;
855 	a.iovp = stackgap_alloc(&sg, nsize);
856 	a.iovcnt = uap->iovcnt;
857 
858 	if ((error = copyout(nio, (caddr_t)a.iovp, nsize)))
859 		goto punt;
860 	error = readv(td, &a);
861 
862 punt:
863 	free(oio, M_TEMP);
864 	free(nio, M_TEMP);
865 	return (error);
866 }
867 
868 int
869 freebsd32_writev(struct thread *td, struct freebsd32_writev_args *uap)
870 {
871 	int error, i, nsize, osize;
872 	caddr_t sg;
873 	struct writev_args /* {
874 		syscallarg(int) fd;
875 		syscallarg(struct iovec *) iovp;
876 		syscallarg(u_int) iovcnt;
877 	} */ a;
878 	struct iovec32 *oio;
879 	struct iovec *nio;
880 
881 	sg = stackgap_init();
882 
883 	if (uap->iovcnt > (STACKGAPLEN / sizeof (struct iovec)))
884 		return (EINVAL);
885 
886 	osize = uap->iovcnt * sizeof (struct iovec32);
887 	nsize = uap->iovcnt * sizeof (struct iovec);
888 
889 	oio = malloc(osize, M_TEMP, M_WAITOK);
890 	nio = malloc(nsize, M_TEMP, M_WAITOK);
891 
892 	error = 0;
893 	if ((error = copyin(uap->iovp, oio, osize)))
894 		goto punt;
895 	for (i = 0; i < uap->iovcnt; i++) {
896 		nio[i].iov_base = PTRIN(oio[i].iov_base);
897 		nio[i].iov_len = oio[i].iov_len;
898 	}
899 
900 	a.fd = uap->fd;
901 	a.iovp = stackgap_alloc(&sg, nsize);
902 	a.iovcnt = uap->iovcnt;
903 
904 	if ((error = copyout(nio, (caddr_t)a.iovp, nsize)))
905 		goto punt;
906 	error = writev(td, &a);
907 
908 punt:
909 	free(oio, M_TEMP);
910 	free(nio, M_TEMP);
911 	return (error);
912 }
913 
914 int
915 freebsd32_settimeofday(struct thread *td,
916 		       struct freebsd32_settimeofday_args *uap)
917 {
918 	int error;
919 	caddr_t sg;
920 	struct timeval32 *p32, s32;
921 	struct timeval *p = NULL, s;
922 
923 	p32 = uap->tv;
924 	if (p32) {
925 		sg = stackgap_init();
926 		p = stackgap_alloc(&sg, sizeof(struct timeval));
927 		uap->tv = (struct timeval32 *)p;
928 		error = copyin(p32, &s32, sizeof(s32));
929 		if (error)
930 			return (error);
931 		CP(s32, s, tv_sec);
932 		CP(s32, s, tv_usec);
933 		error = copyout(&s, p, sizeof(s));
934 		if (error)
935 			return (error);
936 	}
937 	return (settimeofday(td, (struct settimeofday_args *) uap));
938 }
939 
940 int
941 freebsd32_utimes(struct thread *td, struct freebsd32_utimes_args *uap)
942 {
943 	int error;
944 	caddr_t sg;
945 	struct timeval32 *p32, s32[2];
946 	struct timeval *p = NULL, s[2];
947 
948 	p32 = uap->tptr;
949 	if (p32) {
950 		sg = stackgap_init();
951 		p = stackgap_alloc(&sg, 2*sizeof(struct timeval));
952 		uap->tptr = (struct timeval32 *)p;
953 		error = copyin(p32, s32, sizeof(s32));
954 		if (error)
955 			return (error);
956 		CP(s32[0], s[0], tv_sec);
957 		CP(s32[0], s[0], tv_usec);
958 		CP(s32[1], s[1], tv_sec);
959 		CP(s32[1], s[1], tv_usec);
960 		error = copyout(s, p, sizeof(s));
961 		if (error)
962 			return (error);
963 	}
964 	return (utimes(td, (struct utimes_args *) uap));
965 }
966 
967 int
968 freebsd32_adjtime(struct thread *td, struct freebsd32_adjtime_args *uap)
969 {
970 	int error;
971 	caddr_t sg;
972 	struct timeval32 *p32, *op32, s32;
973 	struct timeval *p = NULL, *op = NULL, s;
974 
975 	p32 = uap->delta;
976 	if (p32) {
977 		sg = stackgap_init();
978 		p = stackgap_alloc(&sg, sizeof(struct timeval));
979 		uap->delta = (struct timeval32 *)p;
980 		error = copyin(p32, &s32, sizeof(s32));
981 		if (error)
982 			return (error);
983 		CP(s32, s, tv_sec);
984 		CP(s32, s, tv_usec);
985 		error = copyout(&s, p, sizeof(s));
986 		if (error)
987 			return (error);
988 	}
989 	op32 = uap->olddelta;
990 	if (op32) {
991 		sg = stackgap_init();
992 		op = stackgap_alloc(&sg, sizeof(struct timeval));
993 		uap->olddelta = (struct timeval32 *)op;
994 	}
995 	error = utimes(td, (struct utimes_args *) uap);
996 	if (error)
997 		return error;
998 	if (op32) {
999 		error = copyin(op, &s, sizeof(s));
1000 		if (error)
1001 			return (error);
1002 		CP(s, s32, tv_sec);
1003 		CP(s, s32, tv_usec);
1004 		error = copyout(&s32, op32, sizeof(s32));
1005 	}
1006 	return (error);
1007 }
1008 
1009 int
1010 freebsd32_statfs(struct thread *td, struct freebsd32_statfs_args *uap)
1011 {
1012 	int error;
1013 	caddr_t sg;
1014 	struct statfs32 *p32, s32;
1015 	struct statfs *p = NULL, s;
1016 
1017 	p32 = uap->buf;
1018 	if (p32) {
1019 		sg = stackgap_init();
1020 		p = stackgap_alloc(&sg, sizeof(struct statfs));
1021 		uap->buf = (struct statfs32 *)p;
1022 	}
1023 	error = statfs(td, (struct statfs_args *) uap);
1024 	if (error)
1025 		return (error);
1026 	if (p32) {
1027 		error = copyin(p, &s, sizeof(s));
1028 		if (error)
1029 			return (error);
1030 		copy_statfs(&s, &s32);
1031 		error = copyout(&s32, p32, sizeof(s32));
1032 	}
1033 	return (error);
1034 }
1035 
1036 int
1037 freebsd32_fstatfs(struct thread *td, struct freebsd32_fstatfs_args *uap)
1038 {
1039 	int error;
1040 	caddr_t sg;
1041 	struct statfs32 *p32, s32;
1042 	struct statfs *p = NULL, s;
1043 
1044 	p32 = uap->buf;
1045 	if (p32) {
1046 		sg = stackgap_init();
1047 		p = stackgap_alloc(&sg, sizeof(struct statfs));
1048 		uap->buf = (struct statfs32 *)p;
1049 	}
1050 	error = fstatfs(td, (struct fstatfs_args *) uap);
1051 	if (error)
1052 		return (error);
1053 	if (p32) {
1054 		error = copyin(p, &s, sizeof(s));
1055 		if (error)
1056 			return (error);
1057 		copy_statfs(&s, &s32);
1058 		error = copyout(&s32, p32, sizeof(s32));
1059 	}
1060 	return (error);
1061 }
1062 
1063 int
1064 freebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap)
1065 {
1066 	/*
1067 	 * Vector through to semsys if it is loaded.
1068 	 */
1069 	return sysent[169].sy_call(td, uap);
1070 }
1071 
1072 int
1073 freebsd32_msgsys(struct thread *td, struct freebsd32_msgsys_args *uap)
1074 {
1075 	/*
1076 	 * Vector through to msgsys if it is loaded.
1077 	 */
1078 	return sysent[170].sy_call(td, uap);
1079 }
1080 
1081 int
1082 freebsd32_shmsys(struct thread *td, struct freebsd32_shmsys_args *uap)
1083 {
1084 	/*
1085 	 * Vector through to shmsys if it is loaded.
1086 	 */
1087 	return sysent[171].sy_call(td, uap);
1088 }
1089 
1090 int
1091 freebsd32_pread(struct thread *td, struct freebsd32_pread_args *uap)
1092 {
1093 	struct pread_args ap;
1094 
1095 	ap.fd = uap->fd;
1096 	ap.buf = uap->buf;
1097 	ap.nbyte = uap->nbyte;
1098 	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
1099 	return (pread(td, &ap));
1100 }
1101 
1102 int
1103 freebsd32_pwrite(struct thread *td, struct freebsd32_pwrite_args *uap)
1104 {
1105 	struct pwrite_args ap;
1106 
1107 	ap.fd = uap->fd;
1108 	ap.buf = uap->buf;
1109 	ap.nbyte = uap->nbyte;
1110 	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
1111 	return (pwrite(td, &ap));
1112 }
1113 
1114 int
1115 freebsd32_lseek(struct thread *td, struct freebsd32_lseek_args *uap)
1116 {
1117 	int error;
1118 	struct lseek_args ap;
1119 	off_t pos;
1120 
1121 	ap.fd = uap->fd;
1122 	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
1123 	ap.whence = uap->whence;
1124 	error = lseek(td, &ap);
1125 	/* Expand the quad return into two parts for eax and edx */
1126 	pos = *(off_t *)(td->td_retval);
1127 	td->td_retval[0] = pos & 0xffffffff;	/* %eax */
1128 	td->td_retval[1] = pos >> 32;		/* %edx */
1129 	return error;
1130 }
1131 
1132 int
1133 freebsd32_truncate(struct thread *td, struct freebsd32_truncate_args *uap)
1134 {
1135 	struct truncate_args ap;
1136 
1137 	ap.path = uap->path;
1138 	ap.length = (uap->lengthlo | ((off_t)uap->lengthhi << 32));
1139 	return (truncate(td, &ap));
1140 }
1141 
1142 int
1143 freebsd32_ftruncate(struct thread *td, struct freebsd32_ftruncate_args *uap)
1144 {
1145 	struct ftruncate_args ap;
1146 
1147 	ap.fd = uap->fd;
1148 	ap.length = (uap->lengthlo | ((off_t)uap->lengthhi << 32));
1149 	return (ftruncate(td, &ap));
1150 }
1151 
1152 #ifdef COMPAT_FREEBSD4
1153 int
1154 freebsd4_freebsd32_sendfile(struct thread *td,
1155     struct freebsd4_freebsd32_sendfile_args *uap)
1156 {
1157 	struct freebsd4_sendfile_args ap;
1158 
1159 	ap.fd = uap->fd;
1160 	ap.s = uap->s;
1161 	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
1162 	ap.nbytes = uap->nbytes;	/* XXX check */
1163 	ap.hdtr = uap->hdtr;		/* XXX check */
1164 	ap.sbytes = uap->sbytes;	/* XXX FIXME!! */
1165 	ap.flags = uap->flags;
1166 	return (freebsd4_sendfile(td, &ap));
1167 }
1168 #endif
1169 
1170 int
1171 freebsd32_sendfile(struct thread *td, struct freebsd32_sendfile_args *uap)
1172 {
1173 	struct sendfile_args ap;
1174 
1175 	ap.fd = uap->fd;
1176 	ap.s = uap->s;
1177 	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
1178 	ap.nbytes = uap->nbytes;	/* XXX check */
1179 	ap.hdtr = uap->hdtr;		/* XXX check */
1180 	ap.sbytes = uap->sbytes;	/* XXX FIXME!! */
1181 	ap.flags = uap->flags;
1182 	return (sendfile(td, &ap));
1183 }
1184 
1185 struct stat32 {
1186 	udev_t	st_dev;
1187 	ino_t	st_ino;
1188 	mode_t	st_mode;
1189 	nlink_t	st_nlink;
1190 	uid_t	st_uid;
1191 	gid_t	st_gid;
1192 	udev_t	st_rdev;
1193 	struct timespec32 st_atimespec;
1194 	struct timespec32 st_mtimespec;
1195 	struct timespec32 st_ctimespec;
1196 	off_t	st_size;
1197 	int64_t	st_blocks;
1198 	u_int32_t st_blksize;
1199 	u_int32_t st_flags;
1200 	u_int32_t st_gen;
1201 };
1202 
1203 static void
1204 copy_stat( struct stat *in, struct stat32 *out)
1205 {
1206 	CP(*in, *out, st_dev);
1207 	CP(*in, *out, st_ino);
1208 	CP(*in, *out, st_mode);
1209 	CP(*in, *out, st_nlink);
1210 	CP(*in, *out, st_uid);
1211 	CP(*in, *out, st_gid);
1212 	CP(*in, *out, st_rdev);
1213 	TS_CP(*in, *out, st_atimespec);
1214 	TS_CP(*in, *out, st_mtimespec);
1215 	TS_CP(*in, *out, st_ctimespec);
1216 	CP(*in, *out, st_size);
1217 	CP(*in, *out, st_blocks);
1218 	CP(*in, *out, st_blksize);
1219 	CP(*in, *out, st_flags);
1220 	CP(*in, *out, st_gen);
1221 }
1222 
1223 int
1224 freebsd32_stat(struct thread *td, struct freebsd32_stat_args *uap)
1225 {
1226 	int error;
1227 	caddr_t sg;
1228 	struct stat32 *p32, s32;
1229 	struct stat *p = NULL, s;
1230 
1231 	p32 = uap->ub;
1232 	if (p32) {
1233 		sg = stackgap_init();
1234 		p = stackgap_alloc(&sg, sizeof(struct stat));
1235 		uap->ub = (struct stat32 *)p;
1236 	}
1237 	error = stat(td, (struct stat_args *) uap);
1238 	if (error)
1239 		return (error);
1240 	if (p32) {
1241 		error = copyin(p, &s, sizeof(s));
1242 		if (error)
1243 			return (error);
1244 		copy_stat(&s, &s32);
1245 		error = copyout(&s32, p32, sizeof(s32));
1246 	}
1247 	return (error);
1248 }
1249 
1250 int
1251 freebsd32_fstat(struct thread *td, struct freebsd32_fstat_args *uap)
1252 {
1253 	int error;
1254 	caddr_t sg;
1255 	struct stat32 *p32, s32;
1256 	struct stat *p = NULL, s;
1257 
1258 	p32 = uap->ub;
1259 	if (p32) {
1260 		sg = stackgap_init();
1261 		p = stackgap_alloc(&sg, sizeof(struct stat));
1262 		uap->ub = (struct stat32 *)p;
1263 	}
1264 	error = fstat(td, (struct fstat_args *) uap);
1265 	if (error)
1266 		return (error);
1267 	if (p32) {
1268 		error = copyin(p, &s, sizeof(s));
1269 		if (error)
1270 			return (error);
1271 		copy_stat(&s, &s32);
1272 		error = copyout(&s32, p32, sizeof(s32));
1273 	}
1274 	return (error);
1275 }
1276 
1277 int
1278 freebsd32_lstat(struct thread *td, struct freebsd32_lstat_args *uap)
1279 {
1280 	int error;
1281 	caddr_t sg;
1282 	struct stat32 *p32, s32;
1283 	struct stat *p = NULL, s;
1284 
1285 	p32 = uap->ub;
1286 	if (p32) {
1287 		sg = stackgap_init();
1288 		p = stackgap_alloc(&sg, sizeof(struct stat));
1289 		uap->ub = (struct stat32 *)p;
1290 	}
1291 	error = lstat(td, (struct lstat_args *) uap);
1292 	if (error)
1293 		return (error);
1294 	if (p32) {
1295 		error = copyin(p, &s, sizeof(s));
1296 		if (error)
1297 			return (error);
1298 		copy_stat(&s, &s32);
1299 		error = copyout(&s32, p32, sizeof(s32));
1300 	}
1301 	return (error);
1302 }
1303 
1304 /*
1305  * MPSAFE
1306  */
1307 int
1308 freebsd32_sysctl(struct thread *td, struct freebsd32_sysctl_args *uap)
1309 {
1310 	int error, name[CTL_MAXNAME];
1311 	size_t j, oldlen;
1312 
1313 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
1314 		return (EINVAL);
1315 
1316  	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
1317  	if (error)
1318 		return (error);
1319 
1320 	mtx_lock(&Giant);
1321 
1322 	if (uap->oldlenp)
1323 		oldlen = fuword32(uap->oldlenp);
1324 	else
1325 		oldlen = 0;
1326 	error = userland_sysctl(td, name, uap->namelen,
1327 		uap->old, &oldlen, 1,
1328 		uap->new, uap->newlen, &j);
1329 	if (error && error != ENOMEM)
1330 		goto done2;
1331 	if (uap->oldlenp) {
1332 		suword32(uap->oldlenp, j);
1333 	}
1334 done2:
1335 	mtx_unlock(&Giant);
1336 	return (error);
1337 }
1338 
1339 struct sigaction32 {
1340 	u_int32_t	sa_u;
1341 	int		sa_flags;
1342 	sigset_t	sa_mask;
1343 };
1344 
1345 int
1346 freebsd32_sigaction(struct thread *td, struct freebsd32_sigaction_args *uap)
1347 {
1348 	struct sigaction32 s32;
1349 	struct sigaction sa, osa, *sap;
1350 	int error;
1351 
1352 	if (uap->act) {
1353 		error = copyin(uap->act, &s32, sizeof(s32));
1354 		if (error)
1355 			return (error);
1356 		sa.sa_handler = PTRIN(s32.sa_u);
1357 		CP(s32, sa, sa_flags);
1358 		CP(s32, sa, sa_mask);
1359 		sap = &sa;
1360 	} else
1361 		sap = NULL;
1362 	error = kern_sigaction(td, uap->sig, sap, &osa, 0);
1363 	if (error != 0 && uap->oact != NULL) {
1364 		s32.sa_u = PTROUT(osa.sa_handler);
1365 		CP(osa, s32, sa_flags);
1366 		CP(osa, s32, sa_mask);
1367 		error = copyout(&s32, uap->oact, sizeof(s32));
1368 	}
1369 	return (error);
1370 }
1371 
1372 #ifdef COMPAT_FREEBSD4
1373 int
1374 freebsd4_freebsd32_sigaction(struct thread *td,
1375 			     struct freebsd4_freebsd32_sigaction_args *uap)
1376 {
1377 	struct sigaction32 s32;
1378 	struct sigaction sa, osa, *sap;
1379 	int error;
1380 
1381 	if (uap->act) {
1382 		error = copyin(uap->act, &s32, sizeof(s32));
1383 		if (error)
1384 			return (error);
1385 		sa.sa_handler = PTRIN(s32.sa_u);
1386 		CP(s32, sa, sa_flags);
1387 		CP(s32, sa, sa_mask);
1388 		sap = &sa;
1389 	} else
1390 		sap = NULL;
1391 	error = kern_sigaction(td, uap->sig, sap, &osa, KSA_FREEBSD4);
1392 	if (error != 0 && uap->oact != NULL) {
1393 		s32.sa_u = PTROUT(osa.sa_handler);
1394 		CP(osa, s32, sa_flags);
1395 		CP(osa, s32, sa_mask);
1396 		error = copyout(&s32, uap->oact, sizeof(s32));
1397 	}
1398 	return (error);
1399 }
1400 #endif
1401 
1402 #if 0
1403 
1404 int
1405 freebsd32_xxx(struct thread *td, struct freebsd32_xxx_args *uap)
1406 {
1407 	int error;
1408 	caddr_t sg;
1409 	struct yyy32 *p32, s32;
1410 	struct yyy *p = NULL, s;
1411 
1412 	p32 = uap->zzz;
1413 	if (p32) {
1414 		sg = stackgap_init();
1415 		p = stackgap_alloc(&sg, sizeof(struct yyy));
1416 		uap->zzz = (struct yyy32 *)p;
1417 		error = copyin(p32, &s32, sizeof(s32));
1418 		if (error)
1419 			return (error);
1420 		/* translate in */
1421 		error = copyout(&s, p, sizeof(s));
1422 		if (error)
1423 			return (error);
1424 	}
1425 	error = xxx(td, (struct xxx_args *) uap);
1426 	if (error)
1427 		return (error);
1428 	if (p32) {
1429 		error = copyin(p, &s, sizeof(s));
1430 		if (error)
1431 			return (error);
1432 		/* translate out */
1433 		error = copyout(&s32, p32, sizeof(s32));
1434 	}
1435 	return (error);
1436 }
1437 
1438 #endif
1439