linux_misc.c revision 14703
19313Ssos/*- 29313Ssos * Copyright (c) 1994-1995 S�ren Schmidt 39313Ssos * All rights reserved. 49313Ssos * 59313Ssos * Redistribution and use in source and binary forms, with or without 69313Ssos * modification, are permitted provided that the following conditions 79313Ssos * are met: 89313Ssos * 1. Redistributions of source code must retain the above copyright 914331Speter * notice, this list of conditions and the following disclaimer 109313Ssos * in this position and unchanged. 119313Ssos * 2. Redistributions in binary form must reproduce the above copyright 129313Ssos * notice, this list of conditions and the following disclaimer in the 139313Ssos * documentation and/or other materials provided with the distribution. 149313Ssos * 3. The name of the author may not be used to endorse or promote products 159313Ssos * derived from this software withough specific prior written permission 169313Ssos * 179313Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 189313Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 199313Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 209313Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 219313Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 229313Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 239313Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 249313Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 259313Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 269313Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 279313Ssos * 2814703Sbde * $Id: linux_misc.c,v 1.16 1996/03/12 06:20:14 peter Exp $ 299313Ssos */ 309313Ssos 319313Ssos#include <sys/param.h> 329313Ssos#include <sys/systm.h> 3312458Sbde#include <sys/sysproto.h> 3412458Sbde#include <sys/kernel.h> 359313Ssos#include <sys/exec.h> 369313Ssos#include <sys/mman.h> 379313Ssos#include <sys/proc.h> 389313Ssos#include <sys/dirent.h> 399313Ssos#include <sys/file.h> 409313Ssos#include <sys/filedesc.h> 419313Ssos#include <sys/ioctl.h> 429313Ssos#include <sys/imgact_aout.h> 439313Ssos#include <sys/mount.h> 449313Ssos#include <sys/namei.h> 459313Ssos#include <sys/resource.h> 469313Ssos#include <sys/resourcevar.h> 479313Ssos#include <sys/stat.h> 4812458Sbde#include <sys/sysctl.h> 499313Ssos#include <sys/times.h> 509313Ssos#include <sys/utsname.h> 519313Ssos#include <sys/vnode.h> 529313Ssos#include <sys/wait.h> 5314331Speter#include <sys/time.h> 549313Ssos 5512652Sbde#include <vm/vm.h> 5612689Speter#include <vm/vm_param.h> 5712689Speter#include <vm/pmap.h> 5812689Speter#include <vm/lock.h> 5912458Sbde#include <vm/vm_kern.h> 6012689Speter#include <vm/vm_prot.h> 6112689Speter#include <vm/vm_map.h> 6212842Sbde#include <vm/vm_extern.h> 6312458Sbde 649313Ssos#include <machine/cpu.h> 659313Ssos#include <machine/psl.h> 669313Ssos 6712458Sbde#include <i386/linux/linux.h> 6814331Speter#include <i386/linux/linux_proto.h> 6914331Speter#include <i386/linux/linux_util.h> 709313Ssos 719313Ssosint 729313Ssoslinux_alarm(struct proc *p, struct linux_alarm_args *args, int *retval) 739313Ssos{ 749313Ssos struct itimerval it, old_it; 7512858Speter struct timeval tv; 769313Ssos int s; 779313Ssos 789313Ssos#ifdef DEBUG 799313Ssos printf("Linux-emul(%d): alarm(%d)\n", p->p_pid, args->secs); 809313Ssos#endif 819313Ssos it.it_value.tv_sec = (long)args->secs; 829313Ssos it.it_value.tv_usec = 0; 839313Ssos it.it_interval.tv_sec = 0; 849313Ssos it.it_interval.tv_usec = 0; 859313Ssos s = splclock(); 869313Ssos old_it = p->p_realtimer; 8712858Speter tv = time; 889313Ssos if (timerisset(&old_it.it_value)) 8912858Speter if (timercmp(&old_it.it_value, &tv, <)) 909313Ssos timerclear(&old_it.it_value); 919313Ssos else 9212858Speter timevalsub(&old_it.it_value, &tv); 939313Ssos splx(s); 949313Ssos if (itimerfix(&it.it_value) || itimerfix(&it.it_interval)) 959313Ssos return EINVAL; 969313Ssos s = splclock(); 979313Ssos untimeout(realitexpire, (caddr_t)p); 9812858Speter tv = time; 999313Ssos if (timerisset(&it.it_value)) { 10012858Speter timevaladd(&it.it_value, &tv); 1019313Ssos timeout(realitexpire, (caddr_t)p, hzto(&it.it_value)); 1029313Ssos } 1039313Ssos p->p_realtimer = it; 1049313Ssos splx(s); 1059313Ssos if (old_it.it_value.tv_usec) 1069313Ssos old_it.it_value.tv_sec++; 1079313Ssos *retval = old_it.it_value.tv_sec; 1089313Ssos return 0; 1099313Ssos} 1109313Ssos 1119313Ssosint 1129313Ssoslinux_brk(struct proc *p, struct linux_brk_args *args, int *retval) 1139313Ssos{ 1149313Ssos#if 0 1159313Ssos struct vmspace *vm = p->p_vmspace; 1169313Ssos vm_offset_t new, old; 1179313Ssos int error; 1189313Ssos 1199313Ssos if ((vm_offset_t)args->dsend < (vm_offset_t)vm->vm_daddr) 1209313Ssos return EINVAL; 1219313Ssos if (((caddr_t)args->dsend - (caddr_t)vm->vm_daddr) 1229313Ssos > p->p_rlimit[RLIMIT_DATA].rlim_cur) 1239313Ssos return ENOMEM; 1249313Ssos 1259313Ssos old = round_page((vm_offset_t)vm->vm_daddr) + ctob(vm->vm_dsize); 1269313Ssos new = round_page((vm_offset_t)args->dsend); 1279313Ssos *retval = old; 1289313Ssos if ((new-old) > 0) { 1299313Ssos if (swap_pager_full) 1309313Ssos return ENOMEM; 13113503Sdyson error = vm_map_find(&vm->vm_map, NULL, 0, &old, (new-old), FALSE, 13213503Sdyson VM_PROT_ALL, VM_PROT_ALL, 0); 13314331Speter if (error) 1349313Ssos return error; 1359313Ssos vm->vm_dsize += btoc((new-old)); 1369313Ssos *retval = (int)(vm->vm_daddr + ctob(vm->vm_dsize)); 1379313Ssos } 1389313Ssos return 0; 1399313Ssos#else 1409313Ssos struct vmspace *vm = p->p_vmspace; 1419313Ssos vm_offset_t new, old; 14212858Speter struct obreak_args /* { 14312858Speter char * nsize; 14412858Speter } */ tmp; 1459313Ssos 1469313Ssos#ifdef DEBUG 1479313Ssos printf("Linux-emul(%d): brk(%08x)\n", p->p_pid, args->dsend); 1489313Ssos#endif 1499313Ssos old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize); 1509313Ssos new = (vm_offset_t)args->dsend; 15112858Speter tmp.nsize = (char *) new; 1529313Ssos if (((caddr_t)new > vm->vm_daddr) && !obreak(p, &tmp, retval)) 1539313Ssos retval[0] = (int)new; 1549313Ssos else 1559313Ssos retval[0] = (int)old; 1569313Ssos 1579313Ssos return 0; 1589313Ssos#endif 1599313Ssos} 1609313Ssos 1619313Ssosint 1629313Ssoslinux_uselib(struct proc *p, struct linux_uselib_args *args, int *retval) 1639313Ssos{ 1649313Ssos struct nameidata ni; 16512130Sdg struct vnode *vp; 16614114Speter struct exec *a_out; 1679313Ssos struct vattr attr; 16814703Sbde vm_offset_t vmaddr; 16914703Sbde unsigned long file_offset; 17014703Sbde vm_offset_t buffer; 17114703Sbde unsigned long bss_size; 1729313Ssos char *ptr; 1739313Ssos int error; 17414331Speter caddr_t sg; 17514114Speter int locked; 1769313Ssos 17714331Speter sg = stackgap_init(); 17814331Speter CHECKALTEXIST(p, &sg, args->library); 17914331Speter 1809313Ssos#ifdef DEBUG 1819313Ssos printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, args->library); 1829313Ssos#endif 1839313Ssos 18414114Speter a_out = NULL; 18514114Speter locked = 0; 18614114Speter vp = NULL; 18714114Speter 18814331Speter NDINIT(&ni, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, args->library, p); 1899313Ssos if (error = namei(&ni)) 19014114Speter goto cleanup; 1919313Ssos 19212130Sdg vp = ni.ni_vp; 19314114Speter if (vp == NULL) { 19414114Speter error = ENOEXEC; /* ?? */ 19514114Speter goto cleanup; 19614114Speter } 1979313Ssos 19814114Speter /* 19914114Speter * From here on down, we have a locked vnode that must be unlocked. 20014114Speter */ 20114114Speter locked++; 20214114Speter 20314114Speter /* 20414114Speter * Writable? 20514114Speter */ 20612130Sdg if (vp->v_writecount) { 20714114Speter error = ETXTBSY; 20814114Speter goto cleanup; 20911163Sjulian } 2109313Ssos 21114114Speter /* 21214114Speter * Executable? 21314114Speter */ 21414114Speter if (error = VOP_GETATTR(vp, &attr, p->p_ucred, p)) 21514114Speter goto cleanup; 2169313Ssos 21714114Speter if ((vp->v_mount->mnt_flag & MNT_NOEXEC) || 21814114Speter ((attr.va_mode & 0111) == 0) || 21914114Speter (attr.va_type != VREG)) { 22014114Speter error = ENOEXEC; 22114114Speter goto cleanup; 22211163Sjulian } 2239313Ssos 22414114Speter /* 22514114Speter * Sensible size? 22614114Speter */ 22711163Sjulian if (attr.va_size == 0) { 22814114Speter error = ENOEXEC; 22914114Speter goto cleanup; 23011163Sjulian } 2319313Ssos 23214114Speter /* 23314114Speter * Can we access it? 23414114Speter */ 23514114Speter if (error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p)) 23614114Speter goto cleanup; 2379313Ssos 23814114Speter if (error = VOP_OPEN(vp, FREAD, p->p_ucred, p)) 23914114Speter goto cleanup; 2409313Ssos 24114114Speter /* 24214114Speter * Lock no longer needed 24314114Speter */ 24414114Speter VOP_UNLOCK(vp); 24514114Speter locked = 0; 24611163Sjulian 24714114Speter /* 24814114Speter * Pull in executable header into kernel_map 24914114Speter */ 25014114Speter error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE, 25112130Sdg VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0); 2529313Ssos if (error) 25314114Speter goto cleanup; 2549313Ssos 2559313Ssos /* 2569313Ssos * Is it a Linux binary ? 2579313Ssos */ 25814114Speter if (((a_out->a_magic >> 16) & 0xff) != 0x64) { 25914114Speter error = ENOEXEC; 26014114Speter goto cleanup; 26114114Speter } 2629313Ssos 26314114Speter /* While we are here, we should REALLY do some more checks */ 26414114Speter 2659313Ssos /* 2669313Ssos * Set file/virtual offset based on a.out variant. 2679313Ssos */ 2689313Ssos switch ((int)(a_out->a_magic & 0xffff)) { 2699313Ssos case 0413: /* ZMAGIC */ 2709313Ssos file_offset = 1024; 2719313Ssos break; 2729313Ssos case 0314: /* QMAGIC */ 2739313Ssos file_offset = 0; 2749313Ssos break; 2759313Ssos default: 27614114Speter error = ENOEXEC; 27714114Speter goto cleanup; 2789313Ssos } 2799313Ssos 2809313Ssos bss_size = round_page(a_out->a_bss); 28114114Speter 2829313Ssos /* 28314114Speter * Check various fields in header for validity/bounds. 28414114Speter */ 28514114Speter if (a_out->a_text % NBPG || a_out->a_data % NBPG) { 28614114Speter error = ENOEXEC; 28714114Speter goto cleanup; 28814114Speter } 28914114Speter 29014114Speter /* text + data can't exceed file size */ 29114114Speter if (a_out->a_data + a_out->a_text > attr.va_size) { 29214114Speter error = EFAULT; 29314114Speter goto cleanup; 29414114Speter } 29514114Speter 29614114Speter /* 29714114Speter * text/data/bss must not exceed limits 29814114Speter * XXX: this is not complete. it should check current usage PLUS 29914114Speter * the resources needed by this library. 30014114Speter */ 30114114Speter if (a_out->a_text > MAXTSIZ || a_out->a_data + bss_size > MAXDSIZ || 30214114Speter a_out->a_data+bss_size > p->p_rlimit[RLIMIT_DATA].rlim_cur) { 30314114Speter error = ENOMEM; 30414114Speter goto cleanup; 30514114Speter } 30614114Speter 30714114Speter /* 30814114Speter * prevent more writers 30914114Speter */ 31014114Speter vp->v_flag |= VTEXT; 31114114Speter 31214114Speter /* 3139313Ssos * Check if file_offset page aligned,. 3149313Ssos * Currently we cannot handle misalinged file offsets, 3159313Ssos * and so we read in the entire image (what a waste). 3169313Ssos */ 3179313Ssos if (file_offset & PGOFSET) { 3189313Ssos#ifdef DEBUG 3199313Ssosprintf("uselib: Non page aligned binary %d\n", file_offset); 3209313Ssos#endif 3219313Ssos /* 3229313Ssos * Map text+data read/write/execute 3239313Ssos */ 32414114Speter 32514114Speter /* a_entry is the load address and is page aligned */ 32614114Speter vmaddr = trunc_page(a_out->a_entry); 32714114Speter 32814114Speter /* get anon user mapping, read+write+execute */ 3299313Ssos error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr, 33014114Speter a_out->a_text + a_out->a_data, FALSE, 33114114Speter VM_PROT_ALL, VM_PROT_ALL, 0); 3329313Ssos if (error) 33314114Speter goto cleanup; 3349313Ssos 33514114Speter /* map file into kernel_map */ 3369313Ssos error = vm_mmap(kernel_map, &buffer, 3379313Ssos round_page(a_out->a_text + a_out->a_data + file_offset), 33814584Speter VM_PROT_READ, VM_PROT_READ, 0, 33912130Sdg (caddr_t)vp, trunc_page(file_offset)); 3409313Ssos if (error) 34114114Speter goto cleanup; 3429313Ssos 34314114Speter /* copy from kernel VM space to user space */ 34414331Speter error = copyout((caddr_t)(buffer + file_offset), (caddr_t)vmaddr, 3459313Ssos a_out->a_text + a_out->a_data); 3469313Ssos 34714114Speter /* release temporary kernel space */ 34814114Speter vm_map_remove(kernel_map, buffer, 34914471Speter buffer + round_page(a_out->a_text + a_out->a_data + file_offset)); 3509313Ssos 3519313Ssos if (error) 35214114Speter goto cleanup; 3539313Ssos } 3549313Ssos else { 3559313Ssos#ifdef DEBUG 3569313Ssosprintf("uselib: Page aligned binary %d\n", file_offset); 3579313Ssos#endif 35814114Speter /* 35914114Speter * for QMAGIC, a_entry is 20 bytes beyond the load address 36014114Speter * to skip the executable header 36114114Speter */ 36214114Speter vmaddr = trunc_page(a_out->a_entry); 36314114Speter 36414114Speter /* 36514114Speter * Map it all into the process's space as a single copy-on-write 36614114Speter * "data" segment. 36714114Speter */ 3689313Ssos error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr, 36914114Speter a_out->a_text + a_out->a_data, 3709313Ssos VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED, 37112130Sdg (caddr_t)vp, file_offset); 3729313Ssos if (error) 37314114Speter goto cleanup; 3749313Ssos } 3759313Ssos#ifdef DEBUG 3769313Ssosprintf("mem=%08x = %08x %08x\n", vmaddr, ((int*)vmaddr)[0], ((int*)vmaddr)[1]); 3779313Ssos#endif 3789313Ssos if (bss_size != 0) { 37914114Speter /* 38014114Speter * Calculate BSS start address 38114114Speter */ 38214114Speter vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + a_out->a_data; 38314114Speter 38414114Speter /* 38514114Speter * allocate some 'anon' space 38614114Speter */ 38714331Speter error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr, 38813503Sdyson bss_size, FALSE, 38914114Speter VM_PROT_ALL, VM_PROT_ALL, 0); 3909313Ssos if (error) 39114114Speter goto cleanup; 3929313Ssos } 39314114Speter 39414114Spetercleanup: 39514114Speter /* 39614114Speter * Unlock vnode if needed 39714114Speter */ 39814114Speter if (locked) 39914114Speter VOP_UNLOCK(vp); 40014114Speter 40114114Speter /* 40214114Speter * Release the kernel mapping. 40314114Speter */ 40414114Speter if (a_out) 40514471Speter vm_map_remove(kernel_map, (vm_offset_t)a_out, (vm_offset_t)a_out + PAGE_SIZE); 40614114Speter 40714114Speter return error; 4089313Ssos} 4099313Ssos 41014331Speter/* XXX move */ 41114331Speterstruct linux_select_argv { 41214331Speter int nfds; 41314331Speter fd_set *readfds; 41414331Speter fd_set *writefds; 41514331Speter fd_set *exceptfds; 41614331Speter struct timeval *timeout; 4179313Ssos}; 4189313Ssos 4199313Ssosint 4209313Ssoslinux_select(struct proc *p, struct linux_select_args *args, int *retval) 4219313Ssos{ 42214331Speter struct linux_select_argv linux_args; 42314331Speter struct linux_newselect_args newsel; 4249313Ssos int error; 4259313Ssos 42614331Speter#ifdef SELECT_DEBUG 42714331Speter printf("Linux-emul(%d): select(%x)\n", 42814331Speter p->p_pid, args->ptr); 42914331Speter#endif 4309313Ssos if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args, 4319313Ssos sizeof(linux_args)))) 4329313Ssos return error; 43314331Speter 43414331Speter newsel.nfds = linux_args.nfds; 43514331Speter newsel.readfds = linux_args.readfds; 43614331Speter newsel.writefds = linux_args.writefds; 43714331Speter newsel.exceptfds = linux_args.exceptfds; 43814331Speter newsel.timeout = linux_args.timeout; 43914331Speter 44014331Speter return linux_newselect(p, &newsel, retval); 44114331Speter} 44214331Speter 44314331Speterint 44414331Speterlinux_newselect(struct proc *p, struct linux_newselect_args *args, int *retval) 44514331Speter{ 44614331Speter struct select_args bsa; 44714331Speter struct timeval tv0, tv1, utv, *tvp; 44814331Speter caddr_t sg; 44914331Speter int error; 45014331Speter 4519313Ssos#ifdef DEBUG 45214331Speter printf("Linux-emul(%d): newselect(%d, %x, %x, %x, %x)\n", 45314331Speter p->p_pid, args->nfds, args->readfds, args->writefds, 45414331Speter args->exceptfds, args->timeout); 4559313Ssos#endif 45614331Speter error = 0; 45714331Speter bsa.nd = args->nfds; 45814331Speter bsa.in = args->readfds; 45914331Speter bsa.ou = args->writefds; 46014331Speter bsa.ex = args->exceptfds; 46114331Speter bsa.tv = args->timeout; 46214331Speter 46314331Speter /* 46414331Speter * Store current time for computation of the amount of 46514331Speter * time left. 46614331Speter */ 46714331Speter if (args->timeout) { 46814331Speter if ((error = copyin(args->timeout, &utv, sizeof(utv)))) 46914331Speter goto select_out; 47014331Speter#ifdef DEBUG 47114331Speter printf("Linux-emul(%d): incoming timeout (%d/%d)\n", 47214331Speter p->p_pid, utv.tv_sec, utv.tv_usec); 47314331Speter#endif 47414331Speter if (itimerfix(&utv)) { 47514331Speter /* 47614331Speter * The timeval was invalid. Convert it to something 47714331Speter * valid that will act as it does under Linux. 47814331Speter */ 47914331Speter sg = stackgap_init(); 48014331Speter tvp = stackgap_alloc(&sg, sizeof(utv)); 48114331Speter utv.tv_sec += utv.tv_usec / 1000000; 48214331Speter utv.tv_usec %= 1000000; 48314331Speter if (utv.tv_usec < 0) { 48414331Speter utv.tv_sec -= 1; 48514331Speter utv.tv_usec += 1000000; 48614331Speter } 48714331Speter if (utv.tv_sec < 0) 48814331Speter timerclear(&utv); 48914331Speter if ((error = copyout(&utv, tvp, sizeof(utv)))) 49014331Speter goto select_out; 49114331Speter bsa.tv = tvp; 49214331Speter } 49314331Speter microtime(&tv0); 49414331Speter } 49514331Speter 49614331Speter error = select(p, &bsa, retval); 49714331Speter#ifdef DEBUG 49814331Speter printf("Linux-emul(%d): real select returns %d\n", 49914331Speter p->p_pid, error); 50014331Speter#endif 50114331Speter 50214331Speter if (error) { 50314331Speter /* 50414331Speter * See fs/select.c in the Linux kernel. Without this, 50514331Speter * Maelstrom doesn't work. 50614331Speter */ 50714331Speter if (error == ERESTART) 50814331Speter error = EINTR; 50914331Speter goto select_out; 51014331Speter } 51114331Speter 51214331Speter if (args->timeout) { 51314331Speter if (*retval) { 51414331Speter /* 51514331Speter * Compute how much time was left of the timeout, 51614331Speter * by subtracting the current time and the time 51714331Speter * before we started the call, and subtracting 51814331Speter * that result from the user-supplied value. 51914331Speter */ 52014331Speter microtime(&tv1); 52114331Speter timevalsub(&tv1, &tv0); 52214331Speter timevalsub(&utv, &tv1); 52314331Speter if (utv.tv_sec < 0) 52414331Speter timerclear(&utv); 52514331Speter } else 52614331Speter timerclear(&utv); 52714331Speter#ifdef DEBUG 52814331Speter printf("Linux-emul(%d): outgoing timeout (%d/%d)\n", 52914331Speter p->p_pid, utv.tv_sec, utv.tv_usec); 53014331Speter#endif 53114331Speter if ((error = copyout(&utv, args->timeout, sizeof(utv)))) 53214331Speter goto select_out; 53314331Speter } 53414331Speter 53514331Speterselect_out: 53614331Speter#ifdef DEBUG 53714331Speter printf("Linux-emul(%d): newselect_out -> %d\n", 53814331Speter p->p_pid, error); 53914331Speter#endif 54014331Speter return error; 5419313Ssos} 5429313Ssos 5439313Ssosint 5449313Ssoslinux_getpgid(struct proc *p, struct linux_getpgid_args *args, int *retval) 5459313Ssos{ 5469313Ssos struct proc *curproc; 5479313Ssos 5489313Ssos#ifdef DEBUG 5499313Ssos printf("Linux-emul(%d): getpgid(%d)\n", p->p_pid, args->pid); 5509313Ssos#endif 5519313Ssos if (args->pid != p->p_pid) { 5529313Ssos if (!(curproc = pfind(args->pid))) 5539313Ssos return ESRCH; 5549313Ssos } 5559313Ssos else 5569313Ssos curproc = p; 5579313Ssos *retval = curproc->p_pgid; 5589313Ssos return 0; 5599313Ssos} 5609313Ssos 5619313Ssosint 56214331Speterlinux_fork(struct proc *p, struct linux_fork_args *args, int *retval) 5639313Ssos{ 5649313Ssos int error; 5659313Ssos 5669313Ssos#ifdef DEBUG 5679313Ssos printf("Linux-emul(%d): fork()\n", p->p_pid); 5689313Ssos#endif 56914331Speter if (error = fork(p, (struct fork_args *)args, retval)) 5709313Ssos return error; 5719313Ssos if (retval[1] == 1) 5729313Ssos retval[0] = 0; 5739313Ssos return 0; 5749313Ssos} 5759313Ssos 57614331Speter/* XXX move */ 57714331Speterstruct linux_mmap_argv { 5789313Ssos linux_caddr_t addr; 5799313Ssos int len; 5809313Ssos int prot; 5819313Ssos int flags; 5829313Ssos int fd; 5839313Ssos int pos; 58414331Speter}; 58514331Speter 58614331Speterint 58714331Speterlinux_mmap(struct proc *p, struct linux_mmap_args *args, int *retval) 58814331Speter{ 58912858Speter struct mmap_args /* { 5909313Ssos caddr_t addr; 5919313Ssos size_t len; 5929313Ssos int prot; 5939313Ssos int flags; 5949313Ssos int fd; 5959313Ssos long pad; 5969313Ssos off_t pos; 59712858Speter } */ bsd_args; 5989313Ssos int error; 59914331Speter struct linux_mmap_argv linux_args; 6009313Ssos 6019313Ssos if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args, 6029313Ssos sizeof(linux_args)))) 6039313Ssos return error; 6049313Ssos#ifdef DEBUG 6059313Ssos printf("Linux-emul(%d): mmap(%08x, %d, %d, %08x, %d, %d)\n", 60614331Speter p->p_pid, linux_args.addr, linux_args.len, linux_args.prot, 6079313Ssos linux_args.flags, linux_args.fd, linux_args.pos); 6089313Ssos#endif 6099313Ssos bsd_args.flags = 0; 6109313Ssos if (linux_args.flags & LINUX_MAP_SHARED) 6119313Ssos bsd_args.flags |= MAP_SHARED; 6129313Ssos if (linux_args.flags & LINUX_MAP_PRIVATE) 6139313Ssos bsd_args.flags |= MAP_PRIVATE; 6149313Ssos if (linux_args.flags & LINUX_MAP_FIXED) 6159313Ssos bsd_args.flags |= MAP_FIXED; 6169313Ssos if (linux_args.flags & LINUX_MAP_ANON) 6179313Ssos bsd_args.flags |= MAP_ANON; 6189313Ssos bsd_args.addr = linux_args.addr; 6199313Ssos bsd_args.len = linux_args.len; 6209313Ssos bsd_args.prot = linux_args.prot; 6219313Ssos bsd_args.fd = linux_args.fd; 6229313Ssos bsd_args.pos = linux_args.pos; 6239313Ssos bsd_args.pad = 0; 6249313Ssos return mmap(p, &bsd_args, retval); 6259313Ssos} 6269313Ssos 62714331Speterint 62814331Speterlinux_msync(struct proc *p, struct linux_msync_args *args, int *retval) 62914331Speter{ 63014331Speter struct msync_args bsd_args; 6319313Ssos 63214331Speter bsd_args.addr = args->addr; 63314331Speter bsd_args.len = args->len; 63414331Speter bsd_args.flags = 0; /* XXX ignore */ 63514331Speter 63614331Speter return msync(p, &bsd_args, retval); 63714331Speter} 63814331Speter 6399313Ssosint 6409313Ssoslinux_pipe(struct proc *p, struct linux_pipe_args *args, int *retval) 6419313Ssos{ 6429313Ssos int error; 6439313Ssos 6449313Ssos#ifdef DEBUG 6459313Ssos printf("Linux-emul(%d): pipe(*)\n", p->p_pid); 6469313Ssos#endif 6479313Ssos if (error = pipe(p, 0, retval)) 6489313Ssos return error; 6499313Ssos if (error = copyout(retval, args->pipefds, 2*sizeof(int))) 6509313Ssos return error; 6519313Ssos *retval = 0; 6529313Ssos return 0; 6539313Ssos} 6549313Ssos 6559313Ssosint 6569313Ssoslinux_time(struct proc *p, struct linux_time_args *args, int *retval) 6579313Ssos{ 6589313Ssos struct timeval tv; 6599313Ssos linux_time_t tm; 6609313Ssos int error; 6619313Ssos 6629313Ssos#ifdef DEBUG 6639313Ssos printf("Linux-emul(%d): time(*)\n", p->p_pid); 6649313Ssos#endif 6659313Ssos microtime(&tv); 6669313Ssos tm = tv.tv_sec; 66714331Speter if (args->tm && (error = copyout(&tm, args->tm, sizeof(linux_time_t)))) 6689313Ssos return error; 66914331Speter *retval = tm; 6709313Ssos return 0; 6719313Ssos} 6729313Ssos 67314331Speterstruct linux_times_argv { 6749313Ssos long tms_utime; 6759313Ssos long tms_stime; 6769313Ssos long tms_cutime; 6779313Ssos long tms_cstime; 6789313Ssos}; 6799313Ssos 68014381Speter#define CLK_TCK 100 /* Linux uses 100 */ 68114381Speter#define CONVTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK)) 68214381Speter 6839313Ssosint 68414331Speterlinux_times(struct proc *p, struct linux_times_args *args, int *retval) 6859313Ssos{ 6869313Ssos struct timeval tv; 68714331Speter struct linux_times_argv tms; 68814381Speter struct rusage ru; 68914381Speter int error, s; 6909313Ssos 6919313Ssos#ifdef DEBUG 6929313Ssos printf("Linux-emul(%d): times(*)\n", p->p_pid); 6939313Ssos#endif 69414381Speter calcru(p, &ru.ru_utime, &ru.ru_stime, NULL); 69514381Speter 69614381Speter tms.tms_utime = CONVTCK(ru.ru_utime); 69714381Speter tms.tms_stime = CONVTCK(ru.ru_stime); 69814381Speter 69914381Speter tms.tms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime); 70014381Speter tms.tms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime); 70114381Speter 70214381Speter if ((error = copyout((caddr_t)&tms, (caddr_t)args->buf, 70314381Speter sizeof(struct linux_times_argv)))) 70414381Speter return error; 70514381Speter 7069313Ssos microtime(&tv); 70714381Speter timevalsub(&tv, &boottime); 70814381Speter *retval = (int)CONVTCK(tv); 70914381Speter return 0; 7109313Ssos} 7119313Ssos 71214331Speter/* XXX move */ 7139313Ssosstruct linux_newuname_t { 7149313Ssos char sysname[65]; 7159313Ssos char nodename[65]; 7169313Ssos char release[65]; 7179313Ssos char version[65]; 7189313Ssos char machine[65]; 7199313Ssos char domainname[65]; 7209313Ssos}; 7219313Ssos 7229313Ssosint 7239313Ssoslinux_newuname(struct proc *p, struct linux_newuname_args *args, int *retval) 7249313Ssos{ 7259313Ssos struct linux_newuname_t linux_newuname; 7269313Ssos 7279313Ssos#ifdef DEBUG 7289313Ssos printf("Linux-emul(%d): newuname(*)\n", p->p_pid); 7299313Ssos#endif 7309313Ssos bzero(&linux_newuname, sizeof(struct linux_newuname_args)); 7319313Ssos strncpy(linux_newuname.sysname, ostype, 64); 7329313Ssos strncpy(linux_newuname.nodename, hostname, 64); 7339313Ssos strncpy(linux_newuname.release, osrelease, 64); 7349313Ssos strncpy(linux_newuname.version, version, 64); 7359313Ssos strncpy(linux_newuname.machine, machine, 64); 7369313Ssos strncpy(linux_newuname.domainname, domainname, 64); 7379313Ssos return (copyout((caddr_t)&linux_newuname, (caddr_t)args->buf, 7389313Ssos sizeof(struct linux_newuname_t))); 7399313Ssos} 7409313Ssos 74114381Speterstruct linux_utimbuf { 74214381Speter linux_time_t l_actime; 74314381Speter linux_time_t l_modtime; 74414381Speter}; 7459313Ssos 7469313Ssosint 7479313Ssoslinux_utime(struct proc *p, struct linux_utime_args *args, int *retval) 7489313Ssos{ 74912858Speter struct utimes_args /* { 75012858Speter char *path; 7519313Ssos struct timeval *tptr; 75212858Speter } */ bsdutimes; 75314381Speter struct timeval tv[2], *tvp; 75414381Speter struct linux_utimbuf lut; 75514381Speter int error; 75614331Speter caddr_t sg; 7579313Ssos 75814331Speter sg = stackgap_init(); 75914331Speter CHECKALTEXIST(p, &sg, args->fname); 76014331Speter 7619313Ssos#ifdef DEBUG 7629313Ssos printf("Linux-emul(%d): utime(%s, *)\n", p->p_pid, args->fname); 7639313Ssos#endif 76414381Speter if (args->times) { 76514381Speter if ((error = copyin(args->times, &lut, sizeof lut))) 76614381Speter return error; 76714381Speter tv[0].tv_sec = lut.l_actime; 76814381Speter tv[0].tv_usec = 0; 76914381Speter tv[1].tv_sec = lut.l_modtime; 77014381Speter tv[1].tv_usec = 0; 77114381Speter /* so that utimes can copyin */ 77214381Speter tvp = (struct timeval *)stackgap_alloc(&sg, sizeof(tv)); 77314381Speter if ((error = copyout(tv, tvp, sizeof(tv)))) 77414381Speter return error; 77514381Speter bsdutimes.tptr = tvp; 77614381Speter } else 77714381Speter bsdutimes.tptr = NULL; 77814381Speter 77912858Speter bsdutimes.path = args->fname; 7809313Ssos return utimes(p, &bsdutimes, retval); 7819313Ssos} 7829313Ssos 7839313Ssosint 7849313Ssoslinux_waitpid(struct proc *p, struct linux_waitpid_args *args, int *retval) 7859313Ssos{ 78612858Speter struct wait_args /* { 7879313Ssos int pid; 7889313Ssos int *status; 7899313Ssos int options; 7909313Ssos struct rusage *rusage; 79112858Speter } */ tmp; 7929313Ssos int error, tmpstat; 7939313Ssos 7949313Ssos#ifdef DEBUG 79514331Speter printf("Linux-emul(%d): waitpid(%d, 0x%x, %d)\n", 79614331Speter p->p_pid, args->pid, args->status, args->options); 7979313Ssos#endif 7989313Ssos tmp.pid = args->pid; 7999313Ssos tmp.status = args->status; 8009313Ssos tmp.options = args->options; 8019313Ssos tmp.rusage = NULL; 8029313Ssos 8039313Ssos if (error = wait4(p, &tmp, retval)) 8049313Ssos return error; 80514331Speter if (args->status) { 80614331Speter if (error = copyin(args->status, &tmpstat, sizeof(int))) 80714331Speter return error; 80814331Speter if (WIFSIGNALED(tmpstat)) 80914331Speter tmpstat = (tmpstat & 0xffffff80) | 81014331Speter bsd_to_linux_signal[WTERMSIG(tmpstat)]; 81114331Speter else if (WIFSTOPPED(tmpstat)) 81214331Speter tmpstat = (tmpstat & 0xffff00ff) | 81314331Speter (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8); 81414331Speter return copyout(&tmpstat, args->status, sizeof(int)); 81514331Speter } else 81614331Speter return 0; 8179313Ssos} 8189313Ssos 81914331Speterint 8209313Ssoslinux_wait4(struct proc *p, struct linux_wait4_args *args, int *retval) 8219313Ssos{ 82212858Speter struct wait_args /* { 8239313Ssos int pid; 8249313Ssos int *status; 8259313Ssos int options; 8269313Ssos struct rusage *rusage; 82712858Speter } */ tmp; 8289313Ssos int error, tmpstat; 8299313Ssos 8309313Ssos#ifdef DEBUG 83114331Speter printf("Linux-emul(%d): wait4(%d, 0x%x, %d, 0x%x)\n", 83214331Speter p->p_pid, args->pid, args->status, args->options, args->rusage); 8339313Ssos#endif 8349313Ssos tmp.pid = args->pid; 8359313Ssos tmp.status = args->status; 8369313Ssos tmp.options = args->options; 8379313Ssos tmp.rusage = args->rusage; 8389313Ssos 8399313Ssos if (error = wait4(p, &tmp, retval)) 8409313Ssos return error; 84114331Speter 84214331Speter p->p_siglist &= ~sigmask(SIGCHLD); 84314331Speter 84414331Speter if (args->status) { 84514331Speter if (error = copyin(args->status, &tmpstat, sizeof(int))) 84614331Speter return error; 84714331Speter if (WIFSIGNALED(tmpstat)) 84814331Speter tmpstat = (tmpstat & 0xffffff80) | 84914331Speter bsd_to_linux_signal[WTERMSIG(tmpstat)]; 85014331Speter else if (WIFSTOPPED(tmpstat)) 85114331Speter tmpstat = (tmpstat & 0xffff00ff) | 85214331Speter (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8); 85314331Speter return copyout(&tmpstat, args->status, sizeof(int)); 85414331Speter } else 85514331Speter return 0; 8569313Ssos} 85713420Ssos 85814331Speterint 85913420Ssoslinux_mknod(struct proc *p, struct linux_mknod_args *args, int *retval) 86013420Ssos{ 86114331Speter caddr_t sg; 86214331Speter struct mknod_args bsd_mknod; 86314331Speter struct mkfifo_args bsd_mkfifo; 86414331Speter 86514331Speter sg = stackgap_init(); 86614331Speter 86714331Speter CHECKALTCREAT(p, &sg, args->path); 86814331Speter 86914331Speter#ifdef DEBUG 87014331Speter printf("Linux-emul(%d): mknod(%s, %d, %d)\n", 87114331Speter p->p_pid, args->path, args->mode, args->dev); 87214331Speter#endif 87314331Speter 87414331Speter if (args->mode & S_IFIFO) { 87514331Speter bsd_mkfifo.path = args->path; 87614331Speter bsd_mkfifo.mode = args->mode; 87714331Speter return mkfifo(p, &bsd_mkfifo, retval); 87814331Speter } else { 87914331Speter bsd_mknod.path = args->path; 88014331Speter bsd_mknod.mode = args->mode; 88114331Speter bsd_mknod.dev = args->dev; 88214331Speter return mknod(p, &bsd_mknod, retval); 88314331Speter } 88413420Ssos} 88514331Speter 88614331Speter/* 88714331Speter * UGH! This is just about the dumbest idea I've ever heard!! 88814331Speter */ 88914331Speterint 89014331Speterlinux_personality(struct proc *p, struct linux_personality_args *args, 89114331Speter int *retval) 89214331Speter{ 89314331Speter#ifdef DEBUG 89414331Speter printf("Linux-emul(%d): personality(%d)\n", 89514331Speter p->p_pid, args->per); 89614331Speter#endif 89714331Speter if (args->per != 0) 89814331Speter return EINVAL; 89914331Speter 90014331Speter /* Yes Jim, it's still a Linux... */ 90114331Speter retval[0] = 0; 90214331Speter return 0; 90314331Speter} 90414331Speter 90514331Speter/* 90614331Speter * Wrappers for get/setitimer for debugging.. 90714331Speter */ 90814331Speterint 90914331Speterlinux_setitimer(struct proc *p, struct linux_setitimer_args *args, int *retval) 91014331Speter{ 91114331Speter struct setitimer_args bsa; 91214331Speter struct itimerval foo; 91314331Speter int error; 91414331Speter 91514331Speter#ifdef DEBUG 91614331Speter printf("Linux-emul(%d): setitimer(%08x, %08x)\n", 91714331Speter p->p_pid, args->itv, args->oitv); 91814331Speter#endif 91914331Speter bsa.which = args->which; 92014331Speter bsa.itv = args->itv; 92114331Speter bsa.oitv = args->oitv; 92214331Speter if (args->itv) { 92314331Speter if ((error = copyin((caddr_t)args->itv, (caddr_t)&foo, 92414331Speter sizeof(foo)))) 92514331Speter return error; 92614331Speter#ifdef DEBUG 92714331Speter printf("setitimer: value: sec: %d, usec: %d\n", foo.it_value.tv_sec, foo.it_value.tv_usec); 92814331Speter printf("setitimer: interval: sec: %d, usec: %d\n", foo.it_interval.tv_sec, foo.it_interval.tv_usec); 92914331Speter#endif 93014331Speter } 93114331Speter return setitimer(p, &bsa, retval); 93214331Speter} 93314331Speter 93414331Speterint 93514331Speterlinux_getitimer(struct proc *p, struct linux_getitimer_args *args, int *retval) 93614331Speter{ 93714331Speter struct getitimer_args bsa; 93814331Speter#ifdef DEBUG 93914331Speter printf("Linux-emul(%d): getitimer(%08x)\n", 94014331Speter p->p_pid, args->itv); 94114331Speter#endif 94214331Speter bsa.which = args->which; 94314331Speter bsa.itv = args->itv; 94414331Speter return getitimer(p, &bsa, retval); 94514331Speter} 946