/*- * Copyright (c) 2002 Doug Rabson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD: head/sys/compat/freebsd32/freebsd32_misc.c 100384 2002-07-20 02:56:12Z peter $ */ #include #include #include #include #include #include #include #include #include #include #include #include /* Must come after sys/malloc.h */ #include #include #include #include #include #include #include #include #include #include #include #include /* Must come after sys/selinfo.h */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const char ia32_emul_path[] = "/compat/ia32"; /* * [ taken from the linux emulator ] * Search an alternate path before passing pathname arguments on * to system calls. Useful for keeping a separate 'emulation tree'. * * If cflag is set, we check if an attempt can be made to create * the named file, i.e. we check if the directory it should * be in exists. */ int ia32_emul_find(td, sgp, prefix, path, pbuf, cflag) struct thread *td; caddr_t *sgp; /* Pointer to stackgap memory */ const char *prefix; char *path; char **pbuf; int cflag; { int error; size_t len, sz; char *buf, *cp, *ptr; struct ucred *ucred; struct nameidata nd; struct nameidata ndroot; struct vattr vat; struct vattr vatroot; buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK); *pbuf = path; for (ptr = buf; (*ptr = *prefix) != '\0'; ptr++, prefix++) continue; sz = MAXPATHLEN - (ptr - buf); /* * If sgp is not given then the path is already in kernel space */ if (sgp == NULL) error = copystr(path, ptr, sz, &len); else error = copyinstr(path, ptr, sz, &len); if (error) { free(buf, M_TEMP); return error; } if (*ptr != '/') { free(buf, M_TEMP); return EINVAL; } /* * We know that there is a / somewhere in this pathname. * Search backwards for it, to find the file's parent dir * to see if it exists in the alternate tree. If it does, * and we want to create a file (cflag is set). We don't * need to worry about the root comparison in this case. */ if (cflag) { for (cp = &ptr[len] - 1; *cp != '/'; cp--) ; *cp = '\0'; NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td); if ((error = namei(&nd)) != 0) { free(buf, M_TEMP); return error; } *cp = '/'; } else { NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td); if ((error = namei(&nd)) != 0) { free(buf, M_TEMP); return error; } /* * We now compare the vnode of the ia32_root to the one * vnode asked. If they resolve to be the same, then we * ignore the match so that the real root gets used. * This avoids the problem of traversing "../.." to find the * root directory and never finding it, because "/" resolves * to the emulation root directory. This is expensive :-( */ NDINIT(&ndroot, LOOKUP, FOLLOW, UIO_SYSSPACE, ia32_emul_path, td); if ((error = namei(&ndroot)) != 0) { /* Cannot happen! */ free(buf, M_TEMP); vrele(nd.ni_vp); return error; } ucred = td->td_ucred; if ((error = VOP_GETATTR(nd.ni_vp, &vat, ucred, td)) != 0) { goto bad; } if ((error = VOP_GETATTR(ndroot.ni_vp, &vatroot, ucred, td)) != 0) { goto bad; } if (vat.va_fsid == vatroot.va_fsid && vat.va_fileid == vatroot.va_fileid) { error = ENOENT; goto bad; } } if (sgp == NULL) *pbuf = buf; else { sz = &ptr[len] - buf; *pbuf = stackgap_alloc(sgp, sz + 1); error = copyout(buf, *pbuf, sz); free(buf, M_TEMP); } vrele(nd.ni_vp); if (!cflag) vrele(ndroot.ni_vp); return error; bad: vrele(ndroot.ni_vp); vrele(nd.ni_vp); free(buf, M_TEMP); return error; } int ia32_open(struct thread *td, struct ia32_open_args *uap) { caddr_t sg; sg = stackgap_init(); CHECKALTEXIST(td, &sg, uap->path); return open(td, (struct open_args *) uap); } int ia32_wait4(struct thread *td, struct ia32_wait4_args *uap) { int error; caddr_t sg; struct rusage32 *rusage32, ru32; struct rusage *rusage = NULL, ru; rusage32 = SCARG(uap, rusage); if (rusage32) { sg = stackgap_init(); rusage = stackgap_alloc(&sg, sizeof(struct rusage)); SCARG(uap, rusage) = (struct rusage32 *)rusage; } error = wait4(td, (struct wait_args *)uap); if (error) return (error); if (rusage32 && (error = copyin(rusage, &ru, sizeof(ru)) == 0)) { TV_CP(ru, ru32, ru_utime); TV_CP(ru, ru32, ru_stime); CP(ru, ru32, ru_maxrss); CP(ru, ru32, ru_ixrss); CP(ru, ru32, ru_idrss); CP(ru, ru32, ru_isrss); CP(ru, ru32, ru_minflt); CP(ru, ru32, ru_majflt); CP(ru, ru32, ru_nswap); CP(ru, ru32, ru_inblock); CP(ru, ru32, ru_oublock); CP(ru, ru32, ru_msgsnd); CP(ru, ru32, ru_msgrcv); CP(ru, ru32, ru_nsignals); CP(ru, ru32, ru_nvcsw); CP(ru, ru32, ru_nivcsw); error = copyout(&ru32, rusage32, sizeof(ru32)); } return (error); } static void copy_statfs(struct statfs *in, struct statfs32 *out) { CP(*in, *out, f_bsize); CP(*in, *out, f_iosize); CP(*in, *out, f_blocks); CP(*in, *out, f_bfree); CP(*in, *out, f_bavail); CP(*in, *out, f_files); CP(*in, *out, f_ffree); CP(*in, *out, f_fsid); CP(*in, *out, f_owner); CP(*in, *out, f_type); CP(*in, *out, f_flags); CP(*in, *out, f_flags); CP(*in, *out, f_syncwrites); CP(*in, *out, f_asyncwrites); bcopy(in->f_fstypename, out->f_fstypename, MFSNAMELEN); bcopy(in->f_mntonname, out->f_mntonname, MNAMELEN); CP(*in, *out, f_syncreads); CP(*in, *out, f_asyncreads); bcopy(in->f_mntfromname, out->f_mntfromname, MNAMELEN); } int ia32_getfsstat(struct thread *td, struct ia32_getfsstat_args *uap) { int error; caddr_t sg; struct statfs32 *sp32, stat32; struct statfs *sp = NULL, stat; int maxcount, count, i; sp32 = SCARG(uap, buf); maxcount = SCARG(uap, bufsize) / sizeof(struct statfs32); if (sp32) { sg = stackgap_init(); sp = stackgap_alloc(&sg, sizeof(struct statfs) * maxcount); SCARG(uap, buf) = (struct statfs32 *)sp; } error = getfsstat(td, (struct getfsstat_args *) uap); if (sp32 && !error) { count = td->td_retval[0]; for (i = 0; i < count; i++) { error = copyin(&sp[i], &stat, sizeof(stat)); if (error) return (error); copy_statfs(&stat, &stat32); error = copyout(&stat32, &sp32[i], sizeof(stat32)); if (error) return (error); } } return (error); } int ia32_access(struct thread *td, struct ia32_access_args *uap) { caddr_t sg; sg = stackgap_init(); CHECKALTEXIST(td, &sg, uap->path); return access(td, (struct access_args *)uap); } int ia32_chflags(struct thread *td, struct ia32_chflags_args *uap) { caddr_t sg; sg = stackgap_init(); CHECKALTEXIST(td, &sg, uap->path); return chflags(td, (struct chflags_args *)uap); } struct sigaltstack32 { u_int32_t ss_sp; u_int32_t ss_size; int ss_flags; }; int ia32_sigaltstack(struct thread *td, struct ia32_sigaltstack_args *uap) { int error; caddr_t sg; struct sigaltstack32 *p32, *op32, s32; struct sigaltstack *p = NULL, *op = NULL, s; p32 = SCARG(uap, ss); if (p32) { sg = stackgap_init(); p = stackgap_alloc(&sg, sizeof(struct sigaltstack)); SCARG(uap, ss) = (struct sigaltstack32 *)p; error = copyin(p32, &s32, sizeof(s32)); if (error) return (error); PTRIN_CP(s32, s, ss_sp); CP(s32, s, ss_size); CP(s32, s, ss_flags); error = copyout(&s, p, sizeof(s)); if (error) return (error); } op32 = SCARG(uap, oss); if (op32) { sg = stackgap_init(); op = stackgap_alloc(&sg, sizeof(struct sigaltstack)); SCARG(uap, oss) = (struct sigaltstack32 *)op; } error = sigaltstack(td, (struct sigaltstack_args *) uap); if (error) return (error); if (op32) { error = copyin(op, &s, sizeof(s)); if (error) return (error); PTROUT_CP(s, s32, ss_sp); CP(s, s32, ss_size); CP(s, s32, ss_flags); error = copyout(&s32, op32, sizeof(s32)); } return (error); } int ia32_execve(struct thread *td, struct ia32_execve_args *uap) { int error; caddr_t sg; struct execve_args ap; u_int32_t *p32, arg; char **p; int count; sg = stackgap_init(); CHECKALTEXIST(td, &sg, SCARG(uap, fname)); SCARG(&ap, fname) = SCARG(uap, fname); if (SCARG(uap, argv)) { count = 0; p32 = SCARG(uap, argv); do { error = copyin(p32++, &arg, sizeof(arg)); if (error) return error; count++; } while (arg != 0); p = stackgap_alloc(&sg, count * sizeof(char *)); SCARG(&ap, argv) = p; p32 = SCARG(uap, argv); do { error = copyin(p32++, &arg, sizeof(arg)); if (error) return error; *p++ = PTRIN(arg); } while (arg != 0); } if (SCARG(uap, envv)) { count = 0; p32 = SCARG(uap, envv); do { error = copyin(p32++, &arg, sizeof(arg)); if (error) return error; count++; } while (arg != 0); p = stackgap_alloc(&sg, count * sizeof(char *)); SCARG(&ap, envv) = p; p32 = SCARG(uap, envv); do { error = copyin(p32++, &arg, sizeof(arg)); if (error) return error; *p++ = PTRIN(arg); } while (arg != 0); } return execve(td, &ap); } static int ia32_mmap_partial(struct thread *td, vm_offset_t start, vm_offset_t end, int prot, int fd, off_t pos) { vm_map_t map; vm_map_entry_t entry; int rv; map = &td->td_proc->p_vmspace->vm_map; if (fd != -1) prot |= VM_PROT_WRITE; if (vm_map_lookup_entry(map, start, &entry)) { if ((entry->protection & prot) != prot) { rv = vm_map_protect(map, trunc_page(start), round_page(end), entry->protection | prot, FALSE); if (rv != KERN_SUCCESS) return (EINVAL); } } else { vm_offset_t addr = trunc_page(start); rv = vm_map_find(map, 0, 0, &addr, PAGE_SIZE, FALSE, prot, VM_PROT_ALL, 0); if (rv != KERN_SUCCESS) return (EINVAL); } if (fd != -1) { struct pread_args r; SCARG(&r, fd) = fd; SCARG(&r, buf) = (void *) start; SCARG(&r, nbyte) = end - start; SCARG(&r, offset) = pos; return (pread(td, &r)); } else { while (start < end) { subyte((void *) start, 0); start++; } return (0); } } int ia32_mmap(struct thread *td, struct ia32_mmap_args *uap) { struct mmap_args ap; vm_offset_t addr = (vm_offset_t) SCARG(uap, addr); vm_size_t len = SCARG(uap, len); int prot = SCARG(uap, prot); int flags = SCARG(uap, flags); int fd = SCARG(uap, fd); off_t pos = (SCARG(uap, poslo) | ((off_t)SCARG(uap, poshi) << 32)); vm_size_t pageoff; int error; /* * Attempt to handle page size hassles. */ pageoff = (pos & PAGE_MASK); if (flags & MAP_FIXED) { vm_offset_t start, end; start = addr; end = addr + len; if (start != trunc_page(start)) { error = ia32_mmap_partial(td, start, round_page(start), prot, fd, pos); if (fd != -1) pos += round_page(start) - start; start = round_page(start); } if (end != round_page(end)) { vm_offset_t t = trunc_page(end); error = ia32_mmap_partial(td, t, end, prot, fd, pos + t - start); end = trunc_page(end); } if (end > start && fd != -1 && (pos & PAGE_MASK)) { /* * We can't map this region at all. The specified * address doesn't have the same alignment as the file * position. Fake the mapping by simply reading the * entire region into memory. First we need to make * sure the region exists. */ vm_map_t map; struct pread_args r; int rv; prot |= VM_PROT_WRITE; map = &td->td_proc->p_vmspace->vm_map; rv = vm_map_remove(map, start, end); if (rv != KERN_SUCCESS) return (EINVAL); rv = vm_map_find(map, 0, 0, &start, end - start, FALSE, prot, VM_PROT_ALL, 0); if (rv != KERN_SUCCESS) return (EINVAL); SCARG(&r, fd) = fd; SCARG(&r, buf) = (void *) start; SCARG(&r, nbyte) = end - start; SCARG(&r, offset) = pos; error = pread(td, &r); if (error) return (error); td->td_retval[0] = addr; return (0); } if (end == start) { /* * After dealing with the ragged ends, there * might be none left. */ td->td_retval[0] = addr; return (0); } addr = start; len = end - start; } SCARG(&ap, addr) = (void *) addr; SCARG(&ap, len) = len; SCARG(&ap, prot) = prot; SCARG(&ap, flags) = flags; SCARG(&ap, fd) = fd; SCARG(&ap, pos) = pos; return (mmap(td, &ap)); } struct itimerval32 { struct timeval32 it_interval; struct timeval32 it_value; }; int ia32_setitimer(struct thread *td, struct ia32_setitimer_args *uap) { int error; caddr_t sg; struct itimerval32 *p32, *op32, s32; struct itimerval *p = NULL, *op = NULL, s; p32 = SCARG(uap, itv); if (p32) { sg = stackgap_init(); p = stackgap_alloc(&sg, sizeof(struct itimerval)); SCARG(uap, itv) = (struct itimerval32 *)p; error = copyin(p32, &s32, sizeof(s32)); if (error) return (error); TV_CP(s32, s, it_interval); TV_CP(s32, s, it_value); error = copyout(&s, p, sizeof(s)); if (error) return (error); } op32 = SCARG(uap, oitv); if (op32) { sg = stackgap_init(); op = stackgap_alloc(&sg, sizeof(struct itimerval)); SCARG(uap, oitv) = (struct itimerval32 *)op; } error = setitimer(td, (struct setitimer_args *) uap); if (error) return (error); if (op32) { error = copyin(op, &s, sizeof(s)); if (error) return (error); TV_CP(s, s32, it_interval); TV_CP(s, s32, it_value); error = copyout(&s32, op32, sizeof(s32)); } return (error); } int ia32_select(struct thread *td, struct ia32_select_args *uap) { int error; caddr_t sg; struct timeval32 *p32, s32; struct timeval *p = NULL, s; p32 = SCARG(uap, tv); if (p32) { sg = stackgap_init(); p = stackgap_alloc(&sg, sizeof(struct timeval)); SCARG(uap, tv) = (struct timeval32 *)p; error = copyin(p32, &s32, sizeof(s32)); if (error) return (error); CP(s32, s, tv_sec); CP(s32, s, tv_usec); error = copyout(&s, p, sizeof(s)); if (error) return (error); } /* * XXX big-endian needs to convert the fd_sets too. */ return (select(td, (struct select_args *) uap)); } int ia32_gettimeofday(struct thread *td, struct ia32_gettimeofday_args *uap) { int error; caddr_t sg; struct timeval32 *p32, s32; struct timeval *p = NULL, s; p32 = SCARG(uap, tp); if (p32) { sg = stackgap_init(); p = stackgap_alloc(&sg, sizeof(struct timeval)); SCARG(uap, tp) = (struct timeval32 *)p; } error = gettimeofday(td, (struct gettimeofday_args *) uap); if (error) return (error); if (p32) { error = copyin(p, &s, sizeof(s)); if (error) return (error); CP(s, s32, tv_sec); CP(s, s32, tv_usec); error = copyout(&s32, p32, sizeof(s32)); if (error) return (error); } return (error); } int ia32_getrusage(struct thread *td, struct ia32_getrusage_args *uap) { int error; caddr_t sg; struct rusage32 *p32, s32; struct rusage *p = NULL, s; p32 = SCARG(uap, rusage); if (p32) { sg = stackgap_init(); p = stackgap_alloc(&sg, sizeof(struct rusage)); SCARG(uap, rusage) = (struct rusage32 *)p; } error = getrusage(td, (struct getrusage_args *) uap); if (error) return (error); if (p32) { error = copyin(p, &s, sizeof(s)); if (error) return (error); TV_CP(s, s32, ru_utime); TV_CP(s, s32, ru_stime); CP(s, s32, ru_maxrss); CP(s, s32, ru_ixrss); CP(s, s32, ru_idrss); CP(s, s32, ru_isrss); CP(s, s32, ru_minflt); CP(s, s32, ru_majflt); CP(s, s32, ru_nswap); CP(s, s32, ru_inblock); CP(s, s32, ru_oublock); CP(s, s32, ru_msgsnd); CP(s, s32, ru_msgrcv); CP(s, s32, ru_nsignals); CP(s, s32, ru_nvcsw); CP(s, s32, ru_nivcsw); error = copyout(&s32, p32, sizeof(s32)); } return (error); } struct iovec32 { u_int32_t iov_base; int iov_len; }; #define STACKGAPLEN 400 int ia32_readv(struct thread *td, struct ia32_readv_args *uap) { int error, osize, nsize, i; caddr_t sg; struct readv_args /* { syscallarg(int) fd; syscallarg(struct iovec *) iovp; syscallarg(u_int) iovcnt; } */ a; struct iovec32 *oio; struct iovec *nio; sg = stackgap_init(); if (SCARG(uap, iovcnt) > (STACKGAPLEN / sizeof (struct iovec))) return (EINVAL); osize = SCARG(uap, iovcnt) * sizeof (struct iovec32); nsize = SCARG(uap, iovcnt) * sizeof (struct iovec); oio = malloc(osize, M_TEMP, M_WAITOK); nio = malloc(nsize, M_TEMP, M_WAITOK); error = 0; if ((error = copyin(SCARG(uap, iovp), oio, osize))) goto punt; for (i = 0; i < SCARG(uap, iovcnt); i++) { nio[i].iov_base = PTRIN(oio[i].iov_base); nio[i].iov_len = oio[i].iov_len; } SCARG(&a, fd) = SCARG(uap, fd); SCARG(&a, iovp) = stackgap_alloc(&sg, nsize); SCARG(&a, iovcnt) = SCARG(uap, iovcnt); if ((error = copyout(nio, (caddr_t)SCARG(&a, iovp), nsize))) goto punt; error = readv(td, &a); punt: free(oio, M_TEMP); free(nio, M_TEMP); return (error); } int ia32_writev(struct thread *td, struct ia32_writev_args *uap) { int error, i, nsize, osize; caddr_t sg; struct writev_args /* { syscallarg(int) fd; syscallarg(struct iovec *) iovp; syscallarg(u_int) iovcnt; } */ a; struct iovec32 *oio; struct iovec *nio; sg = stackgap_init(); if (SCARG(uap, iovcnt) > (STACKGAPLEN / sizeof (struct iovec))) return (EINVAL); osize = SCARG(uap, iovcnt) * sizeof (struct iovec32); nsize = SCARG(uap, iovcnt) * sizeof (struct iovec); oio = malloc(osize, M_TEMP, M_WAITOK); nio = malloc(nsize, M_TEMP, M_WAITOK); error = 0; if ((error = copyin(SCARG(uap, iovp), oio, osize))) goto punt; for (i = 0; i < SCARG(uap, iovcnt); i++) { nio[i].iov_base = PTRIN(oio[i].iov_base); nio[i].iov_len = oio[i].iov_len; } SCARG(&a, fd) = SCARG(uap, fd); SCARG(&a, iovp) = stackgap_alloc(&sg, nsize); SCARG(&a, iovcnt) = SCARG(uap, iovcnt); if ((error = copyout(nio, (caddr_t)SCARG(&a, iovp), nsize))) goto punt; error = writev(td, &a); punt: free(oio, M_TEMP); free(nio, M_TEMP); return (error); } int ia32_settimeofday(struct thread *td, struct ia32_settimeofday_args *uap) { int error; caddr_t sg; struct timeval32 *p32, s32; struct timeval *p = NULL, s; p32 = SCARG(uap, tv); if (p32) { sg = stackgap_init(); p = stackgap_alloc(&sg, sizeof(struct timeval)); SCARG(uap, tv) = (struct timeval32 *)p; error = copyin(p32, &s32, sizeof(s32)); if (error) return (error); CP(s32, s, tv_sec); CP(s32, s, tv_usec); error = copyout(&s, p, sizeof(s)); if (error) return (error); } return (settimeofday(td, (struct settimeofday_args *) uap)); } int ia32_utimes(struct thread *td, struct ia32_utimes_args *uap) { int error; caddr_t sg; struct timeval32 *p32, s32[2]; struct timeval *p = NULL, s[2]; p32 = SCARG(uap, tptr); if (p32) { sg = stackgap_init(); p = stackgap_alloc(&sg, 2*sizeof(struct timeval)); SCARG(uap, tptr) = (struct timeval32 *)p; error = copyin(p32, s32, sizeof(s32)); if (error) return (error); CP(s32[0], s[0], tv_sec); CP(s32[0], s[0], tv_usec); CP(s32[1], s[1], tv_sec); CP(s32[1], s[1], tv_usec); error = copyout(s, p, sizeof(s)); if (error) return (error); } return (utimes(td, (struct utimes_args *) uap)); } int ia32_adjtime(struct thread *td, struct ia32_adjtime_args *uap) { int error; caddr_t sg; struct timeval32 *p32, *op32, s32; struct timeval *p = NULL, *op = NULL, s; p32 = SCARG(uap, delta); if (p32) { sg = stackgap_init(); p = stackgap_alloc(&sg, sizeof(struct timeval)); SCARG(uap, delta) = (struct timeval32 *)p; error = copyin(p32, &s32, sizeof(s32)); if (error) return (error); CP(s32, s, tv_sec); CP(s32, s, tv_usec); error = copyout(&s, p, sizeof(s)); if (error) return (error); } op32 = SCARG(uap, olddelta); if (op32) { sg = stackgap_init(); op = stackgap_alloc(&sg, sizeof(struct timeval)); SCARG(uap, olddelta) = (struct timeval32 *)op; } error = utimes(td, (struct utimes_args *) uap); if (error) return error; if (op32) { error = copyin(op, &s, sizeof(s)); if (error) return (error); CP(s, s32, tv_sec); CP(s, s32, tv_usec); error = copyout(&s32, op32, sizeof(s32)); } return (error); } int ia32_statfs(struct thread *td, struct ia32_statfs_args *uap) { int error; caddr_t sg; struct statfs32 *p32, s32; struct statfs *p = NULL, s; p32 = SCARG(uap, buf); if (p32) { sg = stackgap_init(); p = stackgap_alloc(&sg, sizeof(struct statfs)); SCARG(uap, buf) = (struct statfs32 *)p; } error = statfs(td, (struct statfs_args *) uap); if (error) return (error); if (p32) { error = copyin(p, &s, sizeof(s)); if (error) return (error); copy_statfs(&s, &s32); error = copyout(&s32, p32, sizeof(s32)); } return (error); } int ia32_fstatfs(struct thread *td, struct ia32_fstatfs_args *uap) { int error; caddr_t sg; struct statfs32 *p32, s32; struct statfs *p = NULL, s; p32 = SCARG(uap, buf); if (p32) { sg = stackgap_init(); p = stackgap_alloc(&sg, sizeof(struct statfs)); SCARG(uap, buf) = (struct statfs32 *)p; } error = fstatfs(td, (struct fstatfs_args *) uap); if (error) return (error); if (p32) { error = copyin(p, &s, sizeof(s)); if (error) return (error); copy_statfs(&s, &s32); error = copyout(&s32, p32, sizeof(s32)); } return (error); } int ia32_semsys(struct thread *td, struct ia32_semsys_args *uap) { /* * Vector through to semsys if it is loaded. */ return sysent[169].sy_call(td, uap); } int ia32_msgsys(struct thread *td, struct ia32_msgsys_args *uap) { /* * Vector through to msgsys if it is loaded. */ return sysent[170].sy_call(td, uap); } int ia32_shmsys(struct thread *td, struct ia32_shmsys_args *uap) { /* * Vector through to shmsys if it is loaded. */ return sysent[171].sy_call(td, uap); } int ia32_pread(struct thread *td, struct ia32_pread_args *uap) { struct pread_args ap; SCARG(&ap, fd) = SCARG(uap, fd); SCARG(&ap, buf) = SCARG(uap, buf); SCARG(&ap, nbyte) = SCARG(uap, nbyte); SCARG(&ap, offset) = (SCARG(uap, offsetlo) | ((off_t)SCARG(uap, offsethi) << 32)); return (pread(td, &ap)); } int ia32_pwrite(struct thread *td, struct ia32_pwrite_args *uap) { struct pwrite_args ap; SCARG(&ap, fd) = SCARG(uap, fd); SCARG(&ap, buf) = SCARG(uap, buf); SCARG(&ap, nbyte) = SCARG(uap, nbyte); SCARG(&ap, offset) = (SCARG(uap, offsetlo) | ((off_t)SCARG(uap, offsethi) << 32)); return (pwrite(td, &ap)); } int ia32_lseek(struct thread *td, struct ia32_lseek_args *uap) { int error; struct lseek_args ap; off_t pos; SCARG(&ap, fd) = SCARG(uap, fd); SCARG(&ap, offset) = (SCARG(uap, offsetlo) | ((off_t)SCARG(uap, offsethi) << 32)); SCARG(&ap, whence) = SCARG(uap, whence); error = lseek(td, &ap); /* Expand the quad return into two parts for eax and edx */ pos = *(off_t *)(td->td_retval); td->td_retval[0] = pos & 0xffffffff; /* %eax */ td->td_retval[1] = pos >> 32; /* %edx */ return error; } int ia32_truncate(struct thread *td, struct ia32_truncate_args *uap) { struct truncate_args ap; SCARG(&ap, path) = SCARG(uap, path); SCARG(&ap, length) = (SCARG(uap, lengthlo) | ((off_t)SCARG(uap, lengthhi) << 32)); return (truncate(td, &ap)); } int ia32_ftruncate(struct thread *td, struct ia32_ftruncate_args *uap) { struct ftruncate_args ap; SCARG(&ap, fd) = SCARG(uap, fd); SCARG(&ap, length) = (SCARG(uap, lengthlo) | ((off_t)SCARG(uap, lengthhi) << 32)); return (ftruncate(td, &ap)); } int ia32_sendfile(struct thread *td, struct ia32_sendfile_args *uap) { struct sendfile_args ap; SCARG(&ap, fd) = SCARG(uap, fd); SCARG(&ap, s) = SCARG(uap, s); SCARG(&ap, offset) = (SCARG(uap, offsetlo) | ((off_t)SCARG(uap, offsethi) << 32)); SCARG(&ap, nbytes) = SCARG(uap, nbytes); /* XXX check */ SCARG(&ap, hdtr) = SCARG(uap, hdtr); /* XXX check */ SCARG(&ap, sbytes) = SCARG(uap, sbytes); /* XXX FIXME!! */ SCARG(&ap, flags) = SCARG(uap, flags); return (sendfile(td, &ap)); } struct stat32 { udev_t st_dev; ino_t st_ino; mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; udev_t st_rdev; struct timespec32 st_atimespec; struct timespec32 st_mtimespec; struct timespec32 st_ctimespec; off_t st_size; int64_t st_blocks; u_int32_t st_blksize; u_int32_t st_flags; u_int32_t st_gen; }; static void copy_stat( struct stat *in, struct stat32 *out) { CP(*in, *out, st_dev); CP(*in, *out, st_ino); CP(*in, *out, st_mode); CP(*in, *out, st_nlink); CP(*in, *out, st_uid); CP(*in, *out, st_gid); CP(*in, *out, st_rdev); TS_CP(*in, *out, st_atimespec); TS_CP(*in, *out, st_mtimespec); TS_CP(*in, *out, st_ctimespec); CP(*in, *out, st_size); CP(*in, *out, st_blocks); CP(*in, *out, st_blksize); CP(*in, *out, st_flags); CP(*in, *out, st_gen); } int ia32_stat(struct thread *td, struct ia32_stat_args *uap) { int error; caddr_t sg; struct stat32 *p32, s32; struct stat *p = NULL, s; p32 = SCARG(uap, ub); if (p32) { sg = stackgap_init(); p = stackgap_alloc(&sg, sizeof(struct stat)); SCARG(uap, ub) = (struct stat32 *)p; } error = stat(td, (struct stat_args *) uap); if (error) return (error); if (p32) { error = copyin(p, &s, sizeof(s)); if (error) return (error); copy_stat(&s, &s32); error = copyout(&s32, p32, sizeof(s32)); } return (error); } int ia32_fstat(struct thread *td, struct ia32_fstat_args *uap) { int error; caddr_t sg; struct stat32 *p32, s32; struct stat *p = NULL, s; p32 = SCARG(uap, ub); if (p32) { sg = stackgap_init(); p = stackgap_alloc(&sg, sizeof(struct stat)); SCARG(uap, ub) = (struct stat32 *)p; } error = fstat(td, (struct fstat_args *) uap); if (error) return (error); if (p32) { error = copyin(p, &s, sizeof(s)); if (error) return (error); copy_stat(&s, &s32); error = copyout(&s32, p32, sizeof(s32)); } return (error); } int ia32_lstat(struct thread *td, struct ia32_lstat_args *uap) { int error; caddr_t sg; struct stat32 *p32, s32; struct stat *p = NULL, s; p32 = SCARG(uap, ub); if (p32) { sg = stackgap_init(); p = stackgap_alloc(&sg, sizeof(struct stat)); SCARG(uap, ub) = (struct stat32 *)p; } error = lstat(td, (struct lstat_args *) uap); if (error) return (error); if (p32) { error = copyin(p, &s, sizeof(s)); if (error) return (error); copy_stat(&s, &s32); error = copyout(&s32, p32, sizeof(s32)); } return (error); } /* * MPSAFE */ int ia32_sysctl(struct thread *td, struct ia32_sysctl_args *uap) { int error, name[CTL_MAXNAME]; size_t j, oldlen; if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) return (EINVAL); error = copyin(uap->name, &name, uap->namelen * sizeof(int)); if (error) return (error); mtx_lock(&Giant); if (uap->oldlenp) oldlen = fuword32(uap->oldlenp); else oldlen = 0; error = userland_sysctl(td, name, uap->namelen, uap->old, &oldlen, 1, uap->new, uap->newlen, &j); if (error && error != ENOMEM) goto done2; if (uap->oldlenp) { suword32(uap->oldlenp, j); } done2: mtx_unlock(&Giant); return (error); } struct sigaction32 { u_int32_t sa_u; int sa_flags; sigset_t sa_mask; }; int ia32_sigaction(struct thread *td, struct ia32_sigaction_args *uap) { int error; caddr_t sg; struct sigaction32 *p32, *op32, s32; struct sigaction *p = NULL, *op = NULL, s; p32 = SCARG(uap, act); if (p32) { sg = stackgap_init(); p = stackgap_alloc(&sg, sizeof(struct sigaction)); SCARG(uap, act) = (struct sigaction32 *)p; error = copyin(p32, &s32, sizeof(s32)); if (error) return (error); s.sa_handler = PTRIN(s32.sa_u); CP(s32, s, sa_flags); CP(s32, s, sa_mask); error = copyout(&s, p, sizeof(s)); if (error) return (error); } op32 = SCARG(uap, oact); if (op32) { sg = stackgap_init(); op = stackgap_alloc(&sg, sizeof(struct sigaction)); SCARG(uap, oact) = (struct sigaction32 *)op; } error = sigaction(td, (struct sigaction_args *) uap); if (error) return (error); if (op32) { error = copyin(op, &s, sizeof(s)); if (error) return (error); s32.sa_u = PTROUT(s.sa_handler); CP(s, s32, sa_flags); CP(s, s32, sa_mask); error = copyout(&s32, op32, sizeof(s32)); } return (error); } #if 0 int ia32_xxx(struct thread *td, struct ia32_xxx_args *uap) { int error; caddr_t sg; struct yyy32 *p32, s32; struct yyy *p = NULL, s; p32 = SCARG(uap, zzz); if (p32) { sg = stackgap_init(); p = stackgap_alloc(&sg, sizeof(struct yyy)); SCARG(uap, zzz) = (struct yyy32 *)p; error = copyin(p32, &s32, sizeof(s32)); if (error) return (error); /* translate in */ error = copyout(&s, p, sizeof(s)); if (error) return (error); } error = xxx(td, (struct xxx_args *) uap); if (error) return (error); if (p32) { error = copyin(p, &s, sizeof(s)); if (error) return (error); /* translate out */ error = copyout(&s32, p32, sizeof(s32)); } return (error); } #endif