linux_misc.c revision 86852
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 86852 2001-11-24 14:09:50Z des $
299313Ssos */
309313Ssos
3149842Smarcel#include "opt_compat.h"
3249842Smarcel
339313Ssos#include <sys/param.h>
349313Ssos#include <sys/systm.h>
3576166Smarkm#include <sys/fcntl.h>
3676166Smarkm#include <sys/imgact_aout.h>
3712458Sbde#include <sys/kernel.h>
3876166Smarkm#include <sys/lock.h>
399313Ssos#include <sys/mman.h>
409313Ssos#include <sys/mount.h>
4176166Smarkm#include <sys/mutex.h>
429313Ssos#include <sys/namei.h>
4383221Smarcel#include <sys/poll.h>
4476166Smarkm#include <sys/proc.h>
4580180Spirzyk#include <sys/blist.h>
4672538Sjlemon#include <sys/reboot.h>
479313Ssos#include <sys/resourcevar.h>
4876166Smarkm#include <sys/signalvar.h>
499313Ssos#include <sys/stat.h>
5012458Sbde#include <sys/sysctl.h>
5176166Smarkm#include <sys/sysproto.h>
5276166Smarkm#include <sys/time.h>
5341931Sjulian#include <sys/unistd.h>
5480180Spirzyk#include <sys/vmmeter.h>
559313Ssos#include <sys/vnode.h>
569313Ssos#include <sys/wait.h>
579313Ssos
5812652Sbde#include <vm/vm.h>
5912689Speter#include <vm/pmap.h>
6012458Sbde#include <vm/vm_kern.h>
6112689Speter#include <vm/vm_map.h>
6212842Sbde#include <vm/vm_extern.h>
6380180Spirzyk#include <vm/vm_object.h>
6480180Spirzyk#include <vm/vm_zone.h>
6580180Spirzyk#include <vm/swap_pager.h>
6612458Sbde
6730855Skato#include <machine/frame.h>
6865106Smarcel#include <machine/limits.h>
6930837Skato#include <machine/psl.h>
7050818Smarcel#include <machine/sysarch.h>
7168201Sobrien#ifdef __i386__
7250818Smarcel#include <machine/segments.h>
7368201Sobrien#endif
7430837Skato
7549849Smarcel#include <posix4/sched.h>
7649849Smarcel
7764909Smarcel#include <machine/../linux/linux.h>
7868583Smarcel#include <machine/../linux/linux_proto.h>
7964909Smarcel#include <compat/linux/linux_mib.h>
8064909Smarcel#include <compat/linux/linux_util.h>
8164909Smarcel
8268201Sobrien#ifdef __alpha__
8368201Sobrien#define BSD_TO_LINUX_SIGNAL(sig)       (sig)
8468201Sobrien#else
8551793Smarcel#define BSD_TO_LINUX_SIGNAL(sig)	\
8651793Smarcel	(((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
8768201Sobrien#endif
8851793Smarcel
8968201Sobrien#ifndef __alpha__
9083221Smarcelstatic unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = {
9183221Smarcel	RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK,
9283221Smarcel	RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE,
9383221Smarcel	RLIMIT_MEMLOCK, -1
9449626Smarcel};
9568201Sobrien#endif /*!__alpha__*/
9649626Smarcel
9783221Smarcelstruct l_sysinfo {
9883221Smarcel	l_long		uptime;		/* Seconds since boot */
9983221Smarcel	l_ulong		loads[3];	/* 1, 5, and 15 minute load averages */
10083221Smarcel	l_ulong		totalram;	/* Total usable main memory size */
10183221Smarcel	l_ulong		freeram;	/* Available memory size */
10283221Smarcel	l_ulong		sharedram;	/* Amount of shared memory */
10383221Smarcel	l_ulong		bufferram;	/* Memory used by buffers */
10483221Smarcel	l_ulong		totalswap;	/* Total swap space size */
10583221Smarcel	l_ulong		freeswap;	/* swap space still available */
10683221Smarcel	l_ushort	procs;		/* Number of current processes */
10783221Smarcel	char		_f[22];		/* Pads structure to 64 bytes */
10880180Spirzyk};
10968201Sobrien#ifndef __alpha__
1109313Ssosint
11183366Sjulianlinux_sysinfo(struct thread *td, struct linux_sysinfo_args *args)
11280180Spirzyk{
11383221Smarcel	struct l_sysinfo sysinfo;
11483221Smarcel	vm_object_t object;
11583221Smarcel	int i;
11683221Smarcel	struct timespec ts;
11780180Spirzyk
11883221Smarcel	/* Uptime is copied out of print_uptime() in kern_shutdown.c */
11983221Smarcel	getnanouptime(&ts);
12083221Smarcel	i = 0;
12183221Smarcel	if (ts.tv_sec >= 86400) {
12283221Smarcel		ts.tv_sec %= 86400;
12383221Smarcel		i = 1;
12483221Smarcel	}
12583221Smarcel	if (i || ts.tv_sec >= 3600) {
12683221Smarcel		ts.tv_sec %= 3600;
12783221Smarcel		i = 1;
12883221Smarcel	}
12983221Smarcel	if (i || ts.tv_sec >= 60) {
13083221Smarcel		ts.tv_sec %= 60;
13183221Smarcel		i = 1;
13283221Smarcel	}
13383221Smarcel	sysinfo.uptime=ts.tv_sec;
13480180Spirzyk
13583221Smarcel	/* Use the information from the mib to get our load averages */
13683221Smarcel	for (i = 0; i < 3; i++)
13783221Smarcel		sysinfo.loads[i] = averunnable.ldavg[i];
13880180Spirzyk
13983221Smarcel	sysinfo.totalram = physmem * PAGE_SIZE;
14083221Smarcel	sysinfo.freeram = sysinfo.totalram - cnt.v_wire_count * PAGE_SIZE;
14180180Spirzyk
14283221Smarcel	sysinfo.sharedram = 0;
14383221Smarcel	for (object = TAILQ_FIRST(&vm_object_list); object != NULL;
14483221Smarcel	     object = TAILQ_NEXT(object, object_list))
14583221Smarcel		if (object->shadow_count > 1)
14683221Smarcel			sysinfo.sharedram += object->resident_page_count;
14780180Spirzyk
14883221Smarcel	sysinfo.sharedram *= PAGE_SIZE;
14983221Smarcel	sysinfo.bufferram = 0;
15080180Spirzyk
15183221Smarcel	if (swapblist == NULL) {
15283221Smarcel		sysinfo.totalswap= 0;
15383221Smarcel		sysinfo.freeswap = 0;
15483221Smarcel	} else {
15583221Smarcel		sysinfo.totalswap = swapblist->bl_blocks * 1024;
15683221Smarcel		sysinfo.freeswap = swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
15783221Smarcel	}
15880180Spirzyk
15983221Smarcel	sysinfo.procs = 20; /* Hack */
16080180Spirzyk
16183221Smarcel	return copyout(&sysinfo, (caddr_t)args->info, sizeof(sysinfo));
16280180Spirzyk}
16380180Spirzyk#endif /*!__alpha__*/
16480180Spirzyk
16580180Spirzyk#ifndef __alpha__
16680180Spirzykint
16783366Sjulianlinux_alarm(struct thread *td, struct linux_alarm_args *args)
1689313Ssos{
16983221Smarcel	struct itimerval it, old_it;
17083221Smarcel	struct timeval tv;
17183221Smarcel	int s;
1729313Ssos
1739313Ssos#ifdef DEBUG
17472543Sjlemon	if (ldebug(alarm))
17572543Sjlemon		printf(ARGS(alarm, "%u"), args->secs);
1769313Ssos#endif
17783221Smarcel
17883221Smarcel	if (args->secs > 100000000)
17983221Smarcel		return EINVAL;
18083221Smarcel
18183221Smarcel	it.it_value.tv_sec = (long)args->secs;
18283221Smarcel	it.it_value.tv_usec = 0;
18383221Smarcel	it.it_interval.tv_sec = 0;
18483221Smarcel	it.it_interval.tv_usec = 0;
18583221Smarcel	s = splsoftclock();
18683366Sjulian	old_it = td->td_proc->p_realtimer;
18783221Smarcel	getmicrouptime(&tv);
18883221Smarcel	if (timevalisset(&old_it.it_value))
18983366Sjulian		callout_stop(&td->td_proc->p_itcallout);
19083221Smarcel	if (it.it_value.tv_sec != 0) {
19183366Sjulian		callout_reset(&td->td_proc->p_itcallout, tvtohz(&it.it_value),
19286852Sdes		    realitexpire, td->td_proc);
19383221Smarcel		timevaladd(&it.it_value, &tv);
19483221Smarcel	}
19583366Sjulian	td->td_proc->p_realtimer = it;
19683221Smarcel	splx(s);
19783221Smarcel	if (timevalcmp(&old_it.it_value, &tv, >)) {
19883221Smarcel		timevalsub(&old_it.it_value, &tv);
19983221Smarcel		if (old_it.it_value.tv_usec != 0)
20083221Smarcel			old_it.it_value.tv_sec++;
20183366Sjulian		td->td_retval[0] = old_it.it_value.tv_sec;
20283221Smarcel	}
20383221Smarcel	return 0;
2049313Ssos}
20568201Sobrien#endif /*!__alpha__*/
2069313Ssos
2079313Ssosint
20883366Sjulianlinux_brk(struct thread *td, struct linux_brk_args *args)
2099313Ssos{
21083366Sjulian	struct vmspace *vm = td->td_proc->p_vmspace;
21183221Smarcel	vm_offset_t new, old;
21283221Smarcel	struct obreak_args /* {
21383221Smarcel		char * nsize;
21483221Smarcel	} */ tmp;
2159313Ssos
2169313Ssos#ifdef DEBUG
21772543Sjlemon	if (ldebug(brk))
21872543Sjlemon		printf(ARGS(brk, "%p"), (void *)args->dsend);
2199313Ssos#endif
22083221Smarcel	old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
22183221Smarcel	new = (vm_offset_t)args->dsend;
22283221Smarcel	tmp.nsize = (char *) new;
22383366Sjulian	if (((caddr_t)new > vm->vm_daddr) && !obreak(td, &tmp))
22483366Sjulian		td->td_retval[0] = (long)new;
22583221Smarcel	else
22683366Sjulian		td->td_retval[0] = (long)old;
2279313Ssos
22883221Smarcel	return 0;
2299313Ssos}
2309313Ssos
2319313Ssosint
23283366Sjulianlinux_uselib(struct thread *td, struct linux_uselib_args *args)
2339313Ssos{
23483221Smarcel	struct nameidata ni;
23583221Smarcel	struct vnode *vp;
23683221Smarcel	struct exec *a_out;
23783221Smarcel	struct vattr attr;
23883221Smarcel	vm_offset_t vmaddr;
23983221Smarcel	unsigned long file_offset;
24083221Smarcel	vm_offset_t buffer;
24183221Smarcel	unsigned long bss_size;
24283221Smarcel	int error;
24383221Smarcel	caddr_t sg;
24483221Smarcel	int locked;
2459313Ssos
24683221Smarcel	sg = stackgap_init();
24783366Sjulian	CHECKALTEXIST(td, &sg, args->library);
24814331Speter
2499313Ssos#ifdef DEBUG
25072543Sjlemon	if (ldebug(uselib))
25172543Sjlemon		printf(ARGS(uselib, "%s"), args->library);
2529313Ssos#endif
2539313Ssos
25483221Smarcel	a_out = NULL;
25583221Smarcel	locked = 0;
25683221Smarcel	vp = NULL;
25714114Speter
25883366Sjulian	NDINIT(&ni, LOOKUP, FOLLOW|LOCKLEAF, UIO_USERSPACE, args->library, td);
25983221Smarcel	error = namei(&ni);
26083221Smarcel	if (error)
26183221Smarcel		goto cleanup;
2629313Ssos
26383221Smarcel	vp = ni.ni_vp;
26483221Smarcel	/*
26583221Smarcel	 * XXX - This looks like a bogus check. A LOCKLEAF namei should not
26683221Smarcel	 * succeed without returning a vnode.
26783221Smarcel	 */
26883221Smarcel	if (vp == NULL) {
26983221Smarcel		error = ENOEXEC;	/* ?? */
27083221Smarcel		goto cleanup;
27183221Smarcel	}
27283221Smarcel	NDFREE(&ni, NDF_ONLY_PNBUF);
2739313Ssos
27483221Smarcel	/*
27583221Smarcel	 * From here on down, we have a locked vnode that must be unlocked.
27683221Smarcel	 */
27783221Smarcel	locked++;
27814114Speter
27983221Smarcel	/* Writable? */
28083221Smarcel	if (vp->v_writecount) {
28183221Smarcel		error = ETXTBSY;
28283221Smarcel		goto cleanup;
28383221Smarcel	}
2849313Ssos
28583221Smarcel	/* Executable? */
28683366Sjulian	error = VOP_GETATTR(vp, &attr, td->td_proc->p_ucred, td);
28783221Smarcel	if (error)
28883221Smarcel		goto cleanup;
2899313Ssos
29083221Smarcel	if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
29183221Smarcel	    ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) {
29283221Smarcel		error = ENOEXEC;
29383221Smarcel		goto cleanup;
29483221Smarcel	}
2959313Ssos
29683221Smarcel	/* Sensible size? */
29783221Smarcel	if (attr.va_size == 0) {
29883221Smarcel		error = ENOEXEC;
29983221Smarcel		goto cleanup;
30083221Smarcel	}
3019313Ssos
30283221Smarcel	/* Can we access it? */
30383366Sjulian	error = VOP_ACCESS(vp, VEXEC, td->td_proc->p_ucred, td);
30483221Smarcel	if (error)
30583221Smarcel		goto cleanup;
3069313Ssos
30783366Sjulian	error = VOP_OPEN(vp, FREAD, td->td_proc->p_ucred, td);
30883221Smarcel	if (error)
30983221Smarcel		goto cleanup;
3109313Ssos
31183221Smarcel	/*
31283221Smarcel	 * Lock no longer needed
31383221Smarcel	 */
31483366Sjulian	VOP_UNLOCK(vp, 0, td);
31583221Smarcel	locked = 0;
31611163Sjulian
31783221Smarcel	/* Pull in executable header into kernel_map */
31883221Smarcel	error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
31983221Smarcel	    VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
32083221Smarcel	if (error)
32183221Smarcel		goto cleanup;
3229313Ssos
32383221Smarcel	/* Is it a Linux binary ? */
32483221Smarcel	if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
32583221Smarcel		error = ENOEXEC;
32683221Smarcel		goto cleanup;
32783221Smarcel	}
3289313Ssos
32983221Smarcel	/*
33083221Smarcel	 * While we are here, we should REALLY do some more checks
33183221Smarcel	 */
33214114Speter
33383221Smarcel	/* Set file/virtual offset based on a.out variant. */
33483221Smarcel	switch ((int)(a_out->a_magic & 0xffff)) {
33583221Smarcel	case 0413:	/* ZMAGIC */
33683221Smarcel		file_offset = 1024;
33783221Smarcel		break;
33883221Smarcel	case 0314:	/* QMAGIC */
33983221Smarcel		file_offset = 0;
34083221Smarcel		break;
34183221Smarcel	default:
34283221Smarcel		error = ENOEXEC;
34383221Smarcel		goto cleanup;
34483221Smarcel	}
3459313Ssos
34683221Smarcel	bss_size = round_page(a_out->a_bss);
34714114Speter
34883221Smarcel	/* Check various fields in header for validity/bounds. */
34983221Smarcel	if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
35083221Smarcel		error = ENOEXEC;
35183221Smarcel		goto cleanup;
35283221Smarcel	}
35314114Speter
35483221Smarcel	/* text + data can't exceed file size */
35583221Smarcel	if (a_out->a_data + a_out->a_text > attr.va_size) {
35683221Smarcel		error = EFAULT;
35783221Smarcel		goto cleanup;
35883221Smarcel	}
35914114Speter
36083366Sjulian	/* To protect td->td_proc->p_rlimit in the if condition. */
36183221Smarcel	mtx_assert(&Giant, MA_OWNED);
36270061Sjhb
36383221Smarcel	/*
36483221Smarcel	 * text/data/bss must not exceed limits
36583221Smarcel	 * XXX - this is not complete. it should check current usage PLUS
36683221Smarcel	 * the resources needed by this library.
36783221Smarcel	 */
36884783Sps	if (a_out->a_text > maxtsiz ||
36983366Sjulian	    a_out->a_data + bss_size >
37083366Sjulian	    td->td_proc->p_rlimit[RLIMIT_DATA].rlim_cur) {
37183221Smarcel		error = ENOMEM;
37283221Smarcel		goto cleanup;
37383221Smarcel	}
37414114Speter
37583221Smarcel	/* prevent more writers */
37683221Smarcel	vp->v_flag |= VTEXT;
37714114Speter
37883221Smarcel	/*
37983221Smarcel	 * Check if file_offset page aligned. Currently we cannot handle
38083221Smarcel	 * misalinged file offsets, and so we read in the entire image
38183221Smarcel	 * (what a waste).
38283221Smarcel	 */
38383221Smarcel	if (file_offset & PAGE_MASK) {
3849313Ssos#ifdef DEBUG
38583221Smarcel		printf("uselib: Non page aligned binary %lu\n", file_offset);
3869313Ssos#endif
38783221Smarcel		/* Map text+data read/write/execute */
38814114Speter
38983221Smarcel		/* a_entry is the load address and is page aligned */
39083221Smarcel		vmaddr = trunc_page(a_out->a_entry);
39114114Speter
39283221Smarcel		/* get anon user mapping, read+write+execute */
39383366Sjulian		error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
39483366Sjulian		    &vmaddr, a_out->a_text + a_out->a_data, FALSE, VM_PROT_ALL,
39583221Smarcel		    VM_PROT_ALL, 0);
39683221Smarcel		if (error)
39783221Smarcel			goto cleanup;
3989313Ssos
39983221Smarcel		/* map file into kernel_map */
40083221Smarcel		error = vm_mmap(kernel_map, &buffer,
40183221Smarcel		    round_page(a_out->a_text + a_out->a_data + file_offset),
40283221Smarcel		    VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp,
40383221Smarcel		    trunc_page(file_offset));
40483221Smarcel		if (error)
40583221Smarcel			goto cleanup;
4069313Ssos
40783221Smarcel		/* copy from kernel VM space to user space */
40883221Smarcel		error = copyout((caddr_t)(uintptr_t)(buffer + file_offset),
40983221Smarcel		    (caddr_t)vmaddr, a_out->a_text + a_out->a_data);
4109313Ssos
41183221Smarcel		/* release temporary kernel space */
41283221Smarcel		vm_map_remove(kernel_map, buffer, buffer +
41383221Smarcel		    round_page(a_out->a_text + a_out->a_data + file_offset));
4149313Ssos
41583221Smarcel		if (error)
41683221Smarcel			goto cleanup;
41783221Smarcel	} else {
4189313Ssos#ifdef DEBUG
41983221Smarcel		printf("uselib: Page aligned binary %lu\n", file_offset);
4209313Ssos#endif
42183221Smarcel		/*
42283221Smarcel		 * for QMAGIC, a_entry is 20 bytes beyond the load address
42383221Smarcel		 * to skip the executable header
42483221Smarcel		 */
42583221Smarcel		vmaddr = trunc_page(a_out->a_entry);
42614114Speter
42783221Smarcel		/*
42883221Smarcel		 * Map it all into the process's space as a single
42983221Smarcel		 * copy-on-write "data" segment.
43083221Smarcel		 */
43183366Sjulian		error = vm_mmap(&td->td_proc->p_vmspace->vm_map, &vmaddr,
43283221Smarcel		    a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL,
43383221Smarcel		    MAP_PRIVATE | MAP_FIXED, (caddr_t)vp, file_offset);
43483221Smarcel		if (error)
43583221Smarcel			goto cleanup;
43683221Smarcel	}
4379313Ssos#ifdef DEBUG
43883221Smarcel	printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long*)vmaddr)[0],
43983221Smarcel	    ((long*)vmaddr)[1]);
4409313Ssos#endif
44183221Smarcel	if (bss_size != 0) {
44283221Smarcel		/* Calculate BSS start address */
44383221Smarcel		vmaddr = trunc_page(a_out->a_entry) + a_out->a_text +
44483221Smarcel		    a_out->a_data;
44514114Speter
44683221Smarcel		/* allocate some 'anon' space */
44783366Sjulian		error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
44883366Sjulian		    &vmaddr, bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0);
44983221Smarcel		if (error)
45083221Smarcel			goto cleanup;
45183221Smarcel	}
45214114Speter
45314114Spetercleanup:
45483221Smarcel	/* Unlock vnode if needed */
45583221Smarcel	if (locked)
45683366Sjulian		VOP_UNLOCK(vp, 0, td);
45714114Speter
45883221Smarcel	/* Release the kernel mapping. */
45983221Smarcel	if (a_out)
46083221Smarcel		vm_map_remove(kernel_map, (vm_offset_t)a_out,
46183221Smarcel		    (vm_offset_t)a_out + PAGE_SIZE);
46214114Speter
46383221Smarcel	return error;
4649313Ssos}
4659313Ssos
4669313Ssosint
46783366Sjulianlinux_select(struct thread *td, struct linux_select_args *args)
46814331Speter{
46983221Smarcel	struct select_args bsa;
47083221Smarcel	struct timeval tv0, tv1, utv, *tvp;
47183221Smarcel	caddr_t sg;
47283221Smarcel	int error;
47314331Speter
4749313Ssos#ifdef DEBUG
47583221Smarcel	if (ldebug(select))
47683221Smarcel		printf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds,
47783221Smarcel		    (void *)args->readfds, (void *)args->writefds,
47883221Smarcel		    (void *)args->exceptfds, (void *)args->timeout);
4799313Ssos#endif
48014331Speter
48183221Smarcel	error = 0;
48283221Smarcel	bsa.nd = args->nfds;
48383221Smarcel	bsa.in = args->readfds;
48483221Smarcel	bsa.ou = args->writefds;
48583221Smarcel	bsa.ex = args->exceptfds;
48683221Smarcel	bsa.tv = (struct timeval *)args->timeout;
48783221Smarcel
48883221Smarcel	/*
48983221Smarcel	 * Store current time for computation of the amount of
49083221Smarcel	 * time left.
49183221Smarcel	 */
49283221Smarcel	if (args->timeout) {
49383221Smarcel		if ((error = copyin((caddr_t)args->timeout, &utv,
49483221Smarcel		    sizeof(utv))))
49583221Smarcel			goto select_out;
49614331Speter#ifdef DEBUG
49783221Smarcel		if (ldebug(select))
49883221Smarcel			printf(LMSG("incoming timeout (%ld/%ld)"),
49983221Smarcel			    utv.tv_sec, utv.tv_usec);
50014331Speter#endif
50183221Smarcel
50283221Smarcel		if (itimerfix(&utv)) {
50383221Smarcel			/*
50483221Smarcel			 * The timeval was invalid.  Convert it to something
50583221Smarcel			 * valid that will act as it does under Linux.
50683221Smarcel			 */
50783221Smarcel			sg = stackgap_init();
50883221Smarcel			tvp = stackgap_alloc(&sg, sizeof(utv));
50983221Smarcel			utv.tv_sec += utv.tv_usec / 1000000;
51083221Smarcel			utv.tv_usec %= 1000000;
51183221Smarcel			if (utv.tv_usec < 0) {
51283221Smarcel				utv.tv_sec -= 1;
51383221Smarcel				utv.tv_usec += 1000000;
51483221Smarcel			}
51583221Smarcel			if (utv.tv_sec < 0)
51683221Smarcel				timevalclear(&utv);
51783221Smarcel			if ((error = copyout(&utv, tvp, sizeof(utv))))
51883221Smarcel				goto select_out;
51983221Smarcel			bsa.tv = tvp;
52083221Smarcel		}
52183221Smarcel		microtime(&tv0);
52214331Speter	}
52314331Speter
52483366Sjulian	error = select(td, &bsa);
52514331Speter#ifdef DEBUG
52683221Smarcel	if (ldebug(select))
52772543Sjlemon		printf(LMSG("real select returns %d"), error);
52814331Speter#endif
52983221Smarcel	if (error) {
53083221Smarcel		/*
53183221Smarcel		 * See fs/select.c in the Linux kernel.  Without this,
53283221Smarcel		 * Maelstrom doesn't work.
53383221Smarcel		 */
53483221Smarcel		if (error == ERESTART)
53583221Smarcel			error = EINTR;
53683221Smarcel		goto select_out;
53783221Smarcel	}
53814331Speter
53983221Smarcel	if (args->timeout) {
54083366Sjulian		if (td->td_retval[0]) {
54183221Smarcel			/*
54283221Smarcel			 * Compute how much time was left of the timeout,
54383221Smarcel			 * by subtracting the current time and the time
54483221Smarcel			 * before we started the call, and subtracting
54583221Smarcel			 * that result from the user-supplied value.
54683221Smarcel			 */
54783221Smarcel			microtime(&tv1);
54883221Smarcel			timevalsub(&tv1, &tv0);
54983221Smarcel			timevalsub(&utv, &tv1);
55083221Smarcel			if (utv.tv_sec < 0)
55183221Smarcel				timevalclear(&utv);
55283221Smarcel		} else
55383221Smarcel			timevalclear(&utv);
55414331Speter#ifdef DEBUG
55583221Smarcel		if (ldebug(select))
55683221Smarcel			printf(LMSG("outgoing timeout (%ld/%ld)"),
55783221Smarcel			    utv.tv_sec, utv.tv_usec);
55814331Speter#endif
55983221Smarcel		if ((error = copyout(&utv, (caddr_t)args->timeout,
56083221Smarcel		    sizeof(utv))))
56183221Smarcel			goto select_out;
56283221Smarcel	}
56314331Speter
56414331Speterselect_out:
56514331Speter#ifdef DEBUG
56683221Smarcel	if (ldebug(select))
56783221Smarcel		printf(LMSG("select_out -> %d"), error);
56814331Speter#endif
56983221Smarcel	return error;
5709313Ssos}
5719313Ssos
57237548Sjkhint
57383366Sjulianlinux_mremap(struct thread *td, struct linux_mremap_args *args)
57437548Sjkh{
57537548Sjkh	struct munmap_args /* {
57637548Sjkh		void *addr;
57737548Sjkh		size_t len;
57837548Sjkh	} */ bsd_args;
57937548Sjkh	int error = 0;
58037548Sjkh
58137548Sjkh#ifdef DEBUG
58272543Sjlemon	if (ldebug(mremap))
58372543Sjlemon		printf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"),
58472543Sjlemon		    (void *)args->addr,
58572543Sjlemon		    (unsigned long)args->old_len,
58672543Sjlemon		    (unsigned long)args->new_len,
58772543Sjlemon		    (unsigned long)args->flags);
58837548Sjkh#endif
58937548Sjkh	args->new_len = round_page(args->new_len);
59037548Sjkh	args->old_len = round_page(args->old_len);
59137548Sjkh
59237548Sjkh	if (args->new_len > args->old_len) {
59383366Sjulian		td->td_retval[0] = 0;
59437548Sjkh		return ENOMEM;
59537548Sjkh	}
59637548Sjkh
59737548Sjkh	if (args->new_len < args->old_len) {
59883221Smarcel		bsd_args.addr = (caddr_t)(args->addr + args->new_len);
59937548Sjkh		bsd_args.len = args->old_len - args->new_len;
60083366Sjulian		error = munmap(td, &bsd_args);
60137548Sjkh	}
60237548Sjkh
60383366Sjulian	td->td_retval[0] = error ? 0 : (u_long)args->addr;
60437548Sjkh	return error;
60537548Sjkh}
60637548Sjkh
60714331Speterint
60883366Sjulianlinux_msync(struct thread *td, struct linux_msync_args *args)
60914331Speter{
61014331Speter	struct msync_args bsd_args;
6119313Ssos
61283221Smarcel	bsd_args.addr = (caddr_t)args->addr;
61314331Speter	bsd_args.len = args->len;
61414331Speter	bsd_args.flags = 0;	/* XXX ignore */
61514331Speter
61683366Sjulian	return msync(td, &bsd_args);
61714331Speter}
61814331Speter
61968201Sobrien#ifndef __alpha__
6209313Ssosint
62183366Sjulianlinux_time(struct thread *td, struct linux_time_args *args)
6229313Ssos{
62383221Smarcel	struct timeval tv;
62483221Smarcel	l_time_t tm;
62583221Smarcel	int error;
6269313Ssos
6279313Ssos#ifdef DEBUG
62872543Sjlemon	if (ldebug(time))
62972543Sjlemon		printf(ARGS(time, "*"));
6309313Ssos#endif
63183221Smarcel
63283221Smarcel	microtime(&tv);
63383221Smarcel	tm = tv.tv_sec;
63483221Smarcel	if (args->tm && (error = copyout(&tm, (caddr_t)args->tm, sizeof(tm))))
63583221Smarcel		return error;
63683366Sjulian	td->td_retval[0] = tm;
63783221Smarcel	return 0;
6389313Ssos}
63968201Sobrien#endif	/*!__alpha__*/
6409313Ssos
64183221Smarcelstruct l_times_argv {
64283221Smarcel	l_long		tms_utime;
64383221Smarcel	l_long		tms_stime;
64483221Smarcel	l_long		tms_cutime;
64583221Smarcel	l_long		tms_cstime;
6469313Ssos};
6479313Ssos
64874701Sgallatin#ifdef __alpha__
64974701Sgallatin#define CLK_TCK 1024	/* Linux uses 1024 on alpha */
65074701Sgallatin#else
65114381Speter#define CLK_TCK 100	/* Linux uses 100 */
65274701Sgallatin#endif
65374701Sgallatin
65414381Speter#define CONVTCK(r)	(r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
65514381Speter
6569313Ssosint
65783366Sjulianlinux_times(struct thread *td, struct linux_times_args *args)
6589313Ssos{
65983221Smarcel	struct timeval tv;
66083221Smarcel	struct l_times_argv tms;
66183221Smarcel	struct rusage ru;
66283221Smarcel	int error;
6639313Ssos
6649313Ssos#ifdef DEBUG
66572543Sjlemon	if (ldebug(times))
66672543Sjlemon		printf(ARGS(times, "*"));
6679313Ssos#endif
66814381Speter
66983221Smarcel	mtx_lock_spin(&sched_lock);
67083366Sjulian	calcru(td->td_proc, &ru.ru_utime, &ru.ru_stime, NULL);
67183221Smarcel	mtx_unlock_spin(&sched_lock);
67214381Speter
67383221Smarcel	tms.tms_utime = CONVTCK(ru.ru_utime);
67483221Smarcel	tms.tms_stime = CONVTCK(ru.ru_stime);
67514381Speter
67683366Sjulian	tms.tms_cutime = CONVTCK(td->td_proc->p_stats->p_cru.ru_utime);
67783366Sjulian	tms.tms_cstime = CONVTCK(td->td_proc->p_stats->p_cru.ru_stime);
67814381Speter
67983221Smarcel	if ((error = copyout(&tms, (caddr_t)args->buf, sizeof(tms))))
68083221Smarcel		return error;
68183221Smarcel
68283221Smarcel	microuptime(&tv);
68383366Sjulian	td->td_retval[0] = (int)CONVTCK(tv);
68483221Smarcel	return 0;
6859313Ssos}
6869313Ssos
6879313Ssosint
68883366Sjulianlinux_newuname(struct thread *td, struct linux_newuname_args *args)
6899313Ssos{
69083221Smarcel	struct l_new_utsname utsname;
69150465Smarcel	char *osrelease, *osname;
6929313Ssos
6939313Ssos#ifdef DEBUG
69472543Sjlemon	if (ldebug(newuname))
69572543Sjlemon		printf(ARGS(newuname, "*"));
6969313Ssos#endif
69750345Smarcel
69883366Sjulian	osname = linux_get_osname(td->td_proc);
69983366Sjulian	osrelease = linux_get_osrelease(td->td_proc);
70050465Smarcel
70183221Smarcel	bzero(&utsname, sizeof(utsname));
70250465Smarcel	strncpy(utsname.sysname, osname, LINUX_MAX_UTSNAME-1);
70350345Smarcel	strncpy(utsname.nodename, hostname, LINUX_MAX_UTSNAME-1);
70450465Smarcel	strncpy(utsname.release, osrelease, LINUX_MAX_UTSNAME-1);
70550345Smarcel	strncpy(utsname.version, version, LINUX_MAX_UTSNAME-1);
70650345Smarcel	strncpy(utsname.machine, machine, LINUX_MAX_UTSNAME-1);
70750345Smarcel	strncpy(utsname.domainname, domainname, LINUX_MAX_UTSNAME-1);
70850345Smarcel
70983221Smarcel	return (copyout(&utsname, (caddr_t)args->buf, sizeof(utsname)));
7109313Ssos}
7119313Ssos
71283221Smarcel#if defined(__i386__)
71383221Smarcelstruct l_utimbuf {
71483221Smarcel	l_time_t l_actime;
71583221Smarcel	l_time_t l_modtime;
71614381Speter};
7179313Ssos
7189313Ssosint
71983366Sjulianlinux_utime(struct thread *td, struct linux_utime_args *args)
7209313Ssos{
72183221Smarcel	struct utimes_args /* {
72283221Smarcel		char	*path;
72383221Smarcel		struct	timeval *tptr;
72483221Smarcel	} */ bsdutimes;
72583221Smarcel	struct timeval tv[2], *tvp;
72683221Smarcel	struct l_utimbuf lut;
72783221Smarcel	int error;
72883221Smarcel	caddr_t sg;
7299313Ssos
73083221Smarcel	sg = stackgap_init();
73183366Sjulian	CHECKALTEXIST(td, &sg, args->fname);
73214331Speter
7339313Ssos#ifdef DEBUG
73472543Sjlemon	if (ldebug(utime))
73572543Sjlemon		printf(ARGS(utime, "%s, *"), args->fname);
7369313Ssos#endif
73714381Speter
73883221Smarcel	if (args->times) {
73983221Smarcel		if ((error = copyin((caddr_t)args->times, &lut, sizeof lut)))
74083221Smarcel			return error;
74183221Smarcel		tv[0].tv_sec = lut.l_actime;
74283221Smarcel		tv[0].tv_usec = 0;
74383221Smarcel		tv[1].tv_sec = lut.l_modtime;
74483221Smarcel		tv[1].tv_usec = 0;
74583221Smarcel		/* so that utimes can copyin */
74683221Smarcel		tvp = (struct timeval *)stackgap_alloc(&sg, sizeof(tv));
74783221Smarcel		if (tvp == NULL)
74883221Smarcel			return (ENAMETOOLONG);
74983221Smarcel		if ((error = copyout(tv, tvp, sizeof(tv))))
75083221Smarcel			return error;
75183221Smarcel		bsdutimes.tptr = tvp;
75283221Smarcel	} else
75383221Smarcel		bsdutimes.tptr = NULL;
75483221Smarcel
75583221Smarcel	bsdutimes.path = args->fname;
75683366Sjulian	return utimes(td, &bsdutimes);
7579313Ssos}
75883221Smarcel#endif /* __i386__ */
7599313Ssos
76044384Sjulian#define __WCLONE 0x80000000
76144384Sjulian
76268201Sobrien#ifndef __alpha__
7639313Ssosint
76483366Sjulianlinux_waitpid(struct thread *td, struct linux_waitpid_args *args)
7659313Ssos{
76683221Smarcel	struct wait_args /* {
76783221Smarcel		int pid;
76883221Smarcel		int *status;
76983221Smarcel		int options;
77083221Smarcel		struct	rusage *rusage;
77183221Smarcel	} */ tmp;
77283221Smarcel	int error, tmpstat;
7739313Ssos
7749313Ssos#ifdef DEBUG
77572543Sjlemon	if (ldebug(waitpid))
77672543Sjlemon		printf(ARGS(waitpid, "%d, %p, %d"),
77772543Sjlemon		    args->pid, (void *)args->status, args->options);
7789313Ssos#endif
7799313Ssos
78083221Smarcel	tmp.pid = args->pid;
78183221Smarcel	tmp.status = args->status;
78283221Smarcel	tmp.options = (args->options & (WNOHANG | WUNTRACED));
78383221Smarcel	/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
78483221Smarcel	if (args->options & __WCLONE)
78583221Smarcel		tmp.options |= WLINUXCLONE;
78683221Smarcel	tmp.rusage = NULL;
78743208Sjulian
78883366Sjulian	if ((error = wait4(td, &tmp)) != 0)
78983221Smarcel		return error;
79083221Smarcel
79183221Smarcel	if (args->status) {
79283221Smarcel		if ((error = copyin((caddr_t)args->status, &tmpstat,
79383221Smarcel		    sizeof(int))) != 0)
79483221Smarcel			return error;
79583221Smarcel		tmpstat &= 0xffff;
79683221Smarcel		if (WIFSIGNALED(tmpstat))
79783221Smarcel			tmpstat = (tmpstat & 0xffffff80) |
79883221Smarcel			    BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
79983221Smarcel		else if (WIFSTOPPED(tmpstat))
80083221Smarcel			tmpstat = (tmpstat & 0xffff00ff) |
80183221Smarcel			    (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
80283221Smarcel		return copyout(&tmpstat, (caddr_t)args->status, sizeof(int));
80383221Smarcel	}
80483221Smarcel
80514331Speter	return 0;
8069313Ssos}
80768201Sobrien#endif	/*!__alpha__*/
8089313Ssos
80914331Speterint
81083366Sjulianlinux_wait4(struct thread *td, struct linux_wait4_args *args)
8119313Ssos{
81283221Smarcel	struct wait_args /* {
81383221Smarcel		int pid;
81483221Smarcel		int *status;
81583221Smarcel		int options;
81683221Smarcel		struct	rusage *rusage;
81783221Smarcel	} */ tmp;
81883221Smarcel	int error, tmpstat;
8199313Ssos
8209313Ssos#ifdef DEBUG
82172543Sjlemon	if (ldebug(wait4))
82272543Sjlemon		printf(ARGS(wait4, "%d, %p, %d, %p"),
82372543Sjlemon		    args->pid, (void *)args->status, args->options,
82472543Sjlemon		    (void *)args->rusage);
8259313Ssos#endif
8269313Ssos
82783221Smarcel	tmp.pid = args->pid;
82883221Smarcel	tmp.status = args->status;
82983221Smarcel	tmp.options = (args->options & (WNOHANG | WUNTRACED));
83083221Smarcel	/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
83183221Smarcel	if (args->options & __WCLONE)
83283221Smarcel		tmp.options |= WLINUXCLONE;
83383221Smarcel	tmp.rusage = (struct rusage *)args->rusage;
83414331Speter
83583366Sjulian	if ((error = wait4(td, &tmp)) != 0)
83683221Smarcel		return error;
83714331Speter
83883366Sjulian	SIGDELSET(td->td_proc->p_siglist, SIGCHLD);
83983221Smarcel
84083221Smarcel	if (args->status) {
84183221Smarcel		if ((error = copyin((caddr_t)args->status, &tmpstat,
84283221Smarcel		    sizeof(int))) != 0)
84383221Smarcel			return error;
84483221Smarcel		tmpstat &= 0xffff;
84583221Smarcel		if (WIFSIGNALED(tmpstat))
84683221Smarcel			tmpstat = (tmpstat & 0xffffff80) |
84783221Smarcel			    BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
84883221Smarcel		else if (WIFSTOPPED(tmpstat))
84983221Smarcel			tmpstat = (tmpstat & 0xffff00ff) |
85083221Smarcel			    (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
85183221Smarcel		return copyout(&tmpstat, (caddr_t)args->status, sizeof(int));
85283221Smarcel	}
85383221Smarcel
85414331Speter	return 0;
8559313Ssos}
85613420Ssos
85714331Speterint
85883366Sjulianlinux_mknod(struct thread *td, struct linux_mknod_args *args)
85913420Ssos{
86014331Speter	caddr_t sg;
86114331Speter	struct mknod_args bsd_mknod;
86214331Speter	struct mkfifo_args bsd_mkfifo;
86314331Speter
86414331Speter	sg = stackgap_init();
86514331Speter
86683366Sjulian	CHECKALTCREAT(td, &sg, args->path);
86714331Speter
86814331Speter#ifdef DEBUG
86972543Sjlemon	if (ldebug(mknod))
87072543Sjlemon		printf(ARGS(mknod, "%s, %d, %d"),
87172543Sjlemon		    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;
87783366Sjulian		return mkfifo(td, &bsd_mkfifo);
87814331Speter	} else {
87914331Speter		bsd_mknod.path = args->path;
88014331Speter		bsd_mknod.mode = args->mode;
88114331Speter		bsd_mknod.dev = args->dev;
88283366Sjulian		return mknod(td, &bsd_mknod);
88314331Speter	}
88413420Ssos}
88514331Speter
88614331Speter/*
88714331Speter * UGH! This is just about the dumbest idea I've ever heard!!
88814331Speter */
88914331Speterint
89083366Sjulianlinux_personality(struct thread *td, struct linux_personality_args *args)
89114331Speter{
89214331Speter#ifdef DEBUG
89372543Sjlemon	if (ldebug(personality))
89472543Sjlemon		printf(ARGS(personality, "%d"), args->per);
89514331Speter#endif
89668201Sobrien#ifndef __alpha__
89714331Speter	if (args->per != 0)
89814331Speter		return EINVAL;
89968201Sobrien#endif
90014331Speter
90114331Speter	/* Yes Jim, it's still a Linux... */
90283366Sjulian	td->td_retval[0] = 0;
90314331Speter	return 0;
90414331Speter}
90514331Speter
90614331Speter/*
90714331Speter * Wrappers for get/setitimer for debugging..
90814331Speter */
90914331Speterint
91083366Sjulianlinux_setitimer(struct thread *td, struct linux_setitimer_args *args)
91114331Speter{
91214331Speter	struct setitimer_args bsa;
91314331Speter	struct itimerval foo;
91414331Speter	int error;
91514331Speter
91614331Speter#ifdef DEBUG
91772543Sjlemon	if (ldebug(setitimer))
91872543Sjlemon		printf(ARGS(setitimer, "%p, %p"),
91972543Sjlemon		    (void *)args->itv, (void *)args->oitv);
92014331Speter#endif
92114331Speter	bsa.which = args->which;
92283221Smarcel	bsa.itv = (struct itimerval *)args->itv;
92383221Smarcel	bsa.oitv = (struct itimerval *)args->oitv;
92414331Speter	if (args->itv) {
92583221Smarcel	    if ((error = copyin((caddr_t)args->itv, &foo, sizeof(foo))))
92614331Speter		return error;
92714331Speter#ifdef DEBUG
92872543Sjlemon	    if (ldebug(setitimer)) {
92972543Sjlemon	        printf("setitimer: value: sec: %ld, usec: %ld\n",
93072543Sjlemon		    foo.it_value.tv_sec, foo.it_value.tv_usec);
93172543Sjlemon	        printf("setitimer: interval: sec: %ld, usec: %ld\n",
93272543Sjlemon		    foo.it_interval.tv_sec, foo.it_interval.tv_usec);
93372543Sjlemon	    }
93414331Speter#endif
93514331Speter	}
93683366Sjulian	return setitimer(td, &bsa);
93714331Speter}
93814331Speter
93914331Speterint
94083366Sjulianlinux_getitimer(struct thread *td, struct linux_getitimer_args *args)
94114331Speter{
94214331Speter	struct getitimer_args bsa;
94314331Speter#ifdef DEBUG
94472543Sjlemon	if (ldebug(getitimer))
94572543Sjlemon		printf(ARGS(getitimer, "%p"), (void *)args->itv);
94614331Speter#endif
94714331Speter	bsa.which = args->which;
94883221Smarcel	bsa.itv = (struct itimerval *)args->itv;
94983366Sjulian	return getitimer(td, &bsa);
95014331Speter}
95130837Skato
95268201Sobrien#ifndef __alpha__
95330837Skatoint
95483366Sjulianlinux_nice(struct thread *td, struct linux_nice_args *args)
95530837Skato{
95630837Skato	struct setpriority_args	bsd_args;
95730837Skato
95830837Skato	bsd_args.which = PRIO_PROCESS;
95930837Skato	bsd_args.who = 0;	/* current process */
96030837Skato	bsd_args.prio = args->inc;
96183366Sjulian	return setpriority(td, &bsd_args);
96230837Skato}
96368201Sobrien#endif	/*!__alpha__*/
96430837Skato
96542185Ssosint
96683366Sjulianlinux_setgroups(struct thread *td, struct linux_setgroups_args *args)
96742185Ssos{
96877183Srwatson	struct ucred *newcred, *oldcred;
96983221Smarcel	l_gid_t linux_gidset[NGROUPS];
97050350Smarcel	gid_t *bsd_gidset;
97150350Smarcel	int ngrp, error;
97242185Ssos
97383221Smarcel	ngrp = args->gidsetsize;
97483366Sjulian	oldcred = td->td_proc->p_ucred;
97542185Ssos
97650350Smarcel	/*
97750350Smarcel	 * cr_groups[0] holds egid. Setting the whole set from
97850350Smarcel	 * the supplied set will cause egid to be changed too.
97950350Smarcel	 * Keep cr_groups[0] unchanged to prevent that.
98050350Smarcel	 */
98142185Ssos
98277183Srwatson	if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0)
98350350Smarcel		return (error);
98442185Ssos
98550350Smarcel	if (ngrp >= NGROUPS)
98650350Smarcel		return (EINVAL);
98742185Ssos
98877183Srwatson	newcred = crdup(oldcred);
98950350Smarcel	if (ngrp > 0) {
99083221Smarcel		error = copyin((caddr_t)args->grouplist, linux_gidset,
99183221Smarcel			       ngrp * sizeof(l_gid_t));
99250350Smarcel		if (error)
99350350Smarcel			return (error);
99442185Ssos
99577183Srwatson		newcred->cr_ngroups = ngrp + 1;
99650350Smarcel
99777183Srwatson		bsd_gidset = newcred->cr_groups;
99850350Smarcel		ngrp--;
99950350Smarcel		while (ngrp >= 0) {
100050350Smarcel			bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
100150350Smarcel			ngrp--;
100250350Smarcel		}
100350350Smarcel	}
100450350Smarcel	else
100577183Srwatson		newcred->cr_ngroups = 1;
100650350Smarcel
100783366Sjulian	setsugid(td->td_proc);
100883366Sjulian	td->td_proc->p_ucred = newcred;
100977183Srwatson	crfree(oldcred);
101050350Smarcel	return (0);
101142185Ssos}
101242185Ssos
101342185Ssosint
101483366Sjulianlinux_getgroups(struct thread *td, struct linux_getgroups_args *args)
101542185Ssos{
101677183Srwatson	struct ucred *cred;
101783221Smarcel	l_gid_t linux_gidset[NGROUPS];
101850350Smarcel	gid_t *bsd_gidset;
101950350Smarcel	int bsd_gidsetsz, ngrp, error;
102042185Ssos
102183366Sjulian	cred = td->td_proc->p_ucred;
102277183Srwatson	bsd_gidset = cred->cr_groups;
102377183Srwatson	bsd_gidsetsz = cred->cr_ngroups - 1;
102442185Ssos
102550350Smarcel	/*
102650350Smarcel	 * cr_groups[0] holds egid. Returning the whole set
102750350Smarcel	 * here will cause a duplicate. Exclude cr_groups[0]
102850350Smarcel	 * to prevent that.
102950350Smarcel	 */
103042185Ssos
103183221Smarcel	if ((ngrp = args->gidsetsize) == 0) {
103283366Sjulian		td->td_retval[0] = bsd_gidsetsz;
103350350Smarcel		return (0);
103450350Smarcel	}
103542185Ssos
103650546Smarcel	if (ngrp < bsd_gidsetsz)
103750350Smarcel		return (EINVAL);
103842185Ssos
103950546Smarcel	ngrp = 0;
104050350Smarcel	while (ngrp < bsd_gidsetsz) {
104150546Smarcel		linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
104250350Smarcel		ngrp++;
104350350Smarcel	}
104450350Smarcel
104583221Smarcel	if ((error = copyout(linux_gidset, (caddr_t)args->grouplist,
104683221Smarcel	    ngrp * sizeof(l_gid_t))))
104750350Smarcel		return (error);
104850350Smarcel
104983366Sjulian	td->td_retval[0] = ngrp;
105050350Smarcel	return (0);
105142185Ssos}
105249626Smarcel
105368201Sobrien#ifndef __alpha__
105449626Smarcelint
105583366Sjulianlinux_setrlimit(struct thread *td, struct linux_setrlimit_args *args)
105649626Smarcel{
105765099Smarcel	struct __setrlimit_args bsd;
105883221Smarcel	struct l_rlimit rlim;
105965099Smarcel	int error;
106065099Smarcel	caddr_t sg = stackgap_init();
106149842Smarcel
106249626Smarcel#ifdef DEBUG
106372543Sjlemon	if (ldebug(setrlimit))
106472543Sjlemon		printf(ARGS(setrlimit, "%d, %p"),
106583221Smarcel		    args->resource, (void *)args->rlim);
106649626Smarcel#endif
106749626Smarcel
106883221Smarcel	if (args->resource >= LINUX_RLIM_NLIMITS)
106965099Smarcel		return (EINVAL);
107049626Smarcel
107183221Smarcel	bsd.which = linux_to_bsd_resource[args->resource];
107265099Smarcel	if (bsd.which == -1)
107365099Smarcel		return (EINVAL);
107449626Smarcel
107583221Smarcel	error = copyin((caddr_t)args->rlim, &rlim, sizeof(rlim));
107665099Smarcel	if (error)
107765099Smarcel		return (error);
107849626Smarcel
107965099Smarcel	bsd.rlp = stackgap_alloc(&sg, sizeof(struct rlimit));
108065099Smarcel	bsd.rlp->rlim_cur = (rlim_t)rlim.rlim_cur;
108165099Smarcel	bsd.rlp->rlim_max = (rlim_t)rlim.rlim_max;
108283366Sjulian	return (setrlimit(td, &bsd));
108349626Smarcel}
108449626Smarcel
108549626Smarcelint
108683366Sjulianlinux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args)
108749626Smarcel{
108865099Smarcel	struct __getrlimit_args bsd;
108983221Smarcel	struct l_rlimit rlim;
109065099Smarcel	int error;
109165099Smarcel	caddr_t sg = stackgap_init();
109249842Smarcel
109349626Smarcel#ifdef DEBUG
109483221Smarcel	if (ldebug(old_getrlimit))
109583221Smarcel		printf(ARGS(old_getrlimit, "%d, %p"),
109683221Smarcel		    args->resource, (void *)args->rlim);
109749626Smarcel#endif
109849626Smarcel
109983221Smarcel	if (args->resource >= LINUX_RLIM_NLIMITS)
110065099Smarcel		return (EINVAL);
110149626Smarcel
110283221Smarcel	bsd.which = linux_to_bsd_resource[args->resource];
110365099Smarcel	if (bsd.which == -1)
110465099Smarcel		return (EINVAL);
110549626Smarcel
110665099Smarcel	bsd.rlp = stackgap_alloc(&sg, sizeof(struct rlimit));
110783366Sjulian	error = getrlimit(td, &bsd);
110865099Smarcel	if (error)
110965099Smarcel		return (error);
111049626Smarcel
111165099Smarcel	rlim.rlim_cur = (unsigned long)bsd.rlp->rlim_cur;
111265106Smarcel	if (rlim.rlim_cur == ULONG_MAX)
111365106Smarcel		rlim.rlim_cur = LONG_MAX;
111465099Smarcel	rlim.rlim_max = (unsigned long)bsd.rlp->rlim_max;
111565106Smarcel	if (rlim.rlim_max == ULONG_MAX)
111665106Smarcel		rlim.rlim_max = LONG_MAX;
111783221Smarcel	return (copyout(&rlim, (caddr_t)args->rlim, sizeof(rlim)));
111849626Smarcel}
111983221Smarcel
112083221Smarcelint
112183366Sjulianlinux_getrlimit(struct thread *td, struct linux_getrlimit_args *args)
112283221Smarcel{
112383221Smarcel	struct __getrlimit_args bsd;
112483221Smarcel	struct l_rlimit rlim;
112583221Smarcel	int error;
112683221Smarcel	caddr_t sg = stackgap_init();
112783221Smarcel
112883221Smarcel#ifdef DEBUG
112983221Smarcel	if (ldebug(getrlimit))
113083221Smarcel		printf(ARGS(getrlimit, "%d, %p"),
113183221Smarcel		    args->resource, (void *)args->rlim);
113283221Smarcel#endif
113383221Smarcel
113483221Smarcel	if (args->resource >= LINUX_RLIM_NLIMITS)
113583221Smarcel		return (EINVAL);
113683221Smarcel
113783221Smarcel	bsd.which = linux_to_bsd_resource[args->resource];
113883221Smarcel	if (bsd.which == -1)
113983221Smarcel		return (EINVAL);
114083221Smarcel
114183221Smarcel	bsd.rlp = stackgap_alloc(&sg, sizeof(struct rlimit));
114283366Sjulian	error = getrlimit(td, &bsd);
114383221Smarcel	if (error)
114483221Smarcel		return (error);
114583221Smarcel
114683221Smarcel	rlim.rlim_cur = (l_ulong)bsd.rlp->rlim_cur;
114783221Smarcel	rlim.rlim_max = (l_ulong)bsd.rlp->rlim_max;
114883221Smarcel	return (copyout(&rlim, (caddr_t)args->rlim, sizeof(rlim)));
114983221Smarcel}
115068201Sobrien#endif /*!__alpha__*/
115149849Smarcel
115249849Smarcelint
115383366Sjulianlinux_sched_setscheduler(struct thread *td,
115483221Smarcel    struct linux_sched_setscheduler_args *args)
115549849Smarcel{
115649849Smarcel	struct sched_setscheduler_args bsd;
115749849Smarcel
115849849Smarcel#ifdef DEBUG
115972543Sjlemon	if (ldebug(sched_setscheduler))
116072543Sjlemon		printf(ARGS(sched_setscheduler, "%d, %d, %p"),
116183221Smarcel		    args->pid, args->policy, (const void *)args->param);
116249849Smarcel#endif
116349849Smarcel
116483221Smarcel	switch (args->policy) {
116549849Smarcel	case LINUX_SCHED_OTHER:
116649849Smarcel		bsd.policy = SCHED_OTHER;
116749849Smarcel		break;
116849849Smarcel	case LINUX_SCHED_FIFO:
116949849Smarcel		bsd.policy = SCHED_FIFO;
117049849Smarcel		break;
117149849Smarcel	case LINUX_SCHED_RR:
117249849Smarcel		bsd.policy = SCHED_RR;
117349849Smarcel		break;
117449849Smarcel	default:
117549849Smarcel		return EINVAL;
117649849Smarcel	}
117749849Smarcel
117883221Smarcel	bsd.pid = args->pid;
117983221Smarcel	bsd.param = (struct sched_param *)args->param;
118083366Sjulian	return sched_setscheduler(td, &bsd);
118149849Smarcel}
118249849Smarcel
118349849Smarcelint
118483366Sjulianlinux_sched_getscheduler(struct thread *td,
118583221Smarcel    struct linux_sched_getscheduler_args *args)
118649849Smarcel{
118749849Smarcel	struct sched_getscheduler_args bsd;
118849849Smarcel	int error;
118949849Smarcel
119049849Smarcel#ifdef DEBUG
119172543Sjlemon	if (ldebug(sched_getscheduler))
119283221Smarcel		printf(ARGS(sched_getscheduler, "%d"), args->pid);
119349849Smarcel#endif
119449849Smarcel
119583221Smarcel	bsd.pid = args->pid;
119683366Sjulian	error = sched_getscheduler(td, &bsd);
119749849Smarcel
119883366Sjulian	switch (td->td_retval[0]) {
119949849Smarcel	case SCHED_OTHER:
120083366Sjulian		td->td_retval[0] = LINUX_SCHED_OTHER;
120149849Smarcel		break;
120249849Smarcel	case SCHED_FIFO:
120383366Sjulian		td->td_retval[0] = LINUX_SCHED_FIFO;
120449849Smarcel		break;
120549849Smarcel	case SCHED_RR:
120683366Sjulian		td->td_retval[0] = LINUX_SCHED_RR;
120749849Smarcel		break;
120849849Smarcel	}
120949849Smarcel
121049849Smarcel	return error;
121149849Smarcel}
121272538Sjlemon
121375053Salcint
121483366Sjulianlinux_sched_get_priority_max(struct thread *td,
121583221Smarcel    struct linux_sched_get_priority_max_args *args)
121675053Salc{
121775053Salc	struct sched_get_priority_max_args bsd;
121875053Salc
121975053Salc#ifdef DEBUG
122075053Salc	if (ldebug(sched_get_priority_max))
122183221Smarcel		printf(ARGS(sched_get_priority_max, "%d"), args->policy);
122275053Salc#endif
122375053Salc
122483221Smarcel	switch (args->policy) {
122575053Salc	case LINUX_SCHED_OTHER:
122675053Salc		bsd.policy = SCHED_OTHER;
122775053Salc		break;
122875053Salc	case LINUX_SCHED_FIFO:
122975053Salc		bsd.policy = SCHED_FIFO;
123075053Salc		break;
123175053Salc	case LINUX_SCHED_RR:
123275053Salc		bsd.policy = SCHED_RR;
123375053Salc		break;
123475053Salc	default:
123575053Salc		return EINVAL;
123675053Salc	}
123783366Sjulian	return sched_get_priority_max(td, &bsd);
123875053Salc}
123975053Salc
124075053Salcint
124183366Sjulianlinux_sched_get_priority_min(struct thread *td,
124283221Smarcel    struct linux_sched_get_priority_min_args *args)
124375053Salc{
124475053Salc	struct sched_get_priority_min_args bsd;
124575053Salc
124675053Salc#ifdef DEBUG
124775053Salc	if (ldebug(sched_get_priority_min))
124883221Smarcel		printf(ARGS(sched_get_priority_min, "%d"), args->policy);
124975053Salc#endif
125075053Salc
125183221Smarcel	switch (args->policy) {
125275053Salc	case LINUX_SCHED_OTHER:
125375053Salc		bsd.policy = SCHED_OTHER;
125475053Salc		break;
125575053Salc	case LINUX_SCHED_FIFO:
125675053Salc		bsd.policy = SCHED_FIFO;
125775053Salc		break;
125875053Salc	case LINUX_SCHED_RR:
125975053Salc		bsd.policy = SCHED_RR;
126075053Salc		break;
126175053Salc	default:
126275053Salc		return EINVAL;
126375053Salc	}
126483366Sjulian	return sched_get_priority_min(td, &bsd);
126575053Salc}
126675053Salc
126772538Sjlemon#define REBOOT_CAD_ON	0x89abcdef
126872538Sjlemon#define REBOOT_CAD_OFF	0
126972538Sjlemon#define REBOOT_HALT	0xcdef0123
127072538Sjlemon
127172538Sjlemonint
127283366Sjulianlinux_reboot(struct thread *td, struct linux_reboot_args *args)
127372538Sjlemon{
127472538Sjlemon	struct reboot_args bsd_args;
127572538Sjlemon
127672538Sjlemon#ifdef DEBUG
127772538Sjlemon	if (ldebug(reboot))
127883221Smarcel		printf(ARGS(reboot, "0x%x"), args->cmd);
127972538Sjlemon#endif
128083221Smarcel	if (args->cmd == REBOOT_CAD_ON || args->cmd == REBOOT_CAD_OFF)
128172538Sjlemon		return (0);
128283221Smarcel	bsd_args.opt = (args->cmd == REBOOT_HALT) ? RB_HALT : 0;
128383366Sjulian	return (reboot(td, &bsd_args));
128472538Sjlemon}
128583221Smarcel
128683221Smarcel/*
128783221Smarcel * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify
128883366Sjulian * td->td_retval[1] when COMPAT_43 or COMPAT_SUNOS is defined. This
128983221Smarcel * globbers registers that are assumed to be preserved. The following
129083221Smarcel * lightweight syscalls fixes this. See also linux_getgid16() and
129183221Smarcel * linux_getuid16() in linux_uid16.c.
129283221Smarcel *
129383221Smarcel * linux_getpid() - MP SAFE
129483221Smarcel * linux_getgid() - MP SAFE
129583221Smarcel * linux_getuid() - MP SAFE
129683221Smarcel */
129783221Smarcel
129883221Smarcelint
129983366Sjulianlinux_getpid(struct thread *td, struct linux_getpid_args *args)
130083221Smarcel{
130183366Sjulian
130283366Sjulian	td->td_retval[0] = td->td_proc->p_pid;
130383221Smarcel	return (0);
130483221Smarcel}
130583221Smarcel
130683221Smarcelint
130783366Sjulianlinux_getgid(struct thread *td, struct linux_getgid_args *args)
130883221Smarcel{
130983366Sjulian
131083366Sjulian	td->td_retval[0] = td->td_proc->p_ucred->cr_rgid;
131183221Smarcel	return (0);
131283221Smarcel}
131383221Smarcel
131483221Smarcelint
131583366Sjulianlinux_getuid(struct thread *td, struct linux_getuid_args *args)
131683221Smarcel{
131783366Sjulian
131883366Sjulian	td->td_retval[0] = td->td_proc->p_ucred->cr_ruid;
131983221Smarcel	return (0);
132083221Smarcel}
132183503Smr
132283503Smrint
132383503Smrlinux_getsid(struct thread *td, struct linux_getsid_args *args)
132483503Smr{
132583503Smr	struct getsid_args bsd;
132683503Smr	bsd.pid = args->pid;
132783503Smr	return getsid(td, &bsd);
132883503Smr}
1329