linux_pipe.c revision 1.21
11.21Smycroft/* $NetBSD: linux_pipe.c,v 1.21 1995/10/07 06:27:10 mycroft 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.21Smycroft 891.1Sfvdl if (WIFSIGNALED(*status)) 901.1Sfvdl *status = (*status & ~0177) | 911.12Smycroft bsd_to_linux_sig[WTERMSIG(*status)]; 921.1Sfvdl else if (WIFSTOPPED(*status)) 931.1Sfvdl *status = (*status & ~0xff00) | 941.12Smycroft (bsd_to_linux_sig[WSTOPSIG(*status)] << 8); 951.1Sfvdl} 961.1Sfvdl 971.1Sfvdl/* 981.1Sfvdl * waitpid(2). Passed on to the NetBSD call, surrounded by code to 991.1Sfvdl * reserve some space for a NetBSD-style wait status, and converting 1001.1Sfvdl * it to what Linux wants. 1011.1Sfvdl */ 1021.1Sfvdlint 1031.21Smycroftlinux_sys_waitpid(p, v, retval) 1041.1Sfvdl struct proc *p; 1051.20Sthorpej void *v; 1061.20Sthorpej register_t *retval; 1071.20Sthorpej{ 1081.21Smycroft struct linux_sys_waitpid_args /* { 1091.1Sfvdl syscallarg(int) pid; 1101.1Sfvdl syscallarg(int *) status; 1111.1Sfvdl syscallarg(int) options; 1121.20Sthorpej } */ *uap = v; 1131.21Smycroft struct sys_wait4_args w4a; 1141.1Sfvdl int error, *status, tstat; 1151.1Sfvdl caddr_t sg; 1161.1Sfvdl 1171.16Sfvdl if (SCARG(uap, status) != NULL) { 1181.16Sfvdl sg = stackgap_init(p->p_emul); 1191.16Sfvdl status = (int *) stackgap_alloc(&sg, sizeof status); 1201.16Sfvdl } else 1211.16Sfvdl status = NULL; 1221.1Sfvdl 1231.1Sfvdl SCARG(&w4a, pid) = SCARG(uap, pid); 1241.1Sfvdl SCARG(&w4a, status) = status; 1251.1Sfvdl SCARG(&w4a, options) = SCARG(uap, options); 1261.1Sfvdl SCARG(&w4a, rusage) = NULL; 1271.1Sfvdl 1281.21Smycroft if ((error = sys_wait4(p, &w4a, retval))) 1291.1Sfvdl return error; 1301.1Sfvdl 1311.18Sfvdl p->p_siglist &= ~sigmask(SIGCHLD); 1321.18Sfvdl 1331.16Sfvdl if (status != NULL) { 1341.16Sfvdl if ((error = copyin(status, &tstat, sizeof tstat))) 1351.16Sfvdl return error; 1361.16Sfvdl 1371.16Sfvdl bsd_to_linux_wstat(&tstat); 1381.16Sfvdl return copyout(&tstat, SCARG(uap, status), sizeof tstat); 1391.16Sfvdl } 1401.1Sfvdl 1411.16Sfvdl return 0; 1421.1Sfvdl} 1431.1Sfvdl 1441.1Sfvdl/* 1451.1Sfvdl * This is very much the same as waitpid() 1461.1Sfvdl */ 1471.1Sfvdlint 1481.21Smycroftlinux_sys_wait4(p, v, retval) 1491.1Sfvdl struct proc *p; 1501.20Sthorpej void *v; 1511.20Sthorpej register_t *retval; 1521.20Sthorpej{ 1531.21Smycroft struct linux_sys_wait4_args /* { 1541.1Sfvdl syscallarg(int) pid; 1551.1Sfvdl syscallarg(int *) status; 1561.1Sfvdl syscallarg(int) options; 1571.1Sfvdl syscallarg(struct rusage *) rusage; 1581.20Sthorpej } */ *uap = v; 1591.21Smycroft struct sys_wait4_args w4a; 1601.1Sfvdl int error, *status, tstat; 1611.1Sfvdl caddr_t sg; 1621.1Sfvdl 1631.16Sfvdl if (SCARG(uap, status) != NULL) { 1641.16Sfvdl sg = stackgap_init(p->p_emul); 1651.16Sfvdl status = (int *) stackgap_alloc(&sg, sizeof status); 1661.16Sfvdl } else 1671.16Sfvdl status = NULL; 1681.1Sfvdl 1691.1Sfvdl SCARG(&w4a, pid) = SCARG(uap, pid); 1701.1Sfvdl SCARG(&w4a, status) = status; 1711.1Sfvdl SCARG(&w4a, options) = SCARG(uap, options); 1721.1Sfvdl SCARG(&w4a, rusage) = SCARG(uap, rusage); 1731.1Sfvdl 1741.21Smycroft if ((error = sys_wait4(p, &w4a, retval))) 1751.1Sfvdl return error; 1761.1Sfvdl 1771.18Sfvdl p->p_siglist &= ~sigmask(SIGCHLD); 1781.18Sfvdl 1791.16Sfvdl if (status != NULL) { 1801.16Sfvdl if ((error = copyin(status, &tstat, sizeof tstat))) 1811.16Sfvdl return error; 1821.16Sfvdl 1831.16Sfvdl bsd_to_linux_wstat(&tstat); 1841.1Sfvdl 1851.16Sfvdl return copyout(&tstat, SCARG(uap, status), sizeof tstat); 1861.16Sfvdl } 1871.1Sfvdl 1881.16Sfvdl return 0; 1891.1Sfvdl} 1901.1Sfvdl 1911.1Sfvdl/* 1921.1Sfvdl * This is the old brk(2) call. I don't think anything in the Linux 1931.1Sfvdl * world uses this anymore 1941.1Sfvdl */ 1951.1Sfvdlint 1961.21Smycroftlinux_sys_break(p, v, retval) 1971.1Sfvdl struct proc *p; 1981.20Sthorpej void *v; 1991.20Sthorpej register_t *retval; 2001.20Sthorpej{ 2011.21Smycroft struct linux_sys_brk_args /* { 2021.1Sfvdl syscallarg(char *) nsize; 2031.20Sthorpej } */ *uap = v; 2041.20Sthorpej 2051.1Sfvdl return ENOSYS; 2061.1Sfvdl} 2071.1Sfvdl 2081.1Sfvdl/* 2091.1Sfvdl * Linux brk(2). The check if the new address is >= the old one is 2101.1Sfvdl * done in the kernel in Linux. NetBSD does it in the library. 2111.1Sfvdl */ 2121.1Sfvdlint 2131.21Smycroftlinux_sys_brk(p, v, retval) 2141.1Sfvdl struct proc *p; 2151.20Sthorpej void *v; 2161.20Sthorpej register_t *retval; 2171.20Sthorpej{ 2181.21Smycroft struct linux_sys_brk_args /* { 2191.1Sfvdl syscallarg(char *) nsize; 2201.20Sthorpej } */ *uap = v; 2211.1Sfvdl char *nbrk = SCARG(uap, nsize); 2221.21Smycroft struct sys_obreak_args oba; 2231.1Sfvdl struct vmspace *vm = p->p_vmspace; 2241.1Sfvdl int error = 0; 2251.1Sfvdl caddr_t oldbrk, newbrk; 2261.1Sfvdl 2271.1Sfvdl oldbrk = vm->vm_daddr + ctob(vm->vm_dsize); 2281.1Sfvdl /* 2291.1Sfvdl * XXX inconsistent.. Linux always returns at least the old 2301.1Sfvdl * brk value, but it will be page-aligned if this fails, 2311.1Sfvdl * and possibly not page aligned if it succeeds (the user 2321.1Sfvdl * supplied pointer is returned). 2331.1Sfvdl */ 2341.1Sfvdl SCARG(&oba, nsize) = nbrk; 2351.1Sfvdl 2361.21Smycroft if ((caddr_t) nbrk > vm->vm_daddr && sys_obreak(p, &oba, retval) == 0) 2371.21Smycroft retval[0] = (register_t)nbrk; 2381.1Sfvdl else 2391.21Smycroft retval[0] = (register_t)oldbrk; 2401.1Sfvdl 2411.1Sfvdl return 0; 2421.1Sfvdl} 2431.1Sfvdl 2441.1Sfvdl/* 2451.1Sfvdl * I wonder why Linux has gettimeofday() _and_ time().. Still, we 2461.1Sfvdl * need to deal with it. 2471.1Sfvdl */ 2481.1Sfvdlint 2491.21Smycroftlinux_sys_time(p, v, retval) 2501.1Sfvdl struct proc *p; 2511.20Sthorpej void *v; 2521.20Sthorpej register_t *retval; 2531.20Sthorpej{ 2541.21Smycroft struct linux_sys_time_args /* { 2551.1Sfvdl linux_time_t *t; 2561.20Sthorpej } */ *uap = v; 2571.1Sfvdl struct timeval atv; 2581.1Sfvdl linux_time_t tt; 2591.1Sfvdl int error; 2601.1Sfvdl 2611.1Sfvdl microtime(&atv); 2621.1Sfvdl 2631.1Sfvdl tt = atv.tv_sec; 2641.1Sfvdl if (SCARG(uap, t) && (error = copyout(&tt, SCARG(uap, t), sizeof tt))) 2651.1Sfvdl return error; 2661.1Sfvdl 2671.1Sfvdl retval[0] = tt; 2681.1Sfvdl return 0; 2691.1Sfvdl} 2701.1Sfvdl 2711.1Sfvdl/* 2721.2Sfvdl * Convert BSD statfs structure to Linux statfs structure. 2731.2Sfvdl * The Linux structure has less fields, and it also wants 2741.2Sfvdl * the length of a name in a dir entry in a field, which 2751.2Sfvdl * we fake (probably the wrong way). 2761.2Sfvdl */ 2771.2Sfvdlstatic void 2781.2Sfvdlbsd_to_linux_statfs(bsp, lsp) 2791.2Sfvdl struct statfs *bsp; 2801.2Sfvdl struct linux_statfs *lsp; 2811.2Sfvdl{ 2821.21Smycroft 2831.2Sfvdl lsp->l_ftype = bsp->f_type; 2841.2Sfvdl lsp->l_fbsize = bsp->f_bsize; 2851.2Sfvdl lsp->l_fblocks = bsp->f_blocks; 2861.2Sfvdl lsp->l_fbfree = bsp->f_bfree; 2871.2Sfvdl lsp->l_fbavail = bsp->f_bavail; 2881.2Sfvdl lsp->l_ffiles = bsp->f_files; 2891.2Sfvdl lsp->l_fffree = bsp->f_ffree; 2901.2Sfvdl lsp->l_ffsid.val[0] = bsp->f_fsid.val[0]; 2911.2Sfvdl lsp->l_ffsid.val[1] = bsp->f_fsid.val[1]; 2921.2Sfvdl lsp->l_fnamelen = MAXNAMLEN; /* XXX */ 2931.2Sfvdl} 2941.2Sfvdl 2951.2Sfvdl/* 2961.2Sfvdl * Implement the fs stat functions. Straightforward. 2971.1Sfvdl */ 2981.1Sfvdlint 2991.21Smycroftlinux_sys_statfs(p, v, retval) 3001.1Sfvdl struct proc *p; 3011.20Sthorpej void *v; 3021.20Sthorpej register_t *retval; 3031.20Sthorpej{ 3041.21Smycroft struct linux_sys_statfs_args /* { 3051.1Sfvdl syscallarg(char *) path; 3061.1Sfvdl syscallarg(struct linux_statfs *) sp; 3071.20Sthorpej } */ *uap = v; 3081.2Sfvdl struct statfs btmp, *bsp; 3091.2Sfvdl struct linux_statfs ltmp; 3101.21Smycroft struct sys_statfs_args bsa; 3111.2Sfvdl caddr_t sg; 3121.2Sfvdl int error; 3131.2Sfvdl 3141.9Schristos sg = stackgap_init(p->p_emul); 3151.2Sfvdl bsp = (struct statfs *) stackgap_alloc(&sg, sizeof (struct statfs)); 3161.2Sfvdl 3171.9Schristos LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path)); 3181.2Sfvdl 3191.2Sfvdl SCARG(&bsa, path) = SCARG(uap, path); 3201.2Sfvdl SCARG(&bsa, buf) = bsp; 3211.2Sfvdl 3221.21Smycroft if ((error = sys_statfs(p, &bsa, retval))) 3231.2Sfvdl return error; 3241.2Sfvdl 3251.2Sfvdl if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp))) 3261.2Sfvdl return error; 3271.2Sfvdl 3281.2Sfvdl bsd_to_linux_statfs(&btmp, <mp); 3291.2Sfvdl 3301.2Sfvdl return copyout((caddr_t) <mp, (caddr_t) SCARG(uap, sp), sizeof ltmp); 3311.1Sfvdl} 3321.1Sfvdl 3331.1Sfvdlint 3341.21Smycroftlinux_sys_fstatfs(p, v, retval) 3351.1Sfvdl struct proc *p; 3361.20Sthorpej void *v; 3371.20Sthorpej register_t *retval; 3381.20Sthorpej{ 3391.21Smycroft struct linux_sys_fstatfs_args /* { 3401.2Sfvdl syscallarg(int) fd; 3411.1Sfvdl syscallarg(struct linux_statfs *) sp; 3421.20Sthorpej } */ *uap = v; 3431.2Sfvdl struct statfs btmp, *bsp; 3441.2Sfvdl struct linux_statfs ltmp; 3451.21Smycroft struct sys_fstatfs_args bsa; 3461.2Sfvdl caddr_t sg; 3471.2Sfvdl int error; 3481.2Sfvdl 3491.9Schristos sg = stackgap_init(p->p_emul); 3501.2Sfvdl bsp = (struct statfs *) stackgap_alloc(&sg, sizeof (struct statfs)); 3511.2Sfvdl 3521.2Sfvdl SCARG(&bsa, fd) = SCARG(uap, fd); 3531.2Sfvdl SCARG(&bsa, buf) = bsp; 3541.2Sfvdl 3551.21Smycroft if ((error = sys_fstatfs(p, &bsa, retval))) 3561.2Sfvdl return error; 3571.2Sfvdl 3581.2Sfvdl if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp))) 3591.2Sfvdl return error; 3601.2Sfvdl 3611.2Sfvdl bsd_to_linux_statfs(&btmp, <mp); 3621.2Sfvdl 3631.2Sfvdl return copyout((caddr_t) <mp, (caddr_t) SCARG(uap, sp), sizeof ltmp); 3641.1Sfvdl} 3651.1Sfvdl 3661.1Sfvdl/* 3671.1Sfvdl * uname(). Just copy the info from the various strings stored in the 3681.1Sfvdl * kernel, and put it in the Linux utsname structure. That structure 3691.1Sfvdl * is almost the same as the NetBSD one, only it has fields 65 characters 3701.1Sfvdl * long, and an extra domainname field. 3711.1Sfvdl */ 3721.1Sfvdlint 3731.21Smycroftlinux_sys_uname(p, v, retval) 3741.1Sfvdl struct proc *p; 3751.20Sthorpej void *v; 3761.20Sthorpej register_t *retval; 3771.20Sthorpej{ 3781.21Smycroft struct linux_sys_uname_args /* { 3791.1Sfvdl syscallarg(struct linux_utsname *) up; 3801.20Sthorpej } */ *uap = v; 3811.15Smycroft extern char ostype[], hostname[], osrelease[], version[], machine[], 3821.15Smycroft domainname[]; 3831.15Smycroft struct linux_utsname luts; 3841.1Sfvdl int len; 3851.1Sfvdl char *cp; 3861.1Sfvdl 3871.15Smycroft strncpy(luts.l_sysname, ostype, sizeof(luts.l_sysname)); 3881.15Smycroft strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename)); 3891.15Smycroft strncpy(luts.l_release, osrelease, sizeof(luts.l_release)); 3901.15Smycroft strncpy(luts.l_version, version, sizeof(luts.l_version)); 3911.15Smycroft strncpy(luts.l_machine, machine, sizeof(luts.l_machine)); 3921.15Smycroft strncpy(luts.l_domainname, domainname, sizeof(luts.l_domainname)); 3931.1Sfvdl 3941.1Sfvdl /* This part taken from the the uname() in libc */ 3951.15Smycroft len = sizeof(luts.l_version); 3961.15Smycroft for (cp = luts.l_version; len--; ++cp) 3971.1Sfvdl if (*cp == '\n' || *cp == '\t') 3981.1Sfvdl if (len > 1) 3991.1Sfvdl *cp = ' '; 4001.1Sfvdl else 4011.1Sfvdl *cp = '\0'; 4021.1Sfvdl 4031.15Smycroft return copyout(&luts, SCARG(uap, up), sizeof(luts)); 4041.15Smycroft} 4051.15Smycroft 4061.15Smycroftint 4071.21Smycroftlinux_sys_olduname(p, v, retval) 4081.15Smycroft struct proc *p; 4091.20Sthorpej void *v; 4101.20Sthorpej register_t *retval; 4111.20Sthorpej{ 4121.21Smycroft struct linux_sys_uname_args /* { 4131.15Smycroft syscallarg(struct linux_oldutsname *) up; 4141.20Sthorpej } */ *uap = v; 4151.15Smycroft extern char ostype[], hostname[], osrelease[], version[], machine[]; 4161.15Smycroft struct linux_oldutsname luts; 4171.15Smycroft int len; 4181.15Smycroft char *cp; 4191.15Smycroft 4201.15Smycroft strncpy(luts.l_sysname, ostype, sizeof(luts.l_sysname)); 4211.15Smycroft strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename)); 4221.15Smycroft strncpy(luts.l_release, osrelease, sizeof(luts.l_release)); 4231.15Smycroft strncpy(luts.l_version, version, sizeof(luts.l_version)); 4241.15Smycroft strncpy(luts.l_machine, machine, sizeof(luts.l_machine)); 4251.15Smycroft 4261.15Smycroft /* This part taken from the the uname() in libc */ 4271.15Smycroft len = sizeof(luts.l_version); 4281.15Smycroft for (cp = luts.l_version; len--; ++cp) 4291.15Smycroft if (*cp == '\n' || *cp == '\t') 4301.15Smycroft if (len > 1) 4311.15Smycroft *cp = ' '; 4321.15Smycroft else 4331.15Smycroft *cp = '\0'; 4341.15Smycroft 4351.15Smycroft return copyout(&luts, SCARG(uap, up), sizeof(luts)); 4361.15Smycroft} 4371.15Smycroft 4381.15Smycroftint 4391.21Smycroftlinux_sys_oldolduname(p, v, retval) 4401.15Smycroft struct proc *p; 4411.20Sthorpej void *v; 4421.20Sthorpej register_t *retval; 4431.20Sthorpej{ 4441.21Smycroft struct linux_sys_uname_args /* { 4451.15Smycroft syscallarg(struct linux_oldoldutsname *) up; 4461.20Sthorpej } */ *uap = v; 4471.15Smycroft extern char ostype[], hostname[], osrelease[], version[], machine[]; 4481.15Smycroft struct linux_oldoldutsname luts; 4491.15Smycroft int len; 4501.15Smycroft char *cp; 4511.15Smycroft 4521.15Smycroft strncpy(luts.l_sysname, ostype, sizeof(luts.l_sysname)); 4531.15Smycroft strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename)); 4541.15Smycroft strncpy(luts.l_release, osrelease, sizeof(luts.l_release)); 4551.15Smycroft strncpy(luts.l_version, version, sizeof(luts.l_version)); 4561.15Smycroft strncpy(luts.l_machine, machine, sizeof(luts.l_machine)); 4571.15Smycroft 4581.15Smycroft /* This part taken from the the uname() in libc */ 4591.15Smycroft len = sizeof(luts.l_version); 4601.15Smycroft for (cp = luts.l_version; len--; ++cp) 4611.15Smycroft if (*cp == '\n' || *cp == '\t') 4621.15Smycroft if (len > 1) 4631.15Smycroft *cp = ' '; 4641.15Smycroft else 4651.15Smycroft *cp = '\0'; 4661.15Smycroft 4671.15Smycroft return copyout(&luts, SCARG(uap, up), sizeof(luts)); 4681.1Sfvdl} 4691.1Sfvdl 4701.1Sfvdl/* 4711.1Sfvdl * Linux wants to pass everything to a syscall in registers. However, 4721.1Sfvdl * mmap() has 6 of them. Oops: out of register error. They just pass 4731.1Sfvdl * everything in a structure. 4741.1Sfvdl */ 4751.1Sfvdlint 4761.21Smycroftlinux_sys_mmap(p, v, retval) 4771.1Sfvdl struct proc *p; 4781.20Sthorpej void *v; 4791.20Sthorpej register_t *retval; 4801.20Sthorpej{ 4811.21Smycroft struct linux_sys_mmap_args /* { 4821.1Sfvdl syscallarg(struct linux_mmap *) lmp; 4831.20Sthorpej } */ *uap = v; 4841.1Sfvdl struct linux_mmap lmap; 4851.21Smycroft struct sys_mmap_args cma; 4861.1Sfvdl int error, flags; 4871.1Sfvdl 4881.1Sfvdl if ((error = copyin(SCARG(uap, lmp), &lmap, sizeof lmap))) 4891.1Sfvdl return error; 4901.1Sfvdl 4911.1Sfvdl flags = 0; 4921.1Sfvdl flags |= cvtto_bsd_mask(lmap.lm_flags, LINUX_MAP_SHARED, MAP_SHARED); 4931.1Sfvdl flags |= cvtto_bsd_mask(lmap.lm_flags, LINUX_MAP_PRIVATE, MAP_PRIVATE); 4941.1Sfvdl flags |= cvtto_bsd_mask(lmap.lm_flags, LINUX_MAP_FIXED, MAP_FIXED); 4951.1Sfvdl flags |= cvtto_bsd_mask(lmap.lm_flags, LINUX_MAP_ANON, MAP_ANON); 4961.1Sfvdl 4971.1Sfvdl SCARG(&cma,addr) = lmap.lm_addr; 4981.1Sfvdl SCARG(&cma,len) = lmap.lm_len; 4991.1Sfvdl SCARG(&cma,prot) = lmap.lm_prot; 5001.1Sfvdl SCARG(&cma,flags) = flags; 5011.1Sfvdl SCARG(&cma,fd) = lmap.lm_fd; 5021.1Sfvdl SCARG(&cma,pad) = 0; 5031.1Sfvdl SCARG(&cma,pos) = lmap.lm_pos; 5041.1Sfvdl 5051.21Smycroft return sys_mmap(p, &cma, retval); 5061.1Sfvdl} 5071.1Sfvdl 5081.1Sfvdl/* 5091.1Sfvdl * Linux doesn't use the retval[1] value to determine whether 5101.1Sfvdl * we are the child or parent. 5111.1Sfvdl */ 5121.1Sfvdlint 5131.21Smycroftlinux_sys_fork(p, v, retval) 5141.1Sfvdl struct proc *p; 5151.21Smycroft void *v; 5161.1Sfvdl register_t *retval; 5171.1Sfvdl{ 5181.1Sfvdl int error; 5191.1Sfvdl 5201.21Smycroft if ((error = sys_fork(p, v, retval))) 5211.1Sfvdl return error; 5221.1Sfvdl 5231.1Sfvdl if (retval[1] == 1) 5241.1Sfvdl retval[0] = 0; 5251.1Sfvdl 5261.1Sfvdl return 0; 5271.1Sfvdl} 5281.1Sfvdl 5291.1Sfvdl/* 5301.1Sfvdl * This code is partly stolen from src/lib/libc/compat-43/times.c 5311.1Sfvdl * XXX - CLK_TCK isn't declared in /sys, just in <time.h>, done here 5321.1Sfvdl */ 5331.1Sfvdl 5341.1Sfvdl#define CLK_TCK 100 5351.1Sfvdl#define CONVTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK)) 5361.1Sfvdl 5371.1Sfvdlint 5381.21Smycroftlinux_sys_times(p, v, retval) 5391.1Sfvdl struct proc *p; 5401.20Sthorpej void *v; 5411.20Sthorpej register_t *retval; 5421.20Sthorpej{ 5431.21Smycroft struct linux_sys_times_args /* { 5441.1Sfvdl syscallarg(struct times *) tms; 5451.20Sthorpej } */ *uap = v; 5461.1Sfvdl struct timeval t; 5471.1Sfvdl struct linux_tms ltms; 5481.1Sfvdl struct rusage ru; 5491.4Smycroft int error, s; 5501.1Sfvdl 5511.1Sfvdl calcru(p, &ru.ru_utime, &ru.ru_stime, NULL); 5521.1Sfvdl ltms.ltms_utime = CONVTCK(ru.ru_utime); 5531.1Sfvdl ltms.ltms_stime = CONVTCK(ru.ru_stime); 5541.1Sfvdl 5551.1Sfvdl ltms.ltms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime); 5561.1Sfvdl ltms.ltms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime); 5571.1Sfvdl 5581.1Sfvdl if ((error = copyout(<ms, SCARG(uap, tms), sizeof ltms))) 5591.1Sfvdl return error; 5601.1Sfvdl 5611.4Smycroft s = splclock(); 5621.4Smycroft timersub(&time, &boottime, &t); 5631.4Smycroft splx(s); 5641.1Sfvdl 5651.1Sfvdl retval[0] = ((linux_clock_t)(CONVTCK(t))); 5661.1Sfvdl return 0; 5671.1Sfvdl} 5681.1Sfvdl 5691.1Sfvdl/* 5701.1Sfvdl * NetBSD passes fd[0] in retval[0], and fd[1] in retval[1]. 5711.1Sfvdl * Linux directly passes the pointer. 5721.1Sfvdl */ 5731.1Sfvdlint 5741.21Smycroftlinux_sys_pipe(p, v, retval) 5751.1Sfvdl struct proc *p; 5761.20Sthorpej void *v; 5771.20Sthorpej register_t *retval; 5781.20Sthorpej{ 5791.21Smycroft struct linux_sys_pipe_args /* { 5801.1Sfvdl syscallarg(int *) pfds; 5811.20Sthorpej } */ *uap = v; 5821.1Sfvdl int error; 5831.1Sfvdl 5841.21Smycroft if ((error = sys_pipe(p, 0, retval))) 5851.1Sfvdl return error; 5861.1Sfvdl 5871.1Sfvdl /* Assumes register_t is an int */ 5881.1Sfvdl 5891.1Sfvdl if ((error = copyout(retval, SCARG(uap, pfds), 2 * sizeof (int)))) 5901.1Sfvdl return error; 5911.1Sfvdl 5921.1Sfvdl retval[0] = 0; 5931.1Sfvdl return 0; 5941.1Sfvdl} 5951.1Sfvdl 5961.1Sfvdl/* 5971.21Smycroft * Alarm. This is a libc call which uses setitimer(2) in NetBSD. 5981.1Sfvdl * Fiddle with the timers to make it work. 5991.1Sfvdl */ 6001.1Sfvdlint 6011.21Smycroftlinux_sys_alarm(p, v, retval) 6021.1Sfvdl struct proc *p; 6031.20Sthorpej void *v; 6041.20Sthorpej register_t *retval; 6051.20Sthorpej{ 6061.21Smycroft struct linux_sys_alarm_args /* { 6071.1Sfvdl syscallarg(unsigned int) secs; 6081.20Sthorpej } */ *uap = v; 6091.1Sfvdl int error, s; 6101.1Sfvdl struct itimerval *itp, it; 6111.1Sfvdl 6121.1Sfvdl itp = &p->p_realtimer; 6131.1Sfvdl s = splclock(); 6141.1Sfvdl /* 6151.1Sfvdl * Clear any pending timer alarms. 6161.1Sfvdl */ 6171.1Sfvdl untimeout(realitexpire, p); 6181.1Sfvdl timerclear(&itp->it_interval); 6191.1Sfvdl if (timerisset(&itp->it_value) && 6201.1Sfvdl timercmp(&itp->it_value, &time, >)) 6211.3Smycroft timersub(&itp->it_value, &time, &itp->it_value); 6221.1Sfvdl /* 6231.1Sfvdl * Return how many seconds were left (rounded up) 6241.1Sfvdl */ 6251.1Sfvdl retval[0] = itp->it_value.tv_sec; 6261.1Sfvdl if (itp->it_value.tv_usec) 6271.1Sfvdl retval[0]++; 6281.1Sfvdl 6291.1Sfvdl /* 6301.1Sfvdl * alarm(0) just resets the timer. 6311.1Sfvdl */ 6321.1Sfvdl if (SCARG(uap, secs) == 0) { 6331.1Sfvdl timerclear(&itp->it_value); 6341.1Sfvdl splx(s); 6351.1Sfvdl return 0; 6361.1Sfvdl } 6371.1Sfvdl 6381.1Sfvdl /* 6391.1Sfvdl * Check the new alarm time for sanity, and set it. 6401.1Sfvdl */ 6411.1Sfvdl timerclear(&it.it_interval); 6421.1Sfvdl it.it_value.tv_sec = SCARG(uap, secs); 6431.1Sfvdl it.it_value.tv_usec = 0; 6441.1Sfvdl if (itimerfix(&it.it_value) || itimerfix(&it.it_interval)) { 6451.1Sfvdl splx(s); 6461.1Sfvdl return (EINVAL); 6471.1Sfvdl } 6481.1Sfvdl 6491.1Sfvdl if (timerisset(&it.it_value)) { 6501.3Smycroft timeradd(&it.it_value, &time, &it.it_value); 6511.1Sfvdl timeout(realitexpire, p, hzto(&it.it_value)); 6521.1Sfvdl } 6531.1Sfvdl p->p_realtimer = it; 6541.1Sfvdl splx(s); 6551.1Sfvdl 6561.1Sfvdl return 0; 6571.1Sfvdl} 6581.1Sfvdl 6591.1Sfvdl/* 6601.1Sfvdl * utime(). Do conversion to things that utimes() understands, 6611.1Sfvdl * and pass it on. 6621.1Sfvdl */ 6631.1Sfvdlint 6641.21Smycroftlinux_sys_utime(p, v, retval) 6651.1Sfvdl struct proc *p; 6661.20Sthorpej void *v; 6671.20Sthorpej register_t *retval; 6681.20Sthorpej{ 6691.21Smycroft struct linux_sys_utime_args /* { 6701.1Sfvdl syscallarg(char *) path; 6711.1Sfvdl syscallarg(struct linux_utimbuf *)times; 6721.20Sthorpej } */ *uap = v; 6731.1Sfvdl caddr_t sg; 6741.1Sfvdl int error; 6751.21Smycroft struct sys_utimes_args ua; 6761.1Sfvdl struct timeval tv[2], *tvp; 6771.1Sfvdl struct linux_utimbuf lut; 6781.1Sfvdl 6791.9Schristos sg = stackgap_init(p->p_emul); 6801.9Schristos LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path)); 6811.1Sfvdl 6821.1Sfvdl SCARG(&ua, path) = SCARG(uap, path); 6831.1Sfvdl 6841.1Sfvdl if (SCARG(uap, times) != NULL) { 6851.1Sfvdl if ((error = copyin(SCARG(uap, times), &lut, sizeof lut))) 6861.1Sfvdl return error; 6871.1Sfvdl tv[0].tv_usec = tv[1].tv_usec = 0; 6881.1Sfvdl tv[0].tv_sec = lut.l_actime; 6891.1Sfvdl tv[1].tv_sec = lut.l_modtime; 6901.9Schristos tvp = (struct timeval *) stackgap_alloc(&sg, sizeof(tv)); 6911.1Sfvdl if ((error = copyout(tv, tvp, sizeof tv))) 6921.1Sfvdl return error; 6931.1Sfvdl SCARG(&ua, tptr) = tvp; 6941.1Sfvdl } 6951.1Sfvdl else 6961.1Sfvdl SCARG(&ua, tptr) = NULL; 6971.1Sfvdl 6981.21Smycroft return sys_utimes(p, uap, retval); 6991.1Sfvdl} 7001.1Sfvdl 7011.1Sfvdl/* 7021.17Sfvdl * The old Linux readdir was only able to read one entry at a time, 7031.17Sfvdl * even though it had a 'count' argument. In fact, the emulation 7041.17Sfvdl * of the old call was better than the original, because it did handle 7051.17Sfvdl * the count arg properly. Don't bother with it anymore now, and use 7061.17Sfvdl * it to distinguish between old and new. The difference is that the 7071.17Sfvdl * newer one actually does multiple entries, and the reclen field 7081.17Sfvdl * really is the reclen, not the namelength. 7091.17Sfvdl */ 7101.17Sfvdlint 7111.21Smycroftlinux_sys_readdir(p, v, retval) 7121.17Sfvdl struct proc *p; 7131.20Sthorpej void *v; 7141.20Sthorpej register_t *retval; 7151.20Sthorpej{ 7161.21Smycroft struct linux_sys_readdir_args /* { 7171.17Sfvdl syscallarg(int) fd; 7181.17Sfvdl syscallarg(struct linux_dirent *) dent; 7191.17Sfvdl syscallarg(unsigned int) count; 7201.20Sthorpej } */ *uap = v; 7211.20Sthorpej 7221.17Sfvdl SCARG(uap, count) = 1; 7231.21Smycroft return linux_sys_getdents(p, uap, retval); 7241.17Sfvdl} 7251.17Sfvdl 7261.17Sfvdl/* 7271.1Sfvdl * Linux 'readdir' call. This code is mostly taken from the 7281.1Sfvdl * SunOS getdents call (see compat/sunos/sunos_misc.c), though 7291.1Sfvdl * an attempt has been made to keep it a little cleaner (failing 7301.1Sfvdl * miserably, because of the cruft needed if count 1 is passed). 7311.1Sfvdl * 7321.17Sfvdl * The d_off field should contain the offset of the next valid entry, 7331.17Sfvdl * but in Linux it has the offset of the entry itself. We emulate 7341.17Sfvdl * that bug here. 7351.17Sfvdl * 7361.1Sfvdl * Read in BSD-style entries, convert them, and copy them out. 7371.1Sfvdl * 7381.1Sfvdl * Note that this doesn't handle union-mounted filesystems. 7391.1Sfvdl */ 7401.1Sfvdlint 7411.21Smycroftlinux_sys_getdents(p, v, retval) 7421.1Sfvdl struct proc *p; 7431.20Sthorpej void *v; 7441.20Sthorpej register_t *retval; 7451.20Sthorpej{ 7461.21Smycroft struct linux_sys_readdir_args /* { 7471.1Sfvdl syscallarg(int) fd; 7481.21Smycroft syscallarg(caddr_t) dent; 7491.1Sfvdl syscallarg(unsigned int) count; 7501.20Sthorpej } */ *uap = v; 7511.1Sfvdl register struct dirent *bdp; 7521.1Sfvdl struct vnode *vp; 7531.1Sfvdl caddr_t inp, buf; /* BSD-format */ 7541.1Sfvdl int len, reclen; /* BSD-format */ 7551.1Sfvdl caddr_t outp; /* Linux-format */ 7561.21Smycroft int resid, linux_reclen;/* Linux-format */ 7571.1Sfvdl struct file *fp; 7581.1Sfvdl struct uio auio; 7591.1Sfvdl struct iovec aiov; 7601.1Sfvdl struct linux_dirent idb; 7611.1Sfvdl off_t off; /* true file offset */ 7621.17Sfvdl int buflen, error, eofflag, nbytes, oldcall; 7631.1Sfvdl struct vattr va; 7641.1Sfvdl 7651.1Sfvdl if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 7661.1Sfvdl return (error); 7671.1Sfvdl 7681.1Sfvdl if ((fp->f_flag & FREAD) == 0) 7691.1Sfvdl return (EBADF); 7701.1Sfvdl 7711.5Smycroft vp = (struct vnode *)fp->f_data; 7721.1Sfvdl 7731.1Sfvdl if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */ 7741.1Sfvdl return (EINVAL); 7751.1Sfvdl 7761.1Sfvdl if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) 7771.1Sfvdl return error; 7781.1Sfvdl 7791.1Sfvdl nbytes = SCARG(uap, count); 7801.17Sfvdl if (nbytes == 1) { /* emulating old, broken behaviour */ 7811.1Sfvdl nbytes = sizeof (struct linux_dirent); 7821.5Smycroft buflen = max(va.va_blocksize, nbytes); 7831.17Sfvdl oldcall = 1; 7841.5Smycroft } else { 7851.5Smycroft buflen = min(MAXBSIZE, nbytes); 7861.17Sfvdl oldcall = 0; 7871.1Sfvdl } 7881.1Sfvdl buf = malloc(buflen, M_TEMP, M_WAITOK); 7891.1Sfvdl VOP_LOCK(vp); 7901.1Sfvdl off = fp->f_offset; 7911.1Sfvdlagain: 7921.1Sfvdl aiov.iov_base = buf; 7931.1Sfvdl aiov.iov_len = buflen; 7941.1Sfvdl auio.uio_iov = &aiov; 7951.1Sfvdl auio.uio_iovcnt = 1; 7961.1Sfvdl auio.uio_rw = UIO_READ; 7971.1Sfvdl auio.uio_segflg = UIO_SYSSPACE; 7981.1Sfvdl auio.uio_procp = p; 7991.1Sfvdl auio.uio_resid = buflen; 8001.1Sfvdl auio.uio_offset = off; 8011.1Sfvdl /* 8021.1Sfvdl * First we read into the malloc'ed buffer, then 8031.1Sfvdl * we massage it into user space, one record at a time. 8041.1Sfvdl */ 8051.5Smycroft error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0); 8061.1Sfvdl if (error) 8071.1Sfvdl goto out; 8081.1Sfvdl 8091.1Sfvdl inp = buf; 8101.21Smycroft outp = SCARG(uap, dent); 8111.1Sfvdl resid = nbytes; 8121.1Sfvdl if ((len = buflen - auio.uio_resid) == 0) 8131.1Sfvdl goto eof; 8141.1Sfvdl 8151.1Sfvdl for (; len > 0; len -= reclen) { 8161.5Smycroft bdp = (struct dirent *)inp; 8171.5Smycroft reclen = bdp->d_reclen; 8181.1Sfvdl if (reclen & 3) 8191.1Sfvdl panic("linux_readdir"); 8201.19Sfvdl off += reclen; 8211.1Sfvdl if (bdp->d_fileno == 0) { 8221.1Sfvdl inp += reclen; /* it is a hole; squish it out */ 8231.1Sfvdl continue; 8241.1Sfvdl } 8251.21Smycroft linux_reclen = LINUX_RECLEN(&idb, bdp->d_namlen); 8261.21Smycroft if (reclen > len || resid < linux_reclen) { 8271.1Sfvdl /* entry too big for buffer, so just stop */ 8281.1Sfvdl outp++; 8291.1Sfvdl break; 8301.1Sfvdl } 8311.1Sfvdl /* 8321.1Sfvdl * Massage in place to make a Linux-shaped dirent (otherwise 8331.1Sfvdl * we have to worry about touching user memory outside of 8341.1Sfvdl * the copyout() call). 8351.1Sfvdl */ 8361.5Smycroft idb.d_ino = (long)bdp->d_fileno; 8371.19Sfvdl idb.d_off = off - reclen; 8381.17Sfvdl /* 8391.21Smycroft * The old readdir() call misuses the offset and reclen fields. 8401.17Sfvdl */ 8411.21Smycroft idb.d_reclen = oldcall ? (u_short)bdp->d_namlen : linux_reclen; 8421.5Smycroft strcpy(idb.d_name, bdp->d_name); 8431.21Smycroft if ((error = copyout((caddr_t)&idb, outp, linux_reclen))) 8441.1Sfvdl goto out; 8451.1Sfvdl /* advance past this real entry */ 8461.1Sfvdl inp += reclen; 8471.1Sfvdl /* advance output past Linux-shaped entry */ 8481.21Smycroft outp += linux_reclen; 8491.21Smycroft resid -= linux_reclen; 8501.17Sfvdl if (oldcall) 8511.1Sfvdl break; 8521.1Sfvdl } 8531.1Sfvdl 8541.1Sfvdl /* if we squished out the whole block, try again */ 8551.21Smycroft if (outp == SCARG(uap, dent)) 8561.1Sfvdl goto again; 8571.1Sfvdl fp->f_offset = off; /* update the vnode offset */ 8581.1Sfvdl 8591.17Sfvdl if (oldcall) 8601.21Smycroft nbytes = resid + linux_reclen; 8611.1Sfvdl 8621.1Sfvdleof: 8631.1Sfvdl *retval = nbytes - resid; 8641.1Sfvdlout: 8651.1Sfvdl VOP_UNLOCK(vp); 8661.1Sfvdl free(buf, M_TEMP); 8671.1Sfvdl return error; 8681.1Sfvdl} 8691.1Sfvdl 8701.1Sfvdl/* 8711.17Sfvdl * Not sure why the arguments to this older version of select() were put 8721.17Sfvdl * into a structure, because there are 5, and that can all be handled 8731.17Sfvdl * in registers on the i386 like Linux wants to. 8741.17Sfvdl */ 8751.17Sfvdlint 8761.21Smycroftlinux_sys_oldselect(p, v, retval) 8771.17Sfvdl struct proc *p; 8781.20Sthorpej void *v; 8791.20Sthorpej register_t *retval; 8801.20Sthorpej{ 8811.21Smycroft struct linux_sys_oldselect_args /* { 8821.17Sfvdl syscallarg(struct linux_select *) lsp; 8831.20Sthorpej } */ *uap = v; 8841.17Sfvdl struct linux_select ls; 8851.17Sfvdl int error; 8861.17Sfvdl 8871.17Sfvdl if ((error = copyin(SCARG(uap, lsp), &ls, sizeof(ls)))) 8881.17Sfvdl return error; 8891.17Sfvdl 8901.17Sfvdl return linux_select1(p, retval, ls.nfds, ls.readfds, ls.writefds, 8911.17Sfvdl ls.exceptfds, ls.timeout); 8921.17Sfvdl} 8931.17Sfvdl 8941.17Sfvdl/* 8951.17Sfvdl * Even when just using registers to pass arguments to syscalls you can 8961.17Sfvdl * have 5 of them on the i386. So this newer version of select() does 8971.17Sfvdl * this. 8981.1Sfvdl */ 8991.1Sfvdlint 9001.21Smycroftlinux_sys_select(p, v, retval) 9011.1Sfvdl struct proc *p; 9021.20Sthorpej void *v; 9031.20Sthorpej register_t *retval; 9041.20Sthorpej{ 9051.21Smycroft struct linux_sys_select_args /* { 9061.17Sfvdl syscallarg(int) nfds; 9071.17Sfvdl syscallarg(fd_set *) readfds; 9081.17Sfvdl syscallarg(fd_set *) writefds; 9091.17Sfvdl syscallarg(fd_set *) exceptfds; 9101.17Sfvdl syscallarg(struct timeval *) timeout; 9111.20Sthorpej } */ *uap = v; 9121.20Sthorpej 9131.17Sfvdl return linux_select1(p, retval, SCARG(uap, nfds), SCARG(uap, readfds), 9141.17Sfvdl SCARG(uap, writefds), SCARG(uap, exceptfds), SCARG(uap, timeout)); 9151.17Sfvdl} 9161.17Sfvdl 9171.17Sfvdl/* 9181.17Sfvdl * Common code for the old and new versions of select(). A couple of 9191.17Sfvdl * things are important: 9201.17Sfvdl * 1) return the amount of time left in the 'timeout' parameter 9211.17Sfvdl * 2) select never returns ERESTART on Linux, always return EINTR 9221.17Sfvdl */ 9231.17Sfvdlint 9241.17Sfvdllinux_select1(p, retval, nfds, readfds, writefds, exceptfds, timeout) 9251.17Sfvdl struct proc *p; 9261.17Sfvdl register_t *retval; 9271.17Sfvdl int nfds; 9281.17Sfvdl fd_set *readfds, *writefds, *exceptfds; 9291.17Sfvdl struct timeval *timeout; 9301.17Sfvdl{ 9311.21Smycroft struct sys_select_args bsa; 9321.13Smycroft struct timeval tv0, tv1, utv, *tvp; 9331.13Smycroft caddr_t sg; 9341.1Sfvdl int error; 9351.1Sfvdl 9361.17Sfvdl SCARG(&bsa, nd) = nfds; 9371.17Sfvdl SCARG(&bsa, in) = readfds; 9381.17Sfvdl SCARG(&bsa, ou) = writefds; 9391.17Sfvdl SCARG(&bsa, ex) = exceptfds; 9401.17Sfvdl SCARG(&bsa, tv) = timeout; 9411.1Sfvdl 9421.7Sfvdl /* 9431.7Sfvdl * Store current time for computation of the amount of 9441.7Sfvdl * time left. 9451.7Sfvdl */ 9461.17Sfvdl if (timeout) { 9471.17Sfvdl if ((error = copyin(timeout, &utv, sizeof(utv)))) 9481.13Smycroft return error; 9491.13Smycroft if (itimerfix(&utv)) { 9501.13Smycroft /* 9511.13Smycroft * The timeval was invalid. Convert it to something 9521.13Smycroft * valid that will act as it does under Linux. 9531.13Smycroft */ 9541.13Smycroft sg = stackgap_init(p->p_emul); 9551.13Smycroft tvp = stackgap_alloc(&sg, sizeof(utv)); 9561.13Smycroft utv.tv_sec += utv.tv_usec / 1000000; 9571.13Smycroft utv.tv_usec %= 1000000; 9581.13Smycroft if (utv.tv_usec < 0) { 9591.13Smycroft utv.tv_sec -= 1; 9601.13Smycroft utv.tv_usec += 1000000; 9611.13Smycroft } 9621.13Smycroft if (utv.tv_sec < 0) 9631.13Smycroft timerclear(&utv); 9641.13Smycroft if ((error = copyout(&utv, tvp, sizeof(utv)))) 9651.13Smycroft return error; 9661.13Smycroft SCARG(&bsa, tv) = tvp; 9671.13Smycroft } 9681.7Sfvdl microtime(&tv0); 9691.13Smycroft } 9701.7Sfvdl 9711.21Smycroft error = sys_select(p, &bsa, retval); 9721.10Smycroft if (error) { 9731.10Smycroft /* 9741.10Smycroft * See fs/select.c in the Linux kernel. Without this, 9751.10Smycroft * Maelstrom doesn't work. 9761.10Smycroft */ 9771.10Smycroft if (error == ERESTART) 9781.10Smycroft error = EINTR; 9791.7Sfvdl return error; 9801.10Smycroft } 9811.7Sfvdl 9821.17Sfvdl if (timeout) { 9831.14Smycroft if (*retval) { 9841.7Sfvdl /* 9851.13Smycroft * Compute how much time was left of the timeout, 9861.7Sfvdl * by subtracting the current time and the time 9871.7Sfvdl * before we started the call, and subtracting 9881.7Sfvdl * that result from the user-supplied value. 9891.7Sfvdl */ 9901.7Sfvdl microtime(&tv1); 9911.7Sfvdl timersub(&tv1, &tv0, &tv1); 9921.7Sfvdl timersub(&utv, &tv1, &utv); 9931.14Smycroft if (utv.tv_sec < 0) 9941.14Smycroft timerclear(&utv); 9951.14Smycroft } else 9961.14Smycroft timerclear(&utv); 9971.17Sfvdl if ((error = copyout(&utv, timeout, sizeof(utv)))) 9981.7Sfvdl return error; 9991.7Sfvdl } 10001.13Smycroft 10011.7Sfvdl return 0; 10021.1Sfvdl} 10031.1Sfvdl 10041.1Sfvdl/* 10051.1Sfvdl * Get the process group of a certain process. Look it up 10061.1Sfvdl * and return the value. 10071.1Sfvdl */ 10081.1Sfvdlint 10091.21Smycroftlinux_sys_getpgid(p, v, retval) 10101.1Sfvdl struct proc *p; 10111.20Sthorpej void *v; 10121.20Sthorpej register_t *retval; 10131.20Sthorpej{ 10141.21Smycroft struct linux_sys_getpgid_args /* { 10151.1Sfvdl syscallarg(int) pid; 10161.20Sthorpej } */ *uap = v; 10171.1Sfvdl struct proc *targp; 10181.1Sfvdl 10191.1Sfvdl if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != p->p_pid) 10201.1Sfvdl if ((targp = pfind(SCARG(uap, pid))) == 0) 10211.1Sfvdl return ESRCH; 10221.1Sfvdl else 10231.1Sfvdl targp = p; 10241.1Sfvdl 10251.1Sfvdl retval[0] = targp->p_pgid; 10261.6Sfvdl return 0; 10271.6Sfvdl} 10281.6Sfvdl 10291.6Sfvdl/* 10301.6Sfvdl * Set the 'personality' (emulation mode) for the current process. Only 10311.6Sfvdl * accept the Linux personality here (0). This call is needed because 10321.6Sfvdl * the Linux ELF crt0 issues it in an ugly kludge to make sure that 10331.6Sfvdl * ELF binaries run in Linux mode, not SVR4 mode. 10341.6Sfvdl */ 10351.6Sfvdlint 10361.21Smycroftlinux_sys_personality(p, v, retval) 10371.6Sfvdl struct proc *p; 10381.20Sthorpej void *v; 10391.20Sthorpej register_t *retval; 10401.20Sthorpej{ 10411.21Smycroft struct linux_sys_personality_args /* { 10421.6Sfvdl syscallarg(int) per; 10431.20Sthorpej } */ *uap = v; 10441.20Sthorpej 10451.6Sfvdl if (SCARG(uap, per) != 0) 10461.6Sfvdl return EINVAL; 10471.6Sfvdl retval[0] = 0; 10481.1Sfvdl return 0; 10491.18Sfvdl} 10501.18Sfvdl 10511.18Sfvdl/* 10521.18Sfvdl * The calls are here because of type conversions. 10531.18Sfvdl */ 10541.18Sfvdlint 10551.21Smycroftlinux_sys_setreuid(p, v, retval) 10561.18Sfvdl struct proc *p; 10571.20Sthorpej void *v; 10581.20Sthorpej register_t *retval; 10591.20Sthorpej{ 10601.21Smycroft struct linux_sys_setreuid_args /* { 10611.18Sfvdl syscallarg(int) ruid; 10621.18Sfvdl syscallarg(int) euid; 10631.20Sthorpej } */ *uap = v; 10641.21Smycroft struct compat_43_sys_setreuid_args bsa; 10651.18Sfvdl 10661.18Sfvdl SCARG(&bsa, ruid) = ((linux_uid_t)SCARG(uap, ruid) == (linux_uid_t)-1) ? 10671.18Sfvdl (uid_t)-1 : SCARG(uap, ruid); 10681.18Sfvdl SCARG(&bsa, euid) = ((linux_uid_t)SCARG(uap, euid) == (linux_uid_t)-1) ? 10691.18Sfvdl (uid_t)-1 : SCARG(uap, euid); 10701.18Sfvdl 10711.21Smycroft return compat_43_sys_setreuid(p, &bsa, retval); 10721.18Sfvdl} 10731.18Sfvdl 10741.18Sfvdlint 10751.21Smycroftlinux_sys_setregid(p, v, retval) 10761.18Sfvdl struct proc *p; 10771.20Sthorpej void *v; 10781.20Sthorpej register_t *retval; 10791.20Sthorpej{ 10801.21Smycroft struct linux_sys_setregid_args /* { 10811.18Sfvdl syscallarg(int) rgid; 10821.18Sfvdl syscallarg(int) egid; 10831.20Sthorpej } */ *uap = v; 10841.21Smycroft struct compat_43_sys_setregid_args bsa; 10851.18Sfvdl 10861.18Sfvdl SCARG(&bsa, rgid) = ((linux_gid_t)SCARG(uap, rgid) == (linux_gid_t)-1) ? 10871.18Sfvdl (uid_t)-1 : SCARG(uap, rgid); 10881.18Sfvdl SCARG(&bsa, egid) = ((linux_gid_t)SCARG(uap, egid) == (linux_gid_t)-1) ? 10891.18Sfvdl (uid_t)-1 : SCARG(uap, egid); 10901.18Sfvdl 10911.21Smycroft return compat_43_sys_setregid(p, &bsa, retval); 10921.1Sfvdl} 1093