linux_pipe.c revision 1.19
11.19Sfvdl/* $NetBSD: linux_pipe.c,v 1.19 1995/09/13 21:51:14 fvdl Exp $ */ 21.1Sfvdl 31.1Sfvdl/* 41.1Sfvdl * Copyright (c) 1995 Frank van der Linden 51.1Sfvdl * All rights reserved. 61.1Sfvdl * 71.1Sfvdl * Redistribution and use in source and binary forms, with or without 81.1Sfvdl * modification, are permitted provided that the following conditions 91.1Sfvdl * are met: 101.1Sfvdl * 1. Redistributions of source code must retain the above copyright 111.1Sfvdl * notice, this list of conditions and the following disclaimer. 121.1Sfvdl * 2. Redistributions in binary form must reproduce the above copyright 131.1Sfvdl * notice, this list of conditions and the following disclaimer in the 141.1Sfvdl * documentation and/or other materials provided with the distribution. 151.1Sfvdl * 3. All advertising materials mentioning features or use of this software 161.1Sfvdl * must display the following acknowledgement: 171.1Sfvdl * This product includes software developed for the NetBSD Project 181.1Sfvdl * by Frank van der Linden 191.1Sfvdl * 4. The name of the author may not be used to endorse or promote products 201.1Sfvdl * derived from this software without specific prior written permission 211.1Sfvdl * 221.1Sfvdl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 231.1Sfvdl * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 241.1Sfvdl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 251.1Sfvdl * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 261.1Sfvdl * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 271.1Sfvdl * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 281.1Sfvdl * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 291.1Sfvdl * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 301.1Sfvdl * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 311.1Sfvdl * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 321.1Sfvdl */ 331.1Sfvdl 341.1Sfvdl/* 351.1Sfvdl * Linux compatibility module. Try to deal with various Linux system calls. 361.1Sfvdl */ 371.1Sfvdl 381.1Sfvdl#include <sys/param.h> 391.1Sfvdl#include <sys/systm.h> 401.1Sfvdl#include <sys/namei.h> 411.1Sfvdl#include <sys/proc.h> 421.1Sfvdl#include <sys/dir.h> 431.1Sfvdl#include <sys/file.h> 441.1Sfvdl#include <sys/stat.h> 451.1Sfvdl#include <sys/filedesc.h> 461.1Sfvdl#include <sys/ioctl.h> 471.1Sfvdl#include <sys/kernel.h> 481.1Sfvdl#include <sys/malloc.h> 491.1Sfvdl#include <sys/mbuf.h> 501.1Sfvdl#include <sys/mman.h> 511.1Sfvdl#include <sys/mount.h> 521.1Sfvdl#include <sys/ptrace.h> 531.1Sfvdl#include <sys/resource.h> 541.1Sfvdl#include <sys/resourcevar.h> 551.1Sfvdl#include <sys/signal.h> 561.1Sfvdl#include <sys/signalvar.h> 571.1Sfvdl#include <sys/socket.h> 581.1Sfvdl#include <sys/time.h> 591.1Sfvdl#include <sys/times.h> 601.1Sfvdl#include <sys/vnode.h> 611.1Sfvdl#include <sys/uio.h> 621.1Sfvdl#include <sys/wait.h> 631.1Sfvdl#include <sys/utsname.h> 641.1Sfvdl#include <sys/unistd.h> 651.1Sfvdl 661.1Sfvdl#include <sys/syscallargs.h> 671.1Sfvdl 681.1Sfvdl#include <vm/vm.h> 691.1Sfvdl#include <vm/vm_param.h> 701.1Sfvdl 711.1Sfvdl#include <compat/linux/linux_types.h> 721.1Sfvdl#include <compat/linux/linux_fcntl.h> 731.1Sfvdl#include <compat/linux/linux_mmap.h> 741.11Smycroft#include <compat/linux/linux_signal.h> 751.1Sfvdl#include <compat/linux/linux_syscallargs.h> 761.1Sfvdl#include <compat/linux/linux_util.h> 771.1Sfvdl#include <compat/linux/linux_dirent.h> 781.1Sfvdl 791.1Sfvdl/* 801.1Sfvdl * The information on a terminated (or stopped) process needs 811.1Sfvdl * to be converted in order for Linux binaries to get a valid signal 821.1Sfvdl * number out of it. 831.1Sfvdl */ 841.1Sfvdlstatic int 851.1Sfvdlbsd_to_linux_wstat(status) 861.1Sfvdl int *status; 871.1Sfvdl{ 881.1Sfvdl if (WIFSIGNALED(*status)) 891.1Sfvdl *status = (*status & ~0177) | 901.12Smycroft bsd_to_linux_sig[WTERMSIG(*status)]; 911.1Sfvdl else if (WIFSTOPPED(*status)) 921.1Sfvdl *status = (*status & ~0xff00) | 931.12Smycroft (bsd_to_linux_sig[WSTOPSIG(*status)] << 8); 941.1Sfvdl} 951.1Sfvdl 961.1Sfvdl/* 971.1Sfvdl * waitpid(2). Passed on to the NetBSD call, surrounded by code to 981.1Sfvdl * reserve some space for a NetBSD-style wait status, and converting 991.1Sfvdl * it to what Linux wants. 1001.1Sfvdl */ 1011.1Sfvdlint 1021.1Sfvdllinux_waitpid(p, uap, retval) 1031.1Sfvdl struct proc *p; 1041.1Sfvdl struct linux_waitpid_args /* { 1051.1Sfvdl syscallarg(int) pid; 1061.1Sfvdl syscallarg(int *) status; 1071.1Sfvdl syscallarg(int) options; 1081.1Sfvdl } */ *uap; 1091.1Sfvdl register_t *retval; 1101.1Sfvdl{ 1111.1Sfvdl struct wait4_args w4a; 1121.1Sfvdl int error, *status, tstat; 1131.1Sfvdl caddr_t sg; 1141.1Sfvdl 1151.16Sfvdl if (SCARG(uap, status) != NULL) { 1161.16Sfvdl sg = stackgap_init(p->p_emul); 1171.16Sfvdl status = (int *) stackgap_alloc(&sg, sizeof status); 1181.16Sfvdl } else 1191.16Sfvdl status = NULL; 1201.1Sfvdl 1211.1Sfvdl SCARG(&w4a, pid) = SCARG(uap, pid); 1221.1Sfvdl SCARG(&w4a, status) = status; 1231.1Sfvdl SCARG(&w4a, options) = SCARG(uap, options); 1241.1Sfvdl SCARG(&w4a, rusage) = NULL; 1251.1Sfvdl 1261.1Sfvdl if ((error = wait4(p, &w4a, retval))) 1271.1Sfvdl return error; 1281.1Sfvdl 1291.18Sfvdl p->p_siglist &= ~sigmask(SIGCHLD); 1301.18Sfvdl 1311.16Sfvdl if (status != NULL) { 1321.16Sfvdl if ((error = copyin(status, &tstat, sizeof tstat))) 1331.16Sfvdl return error; 1341.16Sfvdl 1351.16Sfvdl bsd_to_linux_wstat(&tstat); 1361.1Sfvdl 1371.16Sfvdl return copyout(&tstat, SCARG(uap, status), sizeof tstat); 1381.16Sfvdl } 1391.1Sfvdl 1401.16Sfvdl return 0; 1411.1Sfvdl} 1421.1Sfvdl 1431.1Sfvdl/* 1441.1Sfvdl * This is very much the same as waitpid() 1451.1Sfvdl */ 1461.1Sfvdlint 1471.1Sfvdllinux_wait4(p, uap, retval) 1481.1Sfvdl struct proc *p; 1491.1Sfvdl struct linux_wait4_args /* { 1501.1Sfvdl syscallarg(int) pid; 1511.1Sfvdl syscallarg(int *) status; 1521.1Sfvdl syscallarg(int) options; 1531.1Sfvdl syscallarg(struct rusage *) rusage; 1541.1Sfvdl } */ *uap; 1551.1Sfvdl register_t *retval; 1561.1Sfvdl{ 1571.1Sfvdl struct wait4_args w4a; 1581.1Sfvdl int error, *status, tstat; 1591.1Sfvdl caddr_t sg; 1601.1Sfvdl 1611.16Sfvdl if (SCARG(uap, status) != NULL) { 1621.16Sfvdl sg = stackgap_init(p->p_emul); 1631.16Sfvdl status = (int *) stackgap_alloc(&sg, sizeof status); 1641.16Sfvdl } else 1651.16Sfvdl status = NULL; 1661.1Sfvdl 1671.1Sfvdl SCARG(&w4a, pid) = SCARG(uap, pid); 1681.1Sfvdl SCARG(&w4a, status) = status; 1691.1Sfvdl SCARG(&w4a, options) = SCARG(uap, options); 1701.1Sfvdl SCARG(&w4a, rusage) = SCARG(uap, rusage); 1711.1Sfvdl 1721.1Sfvdl if ((error = wait4(p, &w4a, retval))) 1731.1Sfvdl return error; 1741.1Sfvdl 1751.18Sfvdl p->p_siglist &= ~sigmask(SIGCHLD); 1761.18Sfvdl 1771.16Sfvdl if (status != NULL) { 1781.16Sfvdl if ((error = copyin(status, &tstat, sizeof tstat))) 1791.16Sfvdl return error; 1801.16Sfvdl 1811.16Sfvdl bsd_to_linux_wstat(&tstat); 1821.1Sfvdl 1831.16Sfvdl return copyout(&tstat, SCARG(uap, status), sizeof tstat); 1841.16Sfvdl } 1851.1Sfvdl 1861.16Sfvdl return 0; 1871.1Sfvdl} 1881.1Sfvdl 1891.1Sfvdl/* 1901.1Sfvdl * This is the old brk(2) call. I don't think anything in the Linux 1911.1Sfvdl * world uses this anymore 1921.1Sfvdl */ 1931.1Sfvdlint 1941.1Sfvdllinux_break(p, uap, retval) 1951.1Sfvdl struct proc *p; 1961.1Sfvdl struct linux_brk_args /* { 1971.1Sfvdl syscallarg(char *) nsize; 1981.1Sfvdl } */ *uap; 1991.1Sfvdl register_t *retval; 2001.1Sfvdl{ 2011.1Sfvdl return ENOSYS; 2021.1Sfvdl} 2031.1Sfvdl 2041.1Sfvdl/* 2051.1Sfvdl * Linux brk(2). The check if the new address is >= the old one is 2061.1Sfvdl * done in the kernel in Linux. NetBSD does it in the library. 2071.1Sfvdl */ 2081.1Sfvdlint 2091.1Sfvdllinux_brk(p, uap, retval) 2101.1Sfvdl struct proc *p; 2111.1Sfvdl struct linux_brk_args /* { 2121.1Sfvdl syscallarg(char *) nsize; 2131.1Sfvdl } */ *uap; 2141.1Sfvdl register_t *retval; 2151.1Sfvdl{ 2161.1Sfvdl char *nbrk = SCARG(uap, nsize); 2171.1Sfvdl struct obreak_args oba; 2181.1Sfvdl struct vmspace *vm = p->p_vmspace; 2191.1Sfvdl int error = 0; 2201.1Sfvdl caddr_t oldbrk, newbrk; 2211.1Sfvdl 2221.1Sfvdl oldbrk = vm->vm_daddr + ctob(vm->vm_dsize); 2231.1Sfvdl /* 2241.1Sfvdl * XXX inconsistent.. Linux always returns at least the old 2251.1Sfvdl * brk value, but it will be page-aligned if this fails, 2261.1Sfvdl * and possibly not page aligned if it succeeds (the user 2271.1Sfvdl * supplied pointer is returned). 2281.1Sfvdl */ 2291.1Sfvdl SCARG(&oba, nsize) = nbrk; 2301.1Sfvdl 2311.1Sfvdl if ((caddr_t) nbrk > vm->vm_daddr && obreak(p, &oba, retval) == 0) 2321.1Sfvdl retval[0] = (register_t) nbrk; 2331.1Sfvdl else 2341.1Sfvdl retval[0] = (register_t) oldbrk; 2351.1Sfvdl 2361.1Sfvdl return 0; 2371.1Sfvdl} 2381.1Sfvdl 2391.1Sfvdl/* 2401.1Sfvdl * I wonder why Linux has gettimeofday() _and_ time().. Still, we 2411.1Sfvdl * need to deal with it. 2421.1Sfvdl */ 2431.1Sfvdlint 2441.1Sfvdllinux_time(p, uap, retval) 2451.1Sfvdl struct proc *p; 2461.1Sfvdl struct linux_time_args /* { 2471.1Sfvdl linux_time_t *t; 2481.1Sfvdl } */ *uap; 2491.1Sfvdl register_t *retval; 2501.1Sfvdl{ 2511.1Sfvdl struct timeval atv; 2521.1Sfvdl linux_time_t tt; 2531.1Sfvdl int error; 2541.1Sfvdl 2551.1Sfvdl microtime(&atv); 2561.1Sfvdl 2571.1Sfvdl tt = atv.tv_sec; 2581.1Sfvdl if (SCARG(uap, t) && (error = copyout(&tt, SCARG(uap, t), sizeof tt))) 2591.1Sfvdl return error; 2601.1Sfvdl 2611.1Sfvdl retval[0] = tt; 2621.1Sfvdl return 0; 2631.1Sfvdl} 2641.1Sfvdl 2651.1Sfvdl/* 2661.2Sfvdl * Convert BSD statfs structure to Linux statfs structure. 2671.2Sfvdl * The Linux structure has less fields, and it also wants 2681.2Sfvdl * the length of a name in a dir entry in a field, which 2691.2Sfvdl * we fake (probably the wrong way). 2701.2Sfvdl */ 2711.2Sfvdlstatic void 2721.2Sfvdlbsd_to_linux_statfs(bsp, lsp) 2731.2Sfvdl struct statfs *bsp; 2741.2Sfvdl struct linux_statfs *lsp; 2751.2Sfvdl{ 2761.2Sfvdl lsp->l_ftype = bsp->f_type; 2771.2Sfvdl lsp->l_fbsize = bsp->f_bsize; 2781.2Sfvdl lsp->l_fblocks = bsp->f_blocks; 2791.2Sfvdl lsp->l_fbfree = bsp->f_bfree; 2801.2Sfvdl lsp->l_fbavail = bsp->f_bavail; 2811.2Sfvdl lsp->l_ffiles = bsp->f_files; 2821.2Sfvdl lsp->l_fffree = bsp->f_ffree; 2831.2Sfvdl lsp->l_ffsid.val[0] = bsp->f_fsid.val[0]; 2841.2Sfvdl lsp->l_ffsid.val[1] = bsp->f_fsid.val[1]; 2851.2Sfvdl lsp->l_fnamelen = MAXNAMLEN; /* XXX */ 2861.2Sfvdl} 2871.2Sfvdl 2881.2Sfvdl/* 2891.2Sfvdl * Implement the fs stat functions. Straightforward. 2901.1Sfvdl */ 2911.1Sfvdlint 2921.1Sfvdllinux_statfs(p, uap, retval) 2931.1Sfvdl struct proc *p; 2941.1Sfvdl struct linux_statfs_args /* { 2951.1Sfvdl syscallarg(char *) path; 2961.1Sfvdl syscallarg(struct linux_statfs *) sp; 2971.1Sfvdl } */ *uap; 2981.1Sfvdl register_t *retval; 2991.1Sfvdl{ 3001.2Sfvdl struct statfs btmp, *bsp; 3011.2Sfvdl struct linux_statfs ltmp; 3021.2Sfvdl struct statfs_args bsa; 3031.2Sfvdl caddr_t sg; 3041.2Sfvdl int error; 3051.2Sfvdl 3061.9Schristos sg = stackgap_init(p->p_emul); 3071.2Sfvdl bsp = (struct statfs *) stackgap_alloc(&sg, sizeof (struct statfs)); 3081.2Sfvdl 3091.9Schristos LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path)); 3101.2Sfvdl 3111.2Sfvdl SCARG(&bsa, path) = SCARG(uap, path); 3121.2Sfvdl SCARG(&bsa, buf) = bsp; 3131.2Sfvdl 3141.2Sfvdl if ((error = statfs(p, &bsa, retval))) 3151.2Sfvdl return error; 3161.2Sfvdl 3171.2Sfvdl if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp))) 3181.2Sfvdl return error; 3191.2Sfvdl 3201.2Sfvdl bsd_to_linux_statfs(&btmp, <mp); 3211.2Sfvdl 3221.2Sfvdl return copyout((caddr_t) <mp, (caddr_t) SCARG(uap, sp), sizeof ltmp); 3231.1Sfvdl} 3241.1Sfvdl 3251.1Sfvdlint 3261.1Sfvdllinux_fstatfs(p, uap, retval) 3271.1Sfvdl struct proc *p; 3281.1Sfvdl struct linux_fstatfs_args /* { 3291.2Sfvdl syscallarg(int) fd; 3301.1Sfvdl syscallarg(struct linux_statfs *) sp; 3311.1Sfvdl } */ *uap; 3321.1Sfvdl register_t *retval; 3331.1Sfvdl{ 3341.2Sfvdl struct statfs btmp, *bsp; 3351.2Sfvdl struct linux_statfs ltmp; 3361.2Sfvdl struct fstatfs_args bsa; 3371.2Sfvdl caddr_t sg; 3381.2Sfvdl int error; 3391.2Sfvdl 3401.9Schristos sg = stackgap_init(p->p_emul); 3411.2Sfvdl bsp = (struct statfs *) stackgap_alloc(&sg, sizeof (struct statfs)); 3421.2Sfvdl 3431.2Sfvdl SCARG(&bsa, fd) = SCARG(uap, fd); 3441.2Sfvdl SCARG(&bsa, buf) = bsp; 3451.2Sfvdl 3461.2Sfvdl if ((error = statfs(p, &bsa, retval))) 3471.2Sfvdl return error; 3481.2Sfvdl 3491.2Sfvdl if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp))) 3501.2Sfvdl return error; 3511.2Sfvdl 3521.2Sfvdl bsd_to_linux_statfs(&btmp, <mp); 3531.2Sfvdl 3541.2Sfvdl return copyout((caddr_t) <mp, (caddr_t) SCARG(uap, sp), sizeof ltmp); 3551.1Sfvdl} 3561.1Sfvdl 3571.1Sfvdl/* 3581.1Sfvdl * uname(). Just copy the info from the various strings stored in the 3591.1Sfvdl * kernel, and put it in the Linux utsname structure. That structure 3601.1Sfvdl * is almost the same as the NetBSD one, only it has fields 65 characters 3611.1Sfvdl * long, and an extra domainname field. 3621.1Sfvdl */ 3631.1Sfvdlint 3641.1Sfvdllinux_uname(p, uap, retval) 3651.1Sfvdl struct proc *p; 3661.1Sfvdl struct linux_uname_args /* { 3671.1Sfvdl syscallarg(struct linux_utsname *) up; 3681.1Sfvdl } */ *uap; 3691.1Sfvdl register_t *retval; 3701.1Sfvdl{ 3711.15Smycroft extern char ostype[], hostname[], osrelease[], version[], machine[], 3721.15Smycroft domainname[]; 3731.15Smycroft struct linux_utsname luts; 3741.1Sfvdl int len; 3751.1Sfvdl char *cp; 3761.1Sfvdl 3771.15Smycroft strncpy(luts.l_sysname, ostype, sizeof(luts.l_sysname)); 3781.15Smycroft strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename)); 3791.15Smycroft strncpy(luts.l_release, osrelease, sizeof(luts.l_release)); 3801.15Smycroft strncpy(luts.l_version, version, sizeof(luts.l_version)); 3811.15Smycroft strncpy(luts.l_machine, machine, sizeof(luts.l_machine)); 3821.15Smycroft strncpy(luts.l_domainname, domainname, sizeof(luts.l_domainname)); 3831.1Sfvdl 3841.1Sfvdl /* This part taken from the the uname() in libc */ 3851.15Smycroft len = sizeof(luts.l_version); 3861.15Smycroft for (cp = luts.l_version; len--; ++cp) 3871.1Sfvdl if (*cp == '\n' || *cp == '\t') 3881.1Sfvdl if (len > 1) 3891.1Sfvdl *cp = ' '; 3901.1Sfvdl else 3911.1Sfvdl *cp = '\0'; 3921.1Sfvdl 3931.15Smycroft return copyout(&luts, SCARG(uap, up), sizeof(luts)); 3941.15Smycroft} 3951.15Smycroft 3961.15Smycroftint 3971.15Smycroftlinux_olduname(p, uap, retval) 3981.15Smycroft struct proc *p; 3991.15Smycroft struct linux_uname_args /* { 4001.15Smycroft syscallarg(struct linux_oldutsname *) up; 4011.15Smycroft } */ *uap; 4021.15Smycroft register_t *retval; 4031.15Smycroft{ 4041.15Smycroft extern char ostype[], hostname[], osrelease[], version[], machine[]; 4051.15Smycroft struct linux_oldutsname luts; 4061.15Smycroft int len; 4071.15Smycroft char *cp; 4081.15Smycroft 4091.15Smycroft strncpy(luts.l_sysname, ostype, sizeof(luts.l_sysname)); 4101.15Smycroft strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename)); 4111.15Smycroft strncpy(luts.l_release, osrelease, sizeof(luts.l_release)); 4121.15Smycroft strncpy(luts.l_version, version, sizeof(luts.l_version)); 4131.15Smycroft strncpy(luts.l_machine, machine, sizeof(luts.l_machine)); 4141.15Smycroft 4151.15Smycroft /* This part taken from the the uname() in libc */ 4161.15Smycroft len = sizeof(luts.l_version); 4171.15Smycroft for (cp = luts.l_version; len--; ++cp) 4181.15Smycroft if (*cp == '\n' || *cp == '\t') 4191.15Smycroft if (len > 1) 4201.15Smycroft *cp = ' '; 4211.15Smycroft else 4221.15Smycroft *cp = '\0'; 4231.15Smycroft 4241.15Smycroft return copyout(&luts, SCARG(uap, up), sizeof(luts)); 4251.15Smycroft} 4261.15Smycroft 4271.15Smycroftint 4281.15Smycroftlinux_oldolduname(p, uap, retval) 4291.15Smycroft struct proc *p; 4301.15Smycroft struct linux_uname_args /* { 4311.15Smycroft syscallarg(struct linux_oldoldutsname *) up; 4321.15Smycroft } */ *uap; 4331.15Smycroft register_t *retval; 4341.15Smycroft{ 4351.15Smycroft extern char ostype[], hostname[], osrelease[], version[], machine[]; 4361.15Smycroft struct linux_oldoldutsname luts; 4371.15Smycroft int len; 4381.15Smycroft char *cp; 4391.15Smycroft 4401.15Smycroft strncpy(luts.l_sysname, ostype, sizeof(luts.l_sysname)); 4411.15Smycroft strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename)); 4421.15Smycroft strncpy(luts.l_release, osrelease, sizeof(luts.l_release)); 4431.15Smycroft strncpy(luts.l_version, version, sizeof(luts.l_version)); 4441.15Smycroft strncpy(luts.l_machine, machine, sizeof(luts.l_machine)); 4451.15Smycroft 4461.15Smycroft /* This part taken from the the uname() in libc */ 4471.15Smycroft len = sizeof(luts.l_version); 4481.15Smycroft for (cp = luts.l_version; len--; ++cp) 4491.15Smycroft if (*cp == '\n' || *cp == '\t') 4501.15Smycroft if (len > 1) 4511.15Smycroft *cp = ' '; 4521.15Smycroft else 4531.15Smycroft *cp = '\0'; 4541.15Smycroft 4551.15Smycroft return copyout(&luts, SCARG(uap, up), sizeof(luts)); 4561.1Sfvdl} 4571.1Sfvdl 4581.1Sfvdl/* 4591.1Sfvdl * Linux wants to pass everything to a syscall in registers. However, 4601.1Sfvdl * mmap() has 6 of them. Oops: out of register error. They just pass 4611.1Sfvdl * everything in a structure. 4621.1Sfvdl */ 4631.1Sfvdlint 4641.1Sfvdllinux_mmap(p, uap, retval) 4651.1Sfvdl struct proc *p; 4661.1Sfvdl struct linux_mmap_args /* { 4671.1Sfvdl syscallarg(struct linux_mmap *) lmp; 4681.1Sfvdl } */ *uap; 4691.1Sfvdl register_t *retval; 4701.1Sfvdl{ 4711.1Sfvdl struct linux_mmap lmap; 4721.1Sfvdl struct mmap_args cma; 4731.1Sfvdl int error, flags; 4741.1Sfvdl 4751.1Sfvdl if ((error = copyin(SCARG(uap, lmp), &lmap, sizeof lmap))) 4761.1Sfvdl return error; 4771.1Sfvdl 4781.1Sfvdl flags = 0; 4791.1Sfvdl flags |= cvtto_bsd_mask(lmap.lm_flags, LINUX_MAP_SHARED, MAP_SHARED); 4801.1Sfvdl flags |= cvtto_bsd_mask(lmap.lm_flags, LINUX_MAP_PRIVATE, MAP_PRIVATE); 4811.1Sfvdl flags |= cvtto_bsd_mask(lmap.lm_flags, LINUX_MAP_FIXED, MAP_FIXED); 4821.1Sfvdl flags |= cvtto_bsd_mask(lmap.lm_flags, LINUX_MAP_ANON, MAP_ANON); 4831.1Sfvdl 4841.1Sfvdl SCARG(&cma,addr) = lmap.lm_addr; 4851.1Sfvdl SCARG(&cma,len) = lmap.lm_len; 4861.1Sfvdl SCARG(&cma,prot) = lmap.lm_prot; 4871.1Sfvdl SCARG(&cma,flags) = flags; 4881.1Sfvdl SCARG(&cma,fd) = lmap.lm_fd; 4891.1Sfvdl SCARG(&cma,pad) = 0; 4901.1Sfvdl SCARG(&cma,pos) = lmap.lm_pos; 4911.1Sfvdl 4921.1Sfvdl return mmap(p, &cma, retval); 4931.1Sfvdl} 4941.1Sfvdl 4951.1Sfvdl/* 4961.1Sfvdl * Linux doesn't use the retval[1] value to determine whether 4971.1Sfvdl * we are the child or parent. 4981.1Sfvdl */ 4991.1Sfvdlint 5001.1Sfvdllinux_fork(p, uap, retval) 5011.1Sfvdl struct proc *p; 5021.1Sfvdl void *uap; 5031.1Sfvdl register_t *retval; 5041.1Sfvdl{ 5051.1Sfvdl int error; 5061.1Sfvdl 5071.1Sfvdl if ((error = fork(p, uap, retval))) 5081.1Sfvdl return error; 5091.1Sfvdl 5101.1Sfvdl if (retval[1] == 1) 5111.1Sfvdl retval[0] = 0; 5121.1Sfvdl 5131.1Sfvdl return 0; 5141.1Sfvdl} 5151.1Sfvdl 5161.1Sfvdl/* 5171.1Sfvdl * This code is partly stolen from src/lib/libc/compat-43/times.c 5181.1Sfvdl * XXX - CLK_TCK isn't declared in /sys, just in <time.h>, done here 5191.1Sfvdl */ 5201.1Sfvdl 5211.1Sfvdl#define CLK_TCK 100 5221.1Sfvdl#define CONVTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK)) 5231.1Sfvdl 5241.1Sfvdlint 5251.1Sfvdllinux_times(p, uap, retval) 5261.1Sfvdl struct proc *p; 5271.1Sfvdl struct linux_times_args /* { 5281.1Sfvdl syscallarg(struct times *) tms; 5291.1Sfvdl } */ *uap; 5301.1Sfvdl register_t *retval; 5311.1Sfvdl{ 5321.1Sfvdl struct timeval t; 5331.1Sfvdl struct linux_tms ltms; 5341.1Sfvdl struct rusage ru; 5351.4Smycroft int error, s; 5361.1Sfvdl 5371.1Sfvdl calcru(p, &ru.ru_utime, &ru.ru_stime, NULL); 5381.1Sfvdl ltms.ltms_utime = CONVTCK(ru.ru_utime); 5391.1Sfvdl ltms.ltms_stime = CONVTCK(ru.ru_stime); 5401.1Sfvdl 5411.1Sfvdl ltms.ltms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime); 5421.1Sfvdl ltms.ltms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime); 5431.1Sfvdl 5441.1Sfvdl if ((error = copyout(<ms, SCARG(uap, tms), sizeof ltms))) 5451.1Sfvdl return error; 5461.1Sfvdl 5471.4Smycroft s = splclock(); 5481.4Smycroft timersub(&time, &boottime, &t); 5491.4Smycroft splx(s); 5501.1Sfvdl 5511.1Sfvdl retval[0] = ((linux_clock_t)(CONVTCK(t))); 5521.1Sfvdl return 0; 5531.1Sfvdl} 5541.1Sfvdl 5551.1Sfvdl/* 5561.1Sfvdl * NetBSD passes fd[0] in retval[0], and fd[1] in retval[1]. 5571.1Sfvdl * Linux directly passes the pointer. 5581.1Sfvdl */ 5591.1Sfvdlint 5601.1Sfvdllinux_pipe(p, uap, retval) 5611.1Sfvdl struct proc *p; 5621.1Sfvdl struct linux_pipe_args /* { 5631.1Sfvdl syscallarg(int *) pfds; 5641.1Sfvdl } */ *uap; 5651.1Sfvdl register_t *retval; 5661.1Sfvdl{ 5671.1Sfvdl int error; 5681.1Sfvdl 5691.1Sfvdl if ((error = pipe(p, 0, retval))) 5701.1Sfvdl return error; 5711.1Sfvdl 5721.1Sfvdl /* Assumes register_t is an int */ 5731.1Sfvdl 5741.1Sfvdl if ((error = copyout(retval, SCARG(uap, pfds), 2 * sizeof (int)))) 5751.1Sfvdl return error; 5761.1Sfvdl 5771.1Sfvdl retval[0] = 0; 5781.1Sfvdl return 0; 5791.1Sfvdl} 5801.1Sfvdl 5811.1Sfvdl/* 5821.1Sfvdl * Alarm. This is a libc call which used setitimer(2) in NetBSD. 5831.1Sfvdl * Fiddle with the timers to make it work. 5841.1Sfvdl */ 5851.1Sfvdlint 5861.1Sfvdllinux_alarm(p, uap, retval) 5871.1Sfvdl struct proc *p; 5881.1Sfvdl struct linux_alarm_args /* { 5891.1Sfvdl syscallarg(unsigned int) secs; 5901.1Sfvdl } */ *uap; 5911.1Sfvdl register_t *retval; 5921.1Sfvdl{ 5931.1Sfvdl int error, s; 5941.1Sfvdl struct itimerval *itp, it; 5951.1Sfvdl 5961.1Sfvdl itp = &p->p_realtimer; 5971.1Sfvdl s = splclock(); 5981.1Sfvdl /* 5991.1Sfvdl * Clear any pending timer alarms. 6001.1Sfvdl */ 6011.1Sfvdl untimeout(realitexpire, p); 6021.1Sfvdl timerclear(&itp->it_interval); 6031.1Sfvdl if (timerisset(&itp->it_value) && 6041.1Sfvdl timercmp(&itp->it_value, &time, >)) 6051.3Smycroft timersub(&itp->it_value, &time, &itp->it_value); 6061.1Sfvdl /* 6071.1Sfvdl * Return how many seconds were left (rounded up) 6081.1Sfvdl */ 6091.1Sfvdl retval[0] = itp->it_value.tv_sec; 6101.1Sfvdl if (itp->it_value.tv_usec) 6111.1Sfvdl retval[0]++; 6121.1Sfvdl 6131.1Sfvdl /* 6141.1Sfvdl * alarm(0) just resets the timer. 6151.1Sfvdl */ 6161.1Sfvdl if (SCARG(uap, secs) == 0) { 6171.1Sfvdl timerclear(&itp->it_value); 6181.1Sfvdl splx(s); 6191.1Sfvdl return 0; 6201.1Sfvdl } 6211.1Sfvdl 6221.1Sfvdl /* 6231.1Sfvdl * Check the new alarm time for sanity, and set it. 6241.1Sfvdl */ 6251.1Sfvdl timerclear(&it.it_interval); 6261.1Sfvdl it.it_value.tv_sec = SCARG(uap, secs); 6271.1Sfvdl it.it_value.tv_usec = 0; 6281.1Sfvdl if (itimerfix(&it.it_value) || itimerfix(&it.it_interval)) { 6291.1Sfvdl splx(s); 6301.1Sfvdl return (EINVAL); 6311.1Sfvdl } 6321.1Sfvdl 6331.1Sfvdl if (timerisset(&it.it_value)) { 6341.3Smycroft timeradd(&it.it_value, &time, &it.it_value); 6351.1Sfvdl timeout(realitexpire, p, hzto(&it.it_value)); 6361.1Sfvdl } 6371.1Sfvdl p->p_realtimer = it; 6381.1Sfvdl splx(s); 6391.1Sfvdl 6401.1Sfvdl return 0; 6411.1Sfvdl} 6421.1Sfvdl 6431.1Sfvdl/* 6441.1Sfvdl * utime(). Do conversion to things that utimes() understands, 6451.1Sfvdl * and pass it on. 6461.1Sfvdl */ 6471.1Sfvdlint 6481.1Sfvdllinux_utime(p, uap, retval) 6491.1Sfvdl struct proc *p; 6501.1Sfvdl struct linux_utime_args /* { 6511.1Sfvdl syscallarg(char *) path; 6521.1Sfvdl syscallarg(struct linux_utimbuf *)times; 6531.1Sfvdl } */ *uap; 6541.1Sfvdl register_t *retval; 6551.1Sfvdl{ 6561.1Sfvdl caddr_t sg; 6571.1Sfvdl int error; 6581.1Sfvdl struct utimes_args ua; 6591.1Sfvdl struct timeval tv[2], *tvp; 6601.1Sfvdl struct linux_utimbuf lut; 6611.1Sfvdl 6621.9Schristos sg = stackgap_init(p->p_emul); 6631.9Schristos LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path)); 6641.1Sfvdl 6651.1Sfvdl SCARG(&ua, path) = SCARG(uap, path); 6661.1Sfvdl 6671.1Sfvdl if (SCARG(uap, times) != NULL) { 6681.1Sfvdl if ((error = copyin(SCARG(uap, times), &lut, sizeof lut))) 6691.1Sfvdl return error; 6701.1Sfvdl tv[0].tv_usec = tv[1].tv_usec = 0; 6711.1Sfvdl tv[0].tv_sec = lut.l_actime; 6721.1Sfvdl tv[1].tv_sec = lut.l_modtime; 6731.9Schristos tvp = (struct timeval *) stackgap_alloc(&sg, sizeof(tv)); 6741.1Sfvdl if ((error = copyout(tv, tvp, sizeof tv))) 6751.1Sfvdl return error; 6761.1Sfvdl SCARG(&ua, tptr) = tvp; 6771.1Sfvdl } 6781.1Sfvdl else 6791.1Sfvdl SCARG(&ua, tptr) = NULL; 6801.1Sfvdl 6811.1Sfvdl return utimes(p, uap, retval); 6821.1Sfvdl} 6831.1Sfvdl 6841.1Sfvdl/* 6851.17Sfvdl * The old Linux readdir was only able to read one entry at a time, 6861.17Sfvdl * even though it had a 'count' argument. In fact, the emulation 6871.17Sfvdl * of the old call was better than the original, because it did handle 6881.17Sfvdl * the count arg properly. Don't bother with it anymore now, and use 6891.17Sfvdl * it to distinguish between old and new. The difference is that the 6901.17Sfvdl * newer one actually does multiple entries, and the reclen field 6911.17Sfvdl * really is the reclen, not the namelength. 6921.17Sfvdl */ 6931.17Sfvdlint 6941.17Sfvdllinux_readdir(p, uap, retval) 6951.17Sfvdl struct proc *p; 6961.17Sfvdl struct linux_readdir_args /* { 6971.17Sfvdl syscallarg(int) fd; 6981.17Sfvdl syscallarg(struct linux_dirent *) dent; 6991.17Sfvdl syscallarg(unsigned int) count; 7001.17Sfvdl } */ *uap; 7011.17Sfvdl register_t *retval; 7021.17Sfvdl{ 7031.17Sfvdl SCARG(uap, count) = 1; 7041.17Sfvdl return linux_getdents(p, uap, retval); 7051.17Sfvdl} 7061.17Sfvdl 7071.17Sfvdl/* 7081.1Sfvdl * Linux 'readdir' call. This code is mostly taken from the 7091.1Sfvdl * SunOS getdents call (see compat/sunos/sunos_misc.c), though 7101.1Sfvdl * an attempt has been made to keep it a little cleaner (failing 7111.1Sfvdl * miserably, because of the cruft needed if count 1 is passed). 7121.1Sfvdl * 7131.17Sfvdl * The d_off field should contain the offset of the next valid entry, 7141.17Sfvdl * but in Linux it has the offset of the entry itself. We emulate 7151.17Sfvdl * that bug here. 7161.17Sfvdl * 7171.1Sfvdl * Read in BSD-style entries, convert them, and copy them out. 7181.1Sfvdl * 7191.1Sfvdl * Note that this doesn't handle union-mounted filesystems. 7201.1Sfvdl */ 7211.1Sfvdlint 7221.17Sfvdllinux_getdents(p, uap, retval) 7231.1Sfvdl struct proc *p; 7241.1Sfvdl struct linux_readdir_args /* { 7251.1Sfvdl syscallarg(int) fd; 7261.1Sfvdl syscallarg(struct linux_dirent *) dent; 7271.1Sfvdl syscallarg(unsigned int) count; 7281.1Sfvdl } */ *uap; 7291.1Sfvdl register_t *retval; 7301.1Sfvdl{ 7311.1Sfvdl register struct dirent *bdp; 7321.1Sfvdl struct vnode *vp; 7331.1Sfvdl caddr_t inp, buf; /* BSD-format */ 7341.1Sfvdl int len, reclen; /* BSD-format */ 7351.1Sfvdl caddr_t outp; /* Linux-format */ 7361.1Sfvdl int resid, linuxreclen; /* Linux-format */ 7371.1Sfvdl struct file *fp; 7381.1Sfvdl struct uio auio; 7391.1Sfvdl struct iovec aiov; 7401.1Sfvdl struct linux_dirent idb; 7411.1Sfvdl off_t off; /* true file offset */ 7421.1Sfvdl linux_off_t soff; /* Linux file offset */ 7431.17Sfvdl int buflen, error, eofflag, nbytes, oldcall; 7441.1Sfvdl struct vattr va; 7451.1Sfvdl 7461.1Sfvdl if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 7471.1Sfvdl return (error); 7481.1Sfvdl 7491.1Sfvdl if ((fp->f_flag & FREAD) == 0) 7501.1Sfvdl return (EBADF); 7511.1Sfvdl 7521.5Smycroft vp = (struct vnode *)fp->f_data; 7531.1Sfvdl 7541.1Sfvdl if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */ 7551.1Sfvdl return (EINVAL); 7561.1Sfvdl 7571.1Sfvdl if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) 7581.1Sfvdl return error; 7591.1Sfvdl 7601.1Sfvdl nbytes = SCARG(uap, count); 7611.17Sfvdl if (nbytes == 1) { /* emulating old, broken behaviour */ 7621.1Sfvdl nbytes = sizeof (struct linux_dirent); 7631.5Smycroft buflen = max(va.va_blocksize, nbytes); 7641.17Sfvdl oldcall = 1; 7651.5Smycroft } else { 7661.5Smycroft buflen = min(MAXBSIZE, nbytes); 7671.17Sfvdl oldcall = 0; 7681.1Sfvdl } 7691.1Sfvdl buf = malloc(buflen, M_TEMP, M_WAITOK); 7701.1Sfvdl VOP_LOCK(vp); 7711.1Sfvdl off = fp->f_offset; 7721.1Sfvdlagain: 7731.1Sfvdl aiov.iov_base = buf; 7741.1Sfvdl aiov.iov_len = buflen; 7751.1Sfvdl auio.uio_iov = &aiov; 7761.1Sfvdl auio.uio_iovcnt = 1; 7771.1Sfvdl auio.uio_rw = UIO_READ; 7781.1Sfvdl auio.uio_segflg = UIO_SYSSPACE; 7791.1Sfvdl auio.uio_procp = p; 7801.1Sfvdl auio.uio_resid = buflen; 7811.1Sfvdl auio.uio_offset = off; 7821.1Sfvdl /* 7831.1Sfvdl * First we read into the malloc'ed buffer, then 7841.1Sfvdl * we massage it into user space, one record at a time. 7851.1Sfvdl */ 7861.5Smycroft error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0); 7871.1Sfvdl if (error) 7881.1Sfvdl goto out; 7891.1Sfvdl 7901.1Sfvdl inp = buf; 7911.1Sfvdl outp = (caddr_t) SCARG(uap, dent); 7921.1Sfvdl resid = nbytes; 7931.1Sfvdl if ((len = buflen - auio.uio_resid) == 0) 7941.1Sfvdl goto eof; 7951.1Sfvdl 7961.1Sfvdl for (; len > 0; len -= reclen) { 7971.5Smycroft bdp = (struct dirent *)inp; 7981.5Smycroft reclen = bdp->d_reclen; 7991.1Sfvdl if (reclen & 3) 8001.1Sfvdl panic("linux_readdir"); 8011.19Sfvdl off += reclen; 8021.1Sfvdl if (bdp->d_fileno == 0) { 8031.1Sfvdl inp += reclen; /* it is a hole; squish it out */ 8041.1Sfvdl continue; 8051.1Sfvdl } 8061.1Sfvdl linuxreclen = LINUX_RECLEN(&idb, bdp->d_namlen); 8071.1Sfvdl if (reclen > len || resid < linuxreclen) { 8081.1Sfvdl /* entry too big for buffer, so just stop */ 8091.1Sfvdl outp++; 8101.1Sfvdl break; 8111.1Sfvdl } 8121.1Sfvdl /* 8131.1Sfvdl * Massage in place to make a Linux-shaped dirent (otherwise 8141.1Sfvdl * we have to worry about touching user memory outside of 8151.1Sfvdl * the copyout() call). 8161.1Sfvdl */ 8171.5Smycroft idb.d_ino = (long)bdp->d_fileno; 8181.19Sfvdl idb.d_off = off - reclen; 8191.17Sfvdl /* 8201.17Sfvdl * The old readdir() call used the reclen field as namlen. 8211.17Sfvdl */ 8221.17Sfvdl idb.d_reclen = oldcall ? (u_short)bdp->d_namlen : linuxreclen; 8231.5Smycroft strcpy(idb.d_name, bdp->d_name); 8241.1Sfvdl if ((error = copyout((caddr_t)&idb, outp, linuxreclen))) 8251.1Sfvdl goto out; 8261.1Sfvdl /* advance past this real entry */ 8271.1Sfvdl inp += reclen; 8281.1Sfvdl /* advance output past Linux-shaped entry */ 8291.1Sfvdl outp += linuxreclen; 8301.1Sfvdl resid -= linuxreclen; 8311.17Sfvdl if (oldcall) 8321.1Sfvdl break; 8331.1Sfvdl } 8341.1Sfvdl 8351.1Sfvdl /* if we squished out the whole block, try again */ 8361.1Sfvdl if (outp == (caddr_t) SCARG(uap, dent)) 8371.1Sfvdl goto again; 8381.1Sfvdl fp->f_offset = off; /* update the vnode offset */ 8391.1Sfvdl 8401.17Sfvdl if (oldcall) 8411.1Sfvdl nbytes = resid + linuxreclen; 8421.1Sfvdl 8431.1Sfvdleof: 8441.1Sfvdl *retval = nbytes - resid; 8451.1Sfvdlout: 8461.1Sfvdl VOP_UNLOCK(vp); 8471.1Sfvdl free(buf, M_TEMP); 8481.1Sfvdl return error; 8491.1Sfvdl} 8501.1Sfvdl 8511.1Sfvdl/* 8521.17Sfvdl * Not sure why the arguments to this older version of select() were put 8531.17Sfvdl * into a structure, because there are 5, and that can all be handled 8541.17Sfvdl * in registers on the i386 like Linux wants to. 8551.17Sfvdl */ 8561.17Sfvdlint 8571.17Sfvdllinux_oldselect(p, uap, retval) 8581.17Sfvdl struct proc *p; 8591.17Sfvdl struct linux_oldselect_args /* { 8601.17Sfvdl syscallarg(struct linux_select *) lsp; 8611.17Sfvdl } */ *uap; 8621.17Sfvdl register_t *retval; 8631.17Sfvdl{ 8641.17Sfvdl struct linux_select ls; 8651.17Sfvdl int error; 8661.17Sfvdl 8671.17Sfvdl if ((error = copyin(SCARG(uap, lsp), &ls, sizeof(ls)))) 8681.17Sfvdl return error; 8691.17Sfvdl 8701.17Sfvdl return linux_select1(p, retval, ls.nfds, ls.readfds, ls.writefds, 8711.17Sfvdl ls.exceptfds, ls.timeout); 8721.17Sfvdl} 8731.17Sfvdl 8741.17Sfvdl/* 8751.17Sfvdl * Even when just using registers to pass arguments to syscalls you can 8761.17Sfvdl * have 5 of them on the i386. So this newer version of select() does 8771.17Sfvdl * this. 8781.1Sfvdl */ 8791.1Sfvdlint 8801.1Sfvdllinux_select(p, uap, retval) 8811.1Sfvdl struct proc *p; 8821.1Sfvdl struct linux_select_args /* { 8831.17Sfvdl syscallarg(int) nfds; 8841.17Sfvdl syscallarg(fd_set *) readfds; 8851.17Sfvdl syscallarg(fd_set *) writefds; 8861.17Sfvdl syscallarg(fd_set *) exceptfds; 8871.17Sfvdl syscallarg(struct timeval *) timeout; 8881.1Sfvdl } */ *uap; 8891.1Sfvdl register_t *retval; 8901.1Sfvdl{ 8911.17Sfvdl return linux_select1(p, retval, SCARG(uap, nfds), SCARG(uap, readfds), 8921.17Sfvdl SCARG(uap, writefds), SCARG(uap, exceptfds), SCARG(uap, timeout)); 8931.17Sfvdl} 8941.17Sfvdl 8951.17Sfvdl/* 8961.17Sfvdl * Common code for the old and new versions of select(). A couple of 8971.17Sfvdl * things are important: 8981.17Sfvdl * 1) return the amount of time left in the 'timeout' parameter 8991.17Sfvdl * 2) select never returns ERESTART on Linux, always return EINTR 9001.17Sfvdl */ 9011.17Sfvdlint 9021.17Sfvdllinux_select1(p, retval, nfds, readfds, writefds, exceptfds, timeout) 9031.17Sfvdl struct proc *p; 9041.17Sfvdl register_t *retval; 9051.17Sfvdl int nfds; 9061.17Sfvdl fd_set *readfds, *writefds, *exceptfds; 9071.17Sfvdl struct timeval *timeout; 9081.17Sfvdl{ 9091.1Sfvdl struct select_args bsa; 9101.13Smycroft struct timeval tv0, tv1, utv, *tvp; 9111.13Smycroft caddr_t sg; 9121.1Sfvdl int error; 9131.1Sfvdl 9141.17Sfvdl SCARG(&bsa, nd) = nfds; 9151.17Sfvdl SCARG(&bsa, in) = readfds; 9161.17Sfvdl SCARG(&bsa, ou) = writefds; 9171.17Sfvdl SCARG(&bsa, ex) = exceptfds; 9181.17Sfvdl SCARG(&bsa, tv) = timeout; 9191.1Sfvdl 9201.7Sfvdl /* 9211.7Sfvdl * Store current time for computation of the amount of 9221.7Sfvdl * time left. 9231.7Sfvdl */ 9241.17Sfvdl if (timeout) { 9251.17Sfvdl if ((error = copyin(timeout, &utv, sizeof(utv)))) 9261.13Smycroft return error; 9271.13Smycroft if (itimerfix(&utv)) { 9281.13Smycroft /* 9291.13Smycroft * The timeval was invalid. Convert it to something 9301.13Smycroft * valid that will act as it does under Linux. 9311.13Smycroft */ 9321.13Smycroft sg = stackgap_init(p->p_emul); 9331.13Smycroft tvp = stackgap_alloc(&sg, sizeof(utv)); 9341.13Smycroft utv.tv_sec += utv.tv_usec / 1000000; 9351.13Smycroft utv.tv_usec %= 1000000; 9361.13Smycroft if (utv.tv_usec < 0) { 9371.13Smycroft utv.tv_sec -= 1; 9381.13Smycroft utv.tv_usec += 1000000; 9391.13Smycroft } 9401.13Smycroft if (utv.tv_sec < 0) 9411.13Smycroft timerclear(&utv); 9421.13Smycroft if ((error = copyout(&utv, tvp, sizeof(utv)))) 9431.13Smycroft return error; 9441.13Smycroft SCARG(&bsa, tv) = tvp; 9451.13Smycroft } 9461.7Sfvdl microtime(&tv0); 9471.13Smycroft } 9481.7Sfvdl 9491.10Smycroft error = select(p, &bsa, retval); 9501.10Smycroft if (error) { 9511.10Smycroft /* 9521.10Smycroft * See fs/select.c in the Linux kernel. Without this, 9531.10Smycroft * Maelstrom doesn't work. 9541.10Smycroft */ 9551.10Smycroft if (error == ERESTART) 9561.10Smycroft error = EINTR; 9571.7Sfvdl return error; 9581.10Smycroft } 9591.7Sfvdl 9601.17Sfvdl if (timeout) { 9611.14Smycroft if (*retval) { 9621.7Sfvdl /* 9631.13Smycroft * Compute how much time was left of the timeout, 9641.7Sfvdl * by subtracting the current time and the time 9651.7Sfvdl * before we started the call, and subtracting 9661.7Sfvdl * that result from the user-supplied value. 9671.7Sfvdl */ 9681.7Sfvdl microtime(&tv1); 9691.7Sfvdl timersub(&tv1, &tv0, &tv1); 9701.7Sfvdl timersub(&utv, &tv1, &utv); 9711.14Smycroft if (utv.tv_sec < 0) 9721.14Smycroft timerclear(&utv); 9731.14Smycroft } else 9741.14Smycroft timerclear(&utv); 9751.17Sfvdl if ((error = copyout(&utv, timeout, sizeof(utv)))) 9761.7Sfvdl return error; 9771.7Sfvdl } 9781.13Smycroft 9791.7Sfvdl return 0; 9801.1Sfvdl} 9811.1Sfvdl 9821.1Sfvdl/* 9831.1Sfvdl * Get the process group of a certain process. Look it up 9841.1Sfvdl * and return the value. 9851.1Sfvdl */ 9861.1Sfvdlint 9871.1Sfvdllinux_getpgid(p, uap, retval) 9881.1Sfvdl struct proc *p; 9891.1Sfvdl struct linux_getpgid_args /* { 9901.1Sfvdl syscallarg(int) pid; 9911.1Sfvdl } */ *uap; 9921.1Sfvdl register_t *retval; 9931.1Sfvdl{ 9941.1Sfvdl struct proc *targp; 9951.1Sfvdl 9961.1Sfvdl if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != p->p_pid) 9971.1Sfvdl if ((targp = pfind(SCARG(uap, pid))) == 0) 9981.1Sfvdl return ESRCH; 9991.1Sfvdl else 10001.1Sfvdl targp = p; 10011.1Sfvdl 10021.1Sfvdl retval[0] = targp->p_pgid; 10031.6Sfvdl return 0; 10041.6Sfvdl} 10051.6Sfvdl 10061.6Sfvdl/* 10071.6Sfvdl * Set the 'personality' (emulation mode) for the current process. Only 10081.6Sfvdl * accept the Linux personality here (0). This call is needed because 10091.6Sfvdl * the Linux ELF crt0 issues it in an ugly kludge to make sure that 10101.6Sfvdl * ELF binaries run in Linux mode, not SVR4 mode. 10111.6Sfvdl */ 10121.6Sfvdlint 10131.6Sfvdllinux_personality(p, uap, retval) 10141.6Sfvdl struct proc *p; 10151.18Sfvdl struct linux_personality_args /* { 10161.6Sfvdl syscallarg(int) per; 10171.6Sfvdl } */ *uap; 10181.6Sfvdl register_t *retval; 10191.6Sfvdl{ 10201.6Sfvdl if (SCARG(uap, per) != 0) 10211.6Sfvdl return EINVAL; 10221.6Sfvdl retval[0] = 0; 10231.1Sfvdl return 0; 10241.18Sfvdl} 10251.18Sfvdl 10261.18Sfvdl/* 10271.18Sfvdl * The calls are here because of type conversions. 10281.18Sfvdl */ 10291.18Sfvdlint 10301.18Sfvdllinux_setreuid(p, uap, retval) 10311.18Sfvdl struct proc *p; 10321.18Sfvdl struct linux_setreuid_args /* { 10331.18Sfvdl syscallarg(int) ruid; 10341.18Sfvdl syscallarg(int) euid; 10351.18Sfvdl } */ *uap; 10361.18Sfvdl register_t *retval; 10371.18Sfvdl{ 10381.18Sfvdl struct compat_43_setreuid_args bsa; 10391.18Sfvdl 10401.18Sfvdl SCARG(&bsa, ruid) = ((linux_uid_t)SCARG(uap, ruid) == (linux_uid_t)-1) ? 10411.18Sfvdl (uid_t)-1 : SCARG(uap, ruid); 10421.18Sfvdl SCARG(&bsa, euid) = ((linux_uid_t)SCARG(uap, euid) == (linux_uid_t)-1) ? 10431.18Sfvdl (uid_t)-1 : SCARG(uap, euid); 10441.18Sfvdl 10451.18Sfvdl return compat_43_setreuid(p, &bsa, retval); 10461.18Sfvdl} 10471.18Sfvdl 10481.18Sfvdlint 10491.18Sfvdllinux_setregid(p, uap, retval) 10501.18Sfvdl struct proc *p; 10511.18Sfvdl struct linux_setregid_args /* { 10521.18Sfvdl syscallarg(int) rgid; 10531.18Sfvdl syscallarg(int) egid; 10541.18Sfvdl } */ *uap; 10551.18Sfvdl register_t *retval; 10561.18Sfvdl{ 10571.18Sfvdl struct compat_43_setregid_args bsa; 10581.18Sfvdl 10591.18Sfvdl SCARG(&bsa, rgid) = ((linux_gid_t)SCARG(uap, rgid) == (linux_gid_t)-1) ? 10601.18Sfvdl (uid_t)-1 : SCARG(uap, rgid); 10611.18Sfvdl SCARG(&bsa, egid) = ((linux_gid_t)SCARG(uap, egid) == (linux_gid_t)-1) ? 10621.18Sfvdl (uid_t)-1 : SCARG(uap, egid); 10631.18Sfvdl 10641.18Sfvdl return compat_43_setregid(p, &bsa, retval); 10651.1Sfvdl} 1066