freebsd32_misc.c revision 123746
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 123746 2003-12-23 03:20:49Z 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
71#include <vm/vm.h>
72#include <vm/vm_kern.h>
73#include <vm/vm_param.h>
74#include <vm/pmap.h>
75#include <vm/vm_map.h>
76#include <vm/vm_object.h>
77#include <vm/vm_extern.h>
78
79#include <compat/freebsd32/freebsd32_util.h>
80#include <compat/freebsd32/freebsd32.h>
81#include <compat/freebsd32/freebsd32_proto.h>
82
83CTASSERT(sizeof(struct timeval32) == 8);
84CTASSERT(sizeof(struct timespec32) == 8);
85CTASSERT(sizeof(struct statfs32) == 256);
86CTASSERT(sizeof(struct rusage32) == 72);
87
88int
89freebsd32_wait4(struct thread *td, struct freebsd32_wait4_args *uap)
90{
91	int error;
92	caddr_t sg;
93	struct rusage32 *rusage32, ru32;
94	struct rusage *rusage = NULL, ru;
95
96	rusage32 = uap->rusage;
97	if (rusage32) {
98		sg = stackgap_init();
99		rusage = stackgap_alloc(&sg, sizeof(struct rusage));
100		uap->rusage = (struct rusage32 *)rusage;
101	}
102	error = wait4(td, (struct wait_args *)uap);
103	if (error)
104		return (error);
105	if (rusage32 && (error = copyin(rusage, &ru, sizeof(ru)) == 0)) {
106		TV_CP(ru, ru32, ru_utime);
107		TV_CP(ru, ru32, ru_stime);
108		CP(ru, ru32, ru_maxrss);
109		CP(ru, ru32, ru_ixrss);
110		CP(ru, ru32, ru_idrss);
111		CP(ru, ru32, ru_isrss);
112		CP(ru, ru32, ru_minflt);
113		CP(ru, ru32, ru_majflt);
114		CP(ru, ru32, ru_nswap);
115		CP(ru, ru32, ru_inblock);
116		CP(ru, ru32, ru_oublock);
117		CP(ru, ru32, ru_msgsnd);
118		CP(ru, ru32, ru_msgrcv);
119		CP(ru, ru32, ru_nsignals);
120		CP(ru, ru32, ru_nvcsw);
121		CP(ru, ru32, ru_nivcsw);
122		error = copyout(&ru32, rusage32, sizeof(ru32));
123	}
124	return (error);
125}
126
127static void
128copy_statfs(struct statfs *in, struct statfs32 *out)
129{
130	CP(*in, *out, f_bsize);
131	CP(*in, *out, f_iosize);
132	CP(*in, *out, f_blocks);
133	CP(*in, *out, f_bfree);
134	CP(*in, *out, f_bavail);
135	CP(*in, *out, f_files);
136	CP(*in, *out, f_ffree);
137	CP(*in, *out, f_fsid);
138	CP(*in, *out, f_owner);
139	CP(*in, *out, f_type);
140	CP(*in, *out, f_flags);
141	CP(*in, *out, f_flags);
142	CP(*in, *out, f_syncwrites);
143	CP(*in, *out, f_asyncwrites);
144	bcopy(in->f_fstypename,
145	      out->f_fstypename, MFSNAMELEN);
146	bcopy(in->f_mntonname,
147	      out->f_mntonname, MNAMELEN);
148	CP(*in, *out, f_syncreads);
149	CP(*in, *out, f_asyncreads);
150	bcopy(in->f_mntfromname,
151	      out->f_mntfromname, MNAMELEN);
152}
153
154int
155freebsd32_getfsstat(struct thread *td, struct freebsd32_getfsstat_args *uap)
156{
157	int error;
158	caddr_t sg;
159	struct statfs32 *sp32, stat32;
160	struct statfs *sp = NULL, stat;
161	int maxcount, count, i;
162
163	sp32 = uap->buf;
164	maxcount = uap->bufsize / sizeof(struct statfs32);
165
166	if (sp32) {
167		sg = stackgap_init();
168		sp = stackgap_alloc(&sg, sizeof(struct statfs) * maxcount);
169		uap->buf = (struct statfs32 *)sp;
170	}
171	error = getfsstat(td, (struct getfsstat_args *) uap);
172	if (sp32 && !error) {
173		count = td->td_retval[0];
174		for (i = 0; i < count; i++) {
175			error = copyin(&sp[i], &stat, sizeof(stat));
176			if (error)
177				return (error);
178			copy_statfs(&stat, &stat32);
179			error = copyout(&stat32, &sp32[i], sizeof(stat32));
180			if (error)
181				return (error);
182		}
183	}
184	return (error);
185}
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_select(struct thread *td, struct freebsd32_select_args *uap)
479{
480	int error;
481	caddr_t sg;
482	struct timeval32 *p32, s32;
483	struct timeval *p = NULL, s;
484
485	p32 = uap->tv;
486	if (p32) {
487		sg = stackgap_init();
488		p = stackgap_alloc(&sg, sizeof(struct timeval));
489		uap->tv = (struct timeval32 *)p;
490		error = copyin(p32, &s32, sizeof(s32));
491		if (error)
492			return (error);
493		CP(s32, s, tv_sec);
494		CP(s32, s, tv_usec);
495		error = copyout(&s, p, sizeof(s));
496		if (error)
497			return (error);
498	}
499	/*
500	 * XXX big-endian needs to convert the fd_sets too.
501	 */
502	return (select(td, (struct select_args *) uap));
503}
504
505struct kevent32 {
506	u_int32_t	ident;		/* identifier for this event */
507	short		filter;		/* filter for event */
508	u_short		flags;
509	u_int		fflags;
510	int32_t		data;
511	u_int32_t	udata;		/* opaque user data identifier */
512};
513
514CTASSERT(sizeof(struct kevent32) == 20);
515
516int
517freebsd32_kevent(struct thread *td, struct freebsd32_kevent_args *uap)
518{
519	int error;
520	caddr_t sg;
521	struct timespec32 ts32;
522	struct timespec ts;
523	struct kevent32 ks32;
524	struct kevent *ks;
525	struct kevent_args a;
526	int i;
527
528	sg = stackgap_init();
529
530	a.fd = uap->fd;
531	a.changelist = uap->changelist;
532	a.nchanges = uap->nchanges;
533	a.eventlist = uap->eventlist;
534	a.nevents = uap->nevents;
535	a.timeout = NULL;
536
537	if (uap->timeout) {
538		a.timeout = stackgap_alloc(&sg, sizeof(struct timespec));
539		error = copyin(uap->timeout, &ts32, sizeof(ts32));
540		if (error)
541			return (error);
542		CP(ts32, ts, tv_sec);
543		CP(ts32, ts, tv_nsec);
544		error = copyout(&ts, (void *)(uintptr_t)a.timeout, sizeof(ts));
545		if (error)
546			return (error);
547	}
548	if (uap->changelist) {
549		a.changelist = (struct kevent *)stackgap_alloc(&sg,
550		    uap->nchanges * sizeof(struct kevent));
551		for (i = 0; i < uap->nchanges; i++) {
552			error = copyin(&uap->changelist[i], &ks32,
553			    sizeof(ks32));
554			if (error)
555				return (error);
556			ks = (struct kevent *)(uintptr_t)&a.changelist[i];
557			CP(ks32, *ks, ident);
558			CP(ks32, *ks, filter);
559			CP(ks32, *ks, flags);
560			CP(ks32, *ks, fflags);
561			CP(ks32, *ks, data);
562			PTRIN_CP(ks32, *ks, udata);
563		}
564	}
565	if (uap->eventlist) {
566		a.eventlist = stackgap_alloc(&sg,
567		    uap->nevents * sizeof(struct kevent));
568	}
569	error = kevent(td, &a);
570	if (uap->eventlist && error > 0) {
571		for (i = 0; i < error; i++) {
572			ks = &a.eventlist[i];
573			CP(*ks, ks32, ident);
574			CP(*ks, ks32, filter);
575			CP(*ks, ks32, flags);
576			CP(*ks, ks32, fflags);
577			CP(*ks, ks32, data);
578			PTROUT_CP(*ks, ks32, udata);
579			error = copyout(&ks32, &uap->eventlist[i],
580			    sizeof(ks32));
581			if (error)
582				return (error);
583		}
584	}
585	return error;
586}
587
588int
589freebsd32_gettimeofday(struct thread *td,
590		       struct freebsd32_gettimeofday_args *uap)
591{
592	struct timeval atv;
593	struct timeval32 atv32;
594	struct timezone rtz;
595	int error = 0;
596
597	if (uap->tp) {
598		microtime(&atv);
599		CP(atv, atv32, tv_sec);
600		CP(atv, atv32, tv_usec);
601		error = copyout(&atv32, uap->tp, sizeof (atv32));
602	}
603	if (error == 0 && uap->tzp != NULL) {
604		rtz.tz_minuteswest = tz_minuteswest;
605		rtz.tz_dsttime = tz_dsttime;
606		error = copyout(&rtz, uap->tzp, sizeof (rtz));
607	}
608	return (error);
609}
610
611int
612freebsd32_getrusage(struct thread *td, struct freebsd32_getrusage_args *uap)
613{
614	int error;
615	caddr_t sg;
616	struct rusage32 *p32, s32;
617	struct rusage *p = NULL, s;
618
619	p32 = uap->rusage;
620	if (p32) {
621		sg = stackgap_init();
622		p = stackgap_alloc(&sg, sizeof(struct rusage));
623		uap->rusage = (struct rusage32 *)p;
624	}
625	error = getrusage(td, (struct getrusage_args *) uap);
626	if (error)
627		return (error);
628	if (p32) {
629		error = copyin(p, &s, sizeof(s));
630		if (error)
631			return (error);
632		TV_CP(s, s32, ru_utime);
633		TV_CP(s, s32, ru_stime);
634		CP(s, s32, ru_maxrss);
635		CP(s, s32, ru_ixrss);
636		CP(s, s32, ru_idrss);
637		CP(s, s32, ru_isrss);
638		CP(s, s32, ru_minflt);
639		CP(s, s32, ru_majflt);
640		CP(s, s32, ru_nswap);
641		CP(s, s32, ru_inblock);
642		CP(s, s32, ru_oublock);
643		CP(s, s32, ru_msgsnd);
644		CP(s, s32, ru_msgrcv);
645		CP(s, s32, ru_nsignals);
646		CP(s, s32, ru_nvcsw);
647		CP(s, s32, ru_nivcsw);
648		error = copyout(&s32, p32, sizeof(s32));
649	}
650	return (error);
651}
652
653struct iovec32 {
654	u_int32_t iov_base;
655	int	iov_len;
656};
657#define	STACKGAPLEN	400
658
659CTASSERT(sizeof(struct iovec32) == 8);
660
661int
662freebsd32_readv(struct thread *td, struct freebsd32_readv_args *uap)
663{
664	int error, osize, nsize, i;
665	caddr_t sg;
666	struct readv_args /* {
667		syscallarg(int) fd;
668		syscallarg(struct iovec *) iovp;
669		syscallarg(u_int) iovcnt;
670	} */ a;
671	struct iovec32 *oio;
672	struct iovec *nio;
673
674	sg = stackgap_init();
675
676	if (uap->iovcnt > (STACKGAPLEN / sizeof (struct iovec)))
677		return (EINVAL);
678
679	osize = uap->iovcnt * sizeof (struct iovec32);
680	nsize = uap->iovcnt * sizeof (struct iovec);
681
682	oio = malloc(osize, M_TEMP, M_WAITOK);
683	nio = malloc(nsize, M_TEMP, M_WAITOK);
684
685	error = 0;
686	if ((error = copyin(uap->iovp, oio, osize)))
687		goto punt;
688	for (i = 0; i < uap->iovcnt; i++) {
689		nio[i].iov_base = PTRIN(oio[i].iov_base);
690		nio[i].iov_len = oio[i].iov_len;
691	}
692
693	a.fd = uap->fd;
694	a.iovp = stackgap_alloc(&sg, nsize);
695	a.iovcnt = uap->iovcnt;
696
697	if ((error = copyout(nio, (caddr_t)a.iovp, nsize)))
698		goto punt;
699	error = readv(td, &a);
700
701punt:
702	free(oio, M_TEMP);
703	free(nio, M_TEMP);
704	return (error);
705}
706
707int
708freebsd32_writev(struct thread *td, struct freebsd32_writev_args *uap)
709{
710	int error, i, nsize, osize;
711	caddr_t sg;
712	struct writev_args /* {
713		syscallarg(int) fd;
714		syscallarg(struct iovec *) iovp;
715		syscallarg(u_int) iovcnt;
716	} */ a;
717	struct iovec32 *oio;
718	struct iovec *nio;
719
720	sg = stackgap_init();
721
722	if (uap->iovcnt > (STACKGAPLEN / sizeof (struct iovec)))
723		return (EINVAL);
724
725	osize = uap->iovcnt * sizeof (struct iovec32);
726	nsize = uap->iovcnt * sizeof (struct iovec);
727
728	oio = malloc(osize, M_TEMP, M_WAITOK);
729	nio = malloc(nsize, M_TEMP, M_WAITOK);
730
731	error = 0;
732	if ((error = copyin(uap->iovp, oio, osize)))
733		goto punt;
734	for (i = 0; i < uap->iovcnt; i++) {
735		nio[i].iov_base = PTRIN(oio[i].iov_base);
736		nio[i].iov_len = oio[i].iov_len;
737	}
738
739	a.fd = uap->fd;
740	a.iovp = stackgap_alloc(&sg, nsize);
741	a.iovcnt = uap->iovcnt;
742
743	if ((error = copyout(nio, (caddr_t)a.iovp, nsize)))
744		goto punt;
745	error = writev(td, &a);
746
747punt:
748	free(oio, M_TEMP);
749	free(nio, M_TEMP);
750	return (error);
751}
752
753int
754freebsd32_settimeofday(struct thread *td,
755		       struct freebsd32_settimeofday_args *uap)
756{
757	int error;
758	caddr_t sg;
759	struct timeval32 *p32, s32;
760	struct timeval *p = NULL, s;
761
762	p32 = uap->tv;
763	if (p32) {
764		sg = stackgap_init();
765		p = stackgap_alloc(&sg, sizeof(struct timeval));
766		uap->tv = (struct timeval32 *)p;
767		error = copyin(p32, &s32, sizeof(s32));
768		if (error)
769			return (error);
770		CP(s32, s, tv_sec);
771		CP(s32, s, tv_usec);
772		error = copyout(&s, p, sizeof(s));
773		if (error)
774			return (error);
775	}
776	return (settimeofday(td, (struct settimeofday_args *) uap));
777}
778
779int
780freebsd32_utimes(struct thread *td, struct freebsd32_utimes_args *uap)
781{
782	int error;
783	caddr_t sg;
784	struct timeval32 *p32, s32[2];
785	struct timeval *p = NULL, s[2];
786
787	p32 = uap->tptr;
788	if (p32) {
789		sg = stackgap_init();
790		p = stackgap_alloc(&sg, 2*sizeof(struct timeval));
791		uap->tptr = (struct timeval32 *)p;
792		error = copyin(p32, s32, sizeof(s32));
793		if (error)
794			return (error);
795		CP(s32[0], s[0], tv_sec);
796		CP(s32[0], s[0], tv_usec);
797		CP(s32[1], s[1], tv_sec);
798		CP(s32[1], s[1], tv_usec);
799		error = copyout(s, p, sizeof(s));
800		if (error)
801			return (error);
802	}
803	return (utimes(td, (struct utimes_args *) uap));
804}
805
806int
807freebsd32_adjtime(struct thread *td, struct freebsd32_adjtime_args *uap)
808{
809	int error;
810	caddr_t sg;
811	struct timeval32 *p32, *op32, s32;
812	struct timeval *p = NULL, *op = NULL, s;
813
814	p32 = uap->delta;
815	if (p32) {
816		sg = stackgap_init();
817		p = stackgap_alloc(&sg, sizeof(struct timeval));
818		uap->delta = (struct timeval32 *)p;
819		error = copyin(p32, &s32, sizeof(s32));
820		if (error)
821			return (error);
822		CP(s32, s, tv_sec);
823		CP(s32, s, tv_usec);
824		error = copyout(&s, p, sizeof(s));
825		if (error)
826			return (error);
827	}
828	op32 = uap->olddelta;
829	if (op32) {
830		sg = stackgap_init();
831		op = stackgap_alloc(&sg, sizeof(struct timeval));
832		uap->olddelta = (struct timeval32 *)op;
833	}
834	error = utimes(td, (struct utimes_args *) uap);
835	if (error)
836		return error;
837	if (op32) {
838		error = copyin(op, &s, sizeof(s));
839		if (error)
840			return (error);
841		CP(s, s32, tv_sec);
842		CP(s, s32, tv_usec);
843		error = copyout(&s32, op32, sizeof(s32));
844	}
845	return (error);
846}
847
848int
849freebsd32_statfs(struct thread *td, struct freebsd32_statfs_args *uap)
850{
851	int error;
852	caddr_t sg;
853	struct statfs32 *p32, s32;
854	struct statfs *p = NULL, s;
855
856	p32 = uap->buf;
857	if (p32) {
858		sg = stackgap_init();
859		p = stackgap_alloc(&sg, sizeof(struct statfs));
860		uap->buf = (struct statfs32 *)p;
861	}
862	error = statfs(td, (struct statfs_args *) uap);
863	if (error)
864		return (error);
865	if (p32) {
866		error = copyin(p, &s, sizeof(s));
867		if (error)
868			return (error);
869		copy_statfs(&s, &s32);
870		error = copyout(&s32, p32, sizeof(s32));
871	}
872	return (error);
873}
874
875int
876freebsd32_fstatfs(struct thread *td, struct freebsd32_fstatfs_args *uap)
877{
878	int error;
879	caddr_t sg;
880	struct statfs32 *p32, s32;
881	struct statfs *p = NULL, s;
882
883	p32 = uap->buf;
884	if (p32) {
885		sg = stackgap_init();
886		p = stackgap_alloc(&sg, sizeof(struct statfs));
887		uap->buf = (struct statfs32 *)p;
888	}
889	error = fstatfs(td, (struct fstatfs_args *) uap);
890	if (error)
891		return (error);
892	if (p32) {
893		error = copyin(p, &s, sizeof(s));
894		if (error)
895			return (error);
896		copy_statfs(&s, &s32);
897		error = copyout(&s32, p32, sizeof(s32));
898	}
899	return (error);
900}
901
902int
903freebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap)
904{
905	/*
906	 * Vector through to semsys if it is loaded.
907	 */
908	return sysent[169].sy_call(td, uap);
909}
910
911int
912freebsd32_msgsys(struct thread *td, struct freebsd32_msgsys_args *uap)
913{
914	/*
915	 * Vector through to msgsys if it is loaded.
916	 */
917	return sysent[170].sy_call(td, uap);
918}
919
920int
921freebsd32_shmsys(struct thread *td, struct freebsd32_shmsys_args *uap)
922{
923	/*
924	 * Vector through to shmsys if it is loaded.
925	 */
926	return sysent[171].sy_call(td, uap);
927}
928
929int
930freebsd32_pread(struct thread *td, struct freebsd32_pread_args *uap)
931{
932	struct pread_args ap;
933
934	ap.fd = uap->fd;
935	ap.buf = uap->buf;
936	ap.nbyte = uap->nbyte;
937	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
938	return (pread(td, &ap));
939}
940
941int
942freebsd32_pwrite(struct thread *td, struct freebsd32_pwrite_args *uap)
943{
944	struct pwrite_args ap;
945
946	ap.fd = uap->fd;
947	ap.buf = uap->buf;
948	ap.nbyte = uap->nbyte;
949	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
950	return (pwrite(td, &ap));
951}
952
953int
954freebsd32_lseek(struct thread *td, struct freebsd32_lseek_args *uap)
955{
956	int error;
957	struct lseek_args ap;
958	off_t pos;
959
960	ap.fd = uap->fd;
961	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
962	ap.whence = uap->whence;
963	error = lseek(td, &ap);
964	/* Expand the quad return into two parts for eax and edx */
965	pos = *(off_t *)(td->td_retval);
966	td->td_retval[0] = pos & 0xffffffff;	/* %eax */
967	td->td_retval[1] = pos >> 32;		/* %edx */
968	return error;
969}
970
971int
972freebsd32_truncate(struct thread *td, struct freebsd32_truncate_args *uap)
973{
974	struct truncate_args ap;
975
976	ap.path = uap->path;
977	ap.length = (uap->lengthlo | ((off_t)uap->lengthhi << 32));
978	return (truncate(td, &ap));
979}
980
981int
982freebsd32_ftruncate(struct thread *td, struct freebsd32_ftruncate_args *uap)
983{
984	struct ftruncate_args ap;
985
986	ap.fd = uap->fd;
987	ap.length = (uap->lengthlo | ((off_t)uap->lengthhi << 32));
988	return (ftruncate(td, &ap));
989}
990
991#ifdef COMPAT_FREEBSD4
992int
993freebsd4_freebsd32_sendfile(struct thread *td,
994    struct freebsd4_freebsd32_sendfile_args *uap)
995{
996	struct freebsd4_sendfile_args ap;
997
998	ap.fd = uap->fd;
999	ap.s = uap->s;
1000	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
1001	ap.nbytes = uap->nbytes;	/* XXX check */
1002	ap.hdtr = uap->hdtr;		/* XXX check */
1003	ap.sbytes = uap->sbytes;	/* XXX FIXME!! */
1004	ap.flags = uap->flags;
1005	return (freebsd4_sendfile(td, &ap));
1006}
1007#endif
1008
1009int
1010freebsd32_sendfile(struct thread *td, struct freebsd32_sendfile_args *uap)
1011{
1012	struct sendfile_args ap;
1013
1014	ap.fd = uap->fd;
1015	ap.s = uap->s;
1016	ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32));
1017	ap.nbytes = uap->nbytes;	/* XXX check */
1018	ap.hdtr = uap->hdtr;		/* XXX check */
1019	ap.sbytes = uap->sbytes;	/* XXX FIXME!! */
1020	ap.flags = uap->flags;
1021	return (sendfile(td, &ap));
1022}
1023
1024struct stat32 {
1025	udev_t	st_dev;
1026	ino_t	st_ino;
1027	mode_t	st_mode;
1028	nlink_t	st_nlink;
1029	uid_t	st_uid;
1030	gid_t	st_gid;
1031	udev_t	st_rdev;
1032	struct timespec32 st_atimespec;
1033	struct timespec32 st_mtimespec;
1034	struct timespec32 st_ctimespec;
1035	off_t	st_size;
1036	int64_t	st_blocks;
1037	u_int32_t st_blksize;
1038	u_int32_t st_flags;
1039	u_int32_t st_gen;
1040	struct timespec32 st_birthtimespec;
1041	unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec32));
1042	unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec32));
1043};
1044
1045
1046CTASSERT(sizeof(struct stat32) == 96);
1047
1048static void
1049copy_stat( struct stat *in, struct stat32 *out)
1050{
1051	CP(*in, *out, st_dev);
1052	CP(*in, *out, st_ino);
1053	CP(*in, *out, st_mode);
1054	CP(*in, *out, st_nlink);
1055	CP(*in, *out, st_uid);
1056	CP(*in, *out, st_gid);
1057	CP(*in, *out, st_rdev);
1058	TS_CP(*in, *out, st_atimespec);
1059	TS_CP(*in, *out, st_mtimespec);
1060	TS_CP(*in, *out, st_ctimespec);
1061	CP(*in, *out, st_size);
1062	CP(*in, *out, st_blocks);
1063	CP(*in, *out, st_blksize);
1064	CP(*in, *out, st_flags);
1065	CP(*in, *out, st_gen);
1066}
1067
1068int
1069freebsd32_stat(struct thread *td, struct freebsd32_stat_args *uap)
1070{
1071	struct stat sb;
1072	struct stat32 sb32;
1073	int error;
1074	struct nameidata nd;
1075
1076#ifdef LOOKUP_SHARED
1077	NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | NOOBJ,
1078	    UIO_USERSPACE, uap->path, td);
1079#else
1080	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1081	    uap->path, td);
1082#endif
1083	if ((error = namei(&nd)) != 0)
1084		return (error);
1085	error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
1086	NDFREE(&nd, NDF_ONLY_PNBUF);
1087	vput(nd.ni_vp);
1088	if (error)
1089		return (error);
1090	copy_stat(&sb, &sb32);
1091	error = copyout(&sb32, uap->ub, sizeof (sb32));
1092	return (error);
1093}
1094
1095int
1096freebsd32_fstat(struct thread *td, struct freebsd32_fstat_args *uap)
1097{
1098	struct file *fp;
1099	struct stat ub;
1100	struct stat32 ub32;
1101	int error;
1102
1103	if ((error = fget(td, uap->fd, &fp)) != 0)
1104		return (error);
1105	mtx_lock(&Giant);
1106	error = fo_stat(fp, &ub, td->td_ucred, td);
1107	mtx_unlock(&Giant);
1108	fdrop(fp, td);
1109	if (error)
1110		return (error);
1111	copy_stat(&ub, &ub32);
1112	error = copyout(&ub32, uap->ub, sizeof(ub32));
1113	return (error);
1114}
1115
1116int
1117freebsd32_lstat(struct thread *td, struct freebsd32_lstat_args *uap)
1118{
1119	int error;
1120	struct vnode *vp;
1121	struct stat sb;
1122	struct stat32 sb32;
1123	struct nameidata nd;
1124
1125	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1126	    uap->path, td);
1127	if ((error = namei(&nd)) != 0)
1128		return (error);
1129	vp = nd.ni_vp;
1130	error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
1131	NDFREE(&nd, NDF_ONLY_PNBUF);
1132	vput(vp);
1133	if (error)
1134		return (error);
1135	copy_stat(&sb, &sb32);
1136	error = copyout(&sb32, uap->ub, sizeof (sb32));
1137	return (error);
1138}
1139
1140/*
1141 * MPSAFE
1142 */
1143int
1144freebsd32_sysctl(struct thread *td, struct freebsd32_sysctl_args *uap)
1145{
1146	int error, name[CTL_MAXNAME];
1147	size_t j, oldlen;
1148
1149	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
1150		return (EINVAL);
1151
1152 	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
1153 	if (error)
1154		return (error);
1155
1156	mtx_lock(&Giant);
1157
1158	if (uap->oldlenp)
1159		oldlen = fuword32(uap->oldlenp);
1160	else
1161		oldlen = 0;
1162	error = userland_sysctl(td, name, uap->namelen,
1163		uap->old, &oldlen, 1,
1164		uap->new, uap->newlen, &j);
1165	if (error && error != ENOMEM)
1166		goto done2;
1167	if (uap->oldlenp) {
1168		suword32(uap->oldlenp, j);
1169	}
1170done2:
1171	mtx_unlock(&Giant);
1172	return (error);
1173}
1174
1175struct sigaction32 {
1176	u_int32_t	sa_u;
1177	int		sa_flags;
1178	sigset_t	sa_mask;
1179};
1180
1181CTASSERT(sizeof(struct sigaction32) == 24);
1182
1183int
1184freebsd32_sigaction(struct thread *td, struct freebsd32_sigaction_args *uap)
1185{
1186	struct sigaction32 s32;
1187	struct sigaction sa, osa, *sap;
1188	int error;
1189
1190	if (uap->act) {
1191		error = copyin(uap->act, &s32, sizeof(s32));
1192		if (error)
1193			return (error);
1194		sa.sa_handler = PTRIN(s32.sa_u);
1195		CP(s32, sa, sa_flags);
1196		CP(s32, sa, sa_mask);
1197		sap = &sa;
1198	} else
1199		sap = NULL;
1200	error = kern_sigaction(td, uap->sig, sap, &osa, 0);
1201	if (error != 0 && uap->oact != NULL) {
1202		s32.sa_u = PTROUT(osa.sa_handler);
1203		CP(osa, s32, sa_flags);
1204		CP(osa, s32, sa_mask);
1205		error = copyout(&s32, uap->oact, sizeof(s32));
1206	}
1207	return (error);
1208}
1209
1210#ifdef COMPAT_FREEBSD4
1211int
1212freebsd4_freebsd32_sigaction(struct thread *td,
1213			     struct freebsd4_freebsd32_sigaction_args *uap)
1214{
1215	struct sigaction32 s32;
1216	struct sigaction sa, osa, *sap;
1217	int error;
1218
1219	if (uap->act) {
1220		error = copyin(uap->act, &s32, sizeof(s32));
1221		if (error)
1222			return (error);
1223		sa.sa_handler = PTRIN(s32.sa_u);
1224		CP(s32, sa, sa_flags);
1225		CP(s32, sa, sa_mask);
1226		sap = &sa;
1227	} else
1228		sap = NULL;
1229	error = kern_sigaction(td, uap->sig, sap, &osa, KSA_FREEBSD4);
1230	if (error != 0 && uap->oact != NULL) {
1231		s32.sa_u = PTROUT(osa.sa_handler);
1232		CP(osa, s32, sa_flags);
1233		CP(osa, s32, sa_mask);
1234		error = copyout(&s32, uap->oact, sizeof(s32));
1235	}
1236	return (error);
1237}
1238#endif
1239
1240#if 0
1241
1242int
1243freebsd32_xxx(struct thread *td, struct freebsd32_xxx_args *uap)
1244{
1245	int error;
1246	caddr_t sg;
1247	struct yyy32 *p32, s32;
1248	struct yyy *p = NULL, s;
1249
1250	p32 = uap->zzz;
1251	if (p32) {
1252		sg = stackgap_init();
1253		p = stackgap_alloc(&sg, sizeof(struct yyy));
1254		uap->zzz = (struct yyy32 *)p;
1255		error = copyin(p32, &s32, sizeof(s32));
1256		if (error)
1257			return (error);
1258		/* translate in */
1259		error = copyout(&s, p, sizeof(s));
1260		if (error)
1261			return (error);
1262	}
1263	error = xxx(td, (struct xxx_args *) uap);
1264	if (error)
1265		return (error);
1266	if (p32) {
1267		error = copyin(p, &s, sizeof(s));
1268		if (error)
1269			return (error);
1270		/* translate out */
1271		error = copyout(&s32, p32, sizeof(s32));
1272	}
1273	return (error);
1274}
1275
1276#endif
1277