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