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