linux_pipe.c revision 1.12
11.12Smycroft/* $NetBSD: linux_pipe.c,v 1.12 1995/08/14 02:58:29 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.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.9Schristos sg = stackgap_init(p->p_emul); 1161.1Sfvdl status = (int *) stackgap_alloc(&sg, sizeof status); 1171.1Sfvdl 1181.1Sfvdl SCARG(&w4a, pid) = SCARG(uap, pid); 1191.1Sfvdl SCARG(&w4a, status) = status; 1201.1Sfvdl SCARG(&w4a, options) = SCARG(uap, options); 1211.1Sfvdl SCARG(&w4a, rusage) = NULL; 1221.1Sfvdl 1231.1Sfvdl if ((error = wait4(p, &w4a, retval))) 1241.1Sfvdl return error; 1251.1Sfvdl 1261.1Sfvdl if ((error = copyin(status, &tstat, sizeof tstat))) 1271.1Sfvdl return error; 1281.1Sfvdl 1291.1Sfvdl bsd_to_linux_wstat(&tstat); 1301.1Sfvdl 1311.1Sfvdl return copyout(&tstat, SCARG(uap, status), sizeof tstat); 1321.1Sfvdl} 1331.1Sfvdl 1341.1Sfvdl/* 1351.1Sfvdl * This is very much the same as waitpid() 1361.1Sfvdl */ 1371.1Sfvdlint 1381.1Sfvdllinux_wait4(p, uap, retval) 1391.1Sfvdl struct proc *p; 1401.1Sfvdl struct linux_wait4_args /* { 1411.1Sfvdl syscallarg(int) pid; 1421.1Sfvdl syscallarg(int *) status; 1431.1Sfvdl syscallarg(int) options; 1441.1Sfvdl syscallarg(struct rusage *) rusage; 1451.1Sfvdl } */ *uap; 1461.1Sfvdl register_t *retval; 1471.1Sfvdl{ 1481.1Sfvdl struct wait4_args w4a; 1491.1Sfvdl int error, *status, tstat; 1501.1Sfvdl caddr_t sg; 1511.1Sfvdl 1521.9Schristos sg = stackgap_init(p->p_emul); 1531.1Sfvdl status = (int *) stackgap_alloc(&sg, sizeof status); 1541.1Sfvdl 1551.1Sfvdl SCARG(&w4a, pid) = SCARG(uap, pid); 1561.1Sfvdl SCARG(&w4a, status) = status; 1571.1Sfvdl SCARG(&w4a, options) = SCARG(uap, options); 1581.1Sfvdl SCARG(&w4a, rusage) = SCARG(uap, rusage); 1591.1Sfvdl 1601.1Sfvdl if ((error = wait4(p, &w4a, retval))) 1611.1Sfvdl return error; 1621.1Sfvdl 1631.1Sfvdl if ((error = copyin(status, &tstat, sizeof tstat))) 1641.1Sfvdl return error; 1651.1Sfvdl 1661.1Sfvdl bsd_to_linux_wstat(&tstat); 1671.1Sfvdl 1681.1Sfvdl return copyout(&tstat, SCARG(uap, status), sizeof tstat); 1691.1Sfvdl} 1701.1Sfvdl 1711.1Sfvdl/* 1721.1Sfvdl * This is the old brk(2) call. I don't think anything in the Linux 1731.1Sfvdl * world uses this anymore 1741.1Sfvdl */ 1751.1Sfvdlint 1761.1Sfvdllinux_break(p, uap, retval) 1771.1Sfvdl struct proc *p; 1781.1Sfvdl struct linux_brk_args /* { 1791.1Sfvdl syscallarg(char *) nsize; 1801.1Sfvdl } */ *uap; 1811.1Sfvdl register_t *retval; 1821.1Sfvdl{ 1831.1Sfvdl return ENOSYS; 1841.1Sfvdl} 1851.1Sfvdl 1861.1Sfvdl/* 1871.1Sfvdl * Linux brk(2). The check if the new address is >= the old one is 1881.1Sfvdl * done in the kernel in Linux. NetBSD does it in the library. 1891.1Sfvdl */ 1901.1Sfvdlint 1911.1Sfvdllinux_brk(p, uap, retval) 1921.1Sfvdl struct proc *p; 1931.1Sfvdl struct linux_brk_args /* { 1941.1Sfvdl syscallarg(char *) nsize; 1951.1Sfvdl } */ *uap; 1961.1Sfvdl register_t *retval; 1971.1Sfvdl{ 1981.1Sfvdl char *nbrk = SCARG(uap, nsize); 1991.1Sfvdl struct obreak_args oba; 2001.1Sfvdl struct vmspace *vm = p->p_vmspace; 2011.1Sfvdl int error = 0; 2021.1Sfvdl caddr_t oldbrk, newbrk; 2031.1Sfvdl 2041.1Sfvdl oldbrk = vm->vm_daddr + ctob(vm->vm_dsize); 2051.1Sfvdl /* 2061.1Sfvdl * XXX inconsistent.. Linux always returns at least the old 2071.1Sfvdl * brk value, but it will be page-aligned if this fails, 2081.1Sfvdl * and possibly not page aligned if it succeeds (the user 2091.1Sfvdl * supplied pointer is returned). 2101.1Sfvdl */ 2111.1Sfvdl SCARG(&oba, nsize) = nbrk; 2121.1Sfvdl 2131.1Sfvdl if ((caddr_t) nbrk > vm->vm_daddr && obreak(p, &oba, retval) == 0) 2141.1Sfvdl retval[0] = (register_t) nbrk; 2151.1Sfvdl else 2161.1Sfvdl retval[0] = (register_t) oldbrk; 2171.1Sfvdl 2181.1Sfvdl return 0; 2191.1Sfvdl} 2201.1Sfvdl 2211.1Sfvdl/* 2221.1Sfvdl * I wonder why Linux has gettimeofday() _and_ time().. Still, we 2231.1Sfvdl * need to deal with it. 2241.1Sfvdl */ 2251.1Sfvdlint 2261.1Sfvdllinux_time(p, uap, retval) 2271.1Sfvdl struct proc *p; 2281.1Sfvdl struct linux_time_args /* { 2291.1Sfvdl linux_time_t *t; 2301.1Sfvdl } */ *uap; 2311.1Sfvdl register_t *retval; 2321.1Sfvdl{ 2331.1Sfvdl struct timeval atv; 2341.1Sfvdl linux_time_t tt; 2351.1Sfvdl int error; 2361.1Sfvdl 2371.1Sfvdl microtime(&atv); 2381.1Sfvdl 2391.1Sfvdl tt = atv.tv_sec; 2401.1Sfvdl if (SCARG(uap, t) && (error = copyout(&tt, SCARG(uap, t), sizeof tt))) 2411.1Sfvdl return error; 2421.1Sfvdl 2431.1Sfvdl retval[0] = tt; 2441.1Sfvdl return 0; 2451.1Sfvdl} 2461.1Sfvdl 2471.1Sfvdl/* 2481.2Sfvdl * Convert BSD statfs structure to Linux statfs structure. 2491.2Sfvdl * The Linux structure has less fields, and it also wants 2501.2Sfvdl * the length of a name in a dir entry in a field, which 2511.2Sfvdl * we fake (probably the wrong way). 2521.2Sfvdl */ 2531.2Sfvdlstatic void 2541.2Sfvdlbsd_to_linux_statfs(bsp, lsp) 2551.2Sfvdl struct statfs *bsp; 2561.2Sfvdl struct linux_statfs *lsp; 2571.2Sfvdl{ 2581.2Sfvdl lsp->l_ftype = bsp->f_type; 2591.2Sfvdl lsp->l_fbsize = bsp->f_bsize; 2601.2Sfvdl lsp->l_fblocks = bsp->f_blocks; 2611.2Sfvdl lsp->l_fbfree = bsp->f_bfree; 2621.2Sfvdl lsp->l_fbavail = bsp->f_bavail; 2631.2Sfvdl lsp->l_ffiles = bsp->f_files; 2641.2Sfvdl lsp->l_fffree = bsp->f_ffree; 2651.2Sfvdl lsp->l_ffsid.val[0] = bsp->f_fsid.val[0]; 2661.2Sfvdl lsp->l_ffsid.val[1] = bsp->f_fsid.val[1]; 2671.2Sfvdl lsp->l_fnamelen = MAXNAMLEN; /* XXX */ 2681.2Sfvdl} 2691.2Sfvdl 2701.2Sfvdl/* 2711.2Sfvdl * Implement the fs stat functions. Straightforward. 2721.1Sfvdl */ 2731.1Sfvdlint 2741.1Sfvdllinux_statfs(p, uap, retval) 2751.1Sfvdl struct proc *p; 2761.1Sfvdl struct linux_statfs_args /* { 2771.1Sfvdl syscallarg(char *) path; 2781.1Sfvdl syscallarg(struct linux_statfs *) sp; 2791.1Sfvdl } */ *uap; 2801.1Sfvdl register_t *retval; 2811.1Sfvdl{ 2821.2Sfvdl struct statfs btmp, *bsp; 2831.2Sfvdl struct linux_statfs ltmp; 2841.2Sfvdl struct statfs_args bsa; 2851.2Sfvdl caddr_t sg; 2861.2Sfvdl int error; 2871.2Sfvdl 2881.9Schristos sg = stackgap_init(p->p_emul); 2891.2Sfvdl bsp = (struct statfs *) stackgap_alloc(&sg, sizeof (struct statfs)); 2901.2Sfvdl 2911.9Schristos LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path)); 2921.2Sfvdl 2931.2Sfvdl SCARG(&bsa, path) = SCARG(uap, path); 2941.2Sfvdl SCARG(&bsa, buf) = bsp; 2951.2Sfvdl 2961.2Sfvdl if ((error = statfs(p, &bsa, retval))) 2971.2Sfvdl return error; 2981.2Sfvdl 2991.2Sfvdl if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp))) 3001.2Sfvdl return error; 3011.2Sfvdl 3021.2Sfvdl bsd_to_linux_statfs(&btmp, <mp); 3031.2Sfvdl 3041.2Sfvdl return copyout((caddr_t) <mp, (caddr_t) SCARG(uap, sp), sizeof ltmp); 3051.1Sfvdl} 3061.1Sfvdl 3071.1Sfvdlint 3081.1Sfvdllinux_fstatfs(p, uap, retval) 3091.1Sfvdl struct proc *p; 3101.1Sfvdl struct linux_fstatfs_args /* { 3111.2Sfvdl syscallarg(int) fd; 3121.1Sfvdl syscallarg(struct linux_statfs *) sp; 3131.1Sfvdl } */ *uap; 3141.1Sfvdl register_t *retval; 3151.1Sfvdl{ 3161.2Sfvdl struct statfs btmp, *bsp; 3171.2Sfvdl struct linux_statfs ltmp; 3181.2Sfvdl struct fstatfs_args bsa; 3191.2Sfvdl caddr_t sg; 3201.2Sfvdl int error; 3211.2Sfvdl 3221.9Schristos sg = stackgap_init(p->p_emul); 3231.2Sfvdl bsp = (struct statfs *) stackgap_alloc(&sg, sizeof (struct statfs)); 3241.2Sfvdl 3251.2Sfvdl SCARG(&bsa, fd) = SCARG(uap, fd); 3261.2Sfvdl SCARG(&bsa, buf) = bsp; 3271.2Sfvdl 3281.2Sfvdl if ((error = statfs(p, &bsa, retval))) 3291.2Sfvdl return error; 3301.2Sfvdl 3311.2Sfvdl if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp))) 3321.2Sfvdl return error; 3331.2Sfvdl 3341.2Sfvdl bsd_to_linux_statfs(&btmp, <mp); 3351.2Sfvdl 3361.2Sfvdl return copyout((caddr_t) <mp, (caddr_t) SCARG(uap, sp), sizeof ltmp); 3371.1Sfvdl} 3381.1Sfvdl 3391.1Sfvdl/* 3401.1Sfvdl * uname(). Just copy the info from the various strings stored in the 3411.1Sfvdl * kernel, and put it in the Linux utsname structure. That structure 3421.1Sfvdl * is almost the same as the NetBSD one, only it has fields 65 characters 3431.1Sfvdl * long, and an extra domainname field. 3441.1Sfvdl */ 3451.1Sfvdlint 3461.1Sfvdllinux_uname(p, uap, retval) 3471.1Sfvdl struct proc *p; 3481.1Sfvdl struct linux_uname_args /* { 3491.1Sfvdl syscallarg(struct linux_utsname *) up; 3501.1Sfvdl } */ *uap; 3511.1Sfvdl register_t *retval; 3521.1Sfvdl{ 3531.1Sfvdl extern char ostype[], osrelease[], version[], hostname[], domainname[]; 3541.1Sfvdl extern char machine[]; 3551.1Sfvdl struct linux_utsname tluts; 3561.1Sfvdl int len; 3571.1Sfvdl char *cp; 3581.1Sfvdl 3591.1Sfvdl strncpy(tluts.l_sysname, ostype, sizeof (tluts.l_sysname)); 3601.1Sfvdl strncpy(tluts.l_nodename, hostname, sizeof (tluts.l_nodename)); 3611.1Sfvdl strncpy(tluts.l_release, osrelease, sizeof (tluts.l_release)); 3621.1Sfvdl strncpy(tluts.l_machine, machine, sizeof (tluts.l_machine)); 3631.1Sfvdl strncpy(tluts.l_domainname, domainname, sizeof (tluts.l_domainname)); 3641.1Sfvdl strncpy(tluts.l_version, version, sizeof (tluts.l_version)); 3651.1Sfvdl 3661.1Sfvdl /* This part taken from the the uname() in libc */ 3671.1Sfvdl len = sizeof (tluts.l_version); 3681.1Sfvdl for (cp = tluts.l_version; len--; ++cp) 3691.1Sfvdl if (*cp == '\n' || *cp == '\t') 3701.1Sfvdl if (len > 1) 3711.1Sfvdl *cp = ' '; 3721.1Sfvdl else 3731.1Sfvdl *cp = '\0'; 3741.1Sfvdl 3751.1Sfvdl return copyout(&tluts, SCARG(uap, up), sizeof tluts); 3761.1Sfvdl} 3771.1Sfvdl 3781.1Sfvdl/* 3791.1Sfvdl * Linux wants to pass everything to a syscall in registers. However, 3801.1Sfvdl * mmap() has 6 of them. Oops: out of register error. They just pass 3811.1Sfvdl * everything in a structure. 3821.1Sfvdl */ 3831.1Sfvdlint 3841.1Sfvdllinux_mmap(p, uap, retval) 3851.1Sfvdl struct proc *p; 3861.1Sfvdl struct linux_mmap_args /* { 3871.1Sfvdl syscallarg(struct linux_mmap *) lmp; 3881.1Sfvdl } */ *uap; 3891.1Sfvdl register_t *retval; 3901.1Sfvdl{ 3911.1Sfvdl struct linux_mmap lmap; 3921.1Sfvdl struct mmap_args cma; 3931.1Sfvdl int error, flags; 3941.1Sfvdl 3951.1Sfvdl if ((error = copyin(SCARG(uap, lmp), &lmap, sizeof lmap))) 3961.1Sfvdl return error; 3971.1Sfvdl 3981.1Sfvdl flags = 0; 3991.1Sfvdl flags |= cvtto_bsd_mask(lmap.lm_flags, LINUX_MAP_SHARED, MAP_SHARED); 4001.1Sfvdl flags |= cvtto_bsd_mask(lmap.lm_flags, LINUX_MAP_PRIVATE, MAP_PRIVATE); 4011.1Sfvdl flags |= cvtto_bsd_mask(lmap.lm_flags, LINUX_MAP_FIXED, MAP_FIXED); 4021.1Sfvdl flags |= cvtto_bsd_mask(lmap.lm_flags, LINUX_MAP_ANON, MAP_ANON); 4031.1Sfvdl 4041.1Sfvdl SCARG(&cma,addr) = lmap.lm_addr; 4051.1Sfvdl SCARG(&cma,len) = lmap.lm_len; 4061.1Sfvdl SCARG(&cma,prot) = lmap.lm_prot; 4071.1Sfvdl SCARG(&cma,flags) = flags; 4081.1Sfvdl SCARG(&cma,fd) = lmap.lm_fd; 4091.1Sfvdl SCARG(&cma,pad) = 0; 4101.1Sfvdl SCARG(&cma,pos) = lmap.lm_pos; 4111.1Sfvdl 4121.1Sfvdl return mmap(p, &cma, retval); 4131.1Sfvdl} 4141.1Sfvdl 4151.1Sfvdl/* 4161.1Sfvdl * Linux doesn't use the retval[1] value to determine whether 4171.1Sfvdl * we are the child or parent. 4181.1Sfvdl */ 4191.1Sfvdlint 4201.1Sfvdllinux_fork(p, uap, retval) 4211.1Sfvdl struct proc *p; 4221.1Sfvdl void *uap; 4231.1Sfvdl register_t *retval; 4241.1Sfvdl{ 4251.1Sfvdl int error; 4261.1Sfvdl 4271.1Sfvdl if ((error = fork(p, uap, retval))) 4281.1Sfvdl return error; 4291.1Sfvdl 4301.1Sfvdl if (retval[1] == 1) 4311.1Sfvdl retval[0] = 0; 4321.1Sfvdl 4331.1Sfvdl return 0; 4341.1Sfvdl} 4351.1Sfvdl 4361.1Sfvdl/* 4371.1Sfvdl * This code is partly stolen from src/lib/libc/compat-43/times.c 4381.1Sfvdl * XXX - CLK_TCK isn't declared in /sys, just in <time.h>, done here 4391.1Sfvdl */ 4401.1Sfvdl 4411.1Sfvdl#define CLK_TCK 100 4421.1Sfvdl#define CONVTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK)) 4431.1Sfvdl 4441.1Sfvdlint 4451.1Sfvdllinux_times(p, uap, retval) 4461.1Sfvdl struct proc *p; 4471.1Sfvdl struct linux_times_args /* { 4481.1Sfvdl syscallarg(struct times *) tms; 4491.1Sfvdl } */ *uap; 4501.1Sfvdl register_t *retval; 4511.1Sfvdl{ 4521.1Sfvdl struct timeval t; 4531.1Sfvdl struct linux_tms ltms; 4541.1Sfvdl struct rusage ru; 4551.4Smycroft int error, s; 4561.1Sfvdl 4571.1Sfvdl calcru(p, &ru.ru_utime, &ru.ru_stime, NULL); 4581.1Sfvdl ltms.ltms_utime = CONVTCK(ru.ru_utime); 4591.1Sfvdl ltms.ltms_stime = CONVTCK(ru.ru_stime); 4601.1Sfvdl 4611.1Sfvdl ltms.ltms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime); 4621.1Sfvdl ltms.ltms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime); 4631.1Sfvdl 4641.1Sfvdl if ((error = copyout(<ms, SCARG(uap, tms), sizeof ltms))) 4651.1Sfvdl return error; 4661.1Sfvdl 4671.4Smycroft s = splclock(); 4681.4Smycroft timersub(&time, &boottime, &t); 4691.4Smycroft splx(s); 4701.1Sfvdl 4711.1Sfvdl retval[0] = ((linux_clock_t)(CONVTCK(t))); 4721.1Sfvdl return 0; 4731.1Sfvdl} 4741.1Sfvdl 4751.1Sfvdl/* 4761.1Sfvdl * NetBSD passes fd[0] in retval[0], and fd[1] in retval[1]. 4771.1Sfvdl * Linux directly passes the pointer. 4781.1Sfvdl */ 4791.1Sfvdlint 4801.1Sfvdllinux_pipe(p, uap, retval) 4811.1Sfvdl struct proc *p; 4821.1Sfvdl struct linux_pipe_args /* { 4831.1Sfvdl syscallarg(int *) pfds; 4841.1Sfvdl } */ *uap; 4851.1Sfvdl register_t *retval; 4861.1Sfvdl{ 4871.1Sfvdl int error; 4881.1Sfvdl 4891.1Sfvdl if ((error = pipe(p, 0, retval))) 4901.1Sfvdl return error; 4911.1Sfvdl 4921.1Sfvdl /* Assumes register_t is an int */ 4931.1Sfvdl 4941.1Sfvdl if ((error = copyout(retval, SCARG(uap, pfds), 2 * sizeof (int)))) 4951.1Sfvdl return error; 4961.1Sfvdl 4971.1Sfvdl retval[0] = 0; 4981.1Sfvdl return 0; 4991.1Sfvdl} 5001.1Sfvdl 5011.1Sfvdl/* 5021.1Sfvdl * Alarm. This is a libc call which used setitimer(2) in NetBSD. 5031.1Sfvdl * Fiddle with the timers to make it work. 5041.1Sfvdl */ 5051.1Sfvdlint 5061.1Sfvdllinux_alarm(p, uap, retval) 5071.1Sfvdl struct proc *p; 5081.1Sfvdl struct linux_alarm_args /* { 5091.1Sfvdl syscallarg(unsigned int) secs; 5101.1Sfvdl } */ *uap; 5111.1Sfvdl register_t *retval; 5121.1Sfvdl{ 5131.1Sfvdl int error, s; 5141.1Sfvdl struct itimerval *itp, it; 5151.1Sfvdl 5161.1Sfvdl itp = &p->p_realtimer; 5171.1Sfvdl s = splclock(); 5181.1Sfvdl /* 5191.1Sfvdl * Clear any pending timer alarms. 5201.1Sfvdl */ 5211.1Sfvdl untimeout(realitexpire, p); 5221.1Sfvdl timerclear(&itp->it_interval); 5231.1Sfvdl if (timerisset(&itp->it_value) && 5241.1Sfvdl timercmp(&itp->it_value, &time, >)) 5251.3Smycroft timersub(&itp->it_value, &time, &itp->it_value); 5261.1Sfvdl /* 5271.1Sfvdl * Return how many seconds were left (rounded up) 5281.1Sfvdl */ 5291.1Sfvdl retval[0] = itp->it_value.tv_sec; 5301.1Sfvdl if (itp->it_value.tv_usec) 5311.1Sfvdl retval[0]++; 5321.1Sfvdl 5331.1Sfvdl /* 5341.1Sfvdl * alarm(0) just resets the timer. 5351.1Sfvdl */ 5361.1Sfvdl if (SCARG(uap, secs) == 0) { 5371.1Sfvdl timerclear(&itp->it_value); 5381.1Sfvdl splx(s); 5391.1Sfvdl return 0; 5401.1Sfvdl } 5411.1Sfvdl 5421.1Sfvdl /* 5431.1Sfvdl * Check the new alarm time for sanity, and set it. 5441.1Sfvdl */ 5451.1Sfvdl timerclear(&it.it_interval); 5461.1Sfvdl it.it_value.tv_sec = SCARG(uap, secs); 5471.1Sfvdl it.it_value.tv_usec = 0; 5481.1Sfvdl if (itimerfix(&it.it_value) || itimerfix(&it.it_interval)) { 5491.1Sfvdl splx(s); 5501.1Sfvdl return (EINVAL); 5511.1Sfvdl } 5521.1Sfvdl 5531.1Sfvdl if (timerisset(&it.it_value)) { 5541.3Smycroft timeradd(&it.it_value, &time, &it.it_value); 5551.1Sfvdl timeout(realitexpire, p, hzto(&it.it_value)); 5561.1Sfvdl } 5571.1Sfvdl p->p_realtimer = it; 5581.1Sfvdl splx(s); 5591.1Sfvdl 5601.1Sfvdl return 0; 5611.1Sfvdl} 5621.1Sfvdl 5631.1Sfvdl/* 5641.1Sfvdl * utime(). Do conversion to things that utimes() understands, 5651.1Sfvdl * and pass it on. 5661.1Sfvdl */ 5671.1Sfvdlint 5681.1Sfvdllinux_utime(p, uap, retval) 5691.1Sfvdl struct proc *p; 5701.1Sfvdl struct linux_utime_args /* { 5711.1Sfvdl syscallarg(char *) path; 5721.1Sfvdl syscallarg(struct linux_utimbuf *)times; 5731.1Sfvdl } */ *uap; 5741.1Sfvdl register_t *retval; 5751.1Sfvdl{ 5761.1Sfvdl caddr_t sg; 5771.1Sfvdl int error; 5781.1Sfvdl struct utimes_args ua; 5791.1Sfvdl struct timeval tv[2], *tvp; 5801.1Sfvdl struct linux_utimbuf lut; 5811.1Sfvdl 5821.9Schristos sg = stackgap_init(p->p_emul); 5831.9Schristos LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path)); 5841.1Sfvdl 5851.1Sfvdl SCARG(&ua, path) = SCARG(uap, path); 5861.1Sfvdl 5871.1Sfvdl if (SCARG(uap, times) != NULL) { 5881.1Sfvdl if ((error = copyin(SCARG(uap, times), &lut, sizeof lut))) 5891.1Sfvdl return error; 5901.1Sfvdl tv[0].tv_usec = tv[1].tv_usec = 0; 5911.1Sfvdl tv[0].tv_sec = lut.l_actime; 5921.1Sfvdl tv[1].tv_sec = lut.l_modtime; 5931.9Schristos tvp = (struct timeval *) stackgap_alloc(&sg, sizeof(tv)); 5941.1Sfvdl if ((error = copyout(tv, tvp, sizeof tv))) 5951.1Sfvdl return error; 5961.1Sfvdl SCARG(&ua, tptr) = tvp; 5971.1Sfvdl } 5981.1Sfvdl else 5991.1Sfvdl SCARG(&ua, tptr) = NULL; 6001.1Sfvdl 6011.1Sfvdl return utimes(p, uap, retval); 6021.1Sfvdl} 6031.1Sfvdl 6041.1Sfvdl/* 6051.1Sfvdl * Linux 'readdir' call. This code is mostly taken from the 6061.1Sfvdl * SunOS getdents call (see compat/sunos/sunos_misc.c), though 6071.1Sfvdl * an attempt has been made to keep it a little cleaner (failing 6081.1Sfvdl * miserably, because of the cruft needed if count 1 is passed). 6091.1Sfvdl * 6101.1Sfvdl * Read in BSD-style entries, convert them, and copy them out. 6111.1Sfvdl * Note that the Linux d_reclen is actually the name length, 6121.1Sfvdl * and d_off is the reclen. 6131.1Sfvdl * 6141.1Sfvdl * Note that this doesn't handle union-mounted filesystems. 6151.1Sfvdl */ 6161.1Sfvdlint 6171.1Sfvdllinux_readdir(p, uap, retval) 6181.1Sfvdl struct proc *p; 6191.1Sfvdl struct linux_readdir_args /* { 6201.1Sfvdl syscallarg(int) fd; 6211.1Sfvdl syscallarg(struct linux_dirent *) dent; 6221.1Sfvdl syscallarg(unsigned int) count; 6231.1Sfvdl } */ *uap; 6241.1Sfvdl register_t *retval; 6251.1Sfvdl{ 6261.1Sfvdl register struct dirent *bdp; 6271.1Sfvdl struct vnode *vp; 6281.1Sfvdl caddr_t inp, buf; /* BSD-format */ 6291.1Sfvdl int len, reclen; /* BSD-format */ 6301.1Sfvdl caddr_t outp; /* Linux-format */ 6311.1Sfvdl int resid, linuxreclen; /* Linux-format */ 6321.1Sfvdl struct file *fp; 6331.1Sfvdl struct uio auio; 6341.1Sfvdl struct iovec aiov; 6351.1Sfvdl struct linux_dirent idb; 6361.1Sfvdl off_t off; /* true file offset */ 6371.1Sfvdl linux_off_t soff; /* Linux file offset */ 6381.1Sfvdl int buflen, error, eofflag, nbytes, justone; 6391.1Sfvdl struct vattr va; 6401.1Sfvdl 6411.1Sfvdl if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 6421.1Sfvdl return (error); 6431.1Sfvdl 6441.1Sfvdl if ((fp->f_flag & FREAD) == 0) 6451.1Sfvdl return (EBADF); 6461.1Sfvdl 6471.5Smycroft vp = (struct vnode *)fp->f_data; 6481.1Sfvdl 6491.1Sfvdl if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */ 6501.1Sfvdl return (EINVAL); 6511.1Sfvdl 6521.1Sfvdl if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) 6531.1Sfvdl return error; 6541.1Sfvdl 6551.1Sfvdl nbytes = SCARG(uap, count); 6561.1Sfvdl if (nbytes == 1) { /* Need this for older Linux libs, apparently */ 6571.1Sfvdl nbytes = sizeof (struct linux_dirent); 6581.5Smycroft buflen = max(va.va_blocksize, nbytes); 6591.1Sfvdl justone = 1; 6601.5Smycroft } else { 6611.5Smycroft buflen = min(MAXBSIZE, nbytes); 6621.5Smycroft justone = 0; 6631.1Sfvdl } 6641.1Sfvdl buf = malloc(buflen, M_TEMP, M_WAITOK); 6651.1Sfvdl VOP_LOCK(vp); 6661.1Sfvdl off = fp->f_offset; 6671.1Sfvdlagain: 6681.1Sfvdl aiov.iov_base = buf; 6691.1Sfvdl aiov.iov_len = buflen; 6701.1Sfvdl auio.uio_iov = &aiov; 6711.1Sfvdl auio.uio_iovcnt = 1; 6721.1Sfvdl auio.uio_rw = UIO_READ; 6731.1Sfvdl auio.uio_segflg = UIO_SYSSPACE; 6741.1Sfvdl auio.uio_procp = p; 6751.1Sfvdl auio.uio_resid = buflen; 6761.1Sfvdl auio.uio_offset = off; 6771.1Sfvdl /* 6781.1Sfvdl * First we read into the malloc'ed buffer, then 6791.1Sfvdl * we massage it into user space, one record at a time. 6801.1Sfvdl */ 6811.5Smycroft error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0); 6821.1Sfvdl if (error) 6831.1Sfvdl goto out; 6841.1Sfvdl 6851.1Sfvdl inp = buf; 6861.1Sfvdl outp = (caddr_t) SCARG(uap, dent); 6871.1Sfvdl resid = nbytes; 6881.1Sfvdl if ((len = buflen - auio.uio_resid) == 0) 6891.1Sfvdl goto eof; 6901.1Sfvdl 6911.1Sfvdl for (; len > 0; len -= reclen) { 6921.5Smycroft bdp = (struct dirent *)inp; 6931.5Smycroft reclen = bdp->d_reclen; 6941.1Sfvdl if (reclen & 3) 6951.1Sfvdl panic("linux_readdir"); 6961.1Sfvdl off += reclen; /* each entry points to next */ 6971.1Sfvdl if (bdp->d_fileno == 0) { 6981.1Sfvdl inp += reclen; /* it is a hole; squish it out */ 6991.1Sfvdl continue; 7001.1Sfvdl } 7011.1Sfvdl linuxreclen = LINUX_RECLEN(&idb, bdp->d_namlen); 7021.1Sfvdl if (reclen > len || resid < linuxreclen) { 7031.1Sfvdl /* entry too big for buffer, so just stop */ 7041.1Sfvdl outp++; 7051.1Sfvdl break; 7061.1Sfvdl } 7071.1Sfvdl /* 7081.1Sfvdl * Massage in place to make a Linux-shaped dirent (otherwise 7091.1Sfvdl * we have to worry about touching user memory outside of 7101.1Sfvdl * the copyout() call). 7111.1Sfvdl */ 7121.5Smycroft idb.d_ino = (long)bdp->d_fileno; 7131.5Smycroft idb.d_off = (linux_off_t)linuxreclen; 7141.5Smycroft idb.d_reclen = (u_short)bdp->d_namlen; 7151.5Smycroft strcpy(idb.d_name, bdp->d_name); 7161.1Sfvdl if ((error = copyout((caddr_t)&idb, outp, linuxreclen))) 7171.1Sfvdl goto out; 7181.1Sfvdl /* advance past this real entry */ 7191.1Sfvdl inp += reclen; 7201.1Sfvdl /* advance output past Linux-shaped entry */ 7211.1Sfvdl outp += linuxreclen; 7221.1Sfvdl resid -= linuxreclen; 7231.1Sfvdl if (justone) 7241.1Sfvdl break; 7251.1Sfvdl } 7261.1Sfvdl 7271.1Sfvdl /* if we squished out the whole block, try again */ 7281.1Sfvdl if (outp == (caddr_t) SCARG(uap, dent)) 7291.1Sfvdl goto again; 7301.1Sfvdl fp->f_offset = off; /* update the vnode offset */ 7311.1Sfvdl 7321.1Sfvdl if (justone) 7331.1Sfvdl nbytes = resid + linuxreclen; 7341.1Sfvdl 7351.1Sfvdleof: 7361.1Sfvdl *retval = nbytes - resid; 7371.1Sfvdlout: 7381.1Sfvdl VOP_UNLOCK(vp); 7391.1Sfvdl free(buf, M_TEMP); 7401.1Sfvdl return error; 7411.1Sfvdl} 7421.1Sfvdl 7431.1Sfvdl/* 7441.7Sfvdl * Out of register error once more.. Also, Linux copies the amount of 7451.7Sfvdl * time left into the user-supplied timeval structure. 7461.1Sfvdl */ 7471.1Sfvdlint 7481.1Sfvdllinux_select(p, uap, retval) 7491.1Sfvdl struct proc *p; 7501.1Sfvdl struct linux_select_args /* { 7511.1Sfvdl syscallarg(struct linux_select *) lsp; 7521.1Sfvdl } */ *uap; 7531.1Sfvdl register_t *retval; 7541.1Sfvdl{ 7551.1Sfvdl struct linux_select ls; 7561.1Sfvdl struct select_args bsa; 7571.7Sfvdl struct timeval tv0, tv1, utv; 7581.1Sfvdl int error; 7591.1Sfvdl 7601.7Sfvdl if ((error = copyin(SCARG(uap, lsp), (caddr_t)&ls, sizeof ls))) 7611.1Sfvdl return error; 7621.1Sfvdl 7631.1Sfvdl SCARG(&bsa, nd) = ls.nfds; 7641.1Sfvdl SCARG(&bsa, in) = ls.readfds; 7651.1Sfvdl SCARG(&bsa, ou) = ls.writefds; 7661.1Sfvdl SCARG(&bsa, ex) = ls.exceptfds; 7671.1Sfvdl SCARG(&bsa, tv) = ls.timeout; 7681.1Sfvdl 7691.7Sfvdl /* 7701.7Sfvdl * Store current time for computation of the amount of 7711.7Sfvdl * time left. 7721.7Sfvdl */ 7731.7Sfvdl if (ls.timeout) 7741.7Sfvdl microtime(&tv0); 7751.7Sfvdl 7761.10Smycroft error = select(p, &bsa, retval); 7771.10Smycroft if (error) { 7781.10Smycroft /* 7791.10Smycroft * See fs/select.c in the Linux kernel. Without this, 7801.10Smycroft * Maelstrom doesn't work. 7811.10Smycroft */ 7821.10Smycroft if (error == ERESTART) 7831.10Smycroft error = EINTR; 7841.7Sfvdl return error; 7851.10Smycroft } 7861.7Sfvdl 7871.7Sfvdl if (ls.timeout) { 7881.7Sfvdl if (!*retval) { 7891.7Sfvdl utv.tv_sec = 0; 7901.7Sfvdl utv.tv_usec = 0; 7911.7Sfvdl } else { 7921.7Sfvdl /* 7931.7Sfvdl * Compute how many time was left of the timeout, 7941.7Sfvdl * by subtracting the current time and the time 7951.7Sfvdl * before we started the call, and subtracting 7961.7Sfvdl * that result from the user-supplied value. 7971.7Sfvdl */ 7981.7Sfvdl microtime(&tv1); 7991.7Sfvdl if ((error = copyin((caddr_t)ls.timeout, (caddr_t)&utv, 8001.7Sfvdl sizeof utv))) 8011.7Sfvdl return error; 8021.7Sfvdl timersub(&tv1, &tv0, &tv1); 8031.7Sfvdl timersub(&utv, &tv1, &utv); 8041.7Sfvdl } 8051.7Sfvdl if ((error = copyout((caddr_t)&utv, (caddr_t)ls.timeout, 8061.7Sfvdl sizeof utv))) 8071.7Sfvdl return error; 8081.7Sfvdl } 8091.7Sfvdl return 0; 8101.1Sfvdl} 8111.1Sfvdl 8121.1Sfvdl/* 8131.1Sfvdl * Get the process group of a certain process. Look it up 8141.1Sfvdl * and return the value. 8151.1Sfvdl */ 8161.1Sfvdlint 8171.1Sfvdllinux_getpgid(p, uap, retval) 8181.1Sfvdl struct proc *p; 8191.1Sfvdl struct linux_getpgid_args /* { 8201.1Sfvdl syscallarg(int) pid; 8211.1Sfvdl } */ *uap; 8221.1Sfvdl register_t *retval; 8231.1Sfvdl{ 8241.1Sfvdl struct proc *targp; 8251.1Sfvdl 8261.1Sfvdl if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != p->p_pid) 8271.1Sfvdl if ((targp = pfind(SCARG(uap, pid))) == 0) 8281.1Sfvdl return ESRCH; 8291.1Sfvdl else 8301.1Sfvdl targp = p; 8311.1Sfvdl 8321.1Sfvdl retval[0] = targp->p_pgid; 8331.6Sfvdl return 0; 8341.6Sfvdl} 8351.6Sfvdl 8361.6Sfvdl/* 8371.6Sfvdl * Set the 'personality' (emulation mode) for the current process. Only 8381.6Sfvdl * accept the Linux personality here (0). This call is needed because 8391.6Sfvdl * the Linux ELF crt0 issues it in an ugly kludge to make sure that 8401.6Sfvdl * ELF binaries run in Linux mode, not SVR4 mode. 8411.6Sfvdl */ 8421.6Sfvdlint 8431.6Sfvdllinux_personality(p, uap, retval) 8441.6Sfvdl struct proc *p; 8451.6Sfvdl struct linux_personality_args /* P 8461.6Sfvdl syscallarg(int) per; 8471.6Sfvdl } */ *uap; 8481.6Sfvdl register_t *retval; 8491.6Sfvdl{ 8501.6Sfvdl if (SCARG(uap, per) != 0) 8511.6Sfvdl return EINVAL; 8521.6Sfvdl retval[0] = 0; 8531.1Sfvdl return 0; 8541.1Sfvdl} 855