xref: /freebsd/sys/compat/freebsd32/freebsd32_misc.c (revision ebccf1e3a6b11b97cbf5f813dd76636e892a9035)
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/namei.h>
39 #include <sys/imgact.h>
40 #include <sys/kernel.h>
41 #include <sys/lock.h>
42 #include <sys/malloc.h>
43 #include <sys/file.h>		/* Must come after sys/malloc.h */
44 #include <sys/mman.h>
45 #include <sys/module.h>
46 #include <sys/mount.h>
47 #include <sys/mutex.h>
48 #include <sys/namei.h>
49 #include <sys/param.h>
50 #include <sys/proc.h>
51 #include <sys/reboot.h>
52 #include <sys/resource.h>
53 #include <sys/resourcevar.h>
54 #include <sys/selinfo.h>
55 #include <sys/pipe.h>		/* Must come after sys/selinfo.h */
56 #include <sys/signal.h>
57 #include <sys/signalvar.h>
58 #include <sys/socket.h>
59 #include <sys/socketvar.h>
60 #include <sys/stat.h>
61 #include <sys/syscallsubr.h>
62 #include <sys/sysctl.h>
63 #include <sys/sysent.h>
64 #include <sys/sysproto.h>
65 #include <sys/systm.h>
66 #include <sys/unistd.h>
67 #include <sys/vnode.h>
68 #include <sys/wait.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 CTASSERT(sizeof(struct timeval32) == 8);
83 CTASSERT(sizeof(struct timespec32) == 8);
84 CTASSERT(sizeof(struct statfs32) == 256);
85 CTASSERT(sizeof(struct rusage32) == 72);
86 
87 int
88 freebsd32_wait4(struct thread *td, struct freebsd32_wait4_args *uap)
89 {
90 	int error, status;
91 	struct rusage32 ru32;
92 	struct rusage ru, *rup;
93 
94 	if (uap->rusage != NULL)
95 		rup = &ru;
96 	else
97 		rup = NULL;
98 	error = kern_wait(td, uap->pid, &status, uap->options, rup);
99 	if (error)
100 		return (error);
101 	if (uap->status != NULL)
102 		error = copyout(&status, uap->status, sizeof(status));
103 	if (uap->rusage != NULL && error == 0) {
104 		TV_CP(ru, ru32, ru_utime);
105 		TV_CP(ru, ru32, ru_stime);
106 		CP(ru, ru32, ru_maxrss);
107 		CP(ru, ru32, ru_ixrss);
108 		CP(ru, ru32, ru_idrss);
109 		CP(ru, ru32, ru_isrss);
110 		CP(ru, ru32, ru_minflt);
111 		CP(ru, ru32, ru_majflt);
112 		CP(ru, ru32, ru_nswap);
113 		CP(ru, ru32, ru_inblock);
114 		CP(ru, ru32, ru_oublock);
115 		CP(ru, ru32, ru_msgsnd);
116 		CP(ru, ru32, ru_msgrcv);
117 		CP(ru, ru32, ru_nsignals);
118 		CP(ru, ru32, ru_nvcsw);
119 		CP(ru, ru32, ru_nivcsw);
120 		error = copyout(&ru32, uap->rusage, sizeof(ru32));
121 	}
122 	return (error);
123 }
124 
125 #ifdef COMPAT_FREEBSD4
126 static void
127 copy_statfs(struct statfs *in, struct statfs32 *out)
128 {
129 	CP(*in, *out, f_bsize);
130 	CP(*in, *out, f_iosize);
131 	CP(*in, *out, f_blocks);
132 	CP(*in, *out, f_bfree);
133 	CP(*in, *out, f_bavail);
134 	CP(*in, *out, f_files);
135 	CP(*in, *out, f_ffree);
136 	CP(*in, *out, f_fsid);
137 	CP(*in, *out, f_owner);
138 	CP(*in, *out, f_type);
139 	CP(*in, *out, f_flags);
140 	CP(*in, *out, f_flags);
141 	CP(*in, *out, f_syncwrites);
142 	CP(*in, *out, f_asyncwrites);
143 	bcopy(in->f_fstypename,
144 	      out->f_fstypename, MFSNAMELEN);
145 	bcopy(in->f_mntonname,
146 	      out->f_mntonname, min(MNAMELEN, FREEBSD4_MNAMELEN));
147 	CP(*in, *out, f_syncreads);
148 	CP(*in, *out, f_asyncreads);
149 	bcopy(in->f_mntfromname,
150 	      out->f_mntfromname, min(MNAMELEN, FREEBSD4_MNAMELEN));
151 }
152 #endif
153 
154 #ifdef COMPAT_FREEBSD4
155 int
156 freebsd4_freebsd32_getfsstat(struct thread *td, struct freebsd4_freebsd32_getfsstat_args *uap)
157 {
158 	int error;
159 	caddr_t sg;
160 	struct statfs32 *sp32, stat32;
161 	struct statfs *sp = NULL, stat;
162 	int maxcount, count, i;
163 
164 	sp32 = uap->buf;
165 	maxcount = uap->bufsize / sizeof(struct statfs32);
166 
167 	if (sp32) {
168 		sg = stackgap_init();
169 		sp = stackgap_alloc(&sg, sizeof(struct statfs) * maxcount);
170 		uap->buf = (struct statfs32 *)sp;
171 	}
172 	error = getfsstat(td, (struct getfsstat_args *) uap);
173 	if (sp32 && !error) {
174 		count = td->td_retval[0];
175 		for (i = 0; i < count; i++) {
176 			error = copyin(&sp[i], &stat, sizeof(stat));
177 			if (error)
178 				return (error);
179 			copy_statfs(&stat, &stat32);
180 			error = copyout(&stat32, &sp32[i], sizeof(stat32));
181 			if (error)
182 				return (error);
183 		}
184 	}
185 	return (error);
186 }
187 #endif
188 
189 struct sigaltstack32 {
190 	u_int32_t	ss_sp;
191 	u_int32_t	ss_size;
192 	int		ss_flags;
193 };
194 
195 CTASSERT(sizeof(struct sigaltstack32) == 12);
196 
197 int
198 freebsd32_sigaltstack(struct thread *td,
199 		      struct freebsd32_sigaltstack_args *uap)
200 {
201 	struct sigaltstack32 s32;
202 	struct sigaltstack ss, oss, *ssp;
203 	int error;
204 
205 	if (uap->ss != NULL) {
206 		error = copyin(uap->ss, &s32, sizeof(s32));
207 		if (error)
208 			return (error);
209 		PTRIN_CP(s32, ss, ss_sp);
210 		CP(s32, ss, ss_size);
211 		CP(s32, ss, ss_flags);
212 		ssp = &ss;
213 	} else
214 		ssp = NULL;
215 	error = kern_sigaltstack(td, ssp, &oss);
216 	if (error == 0 && uap->oss != NULL) {
217 		PTROUT_CP(oss, s32, ss_sp);
218 		CP(oss, s32, ss_size);
219 		CP(oss, s32, ss_flags);
220 		error = copyout(&s32, uap->oss, sizeof(s32));
221 	}
222 	return (error);
223 }
224 
225 /*
226  * Custom version of exec_copyin_args() so that we can translate
227  * the pointers.
228  */
229 static int
230 freebsd32_exec_copyin_args(struct image_args *args, char *fname,
231     enum uio_seg segflg, u_int32_t *argv, u_int32_t *envv)
232 {
233 	char *argp, *envp;
234 	u_int32_t *p32, arg;
235 	size_t length;
236 	int error;
237 
238 	bzero(args, sizeof(*args));
239 	if (argv == NULL)
240 		return (EFAULT);
241 
242 	/*
243 	 * Allocate temporary demand zeroed space for argument and
244 	 *	environment strings
245 	 */
246 	args->buf = (char *) kmem_alloc_wait(exec_map, PATH_MAX + ARG_MAX);
247 	if (args->buf == NULL)
248 		return (ENOMEM);
249 	args->begin_argv = args->buf;
250 	args->endp = args->begin_argv;
251 	args->stringspace = ARG_MAX;
252 
253 	args->fname = args->buf + ARG_MAX;
254 
255 	/*
256 	 * Copy the file name.
257 	 */
258 	error = (segflg == UIO_SYSSPACE) ?
259 	    copystr(fname, args->fname, PATH_MAX, &length) :
260 	    copyinstr(fname, args->fname, PATH_MAX, &length);
261 	if (error != 0)
262 		return (error);
263 
264 	/*
265 	 * extract arguments first
266 	 */
267 	p32 = argv;
268 	for (;;) {
269 		error = copyin(p32++, &arg, sizeof(arg));
270 		if (error)
271 			return (error);
272 		if (arg == 0)
273 			break;
274 		argp = PTRIN(arg);
275 		error = copyinstr(argp, args->endp, args->stringspace, &length);
276 		if (error) {
277 			if (error == ENAMETOOLONG)
278 				return (E2BIG);
279 			else
280 				return (error);
281 		}
282 		args->stringspace -= length;
283 		args->endp += length;
284 		args->argc++;
285 	}
286 
287 	args->begin_envv = args->endp;
288 
289 	/*
290 	 * extract environment strings
291 	 */
292 	if (envv) {
293 		p32 = envv;
294 		for (;;) {
295 			error = copyin(p32++, &arg, sizeof(arg));
296 			if (error)
297 				return (error);
298 			if (arg == 0)
299 				break;
300 			envp = PTRIN(arg);
301 			error = copyinstr(envp, args->endp, args->stringspace,
302 			    &length);
303 			if (error) {
304 				if (error == ENAMETOOLONG)
305 					return (E2BIG);
306 				else
307 					return (error);
308 			}
309 			args->stringspace -= length;
310 			args->endp += length;
311 			args->envc++;
312 		}
313 	}
314 
315 	return (0);
316 }
317 
318 int
319 freebsd32_execve(struct thread *td, struct freebsd32_execve_args *uap)
320 {
321 	struct image_args eargs;
322 	int error;
323 
324 	error = freebsd32_exec_copyin_args(&eargs, uap->fname, UIO_USERSPACE,
325 	    uap->argv, uap->envv);
326 	if (error == 0)
327 		error = kern_execve(td, &eargs, NULL);
328 	exec_free_args(&eargs);
329 	return (error);
330 }
331 
332 #ifdef __ia64__
333 static int
334 freebsd32_mmap_partial(struct thread *td, vm_offset_t start, vm_offset_t end,
335 		       int prot, int fd, off_t pos)
336 {
337 	vm_map_t map;
338 	vm_map_entry_t entry;
339 	int rv;
340 
341 	map = &td->td_proc->p_vmspace->vm_map;
342 	if (fd != -1)
343 		prot |= VM_PROT_WRITE;
344 
345 	if (vm_map_lookup_entry(map, start, &entry)) {
346 		if ((entry->protection & prot) != prot) {
347 			rv = vm_map_protect(map,
348 					    trunc_page(start),
349 					    round_page(end),
350 					    entry->protection | prot,
351 					    FALSE);
352 			if (rv != KERN_SUCCESS)
353 				return (EINVAL);
354 		}
355 	} else {
356 		vm_offset_t addr = trunc_page(start);
357 		rv = vm_map_find(map, 0, 0,
358 				 &addr, PAGE_SIZE, FALSE, prot,
359 				 VM_PROT_ALL, 0);
360 		if (rv != KERN_SUCCESS)
361 			return (EINVAL);
362 	}
363 
364 	if (fd != -1) {
365 		struct pread_args r;
366 		r.fd = fd;
367 		r.buf = (void *) start;
368 		r.nbyte = end - start;
369 		r.offset = pos;
370 		return (pread(td, &r));
371 	} else {
372 		while (start < end) {
373 			subyte((void *) start, 0);
374 			start++;
375 		}
376 		return (0);
377 	}
378 }
379 #endif
380 
381 int
382 freebsd32_mmap(struct thread *td, struct freebsd32_mmap_args *uap)
383 {
384 	struct mmap_args ap;
385 	vm_offset_t addr = (vm_offset_t) uap->addr;
386 	vm_size_t len	 = uap->len;
387 	int prot	 = uap->prot;
388 	int flags	 = uap->flags;
389 	int fd		 = uap->fd;
390 	off_t pos	 = (uap->poslo
391 			    | ((off_t)uap->poshi << 32));
392 #ifdef __ia64__
393 	vm_size_t pageoff;
394 	int error;
395 
396 	/*
397 	 * Attempt to handle page size hassles.
398 	 */
399 	pageoff = (pos & PAGE_MASK);
400 	if (flags & MAP_FIXED) {
401 		vm_offset_t start, end;
402 		start = addr;
403 		end = addr + len;
404 
405 		if (start != trunc_page(start)) {
406 			error = freebsd32_mmap_partial(td, start,
407 						       round_page(start), prot,
408 						       fd, pos);
409 			if (fd != -1)
410 				pos += round_page(start) - start;
411 			start = round_page(start);
412 		}
413 		if (end != round_page(end)) {
414 			vm_offset_t t = trunc_page(end);
415 			error = freebsd32_mmap_partial(td, t, end,
416 						  prot, fd,
417 						  pos + t - start);
418 			end = trunc_page(end);
419 		}
420 		if (end > start && fd != -1 && (pos & PAGE_MASK)) {
421 			/*
422 			 * We can't map this region at all. The specified
423 			 * address doesn't have the same alignment as the file
424 			 * position. Fake the mapping by simply reading the
425 			 * entire region into memory. First we need to make
426 			 * sure the region exists.
427 			 */
428 			vm_map_t map;
429 			struct pread_args r;
430 			int rv;
431 
432 			prot |= VM_PROT_WRITE;
433 			map = &td->td_proc->p_vmspace->vm_map;
434 			rv = vm_map_remove(map, start, end);
435 			if (rv != KERN_SUCCESS)
436 				return (EINVAL);
437 			rv = vm_map_find(map, 0, 0,
438 					 &start, end - start, FALSE,
439 					 prot, VM_PROT_ALL, 0);
440 			if (rv != KERN_SUCCESS)
441 				return (EINVAL);
442 			r.fd = fd;
443 			r.buf = (void *) start;
444 			r.nbyte = end - start;
445 			r.offset = pos;
446 			error = pread(td, &r);
447 			if (error)
448 				return (error);
449 
450 			td->td_retval[0] = addr;
451 			return (0);
452 		}
453 		if (end == start) {
454 			/*
455 			 * After dealing with the ragged ends, there
456 			 * might be none left.
457 			 */
458 			td->td_retval[0] = addr;
459 			return (0);
460 		}
461 		addr = start;
462 		len = end - start;
463 	}
464 #endif
465 
466 	ap.addr = (void *) addr;
467 	ap.len = len;
468 	ap.prot = prot;
469 	ap.flags = flags;
470 	ap.fd = fd;
471 	ap.pos = pos;
472 
473 	return (mmap(td, &ap));
474 }
475 
476 struct itimerval32 {
477 	struct timeval32 it_interval;
478 	struct timeval32 it_value;
479 };
480 
481 CTASSERT(sizeof(struct itimerval32) == 16);
482 
483 int
484 freebsd32_setitimer(struct thread *td, struct freebsd32_setitimer_args *uap)
485 {
486 	struct itimerval itv, oitv, *itvp;
487 	struct itimerval32 i32;
488 	int error;
489 
490 	if (uap->itv != NULL) {
491 		error = copyin(uap->itv, &i32, sizeof(i32));
492 		if (error)
493 			return (error);
494 		TV_CP(i32, itv, it_interval);
495 		TV_CP(i32, itv, it_value);
496 		itvp = &itv;
497 	} else
498 		itvp = NULL;
499 	error = kern_setitimer(td, uap->which, itvp, &oitv);
500 	if (error || uap->oitv == NULL)
501 		return (error);
502 	TV_CP(oitv, i32, it_interval);
503 	TV_CP(oitv, i32, it_value);
504 	return (copyout(&i32, uap->oitv, sizeof(i32)));
505 }
506 
507 int
508 freebsd32_getitimer(struct thread *td, struct freebsd32_getitimer_args *uap)
509 {
510 	struct itimerval itv;
511 	struct itimerval32 i32;
512 	int error;
513 
514 	error = kern_getitimer(td, uap->which, &itv);
515 	if (error || uap->itv == NULL)
516 		return (error);
517 	TV_CP(itv, i32, it_interval);
518 	TV_CP(itv, i32, it_value);
519 	return (copyout(&i32, uap->itv, sizeof(i32)));
520 }
521 
522 int
523 freebsd32_select(struct thread *td, struct freebsd32_select_args *uap)
524 {
525 	struct timeval32 tv32;
526 	struct timeval tv, *tvp;
527 	int error;
528 
529 	if (uap->tv != NULL) {
530 		error = copyin(uap->tv, &tv32, sizeof(tv32));
531 		if (error)
532 			return (error);
533 		CP(tv32, tv, tv_sec);
534 		CP(tv32, tv, tv_usec);
535 		tvp = &tv;
536 	} else
537 		tvp = NULL;
538 	/*
539 	 * XXX big-endian needs to convert the fd_sets too.
540 	 * XXX Do pointers need PTRIN()?
541 	 */
542 	return (kern_select(td, uap->nd, uap->in, uap->ou, uap->ex, tvp));
543 }
544 
545 struct kevent32 {
546 	u_int32_t	ident;		/* identifier for this event */
547 	short		filter;		/* filter for event */
548 	u_short		flags;
549 	u_int		fflags;
550 	int32_t		data;
551 	u_int32_t	udata;		/* opaque user data identifier */
552 };
553 
554 CTASSERT(sizeof(struct kevent32) == 20);
555 
556 int
557 freebsd32_kevent(struct thread *td, struct freebsd32_kevent_args *uap)
558 {
559 	struct timespec32 ts32;
560 	struct timespec ts, *tsp;
561 	struct kevent *ks;
562 	struct kevent32 ks32;
563 	struct kevent *changes, *events;
564 	int error, i;
565 
566 
567 	if (uap->timeout) {
568 		error = copyin(uap->timeout, &ts32, sizeof(ts32));
569 		if (error)
570 			return (error);
571 		CP(ts32, ts, tv_sec);
572 		CP(ts32, ts, tv_nsec);
573 		tsp = &ts;
574 	} else
575 		tsp = NULL;
576 	if (uap->changelist && uap->nchanges > 0) {
577 		changes = malloc(sizeof(struct kevent) * uap->nchanges, M_TEMP,
578 		    M_WAITOK);
579 		for (i = 0; i < uap->nchanges; i++) {
580 			error = copyin(&uap->changelist[i], &ks32,
581 			    sizeof(ks32));
582 			if (error) {
583 				free(changes, M_TEMP);
584 				return (error);
585 			}
586 			ks = &changes[i];
587 			CP(ks32, *ks, ident);
588 			CP(ks32, *ks, filter);
589 			CP(ks32, *ks, flags);
590 			CP(ks32, *ks, fflags);
591 			CP(ks32, *ks, data);
592 			PTRIN_CP(ks32, *ks, udata);
593 		}
594 	} else
595 		changes = NULL;
596 	if (uap->eventlist && uap->nevents > 0)
597 		events = malloc(sizeof(struct kevent) * uap->nevents, M_TEMP,
598 		    M_WAITOK);
599 	else
600 		events = NULL;
601 	error = kern_kevent(td, uap->fd, changes, uap->nchanges, UIO_SYSSPACE,
602 	    events, uap->nevents, UIO_SYSSPACE, tsp);
603 	free(changes, M_TEMP);
604 	if (uap->eventlist && events && td->td_retval[0] > 0) {
605 		for (i = 0; i < td->td_retval[0]; i++) {
606 			ks = &events[i];
607 			CP(*ks, ks32, ident);
608 			CP(*ks, ks32, filter);
609 			CP(*ks, ks32, flags);
610 			CP(*ks, ks32, fflags);
611 			CP(*ks, ks32, data);
612 			PTROUT_CP(*ks, ks32, udata);
613 			error = copyout(&ks32, &uap->eventlist[i],
614 			    sizeof(ks32));
615 			if (error)
616 				break;
617 		}
618 	}
619 	if (events)
620 		free(events, M_TEMP);
621 	return (error);
622 }
623 
624 int
625 freebsd32_gettimeofday(struct thread *td,
626 		       struct freebsd32_gettimeofday_args *uap)
627 {
628 	struct timeval atv;
629 	struct timeval32 atv32;
630 	struct timezone rtz;
631 	int error = 0;
632 
633 	if (uap->tp) {
634 		microtime(&atv);
635 		CP(atv, atv32, tv_sec);
636 		CP(atv, atv32, tv_usec);
637 		error = copyout(&atv32, uap->tp, sizeof (atv32));
638 	}
639 	if (error == 0 && uap->tzp != NULL) {
640 		rtz.tz_minuteswest = tz_minuteswest;
641 		rtz.tz_dsttime = tz_dsttime;
642 		error = copyout(&rtz, uap->tzp, sizeof (rtz));
643 	}
644 	return (error);
645 }
646 
647 int
648 freebsd32_getrusage(struct thread *td, struct freebsd32_getrusage_args *uap)
649 {
650 	struct rusage32 s32;
651 	struct rusage s;
652 	int error;
653 
654 	error = kern_getrusage(td, uap->who, &s);
655 	if (error)
656 		return (error);
657 	if (uap->rusage != NULL) {
658 		TV_CP(s, s32, ru_utime);
659 		TV_CP(s, s32, ru_stime);
660 		CP(s, s32, ru_maxrss);
661 		CP(s, s32, ru_ixrss);
662 		CP(s, s32, ru_idrss);
663 		CP(s, s32, ru_isrss);
664 		CP(s, s32, ru_minflt);
665 		CP(s, s32, ru_majflt);
666 		CP(s, s32, ru_nswap);
667 		CP(s, s32, ru_inblock);
668 		CP(s, s32, ru_oublock);
669 		CP(s, s32, ru_msgsnd);
670 		CP(s, s32, ru_msgrcv);
671 		CP(s, s32, ru_nsignals);
672 		CP(s, s32, ru_nvcsw);
673 		CP(s, s32, ru_nivcsw);
674 		error = copyout(&s32, uap->rusage, sizeof(s32));
675 	}
676 	return (error);
677 }
678 
679 struct iovec32 {
680 	u_int32_t iov_base;
681 	int	iov_len;
682 };
683 
684 CTASSERT(sizeof(struct iovec32) == 8);
685 
686 static int
687 freebsd32_copyinuio(struct iovec32 *iovp, u_int iovcnt, struct uio **uiop)
688 {
689 	struct iovec32 iov32;
690 	struct iovec *iov;
691 	struct uio *uio;
692 	u_int iovlen;
693 	int error, i;
694 
695 	*uiop = NULL;
696 	if (iovcnt > UIO_MAXIOV)
697 		return (EINVAL);
698 	iovlen = iovcnt * sizeof(struct iovec);
699 	uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK);
700 	iov = (struct iovec *)(uio + 1);
701 	for (i = 0; i < iovcnt; i++) {
702 		error = copyin(&iovp[i], &iov32, sizeof(struct iovec32));
703 		if (error) {
704 			free(uio, M_IOV);
705 			return (error);
706 		}
707 		iov[i].iov_base = PTRIN(iov32.iov_base);
708 		iov[i].iov_len = iov32.iov_len;
709 	}
710 	uio->uio_iov = iov;
711 	uio->uio_iovcnt = iovcnt;
712 	uio->uio_segflg = UIO_USERSPACE;
713 	uio->uio_offset = -1;
714 	uio->uio_resid = 0;
715 	for (i = 0; i < iovcnt; i++) {
716 		if (iov->iov_len > INT_MAX - uio->uio_resid) {
717 			free(uio, M_IOV);
718 			return (EINVAL);
719 		}
720 		uio->uio_resid += iov->iov_len;
721 		iov++;
722 	}
723 	*uiop = uio;
724 	return (0);
725 }
726 
727 int
728 freebsd32_readv(struct thread *td, struct freebsd32_readv_args *uap)
729 {
730 	struct uio *auio;
731 	int error;
732 
733 	error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio);
734 	if (error)
735 		return (error);
736 	error = kern_readv(td, uap->fd, auio);
737 	free(auio, M_IOV);
738 	return (error);
739 }
740 
741 int
742 freebsd32_writev(struct thread *td, struct freebsd32_writev_args *uap)
743 {
744 	struct uio *auio;
745 	int error;
746 
747 	error = freebsd32_copyinuio(uap->iovp, uap->iovcnt, &auio);
748 	if (error)
749 		return (error);
750 	error = kern_writev(td, uap->fd, auio);
751 	free(auio, M_IOV);
752 	return (error);
753 }
754 
755 int
756 freebsd32_settimeofday(struct thread *td,
757 		       struct freebsd32_settimeofday_args *uap)
758 {
759 	struct timeval32 tv32;
760 	struct timeval tv, *tvp;
761 	struct timezone tz, *tzp;
762 	int error;
763 
764 	if (uap->tv) {
765 		error = copyin(uap->tv, &tv32, sizeof(tv32));
766 		if (error)
767 			return (error);
768 		CP(tv32, tv, tv_sec);
769 		CP(tv32, tv, tv_usec);
770 		tvp = &tv;
771 	} else
772 		tvp = NULL;
773 	if (uap->tzp) {
774 		error = copyin(uap->tzp, &tz, sizeof(tz));
775 		if (error)
776 			return (error);
777 		tzp = &tz;
778 	} else
779 		tzp = NULL;
780 	return (kern_settimeofday(td, tvp, tzp));
781 }
782 
783 int
784 freebsd32_utimes(struct thread *td, struct freebsd32_utimes_args *uap)
785 {
786 	struct timeval32 s32[2];
787 	struct timeval s[2], *sp;
788 	int error;
789 
790 	if (uap->tptr != NULL) {
791 		error = copyin(uap->tptr, s32, sizeof(s32));
792 		if (error)
793 			return (error);
794 		CP(s32[0], s[0], tv_sec);
795 		CP(s32[0], s[0], tv_usec);
796 		CP(s32[1], s[1], tv_sec);
797 		CP(s32[1], s[1], tv_usec);
798 		sp = s;
799 	} else
800 		sp = NULL;
801 	return (kern_utimes(td, uap->path, UIO_USERSPACE, sp, UIO_SYSSPACE));
802 }
803 
804 int
805 freebsd32_adjtime(struct thread *td, struct freebsd32_adjtime_args *uap)
806 {
807 	struct timeval32 tv32;
808 	struct timeval delta, olddelta, *deltap;
809 	int error;
810 
811 	if (uap->delta) {
812 		error = copyin(uap->delta, &tv32, sizeof(tv32));
813 		if (error)
814 			return (error);
815 		CP(tv32, delta, tv_sec);
816 		CP(tv32, delta, tv_usec);
817 		deltap = &delta;
818 	} else
819 		deltap = NULL;
820 	error = kern_adjtime(td, deltap, &olddelta);
821 	if (uap->olddelta && error == 0) {
822 		CP(olddelta, tv32, tv_sec);
823 		CP(olddelta, tv32, tv_usec);
824 		error = copyout(&tv32, uap->olddelta, sizeof(tv32));
825 	}
826 	return (error);
827 }
828 
829 #ifdef COMPAT_FREEBSD4
830 int
831 freebsd4_freebsd32_statfs(struct thread *td, struct freebsd4_freebsd32_statfs_args *uap)
832 {
833 	struct statfs32 s32;
834 	struct statfs s;
835 	int error;
836 
837 	error = kern_statfs(td, uap->path, UIO_USERSPACE, &s);
838 	if (error)
839 		return (error);
840 	copy_statfs(&s, &s32);
841 	return (copyout(&s32, uap->buf, sizeof(s32)));
842 }
843 #endif
844 
845 #ifdef COMPAT_FREEBSD4
846 int
847 freebsd4_freebsd32_fstatfs(struct thread *td, struct freebsd4_freebsd32_fstatfs_args *uap)
848 {
849 	struct statfs32 s32;
850 	struct statfs s;
851 	int error;
852 
853 	error = kern_fstatfs(td, uap->fd, &s);
854 	if (error)
855 		return (error);
856 	copy_statfs(&s, &s32);
857 	return (copyout(&s32, uap->buf, sizeof(s32)));
858 }
859 #endif
860 
861 #ifdef COMPAT_FREEBSD4
862 int
863 freebsd4_freebsd32_fhstatfs(struct thread *td, struct freebsd4_freebsd32_fhstatfs_args *uap)
864 {
865 	struct statfs32 s32;
866 	struct statfs s;
867 	fhandle_t fh;
868 	int error;
869 
870 	if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0)
871 		return (error);
872 	error = kern_fhstatfs(td, fh, &s);
873 	if (error)
874 		return (error);
875 	copy_statfs(&s, &s32);
876 	return (copyout(&s32, uap->buf, sizeof(s32)));
877 }
878 #endif
879 
880 int
881 freebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap)
882 {
883 	/*
884 	 * Vector through to semsys if it is loaded.
885 	 */
886 	return sysent[169].sy_call(td, uap);
887 }
888 
889 int
890 freebsd32_msgsys(struct thread *td, struct freebsd32_msgsys_args *uap)
891 {
892 	/*
893 	 * Vector through to msgsys if it is loaded.
894 	 */
895 	return sysent[170].sy_call(td, uap);
896 }
897 
898 int
899 freebsd32_shmsys(struct thread *td, struct freebsd32_shmsys_args *uap)
900 {
901 	/*
902 	 * Vector through to shmsys if it is loaded.
903 	 */
904 	return sysent[171].sy_call(td, uap);
905 }
906 
907 int
908 freebsd32_pread(struct thread *td, struct freebsd32_pread_args *uap)
909 {
910 	struct pread_args ap;
911 
912 	ap.fd = uap->fd;
913 	ap.buf = uap->buf;
914 	ap.nbyte = uap->nbyte;
915 	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
916 	return (pread(td, &ap));
917 }
918 
919 int
920 freebsd32_pwrite(struct thread *td, struct freebsd32_pwrite_args *uap)
921 {
922 	struct pwrite_args ap;
923 
924 	ap.fd = uap->fd;
925 	ap.buf = uap->buf;
926 	ap.nbyte = uap->nbyte;
927 	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
928 	return (pwrite(td, &ap));
929 }
930 
931 int
932 freebsd32_lseek(struct thread *td, struct freebsd32_lseek_args *uap)
933 {
934 	int error;
935 	struct lseek_args ap;
936 	off_t pos;
937 
938 	ap.fd = uap->fd;
939 	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
940 	ap.whence = uap->whence;
941 	error = lseek(td, &ap);
942 	/* Expand the quad return into two parts for eax and edx */
943 	pos = *(off_t *)(td->td_retval);
944 	td->td_retval[0] = pos & 0xffffffff;	/* %eax */
945 	td->td_retval[1] = pos >> 32;		/* %edx */
946 	return error;
947 }
948 
949 int
950 freebsd32_truncate(struct thread *td, struct freebsd32_truncate_args *uap)
951 {
952 	struct truncate_args ap;
953 
954 	ap.path = uap->path;
955 	ap.length = (uap->lengthlo | ((off_t)uap->lengthhi << 32));
956 	return (truncate(td, &ap));
957 }
958 
959 int
960 freebsd32_ftruncate(struct thread *td, struct freebsd32_ftruncate_args *uap)
961 {
962 	struct ftruncate_args ap;
963 
964 	ap.fd = uap->fd;
965 	ap.length = (uap->lengthlo | ((off_t)uap->lengthhi << 32));
966 	return (ftruncate(td, &ap));
967 }
968 
969 #ifdef COMPAT_FREEBSD4
970 int
971 freebsd4_freebsd32_sendfile(struct thread *td,
972     struct freebsd4_freebsd32_sendfile_args *uap)
973 {
974 	struct freebsd4_sendfile_args ap;
975 
976 	ap.fd = uap->fd;
977 	ap.s = uap->s;
978 	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
979 	ap.nbytes = uap->nbytes;	/* XXX check */
980 	ap.hdtr = uap->hdtr;		/* XXX check */
981 	ap.sbytes = uap->sbytes;	/* XXX FIXME!! */
982 	ap.flags = uap->flags;
983 	return (freebsd4_sendfile(td, &ap));
984 }
985 #endif
986 
987 int
988 freebsd32_sendfile(struct thread *td, struct freebsd32_sendfile_args *uap)
989 {
990 	struct sendfile_args ap;
991 
992 	ap.fd = uap->fd;
993 	ap.s = uap->s;
994 	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
995 	ap.nbytes = uap->nbytes;	/* XXX check */
996 	ap.hdtr = uap->hdtr;		/* XXX check */
997 	ap.sbytes = uap->sbytes;	/* XXX FIXME!! */
998 	ap.flags = uap->flags;
999 	return (sendfile(td, &ap));
1000 }
1001 
1002 struct stat32 {
1003 	dev_t	st_dev;
1004 	ino_t	st_ino;
1005 	mode_t	st_mode;
1006 	nlink_t	st_nlink;
1007 	uid_t	st_uid;
1008 	gid_t	st_gid;
1009 	dev_t	st_rdev;
1010 	struct timespec32 st_atimespec;
1011 	struct timespec32 st_mtimespec;
1012 	struct timespec32 st_ctimespec;
1013 	off_t	st_size;
1014 	int64_t	st_blocks;
1015 	u_int32_t st_blksize;
1016 	u_int32_t st_flags;
1017 	u_int32_t st_gen;
1018 	struct timespec32 st_birthtimespec;
1019 	unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec32));
1020 	unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec32));
1021 };
1022 
1023 
1024 CTASSERT(sizeof(struct stat32) == 96);
1025 
1026 static void
1027 copy_stat( struct stat *in, struct stat32 *out)
1028 {
1029 	CP(*in, *out, st_dev);
1030 	CP(*in, *out, st_ino);
1031 	CP(*in, *out, st_mode);
1032 	CP(*in, *out, st_nlink);
1033 	CP(*in, *out, st_uid);
1034 	CP(*in, *out, st_gid);
1035 	CP(*in, *out, st_rdev);
1036 	TS_CP(*in, *out, st_atimespec);
1037 	TS_CP(*in, *out, st_mtimespec);
1038 	TS_CP(*in, *out, st_ctimespec);
1039 	CP(*in, *out, st_size);
1040 	CP(*in, *out, st_blocks);
1041 	CP(*in, *out, st_blksize);
1042 	CP(*in, *out, st_flags);
1043 	CP(*in, *out, st_gen);
1044 }
1045 
1046 int
1047 freebsd32_stat(struct thread *td, struct freebsd32_stat_args *uap)
1048 {
1049 	struct stat sb;
1050 	struct stat32 sb32;
1051 	int error;
1052 
1053 	error = kern_stat(td, uap->path, UIO_USERSPACE, &sb);
1054 	if (error)
1055 		return (error);
1056 	copy_stat(&sb, &sb32);
1057 	error = copyout(&sb32, uap->ub, sizeof (sb32));
1058 	return (error);
1059 }
1060 
1061 int
1062 freebsd32_fstat(struct thread *td, struct freebsd32_fstat_args *uap)
1063 {
1064 	struct stat ub;
1065 	struct stat32 ub32;
1066 	int error;
1067 
1068 	error = kern_fstat(td, uap->fd, &ub);
1069 	if (error)
1070 		return (error);
1071 	copy_stat(&ub, &ub32);
1072 	error = copyout(&ub32, uap->ub, sizeof(ub32));
1073 	return (error);
1074 }
1075 
1076 int
1077 freebsd32_lstat(struct thread *td, struct freebsd32_lstat_args *uap)
1078 {
1079 	struct stat sb;
1080 	struct stat32 sb32;
1081 	int error;
1082 
1083 	error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb);
1084 	if (error)
1085 		return (error);
1086 	copy_stat(&sb, &sb32);
1087 	error = copyout(&sb32, uap->ub, sizeof (sb32));
1088 	return (error);
1089 }
1090 
1091 /*
1092  * MPSAFE
1093  */
1094 int
1095 freebsd32_sysctl(struct thread *td, struct freebsd32_sysctl_args *uap)
1096 {
1097 	int error, name[CTL_MAXNAME];
1098 	size_t j, oldlen;
1099 
1100 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
1101 		return (EINVAL);
1102  	error = copyin(uap->name, name, uap->namelen * sizeof(int));
1103  	if (error)
1104 		return (error);
1105 	mtx_lock(&Giant);
1106 	if (uap->oldlenp)
1107 		oldlen = fuword32(uap->oldlenp);
1108 	else
1109 		oldlen = 0;
1110 	error = userland_sysctl(td, name, uap->namelen,
1111 		uap->old, &oldlen, 1,
1112 		uap->new, uap->newlen, &j, SCTL_MASK32);
1113 	if (error && error != ENOMEM)
1114 		goto done2;
1115 	if (uap->oldlenp)
1116 		suword32(uap->oldlenp, j);
1117 done2:
1118 	mtx_unlock(&Giant);
1119 	return (error);
1120 }
1121 
1122 struct sigaction32 {
1123 	u_int32_t	sa_u;
1124 	int		sa_flags;
1125 	sigset_t	sa_mask;
1126 };
1127 
1128 CTASSERT(sizeof(struct sigaction32) == 24);
1129 
1130 int
1131 freebsd32_sigaction(struct thread *td, struct freebsd32_sigaction_args *uap)
1132 {
1133 	struct sigaction32 s32;
1134 	struct sigaction sa, osa, *sap;
1135 	int error;
1136 
1137 	if (uap->act) {
1138 		error = copyin(uap->act, &s32, sizeof(s32));
1139 		if (error)
1140 			return (error);
1141 		sa.sa_handler = PTRIN(s32.sa_u);
1142 		CP(s32, sa, sa_flags);
1143 		CP(s32, sa, sa_mask);
1144 		sap = &sa;
1145 	} else
1146 		sap = NULL;
1147 	error = kern_sigaction(td, uap->sig, sap, &osa, 0);
1148 	if (error != 0 && uap->oact != NULL) {
1149 		s32.sa_u = PTROUT(osa.sa_handler);
1150 		CP(osa, s32, sa_flags);
1151 		CP(osa, s32, sa_mask);
1152 		error = copyout(&s32, uap->oact, sizeof(s32));
1153 	}
1154 	return (error);
1155 }
1156 
1157 #ifdef COMPAT_FREEBSD4
1158 int
1159 freebsd4_freebsd32_sigaction(struct thread *td,
1160 			     struct freebsd4_freebsd32_sigaction_args *uap)
1161 {
1162 	struct sigaction32 s32;
1163 	struct sigaction sa, osa, *sap;
1164 	int error;
1165 
1166 	if (uap->act) {
1167 		error = copyin(uap->act, &s32, sizeof(s32));
1168 		if (error)
1169 			return (error);
1170 		sa.sa_handler = PTRIN(s32.sa_u);
1171 		CP(s32, sa, sa_flags);
1172 		CP(s32, sa, sa_mask);
1173 		sap = &sa;
1174 	} else
1175 		sap = NULL;
1176 	error = kern_sigaction(td, uap->sig, sap, &osa, KSA_FREEBSD4);
1177 	if (error != 0 && uap->oact != NULL) {
1178 		s32.sa_u = PTROUT(osa.sa_handler);
1179 		CP(osa, s32, sa_flags);
1180 		CP(osa, s32, sa_mask);
1181 		error = copyout(&s32, uap->oact, sizeof(s32));
1182 	}
1183 	return (error);
1184 }
1185 #endif
1186 
1187 int
1188 freebsd32_nanosleep(struct thread *td, struct freebsd32_nanosleep_args *uap)
1189 {
1190 	struct timespec32 rmt32, rqt32;
1191 	struct timespec rmt, rqt;
1192 	int error;
1193 
1194 	error = copyin(uap->rqtp, &rqt32, sizeof(rqt));
1195 	if (error)
1196 		return (error);
1197 
1198 	CP(rqt32, rqt, tv_sec);
1199 	CP(rqt32, rqt, tv_nsec);
1200 
1201 	if (uap->rmtp &&
1202 	    !useracc((caddr_t)uap->rmtp, sizeof(rmt), VM_PROT_WRITE))
1203 		return (EFAULT);
1204 	error = kern_nanosleep(td, &rqt, &rmt);
1205 	if (error && uap->rmtp) {
1206 		int error2;
1207 
1208 		CP(rmt, rmt32, tv_sec);
1209 		CP(rmt, rmt32, tv_nsec);
1210 
1211 		error2 = copyout(&rmt32, uap->rmtp, sizeof(rmt));
1212 		if (error2)
1213 			error = error2;
1214 	}
1215 	return (error);
1216 }
1217 
1218 #if 0
1219 
1220 int
1221 freebsd32_xxx(struct thread *td, struct freebsd32_xxx_args *uap)
1222 {
1223 	int error;
1224 	caddr_t sg;
1225 	struct yyy32 *p32, s32;
1226 	struct yyy *p = NULL, s;
1227 
1228 	p32 = uap->zzz;
1229 	if (p32) {
1230 		sg = stackgap_init();
1231 		p = stackgap_alloc(&sg, sizeof(struct yyy));
1232 		uap->zzz = (struct yyy32 *)p;
1233 		error = copyin(p32, &s32, sizeof(s32));
1234 		if (error)
1235 			return (error);
1236 		/* translate in */
1237 		error = copyout(&s, p, sizeof(s));
1238 		if (error)
1239 			return (error);
1240 	}
1241 	error = xxx(td, (struct xxx_args *) uap);
1242 	if (error)
1243 		return (error);
1244 	if (p32) {
1245 		error = copyin(p, &s, sizeof(s));
1246 		if (error)
1247 			return (error);
1248 		/* translate out */
1249 		error = copyout(&s32, p32, sizeof(s32));
1250 	}
1251 	return (error);
1252 }
1253 
1254 #endif
1255