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