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