linux_misc.c revision 68583
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 *
2850477Speter * $FreeBSD: head/sys/compat/linux/linux_misc.c 68583 2000-11-10 21:30:19Z marcel $
299313Ssos */
309313Ssos
3149842Smarcel#include "opt_compat.h"
3249842Smarcel
339313Ssos#include <sys/param.h>
349313Ssos#include <sys/systm.h>
3512458Sbde#include <sys/sysproto.h>
3612458Sbde#include <sys/kernel.h>
379313Ssos#include <sys/mman.h>
389313Ssos#include <sys/proc.h>
3924131Sbde#include <sys/fcntl.h>
409313Ssos#include <sys/imgact_aout.h>
419313Ssos#include <sys/mount.h>
429313Ssos#include <sys/namei.h>
439313Ssos#include <sys/resourcevar.h>
449313Ssos#include <sys/stat.h>
4512458Sbde#include <sys/sysctl.h>
4641931Sjulian#include <sys/unistd.h>
479313Ssos#include <sys/vnode.h>
489313Ssos#include <sys/wait.h>
4914331Speter#include <sys/time.h>
5051793Smarcel#include <sys/signalvar.h>
519313Ssos
5212652Sbde#include <vm/vm.h>
5312689Speter#include <vm/pmap.h>
5412458Sbde#include <vm/vm_kern.h>
5512689Speter#include <vm/vm_map.h>
5612842Sbde#include <vm/vm_extern.h>
5712458Sbde
5830855Skato#include <machine/frame.h>
5965106Smarcel#include <machine/limits.h>
6030837Skato#include <machine/psl.h>
6150818Smarcel#include <machine/sysarch.h>
6268201Sobrien#ifdef __i386__
6350818Smarcel#include <machine/segments.h>
6468201Sobrien#endif
6530837Skato
6649849Smarcel#include <posix4/sched.h>
6749849Smarcel
6864909Smarcel#include <machine/../linux/linux.h>
6968583Smarcel#ifdef __alpha__
7068201Sobrien#include <linux_proto.h>
7168583Smarcel#else
7268583Smarcel#include <machine/../linux/linux_proto.h>
7368583Smarcel#endif
7464909Smarcel#include <compat/linux/linux_mib.h>
7564909Smarcel#include <compat/linux/linux_util.h>
7664909Smarcel
7768201Sobrien#ifdef __alpha__
7868201Sobrien#define BSD_TO_LINUX_SIGNAL(sig)       (sig)
7968201Sobrien#else
8051793Smarcel#define BSD_TO_LINUX_SIGNAL(sig)	\
8151793Smarcel	(((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
8268201Sobrien#endif
8351793Smarcel
8465099Smarcelstruct linux_rlimit {
8565099Smarcel	unsigned long rlim_cur;
8665099Smarcel	unsigned long rlim_max;
8765099Smarcel};
8865099Smarcel
8968201Sobrien#ifndef __alpha__
9049626Smarcelstatic unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] =
9149626Smarcel{ RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK,
9249626Smarcel  RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE,
9349626Smarcel  RLIMIT_MEMLOCK, -1
9449626Smarcel};
9568201Sobrien#endif /*!__alpha__*/
9649626Smarcel
9768201Sobrien#ifndef __alpha__
989313Ssosint
9930994Sphklinux_alarm(struct proc *p, struct linux_alarm_args *args)
1009313Ssos{
1019313Ssos    struct itimerval it, old_it;
10212858Speter    struct timeval tv;
1039313Ssos    int s;
1049313Ssos
1059313Ssos#ifdef DEBUG
10638127Sbde    printf("Linux-emul(%ld): alarm(%u)\n", (long)p->p_pid, args->secs);
1079313Ssos#endif
10838127Sbde    if (args->secs > 100000000)
10938127Sbde	return EINVAL;
1109313Ssos    it.it_value.tv_sec = (long)args->secs;
1119313Ssos    it.it_value.tv_usec = 0;
1129313Ssos    it.it_interval.tv_sec = 0;
1139313Ssos    it.it_interval.tv_usec = 0;
11438127Sbde    s = splsoftclock();
1159313Ssos    old_it = p->p_realtimer;
11638127Sbde    getmicrouptime(&tv);
11735058Sphk    if (timevalisset(&old_it.it_value))
11838127Sbde	untimeout(realitexpire, (caddr_t)p, p->p_ithandle);
11938127Sbde    if (it.it_value.tv_sec != 0) {
12038127Sbde	p->p_ithandle = timeout(realitexpire, (caddr_t)p, tvtohz(&it.it_value));
12112858Speter	timevaladd(&it.it_value, &tv);
1229313Ssos    }
1239313Ssos    p->p_realtimer = it;
1249313Ssos    splx(s);
12538127Sbde    if (timevalcmp(&old_it.it_value, &tv, >)) {
12638127Sbde	timevalsub(&old_it.it_value, &tv);
12738127Sbde	if (old_it.it_value.tv_usec != 0)
12838127Sbde	    old_it.it_value.tv_sec++;
12938127Sbde	p->p_retval[0] = old_it.it_value.tv_sec;
13038127Sbde    }
1319313Ssos    return 0;
1329313Ssos}
13368201Sobrien#endif /*!__alpha__*/
1349313Ssos
1359313Ssosint
13630994Sphklinux_brk(struct proc *p, struct linux_brk_args *args)
1379313Ssos{
1389313Ssos#if 0
1399313Ssos    struct vmspace *vm = p->p_vmspace;
1409313Ssos    vm_offset_t new, old;
1419313Ssos    int error;
1429313Ssos
1439313Ssos    if ((vm_offset_t)args->dsend < (vm_offset_t)vm->vm_daddr)
1449313Ssos	return EINVAL;
1459313Ssos    if (((caddr_t)args->dsend - (caddr_t)vm->vm_daddr)
1469313Ssos	> p->p_rlimit[RLIMIT_DATA].rlim_cur)
1479313Ssos	return ENOMEM;
1489313Ssos
1499313Ssos    old = round_page((vm_offset_t)vm->vm_daddr) + ctob(vm->vm_dsize);
1509313Ssos    new = round_page((vm_offset_t)args->dsend);
15130994Sphk    p->p_retval[0] = old;
1529313Ssos    if ((new-old) > 0) {
1539313Ssos	if (swap_pager_full)
1549313Ssos	    return ENOMEM;
15513503Sdyson	error = vm_map_find(&vm->vm_map, NULL, 0, &old, (new-old), FALSE,
15613503Sdyson			VM_PROT_ALL, VM_PROT_ALL, 0);
15714331Speter	if (error)
1589313Ssos	    return error;
1599313Ssos	vm->vm_dsize += btoc((new-old));
16030994Sphk	p->p_retval[0] = (int)(vm->vm_daddr + ctob(vm->vm_dsize));
1619313Ssos    }
1629313Ssos    return 0;
1639313Ssos#else
1649313Ssos    struct vmspace *vm = p->p_vmspace;
1659313Ssos    vm_offset_t new, old;
16612858Speter    struct obreak_args /* {
16712858Speter	char * nsize;
16812858Speter    } */ tmp;
1699313Ssos
1709313Ssos#ifdef DEBUG
17137950Sbde    printf("Linux-emul(%ld): brk(%p)\n", (long)p->p_pid, (void *)args->dsend);
1729313Ssos#endif
1739313Ssos    old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
1749313Ssos    new = (vm_offset_t)args->dsend;
17512858Speter    tmp.nsize = (char *) new;
17630994Sphk    if (((caddr_t)new > vm->vm_daddr) && !obreak(p, &tmp))
17768201Sobrien	p->p_retval[0] = (long)new;
1789313Ssos    else
17968201Sobrien	p->p_retval[0] = (long)old;
1809313Ssos
1819313Ssos    return 0;
1829313Ssos#endif
1839313Ssos}
1849313Ssos
1859313Ssosint
18630994Sphklinux_uselib(struct proc *p, struct linux_uselib_args *args)
1879313Ssos{
1889313Ssos    struct nameidata ni;
18912130Sdg    struct vnode *vp;
19014114Speter    struct exec *a_out;
1919313Ssos    struct vattr attr;
19214703Sbde    vm_offset_t vmaddr;
19314703Sbde    unsigned long file_offset;
19414703Sbde    vm_offset_t buffer;
19514703Sbde    unsigned long bss_size;
1969313Ssos    int error;
19714331Speter    caddr_t sg;
19814114Speter    int locked;
1999313Ssos
20014331Speter    sg = stackgap_init();
20114331Speter    CHECKALTEXIST(p, &sg, args->library);
20214331Speter
2039313Ssos#ifdef DEBUG
20449959Smarcel    printf("Linux-emul(%ld): uselib(%s)\n", (long)p->p_pid, args->library);
2059313Ssos#endif
2069313Ssos
20714114Speter    a_out = NULL;
20814114Speter    locked = 0;
20914114Speter    vp = NULL;
21014114Speter
21149523Smarcel    NDINIT(&ni, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, args->library, p);
21246571Speter    error = namei(&ni);
21346571Speter    if (error)
21414114Speter	goto cleanup;
2159313Ssos
21612130Sdg    vp = ni.ni_vp;
21754655Seivind    /*
21854655Seivind     * XXX This looks like a bogus check - a LOCKLEAF namei should not succeed
21954655Seivind     * without returning a vnode.
22054655Seivind     */
22114114Speter    if (vp == NULL) {
22214114Speter	error = ENOEXEC;	/* ?? */
22314114Speter	goto cleanup;
22414114Speter    }
22554655Seivind    NDFREE(&ni, NDF_ONLY_PNBUF);
2269313Ssos
22714114Speter    /*
22814114Speter     * From here on down, we have a locked vnode that must be unlocked.
22914114Speter     */
23014114Speter    locked++;
23114114Speter
23214114Speter    /*
23314114Speter     * Writable?
23414114Speter     */
23512130Sdg    if (vp->v_writecount) {
23614114Speter	error = ETXTBSY;
23714114Speter	goto cleanup;
23811163Sjulian    }
2399313Ssos
24014114Speter    /*
24114114Speter     * Executable?
24214114Speter     */
24346571Speter    error = VOP_GETATTR(vp, &attr, p->p_ucred, p);
24446571Speter    if (error)
24514114Speter	goto cleanup;
2469313Ssos
24714114Speter    if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
24814114Speter	((attr.va_mode & 0111) == 0) ||
24914114Speter	(attr.va_type != VREG)) {
25014114Speter	    error = ENOEXEC;
25114114Speter	    goto cleanup;
25211163Sjulian    }
2539313Ssos
25414114Speter    /*
25514114Speter     * Sensible size?
25614114Speter     */
25711163Sjulian    if (attr.va_size == 0) {
25814114Speter	error = ENOEXEC;
25914114Speter	goto cleanup;
26011163Sjulian    }
2619313Ssos
26214114Speter    /*
26314114Speter     * Can we access it?
26414114Speter     */
26546571Speter    error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
26646571Speter    if (error)
26714114Speter	goto cleanup;
2689313Ssos
26946571Speter    error = VOP_OPEN(vp, FREAD, p->p_ucred, p);
27046571Speter    if (error)
27114114Speter	goto cleanup;
2729313Ssos
27314114Speter    /*
27414114Speter     * Lock no longer needed
27514114Speter     */
27622543Smpp    VOP_UNLOCK(vp, 0, p);
27714114Speter    locked = 0;
27811163Sjulian
27914114Speter    /*
28014114Speter     * Pull in executable header into kernel_map
28114114Speter     */
28214114Speter    error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
28312130Sdg	    	    VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
2849313Ssos    if (error)
28514114Speter	goto cleanup;
2869313Ssos
2879313Ssos    /*
2889313Ssos     * Is it a Linux binary ?
2899313Ssos     */
29014114Speter    if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
29114114Speter	error = ENOEXEC;
29214114Speter	goto cleanup;
29314114Speter    }
2949313Ssos
29514114Speter    /* While we are here, we should REALLY do some more checks */
29614114Speter
2979313Ssos    /*
2989313Ssos     * Set file/virtual offset based on a.out variant.
2999313Ssos     */
3009313Ssos    switch ((int)(a_out->a_magic & 0xffff)) {
3019313Ssos    case 0413:	/* ZMAGIC */
3029313Ssos	file_offset = 1024;
3039313Ssos	break;
3049313Ssos    case 0314:	/* QMAGIC */
3059313Ssos	file_offset = 0;
3069313Ssos	break;
3079313Ssos    default:
30814114Speter	error = ENOEXEC;
30914114Speter	goto cleanup;
3109313Ssos    }
3119313Ssos
3129313Ssos    bss_size = round_page(a_out->a_bss);
31314114Speter
3149313Ssos    /*
31514114Speter     * Check various fields in header for validity/bounds.
31614114Speter     */
31715538Sphk    if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
31814114Speter	error = ENOEXEC;
31914114Speter	goto cleanup;
32014114Speter    }
32114114Speter
32214114Speter    /* text + data can't exceed file size */
32314114Speter    if (a_out->a_data + a_out->a_text > attr.va_size) {
32414114Speter	error = EFAULT;
32514114Speter	goto cleanup;
32614114Speter    }
32714114Speter
32814114Speter    /*
32914114Speter     * text/data/bss must not exceed limits
33014114Speter     * XXX: this is not complete. it should check current usage PLUS
33114114Speter     * the resources needed by this library.
33214114Speter     */
33333821Sbde    if (a_out->a_text > MAXTSIZ ||
33433821Sbde	a_out->a_data + bss_size > p->p_rlimit[RLIMIT_DATA].rlim_cur) {
33514114Speter	error = ENOMEM;
33614114Speter	goto cleanup;
33714114Speter    }
33814114Speter
33914114Speter    /*
34014114Speter     * prevent more writers
34114114Speter     */
34214114Speter    vp->v_flag |= VTEXT;
34314114Speter
34414114Speter    /*
3459313Ssos     * Check if file_offset page aligned,.
3469313Ssos     * Currently we cannot handle misalinged file offsets,
3479313Ssos     * and so we read in the entire image (what a waste).
3489313Ssos     */
34915538Sphk    if (file_offset & PAGE_MASK) {
3509313Ssos#ifdef DEBUG
35137950Sbdeprintf("uselib: Non page aligned binary %lu\n", file_offset);
3529313Ssos#endif
3539313Ssos	/*
3549313Ssos	 * Map text+data read/write/execute
3559313Ssos	 */
35614114Speter
35714114Speter	/* a_entry is the load address and is page aligned */
35814114Speter	vmaddr = trunc_page(a_out->a_entry);
35914114Speter
36014114Speter	/* get anon user mapping, read+write+execute */
3619313Ssos	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
36214114Speter		    	    a_out->a_text + a_out->a_data, FALSE,
36314114Speter			    VM_PROT_ALL, VM_PROT_ALL, 0);
3649313Ssos	if (error)
36514114Speter	    goto cleanup;
3669313Ssos
36714114Speter	/* map file into kernel_map */
3689313Ssos	error = vm_mmap(kernel_map, &buffer,
3699313Ssos			round_page(a_out->a_text + a_out->a_data + file_offset),
37014584Speter		   	VM_PROT_READ, VM_PROT_READ, 0,
37112130Sdg			(caddr_t)vp, trunc_page(file_offset));
3729313Ssos	if (error)
37314114Speter	    goto cleanup;
3749313Ssos
37514114Speter	/* copy from kernel VM space to user space */
37638354Sbde	error = copyout((caddr_t)(void *)(uintptr_t)(buffer + file_offset),
37738354Sbde			(caddr_t)vmaddr, a_out->a_text + a_out->a_data);
3789313Ssos
37914114Speter	/* release temporary kernel space */
38014114Speter	vm_map_remove(kernel_map, buffer,
38114471Speter		      buffer + round_page(a_out->a_text + a_out->a_data + file_offset));
3829313Ssos
3839313Ssos	if (error)
38414114Speter	    goto cleanup;
3859313Ssos    }
3869313Ssos    else {
3879313Ssos#ifdef DEBUG
38837950Sbdeprintf("uselib: Page aligned binary %lu\n", file_offset);
3899313Ssos#endif
39014114Speter	/*
39114114Speter	 * for QMAGIC, a_entry is 20 bytes beyond the load address
39214114Speter	 * to skip the executable header
39314114Speter	 */
39414114Speter	vmaddr = trunc_page(a_out->a_entry);
39514114Speter
39614114Speter	/*
39714114Speter	 * Map it all into the process's space as a single copy-on-write
39814114Speter	 * "data" segment.
39914114Speter	 */
4009313Ssos	error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr,
40114114Speter		   	a_out->a_text + a_out->a_data,
4029313Ssos			VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
40312130Sdg			(caddr_t)vp, file_offset);
4049313Ssos	if (error)
40514114Speter	    goto cleanup;
4069313Ssos    }
4079313Ssos#ifdef DEBUG
40868201Sobrienprintf("mem=%08lx = %08lx %08lx\n", vmaddr, ((long*)vmaddr)[0], ((long*)vmaddr)[1]);
4099313Ssos#endif
4109313Ssos    if (bss_size != 0) {
41114114Speter        /*
41214114Speter	 * Calculate BSS start address
41314114Speter	 */
41414114Speter	vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + a_out->a_data;
41514114Speter
41614114Speter	/*
41714114Speter	 * allocate some 'anon' space
41814114Speter	 */
41914331Speter	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
42013503Sdyson			    bss_size, FALSE,
42114114Speter			    VM_PROT_ALL, VM_PROT_ALL, 0);
4229313Ssos	if (error)
42314114Speter	    goto cleanup;
4249313Ssos    }
42514114Speter
42614114Spetercleanup:
42714114Speter    /*
42814114Speter     * Unlock vnode if needed
42914114Speter     */
43014114Speter    if (locked)
43122543Smpp	VOP_UNLOCK(vp, 0, p);
43214114Speter
43314114Speter    /*
43414114Speter     * Release the kernel mapping.
43514114Speter     */
43614114Speter    if (a_out)
43714471Speter	vm_map_remove(kernel_map, (vm_offset_t)a_out, (vm_offset_t)a_out + PAGE_SIZE);
43814114Speter
43914114Speter    return error;
4409313Ssos}
4419313Ssos
4429313Ssosint
44330994Sphklinux_newselect(struct proc *p, struct linux_newselect_args *args)
44414331Speter{
44514331Speter    struct select_args bsa;
44614331Speter    struct timeval tv0, tv1, utv, *tvp;
44714331Speter    caddr_t sg;
44814331Speter    int error;
44914331Speter
4509313Ssos#ifdef DEBUG
45137950Sbde    printf("Linux-emul(%ld): newselect(%d, %p, %p, %p, %p)\n",
45237950Sbde  	(long)p->p_pid, args->nfds, (void *)args->readfds,
45337950Sbde	(void *)args->writefds, (void *)args->exceptfds,
45437950Sbde	(void *)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
47137950Sbde	printf("Linux-emul(%ld): incoming timeout (%ld/%ld)\n",
47237950Sbde	    (long)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)
48835058Sphk		timevalclear(&utv);
48914331Speter	    if ((error = copyout(&utv, tvp, sizeof(utv))))
49014331Speter		goto select_out;
49114331Speter	    bsa.tv = tvp;
49214331Speter	}
49314331Speter	microtime(&tv0);
49414331Speter    }
49514331Speter
49630994Sphk    error = select(p, &bsa);
49714331Speter#ifdef DEBUG
49849959Smarcel    printf("Linux-emul(%ld): real select returns %d\n", (long)p->p_pid, error);
49914331Speter#endif
50014331Speter
50114331Speter    if (error) {
50214331Speter	/*
50314331Speter	 * See fs/select.c in the Linux kernel.  Without this,
50414331Speter	 * Maelstrom doesn't work.
50514331Speter	 */
50614331Speter	if (error == ERESTART)
50714331Speter	    error = EINTR;
50814331Speter	goto select_out;
50914331Speter    }
51014331Speter
51114331Speter    if (args->timeout) {
51230994Sphk	if (p->p_retval[0]) {
51314331Speter	    /*
51414331Speter	     * Compute how much time was left of the timeout,
51514331Speter	     * by subtracting the current time and the time
51614331Speter	     * before we started the call, and subtracting
51714331Speter	     * that result from the user-supplied value.
51814331Speter	     */
51914331Speter	    microtime(&tv1);
52014331Speter	    timevalsub(&tv1, &tv0);
52114331Speter	    timevalsub(&utv, &tv1);
52214331Speter	    if (utv.tv_sec < 0)
52335058Sphk		timevalclear(&utv);
52414331Speter	} else
52535058Sphk	    timevalclear(&utv);
52614331Speter#ifdef DEBUG
52737950Sbde	printf("Linux-emul(%ld): outgoing timeout (%ld/%ld)\n",
52837950Sbde	    (long)p->p_pid, utv.tv_sec, utv.tv_usec);
52914331Speter#endif
53014331Speter	if ((error = copyout(&utv, args->timeout, sizeof(utv))))
53114331Speter	    goto select_out;
53214331Speter    }
53314331Speter
53414331Speterselect_out:
53514331Speter#ifdef DEBUG
53649959Smarcel    printf("Linux-emul(%ld): newselect_out -> %d\n", (long)p->p_pid, error);
53714331Speter#endif
53814331Speter    return error;
5399313Ssos}
5409313Ssos
5419313Ssosint
54230994Sphklinux_getpgid(struct proc *p, struct linux_getpgid_args *args)
5439313Ssos{
54446129Sluoqi    struct proc *curp;
5459313Ssos
5469313Ssos#ifdef DEBUG
54749959Smarcel    printf("Linux-emul(%ld): getpgid(%d)\n", (long)p->p_pid, args->pid);
5489313Ssos#endif
5499313Ssos    if (args->pid != p->p_pid) {
55046129Sluoqi	if (!(curp = pfind(args->pid)))
5519313Ssos	    return ESRCH;
5529313Ssos    }
5539313Ssos    else
55446129Sluoqi	curp = p;
55546129Sluoqi    p->p_retval[0] = curp->p_pgid;
5569313Ssos    return 0;
5579313Ssos}
5589313Ssos
55937548Sjkhint
56037548Sjkhlinux_mremap(struct proc *p, struct linux_mremap_args *args)
56137548Sjkh{
56237548Sjkh	struct munmap_args /* {
56337548Sjkh		void *addr;
56437548Sjkh		size_t len;
56537548Sjkh	} */ bsd_args;
56637548Sjkh	int error = 0;
56737548Sjkh
56837548Sjkh#ifdef DEBUG
56968201Sobrien	printf("Linux-emul(%ld): mremap(%p, %08lx, %08lx, %08lx)\n",
57068201Sobrien	    (long)p->p_pid, (void *)args->addr,
57168201Sobrien	    (unsigned long)args->old_len,
57268201Sobrien	    (unsigned long)args->new_len,
57368201Sobrien	    (unsigned long)args->flags);
57437548Sjkh#endif
57537548Sjkh	args->new_len = round_page(args->new_len);
57637548Sjkh	args->old_len = round_page(args->old_len);
57737548Sjkh
57837548Sjkh	if (args->new_len > args->old_len) {
57937548Sjkh		p->p_retval[0] = 0;
58037548Sjkh		return ENOMEM;
58137548Sjkh	}
58237548Sjkh
58337548Sjkh	if (args->new_len < args->old_len) {
58437548Sjkh		bsd_args.addr = args->addr + args->new_len;
58537548Sjkh		bsd_args.len = args->old_len - args->new_len;
58637548Sjkh		error = munmap(p, &bsd_args);
58737548Sjkh	}
58837548Sjkh
58968201Sobrien	p->p_retval[0] = error ? 0 : (u_long)args->addr;
59037548Sjkh	return error;
59137548Sjkh}
59237548Sjkh
59314331Speterint
59430994Sphklinux_msync(struct proc *p, struct linux_msync_args *args)
59514331Speter{
59614331Speter	struct msync_args bsd_args;
5979313Ssos
59814331Speter	bsd_args.addr = args->addr;
59914331Speter	bsd_args.len = args->len;
60014331Speter	bsd_args.flags = 0;	/* XXX ignore */
60114331Speter
60230994Sphk	return msync(p, &bsd_args);
60314331Speter}
60414331Speter
60568201Sobrien#ifndef __alpha__
6069313Ssosint
60730994Sphklinux_time(struct proc *p, struct linux_time_args *args)
6089313Ssos{
6099313Ssos    struct timeval tv;
6109313Ssos    linux_time_t tm;
6119313Ssos    int error;
6129313Ssos
6139313Ssos#ifdef DEBUG
61449959Smarcel    printf("Linux-emul(%ld): time(*)\n", (long)p->p_pid);
6159313Ssos#endif
6169313Ssos    microtime(&tv);
6179313Ssos    tm = tv.tv_sec;
61814331Speter    if (args->tm && (error = copyout(&tm, args->tm, sizeof(linux_time_t))))
6199313Ssos	return error;
62030994Sphk    p->p_retval[0] = tm;
6219313Ssos    return 0;
6229313Ssos}
62368201Sobrien#endif	/*!__alpha__*/
6249313Ssos
62514331Speterstruct linux_times_argv {
6269313Ssos    long    tms_utime;
6279313Ssos    long    tms_stime;
6289313Ssos    long    tms_cutime;
6299313Ssos    long    tms_cstime;
6309313Ssos};
6319313Ssos
63214381Speter#define CLK_TCK 100	/* Linux uses 100 */
63314381Speter#define CONVTCK(r)	(r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
63414381Speter
6359313Ssosint
63630994Sphklinux_times(struct proc *p, struct linux_times_args *args)
6379313Ssos{
6389313Ssos    struct timeval tv;
63914331Speter    struct linux_times_argv tms;
64014381Speter    struct rusage ru;
64116322Sgpalmer    int error;
6429313Ssos
6439313Ssos#ifdef DEBUG
64449959Smarcel    printf("Linux-emul(%ld): times(*)\n", (long)p->p_pid);
6459313Ssos#endif
64614381Speter    calcru(p, &ru.ru_utime, &ru.ru_stime, NULL);
64714381Speter
64814381Speter    tms.tms_utime = CONVTCK(ru.ru_utime);
64914381Speter    tms.tms_stime = CONVTCK(ru.ru_stime);
65014381Speter
65114381Speter    tms.tms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime);
65214381Speter    tms.tms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime);
65314381Speter
65414381Speter    if ((error = copyout((caddr_t)&tms, (caddr_t)args->buf,
65514381Speter	    	    sizeof(struct linux_times_argv))))
65614381Speter	return error;
65714381Speter
65836119Sphk    microuptime(&tv);
65930994Sphk    p->p_retval[0] = (int)CONVTCK(tv);
66014381Speter    return 0;
6619313Ssos}
6629313Ssos
6639313Ssosint
66430994Sphklinux_newuname(struct proc *p, struct linux_newuname_args *args)
6659313Ssos{
66650345Smarcel	struct linux_new_utsname utsname;
66750465Smarcel	char *osrelease, *osname;
6689313Ssos
6699313Ssos#ifdef DEBUG
67050345Smarcel	printf("Linux-emul(%ld): newuname(*)\n", (long)p->p_pid);
6719313Ssos#endif
67250345Smarcel
67350465Smarcel	osname = linux_get_osname(p);
67450465Smarcel	osrelease = linux_get_osrelease(p);
67550465Smarcel
67650345Smarcel	bzero(&utsname, sizeof(struct linux_new_utsname));
67750465Smarcel	strncpy(utsname.sysname, osname, LINUX_MAX_UTSNAME-1);
67850345Smarcel	strncpy(utsname.nodename, hostname, LINUX_MAX_UTSNAME-1);
67950465Smarcel	strncpy(utsname.release, osrelease, LINUX_MAX_UTSNAME-1);
68050345Smarcel	strncpy(utsname.version, version, LINUX_MAX_UTSNAME-1);
68150345Smarcel	strncpy(utsname.machine, machine, LINUX_MAX_UTSNAME-1);
68250345Smarcel	strncpy(utsname.domainname, domainname, LINUX_MAX_UTSNAME-1);
68350345Smarcel
68450345Smarcel	return (copyout((caddr_t)&utsname, (caddr_t)args->buf,
68550345Smarcel			sizeof(struct linux_new_utsname)));
6869313Ssos}
6879313Ssos
68814381Speterstruct linux_utimbuf {
68914381Speter	linux_time_t l_actime;
69014381Speter	linux_time_t l_modtime;
69114381Speter};
6929313Ssos
6939313Ssosint
69430994Sphklinux_utime(struct proc *p, struct linux_utime_args *args)
6959313Ssos{
69612858Speter    struct utimes_args /* {
69712858Speter	char	*path;
6989313Ssos	struct	timeval *tptr;
69912858Speter    } */ bsdutimes;
70014381Speter    struct timeval tv[2], *tvp;
70114381Speter    struct linux_utimbuf lut;
70214381Speter    int error;
70314331Speter    caddr_t sg;
7049313Ssos
70514331Speter    sg = stackgap_init();
70614331Speter    CHECKALTEXIST(p, &sg, args->fname);
70714331Speter
7089313Ssos#ifdef DEBUG
70949959Smarcel    printf("Linux-emul(%ld): utime(%s, *)\n", (long)p->p_pid, args->fname);
7109313Ssos#endif
71114381Speter    if (args->times) {
71214381Speter	if ((error = copyin(args->times, &lut, sizeof lut)))
71314381Speter	    return error;
71414381Speter	tv[0].tv_sec = lut.l_actime;
71514381Speter	tv[0].tv_usec = 0;
71614381Speter	tv[1].tv_sec = lut.l_modtime;
71714381Speter	tv[1].tv_usec = 0;
71814381Speter	/* so that utimes can copyin */
71914381Speter	tvp = (struct timeval *)stackgap_alloc(&sg, sizeof(tv));
72063778Smarcel	if (tvp == NULL)
72163778Smarcel		return (ENAMETOOLONG);
72214381Speter	if ((error = copyout(tv, tvp, sizeof(tv))))
72314381Speter	    return error;
72414381Speter	bsdutimes.tptr = tvp;
72514381Speter    } else
72614381Speter	bsdutimes.tptr = NULL;
72714381Speter
72812858Speter    bsdutimes.path = args->fname;
72930994Sphk    return utimes(p, &bsdutimes);
7309313Ssos}
7319313Ssos
73244384Sjulian#define __WCLONE 0x80000000
73344384Sjulian
73468201Sobrien#ifndef __alpha__
7359313Ssosint
73630994Sphklinux_waitpid(struct proc *p, struct linux_waitpid_args *args)
7379313Ssos{
73812858Speter    struct wait_args /* {
7399313Ssos	int pid;
7409313Ssos	int *status;
7419313Ssos	int options;
7429313Ssos	struct	rusage *rusage;
74312858Speter    } */ tmp;
7449313Ssos    int error, tmpstat;
7459313Ssos
7469313Ssos#ifdef DEBUG
74737950Sbde    printf("Linux-emul(%ld): waitpid(%d, %p, %d)\n",
74837950Sbde	(long)p->p_pid, args->pid, (void *)args->status, args->options);
7499313Ssos#endif
7509313Ssos    tmp.pid = args->pid;
7519313Ssos    tmp.status = args->status;
75241931Sjulian    tmp.options = (args->options & (WNOHANG | WUNTRACED));
75344384Sjulian    /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
75444384Sjulian    if (args->options & __WCLONE)
75544384Sjulian	tmp.options |= WLINUXCLONE;
7569313Ssos    tmp.rusage = NULL;
7579313Ssos
75844384Sjulian    if ((error = wait4(p, &tmp)) != 0)
7599313Ssos	return error;
76043208Sjulian
76114331Speter    if (args->status) {
76244384Sjulian	if ((error = copyin(args->status, &tmpstat, sizeof(int))) != 0)
76314331Speter	    return error;
76457867Smarcel	tmpstat &= 0xffff;
76514331Speter	if (WIFSIGNALED(tmpstat))
76614331Speter	    tmpstat = (tmpstat & 0xffffff80) |
76751793Smarcel		      BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
76814331Speter	else if (WIFSTOPPED(tmpstat))
76914331Speter	    tmpstat = (tmpstat & 0xffff00ff) |
77051793Smarcel		      (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
77114331Speter	return copyout(&tmpstat, args->status, sizeof(int));
77214331Speter    } else
77314331Speter	return 0;
7749313Ssos}
77568201Sobrien#endif	/*!__alpha__*/
7769313Ssos
77714331Speterint
77830994Sphklinux_wait4(struct proc *p, struct linux_wait4_args *args)
7799313Ssos{
78012858Speter    struct wait_args /* {
7819313Ssos	int pid;
7829313Ssos	int *status;
7839313Ssos	int options;
7849313Ssos	struct	rusage *rusage;
78512858Speter    } */ tmp;
7869313Ssos    int error, tmpstat;
7879313Ssos
7889313Ssos#ifdef DEBUG
78937950Sbde    printf("Linux-emul(%ld): wait4(%d, %p, %d, %p)\n",
79037950Sbde	(long)p->p_pid, args->pid, (void *)args->status, args->options,
79137950Sbde	(void *)args->rusage);
7929313Ssos#endif
7939313Ssos    tmp.pid = args->pid;
7949313Ssos    tmp.status = args->status;
79541931Sjulian    tmp.options = (args->options & (WNOHANG | WUNTRACED));
79644384Sjulian    /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
79744384Sjulian    if (args->options & __WCLONE)
79844384Sjulian	tmp.options |= WLINUXCLONE;
7999313Ssos    tmp.rusage = args->rusage;
8009313Ssos
80144384Sjulian    if ((error = wait4(p, &tmp)) != 0)
8029313Ssos	return error;
80314331Speter
80451793Smarcel    SIGDELSET(p->p_siglist, SIGCHLD);
80514331Speter
80614331Speter    if (args->status) {
80744384Sjulian	if ((error = copyin(args->status, &tmpstat, sizeof(int))) != 0)
80814331Speter	    return error;
80957867Smarcel	tmpstat &= 0xffff;
81014331Speter	if (WIFSIGNALED(tmpstat))
81114331Speter	    tmpstat = (tmpstat & 0xffffff80) |
81251793Smarcel		  BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
81314331Speter	else if (WIFSTOPPED(tmpstat))
81414331Speter	    tmpstat = (tmpstat & 0xffff00ff) |
81551793Smarcel		  (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
81614331Speter	return copyout(&tmpstat, args->status, sizeof(int));
81714331Speter    } else
81814331Speter	return 0;
8199313Ssos}
82013420Ssos
82114331Speterint
82230994Sphklinux_mknod(struct proc *p, struct linux_mknod_args *args)
82313420Ssos{
82414331Speter	caddr_t sg;
82514331Speter	struct mknod_args bsd_mknod;
82614331Speter	struct mkfifo_args bsd_mkfifo;
82714331Speter
82814331Speter	sg = stackgap_init();
82914331Speter
83014331Speter	CHECKALTCREAT(p, &sg, args->path);
83114331Speter
83214331Speter#ifdef DEBUG
83349959Smarcel	printf("Linux-emul(%ld): mknod(%s, %d, %d)\n",
83449959Smarcel	   (long)p->p_pid, args->path, args->mode, args->dev);
83514331Speter#endif
83614331Speter
83714331Speter	if (args->mode & S_IFIFO) {
83814331Speter		bsd_mkfifo.path = args->path;
83914331Speter		bsd_mkfifo.mode = args->mode;
84030994Sphk		return mkfifo(p, &bsd_mkfifo);
84114331Speter	} else {
84214331Speter		bsd_mknod.path = args->path;
84314331Speter		bsd_mknod.mode = args->mode;
84414331Speter		bsd_mknod.dev = args->dev;
84530994Sphk		return mknod(p, &bsd_mknod);
84614331Speter	}
84713420Ssos}
84814331Speter
84914331Speter/*
85014331Speter * UGH! This is just about the dumbest idea I've ever heard!!
85114331Speter */
85214331Speterint
85330994Sphklinux_personality(struct proc *p, struct linux_personality_args *args)
85414331Speter{
85514331Speter#ifdef DEBUG
85649959Smarcel	printf("Linux-emul(%ld): personality(%d)\n",
85749959Smarcel	   (long)p->p_pid, args->per);
85814331Speter#endif
85968201Sobrien#ifndef __alpha__
86014331Speter	if (args->per != 0)
86114331Speter		return EINVAL;
86268201Sobrien#endif
86314331Speter
86414331Speter	/* Yes Jim, it's still a Linux... */
86530994Sphk	p->p_retval[0] = 0;
86614331Speter	return 0;
86714331Speter}
86814331Speter
86914331Speter/*
87014331Speter * Wrappers for get/setitimer for debugging..
87114331Speter */
87214331Speterint
87330994Sphklinux_setitimer(struct proc *p, struct linux_setitimer_args *args)
87414331Speter{
87514331Speter	struct setitimer_args bsa;
87614331Speter	struct itimerval foo;
87714331Speter	int error;
87814331Speter
87914331Speter#ifdef DEBUG
88037950Sbde	printf("Linux-emul(%ld): setitimer(%p, %p)\n",
88137950Sbde	    (long)p->p_pid, (void *)args->itv, (void *)args->oitv);
88214331Speter#endif
88314331Speter	bsa.which = args->which;
88414331Speter	bsa.itv = args->itv;
88514331Speter	bsa.oitv = args->oitv;
88614331Speter	if (args->itv) {
88714331Speter	    if ((error = copyin((caddr_t)args->itv, (caddr_t)&foo,
88814331Speter			sizeof(foo))))
88914331Speter		return error;
89014331Speter#ifdef DEBUG
89137950Sbde	    printf("setitimer: value: sec: %ld, usec: %ld\n",
89237950Sbde		foo.it_value.tv_sec, foo.it_value.tv_usec);
89337950Sbde	    printf("setitimer: interval: sec: %ld, usec: %ld\n",
89437950Sbde		foo.it_interval.tv_sec, foo.it_interval.tv_usec);
89514331Speter#endif
89614331Speter	}
89730994Sphk	return setitimer(p, &bsa);
89814331Speter}
89914331Speter
90014331Speterint
90130994Sphklinux_getitimer(struct proc *p, struct linux_getitimer_args *args)
90214331Speter{
90314331Speter	struct getitimer_args bsa;
90414331Speter#ifdef DEBUG
90537950Sbde	printf("Linux-emul(%ld): getitimer(%p)\n",
90637950Sbde	    (long)p->p_pid, (void *)args->itv);
90714331Speter#endif
90814331Speter	bsa.which = args->which;
90914331Speter	bsa.itv = args->itv;
91030994Sphk	return getitimer(p, &bsa);
91114331Speter}
91230837Skato
91368201Sobrien#ifndef __alpha__
91430837Skatoint
91530994Sphklinux_nice(struct proc *p, struct linux_nice_args *args)
91630837Skato{
91730837Skato	struct setpriority_args	bsd_args;
91830837Skato
91930837Skato	bsd_args.which = PRIO_PROCESS;
92030837Skato	bsd_args.who = 0;	/* current process */
92130837Skato	bsd_args.prio = args->inc;
92230994Sphk	return setpriority(p, &bsd_args);
92330837Skato}
92468201Sobrien#endif	/*!__alpha__*/
92530837Skato
92642185Ssosint
92742185Ssoslinux_setgroups(p, uap)
92850350Smarcel	struct proc *p;
92950350Smarcel	struct linux_setgroups_args *uap;
93042185Ssos{
93150350Smarcel	struct pcred *pc;
93250350Smarcel	linux_gid_t linux_gidset[NGROUPS];
93350350Smarcel	gid_t *bsd_gidset;
93450350Smarcel	int ngrp, error;
93542185Ssos
93650350Smarcel	pc = p->p_cred;
93750350Smarcel	ngrp = uap->gidsetsize;
93842185Ssos
93950350Smarcel	/*
94050350Smarcel	 * cr_groups[0] holds egid. Setting the whole set from
94150350Smarcel	 * the supplied set will cause egid to be changed too.
94250350Smarcel	 * Keep cr_groups[0] unchanged to prevent that.
94350350Smarcel	 */
94442185Ssos
94550350Smarcel	if ((error = suser(p)) != 0)
94650350Smarcel		return (error);
94742185Ssos
94850350Smarcel	if (ngrp >= NGROUPS)
94950350Smarcel		return (EINVAL);
95042185Ssos
95150350Smarcel	pc->pc_ucred = crcopy(pc->pc_ucred);
95250350Smarcel	if (ngrp > 0) {
95350350Smarcel		error = copyin((caddr_t)uap->gidset, (caddr_t)linux_gidset,
95450350Smarcel			       ngrp * sizeof(linux_gid_t));
95550350Smarcel		if (error)
95650350Smarcel			return (error);
95742185Ssos
95850350Smarcel		pc->pc_ucred->cr_ngroups = ngrp + 1;
95950350Smarcel
96050350Smarcel		bsd_gidset = pc->pc_ucred->cr_groups;
96150350Smarcel		ngrp--;
96250350Smarcel		while (ngrp >= 0) {
96350350Smarcel			bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
96450350Smarcel			ngrp--;
96550350Smarcel		}
96650350Smarcel	}
96750350Smarcel	else
96850350Smarcel		pc->pc_ucred->cr_ngroups = 1;
96950350Smarcel
97050350Smarcel	setsugid(p);
97150350Smarcel	return (0);
97242185Ssos}
97342185Ssos
97442185Ssosint
97542185Ssoslinux_getgroups(p, uap)
97650350Smarcel	struct proc *p;
97750350Smarcel	struct linux_getgroups_args *uap;
97842185Ssos{
97950350Smarcel	struct pcred *pc;
98050350Smarcel	linux_gid_t linux_gidset[NGROUPS];
98150350Smarcel	gid_t *bsd_gidset;
98250350Smarcel	int bsd_gidsetsz, ngrp, error;
98342185Ssos
98450350Smarcel	pc = p->p_cred;
98550350Smarcel	bsd_gidset = pc->pc_ucred->cr_groups;
98650546Smarcel	bsd_gidsetsz = pc->pc_ucred->cr_ngroups - 1;
98742185Ssos
98850350Smarcel	/*
98950350Smarcel	 * cr_groups[0] holds egid. Returning the whole set
99050350Smarcel	 * here will cause a duplicate. Exclude cr_groups[0]
99150350Smarcel	 * to prevent that.
99250350Smarcel	 */
99342185Ssos
99450350Smarcel	if ((ngrp = uap->gidsetsize) == 0) {
99550546Smarcel		p->p_retval[0] = bsd_gidsetsz;
99650350Smarcel		return (0);
99750350Smarcel	}
99842185Ssos
99950546Smarcel	if (ngrp < bsd_gidsetsz)
100050350Smarcel		return (EINVAL);
100142185Ssos
100250546Smarcel	ngrp = 0;
100350350Smarcel	while (ngrp < bsd_gidsetsz) {
100450546Smarcel		linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
100550350Smarcel		ngrp++;
100650350Smarcel	}
100750350Smarcel
100850350Smarcel	if ((error = copyout((caddr_t)linux_gidset, (caddr_t)uap->gidset,
100950350Smarcel	    ngrp * sizeof(linux_gid_t))))
101050350Smarcel		return (error);
101150350Smarcel
101250546Smarcel	p->p_retval[0] = ngrp;
101350350Smarcel	return (0);
101442185Ssos}
101549626Smarcel
101668201Sobrien#ifndef __alpha__
101749626Smarcelint
101849626Smarcellinux_setrlimit(p, uap)
101965099Smarcel	struct proc *p;
102065099Smarcel	struct linux_setrlimit_args *uap;
102149626Smarcel{
102265099Smarcel	struct __setrlimit_args bsd;
102365099Smarcel	struct linux_rlimit rlim;
102465099Smarcel	int error;
102565099Smarcel	caddr_t sg = stackgap_init();
102649842Smarcel
102749626Smarcel#ifdef DEBUG
102865099Smarcel	printf("Linux-emul(%ld): setrlimit(%d, %p)\n", (long)p->p_pid,
102965099Smarcel	    uap->resource, (void *)uap->rlim);
103049626Smarcel#endif
103149626Smarcel
103265099Smarcel	if (uap->resource >= LINUX_RLIM_NLIMITS)
103365099Smarcel		return (EINVAL);
103449626Smarcel
103565099Smarcel	bsd.which = linux_to_bsd_resource[uap->resource];
103665099Smarcel	if (bsd.which == -1)
103765099Smarcel		return (EINVAL);
103849626Smarcel
103965099Smarcel	error = copyin(uap->rlim, &rlim, sizeof(rlim));
104065099Smarcel	if (error)
104165099Smarcel		return (error);
104249626Smarcel
104365099Smarcel	bsd.rlp = stackgap_alloc(&sg, sizeof(struct rlimit));
104465099Smarcel	bsd.rlp->rlim_cur = (rlim_t)rlim.rlim_cur;
104565099Smarcel	bsd.rlp->rlim_max = (rlim_t)rlim.rlim_max;
104665099Smarcel	return (setrlimit(p, &bsd));
104749626Smarcel}
104849626Smarcel
104949626Smarcelint
105049626Smarcellinux_getrlimit(p, uap)
105165099Smarcel	struct proc *p;
105265099Smarcel	struct linux_getrlimit_args *uap;
105349626Smarcel{
105465099Smarcel	struct __getrlimit_args bsd;
105565099Smarcel	struct linux_rlimit rlim;
105665099Smarcel	int error;
105765099Smarcel	caddr_t sg = stackgap_init();
105849842Smarcel
105949626Smarcel#ifdef DEBUG
106065099Smarcel	printf("Linux-emul(%ld): getrlimit(%d, %p)\n", (long)p->p_pid,
106165099Smarcel	    uap->resource, (void *)uap->rlim);
106249626Smarcel#endif
106349626Smarcel
106465099Smarcel	if (uap->resource >= LINUX_RLIM_NLIMITS)
106565099Smarcel		return (EINVAL);
106649626Smarcel
106765099Smarcel	bsd.which = linux_to_bsd_resource[uap->resource];
106865099Smarcel	if (bsd.which == -1)
106965099Smarcel		return (EINVAL);
107049626Smarcel
107165099Smarcel	bsd.rlp = stackgap_alloc(&sg, sizeof(struct rlimit));
107265099Smarcel	error = getrlimit(p, &bsd);
107365099Smarcel	if (error)
107465099Smarcel		return (error);
107549626Smarcel
107665099Smarcel	rlim.rlim_cur = (unsigned long)bsd.rlp->rlim_cur;
107765106Smarcel	if (rlim.rlim_cur == ULONG_MAX)
107865106Smarcel		rlim.rlim_cur = LONG_MAX;
107965099Smarcel	rlim.rlim_max = (unsigned long)bsd.rlp->rlim_max;
108065106Smarcel	if (rlim.rlim_max == ULONG_MAX)
108165106Smarcel		rlim.rlim_max = LONG_MAX;
108265099Smarcel	return (copyout(&rlim, uap->rlim, sizeof(rlim)));
108349626Smarcel}
108468201Sobrien#endif /*!__alpha__*/
108549849Smarcel
108649849Smarcelint
108749849Smarcellinux_sched_setscheduler(p, uap)
108849849Smarcel	struct proc *p;
108949849Smarcel	struct linux_sched_setscheduler_args *uap;
109049849Smarcel{
109149849Smarcel	struct sched_setscheduler_args bsd;
109249849Smarcel
109349849Smarcel#ifdef DEBUG
109449849Smarcel	printf("Linux-emul(%ld): sched_setscheduler(%d, %d, %p)\n",
109551793Smarcel	    (long)p->p_pid, uap->pid, uap->policy, (const void *)uap->param);
109649849Smarcel#endif
109749849Smarcel
109849849Smarcel	switch (uap->policy) {
109949849Smarcel	case LINUX_SCHED_OTHER:
110049849Smarcel		bsd.policy = SCHED_OTHER;
110149849Smarcel		break;
110249849Smarcel	case LINUX_SCHED_FIFO:
110349849Smarcel		bsd.policy = SCHED_FIFO;
110449849Smarcel		break;
110549849Smarcel	case LINUX_SCHED_RR:
110649849Smarcel		bsd.policy = SCHED_RR;
110749849Smarcel		break;
110849849Smarcel	default:
110949849Smarcel		return EINVAL;
111049849Smarcel	}
111149849Smarcel
111249849Smarcel	bsd.pid = uap->pid;
111349849Smarcel	bsd.param = uap->param;
111449849Smarcel	return sched_setscheduler(p, &bsd);
111549849Smarcel}
111649849Smarcel
111749849Smarcelint
111849849Smarcellinux_sched_getscheduler(p, uap)
111949849Smarcel	struct proc *p;
112049849Smarcel	struct linux_sched_getscheduler_args *uap;
112149849Smarcel{
112249849Smarcel	struct sched_getscheduler_args bsd;
112349849Smarcel	int error;
112449849Smarcel
112549849Smarcel#ifdef DEBUG
112649849Smarcel	printf("Linux-emul(%ld): sched_getscheduler(%d)\n",
112749849Smarcel	       (long)p->p_pid, uap->pid);
112849849Smarcel#endif
112949849Smarcel
113049849Smarcel	bsd.pid = uap->pid;
113149849Smarcel	error = sched_getscheduler(p, &bsd);
113249849Smarcel
113349849Smarcel	switch (p->p_retval[0]) {
113449849Smarcel	case SCHED_OTHER:
113549849Smarcel		p->p_retval[0] = LINUX_SCHED_OTHER;
113649849Smarcel		break;
113749849Smarcel	case SCHED_FIFO:
113849849Smarcel		p->p_retval[0] = LINUX_SCHED_FIFO;
113949849Smarcel		break;
114049849Smarcel	case SCHED_RR:
114149849Smarcel		p->p_retval[0] = LINUX_SCHED_RR;
114249849Smarcel		break;
114349849Smarcel	}
114449849Smarcel
114549849Smarcel	return error;
114649849Smarcel}
1147