linux_misc.c revision 161420
19313Ssos/*-
2133749Stjr * Copyright (c) 2002 Doug Rabson
39313Ssos * Copyright (c) 1994-1995 S�ren Schmidt
49313Ssos * All rights reserved.
59313Ssos *
69313Ssos * Redistribution and use in source and binary forms, with or without
79313Ssos * modification, are permitted provided that the following conditions
89313Ssos * are met:
99313Ssos * 1. Redistributions of source code must retain the above copyright
1014331Speter *    notice, this list of conditions and the following disclaimer
119313Ssos *    in this position and unchanged.
129313Ssos * 2. Redistributions in binary form must reproduce the above copyright
139313Ssos *    notice, this list of conditions and the following disclaimer in the
149313Ssos *    documentation and/or other materials provided with the distribution.
159313Ssos * 3. The name of the author may not be used to endorse or promote products
1697748Sschweikh *    derived from this software without specific prior written permission
179313Ssos *
189313Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
199313Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
209313Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
219313Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
229313Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
239313Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
249313Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
259313Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
269313Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
279313Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
289313Ssos */
299313Ssos
30116173Sobrien#include <sys/cdefs.h>
31116173Sobrien__FBSDID("$FreeBSD: head/sys/compat/linux/linux_misc.c 161420 2006-08-17 21:21:30Z netchild $");
32116173Sobrien
33156874Sru#include "opt_compat.h"
34101189Srwatson#include "opt_mac.h"
3549842Smarcel
369313Ssos#include <sys/param.h>
37102954Sbde#include <sys/blist.h>
3876166Smarkm#include <sys/fcntl.h>
39158415Snetchild#if defined(__i386__)
4076166Smarkm#include <sys/imgact_aout.h>
41133816Stjr#endif
4291385Srobert#include <sys/jail.h>
4312458Sbde#include <sys/kernel.h>
44114216Skan#include <sys/limits.h>
4576166Smarkm#include <sys/lock.h>
46101189Srwatson#include <sys/mac.h>
47102954Sbde#include <sys/malloc.h>
489313Ssos#include <sys/mman.h>
499313Ssos#include <sys/mount.h>
5076166Smarkm#include <sys/mutex.h>
519313Ssos#include <sys/namei.h>
5276166Smarkm#include <sys/proc.h>
5372538Sjlemon#include <sys/reboot.h>
549313Ssos#include <sys/resourcevar.h>
5576166Smarkm#include <sys/signalvar.h>
569313Ssos#include <sys/stat.h>
57102814Siedowse#include <sys/syscallsubr.h>
5812458Sbde#include <sys/sysctl.h>
5976166Smarkm#include <sys/sysproto.h>
60102954Sbde#include <sys/systm.h>
6176166Smarkm#include <sys/time.h>
6280180Spirzyk#include <sys/vmmeter.h>
639313Ssos#include <sys/vnode.h>
649313Ssos#include <sys/wait.h>
659313Ssos
6612652Sbde#include <vm/vm.h>
6712689Speter#include <vm/pmap.h>
6812458Sbde#include <vm/vm_kern.h>
6912689Speter#include <vm/vm_map.h>
7012842Sbde#include <vm/vm_extern.h>
7180180Spirzyk#include <vm/vm_object.h>
7280180Spirzyk#include <vm/swap_pager.h>
7312458Sbde
7449849Smarcel#include <posix4/sched.h>
7549849Smarcel
76143197Ssobomax#include <compat/linux/linux_sysproto.h>
77161310Snetchild#include <compat/linux/linux_emul.h>
78143197Ssobomax
79140214Sobrien#ifdef COMPAT_LINUX32
80140214Sobrien#include <machine/../linux32/linux.h>
81140214Sobrien#include <machine/../linux32/linux32_proto.h>
82140214Sobrien#else
8364909Smarcel#include <machine/../linux/linux.h>
8468583Smarcel#include <machine/../linux/linux_proto.h>
85133816Stjr#endif
86102954Sbde
8764909Smarcel#include <compat/linux/linux_mib.h>
8864909Smarcel#include <compat/linux/linux_util.h>
8964909Smarcel
90118149Sdes#ifdef __i386__
91118149Sdes#include <machine/cputypes.h>
92118149Sdes#endif
93118149Sdes
9451793Smarcel#define BSD_TO_LINUX_SIGNAL(sig)	\
9551793Smarcel	(((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
9651793Smarcel
9783221Smarcelstatic unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = {
9883221Smarcel	RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK,
9983221Smarcel	RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE,
10083221Smarcel	RLIMIT_MEMLOCK, -1
10149626Smarcel};
10249626Smarcel
10383221Smarcelstruct l_sysinfo {
10483221Smarcel	l_long		uptime;		/* Seconds since boot */
10583221Smarcel	l_ulong		loads[3];	/* 1, 5, and 15 minute load averages */
106122802Ssobomax#define LINUX_SYSINFO_LOADS_SCALE 65536
10783221Smarcel	l_ulong		totalram;	/* Total usable main memory size */
10883221Smarcel	l_ulong		freeram;	/* Available memory size */
10983221Smarcel	l_ulong		sharedram;	/* Amount of shared memory */
11083221Smarcel	l_ulong		bufferram;	/* Memory used by buffers */
11183221Smarcel	l_ulong		totalswap;	/* Total swap space size */
11283221Smarcel	l_ulong		freeswap;	/* swap space still available */
11383221Smarcel	l_ushort	procs;		/* Number of current processes */
114122802Ssobomax	l_ulong		totalbig;
115122802Ssobomax	l_ulong		freebig;
116122802Ssobomax	l_uint		mem_unit;
117122802Ssobomax	char		_f[6];		/* Pads structure to 64 bytes */
11880180Spirzyk};
1199313Ssosint
12083366Sjulianlinux_sysinfo(struct thread *td, struct linux_sysinfo_args *args)
12180180Spirzyk{
12283221Smarcel	struct l_sysinfo sysinfo;
12383221Smarcel	vm_object_t object;
124117723Sphk	int i, j;
12583221Smarcel	struct timespec ts;
12680180Spirzyk
12783221Smarcel	getnanouptime(&ts);
128147816Sjhb	if (ts.tv_nsec != 0)
129147816Sjhb		ts.tv_sec++;
130147816Sjhb	sysinfo.uptime = ts.tv_sec;
13180180Spirzyk
13283221Smarcel	/* Use the information from the mib to get our load averages */
13383221Smarcel	for (i = 0; i < 3; i++)
134122802Ssobomax		sysinfo.loads[i] = averunnable.ldavg[i] *
135122802Ssobomax		    LINUX_SYSINFO_LOADS_SCALE / averunnable.fscale;
13680180Spirzyk
13783221Smarcel	sysinfo.totalram = physmem * PAGE_SIZE;
13883221Smarcel	sysinfo.freeram = sysinfo.totalram - cnt.v_wire_count * PAGE_SIZE;
13980180Spirzyk
14083221Smarcel	sysinfo.sharedram = 0;
141124082Salc	mtx_lock(&vm_object_list_mtx);
142124082Salc	TAILQ_FOREACH(object, &vm_object_list, object_list)
14383221Smarcel		if (object->shadow_count > 1)
14483221Smarcel			sysinfo.sharedram += object->resident_page_count;
145124082Salc	mtx_unlock(&vm_object_list_mtx);
14680180Spirzyk
14783221Smarcel	sysinfo.sharedram *= PAGE_SIZE;
14883221Smarcel	sysinfo.bufferram = 0;
14980180Spirzyk
150117723Sphk	swap_pager_status(&i, &j);
151117723Sphk	sysinfo.totalswap= i * PAGE_SIZE;
152117723Sphk	sysinfo.freeswap = (i - j) * PAGE_SIZE;
15380180Spirzyk
154122802Ssobomax	sysinfo.procs = nprocs;
15580180Spirzyk
156122802Ssobomax	/* The following are only present in newer Linux kernels. */
157122802Ssobomax	sysinfo.totalbig = 0;
158122802Ssobomax	sysinfo.freebig = 0;
159122802Ssobomax	sysinfo.mem_unit = 1;
160122802Ssobomax
161111797Sdes	return copyout(&sysinfo, args->info, sizeof(sysinfo));
16280180Spirzyk}
16380180Spirzyk
16480180Spirzykint
16583366Sjulianlinux_alarm(struct thread *td, struct linux_alarm_args *args)
1669313Ssos{
16783221Smarcel	struct itimerval it, old_it;
168141467Sjhb	int error;
1699313Ssos
1709313Ssos#ifdef DEBUG
17172543Sjlemon	if (ldebug(alarm))
17272543Sjlemon		printf(ARGS(alarm, "%u"), args->secs);
1739313Ssos#endif
17483221Smarcel
17583221Smarcel	if (args->secs > 100000000)
176141467Sjhb		return (EINVAL);
17783221Smarcel
17883221Smarcel	it.it_value.tv_sec = (long)args->secs;
17983221Smarcel	it.it_value.tv_usec = 0;
18083221Smarcel	it.it_interval.tv_sec = 0;
18183221Smarcel	it.it_interval.tv_usec = 0;
182141467Sjhb	error = kern_setitimer(td, ITIMER_REAL, &it, &old_it);
183141467Sjhb	if (error)
184141467Sjhb		return (error);
185141467Sjhb	if (timevalisset(&old_it.it_value)) {
18683221Smarcel		if (old_it.it_value.tv_usec != 0)
18783221Smarcel			old_it.it_value.tv_sec++;
18883366Sjulian		td->td_retval[0] = old_it.it_value.tv_sec;
18983221Smarcel	}
190141467Sjhb	return (0);
1919313Ssos}
1929313Ssos
1939313Ssosint
19483366Sjulianlinux_brk(struct thread *td, struct linux_brk_args *args)
1959313Ssos{
19683366Sjulian	struct vmspace *vm = td->td_proc->p_vmspace;
19783221Smarcel	vm_offset_t new, old;
19883221Smarcel	struct obreak_args /* {
19983221Smarcel		char * nsize;
20083221Smarcel	} */ tmp;
2019313Ssos
2029313Ssos#ifdef DEBUG
20372543Sjlemon	if (ldebug(brk))
204133845Sobrien		printf(ARGS(brk, "%p"), (void *)(uintptr_t)args->dsend);
2059313Ssos#endif
20683221Smarcel	old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
20783221Smarcel	new = (vm_offset_t)args->dsend;
20883221Smarcel	tmp.nsize = (char *) new;
20983366Sjulian	if (((caddr_t)new > vm->vm_daddr) && !obreak(td, &tmp))
21083366Sjulian		td->td_retval[0] = (long)new;
21183221Smarcel	else
21283366Sjulian		td->td_retval[0] = (long)old;
2139313Ssos
21483221Smarcel	return 0;
2159313Ssos}
2169313Ssos
217158415Snetchild#if defined(__i386__)
218158415Snetchild/* XXX: what about amd64/linux32? */
219133816Stjr
2209313Ssosint
22183366Sjulianlinux_uselib(struct thread *td, struct linux_uselib_args *args)
2229313Ssos{
22383221Smarcel	struct nameidata ni;
22483221Smarcel	struct vnode *vp;
22583221Smarcel	struct exec *a_out;
22683221Smarcel	struct vattr attr;
22783221Smarcel	vm_offset_t vmaddr;
22883221Smarcel	unsigned long file_offset;
22983221Smarcel	vm_offset_t buffer;
23083221Smarcel	unsigned long bss_size;
231102814Siedowse	char *library;
23283221Smarcel	int error;
233160555Sjhb	int locked, vfslocked;
2349313Ssos
235102814Siedowse	LCONVPATHEXIST(td, args->library, &library);
23614331Speter
2379313Ssos#ifdef DEBUG
23872543Sjlemon	if (ldebug(uselib))
239102814Siedowse		printf(ARGS(uselib, "%s"), library);
2409313Ssos#endif
2419313Ssos
24283221Smarcel	a_out = NULL;
243160555Sjhb	vfslocked = 0;
24483221Smarcel	locked = 0;
24583221Smarcel	vp = NULL;
24614114Speter
247160555Sjhb	NDINIT(&ni, LOOKUP, ISOPEN | FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
248160555Sjhb	    UIO_SYSSPACE, library, td);
24983221Smarcel	error = namei(&ni);
250102814Siedowse	LFREEPATH(library);
25183221Smarcel	if (error)
25283221Smarcel		goto cleanup;
2539313Ssos
25483221Smarcel	vp = ni.ni_vp;
255160555Sjhb	vfslocked = NDHASGIANT(&ni);
25683221Smarcel	NDFREE(&ni, NDF_ONLY_PNBUF);
2579313Ssos
25883221Smarcel	/*
25983221Smarcel	 * From here on down, we have a locked vnode that must be unlocked.
260160555Sjhb	 * XXX: The code below largely duplicates exec_check_permissions().
26183221Smarcel	 */
262160555Sjhb	locked = 1;
26314114Speter
26483221Smarcel	/* Writable? */
26583221Smarcel	if (vp->v_writecount) {
26683221Smarcel		error = ETXTBSY;
26783221Smarcel		goto cleanup;
26883221Smarcel	}
2699313Ssos
27083221Smarcel	/* Executable? */
27191406Sjhb	error = VOP_GETATTR(vp, &attr, td->td_ucred, td);
27283221Smarcel	if (error)
27383221Smarcel		goto cleanup;
2749313Ssos
27583221Smarcel	if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
27683221Smarcel	    ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) {
277160555Sjhb		/* EACCESS is what exec(2) returns. */
27883221Smarcel		error = ENOEXEC;
27983221Smarcel		goto cleanup;
28083221Smarcel	}
2819313Ssos
28283221Smarcel	/* Sensible size? */
28383221Smarcel	if (attr.va_size == 0) {
28483221Smarcel		error = ENOEXEC;
28583221Smarcel		goto cleanup;
28683221Smarcel	}
2879313Ssos
28883221Smarcel	/* Can we access it? */
28991406Sjhb	error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
29083221Smarcel	if (error)
29183221Smarcel		goto cleanup;
2929313Ssos
29398209Srwatson	/*
29498209Srwatson	 * XXX: This should use vn_open() so that it is properly authorized,
29598209Srwatson	 * and to reduce code redundancy all over the place here.
296160555Sjhb	 * XXX: Not really, it duplicates far more of exec_check_permissions()
297160555Sjhb	 * than vn_open().
29898209Srwatson	 */
299101189Srwatson#ifdef MAC
300101189Srwatson	error = mac_check_vnode_open(td->td_ucred, vp, FREAD);
301101189Srwatson	if (error)
302101189Srwatson		goto cleanup;
303101189Srwatson#endif
304118047Sphk	error = VOP_OPEN(vp, FREAD, td->td_ucred, td, -1);
30583221Smarcel	if (error)
30683221Smarcel		goto cleanup;
3079313Ssos
308103941Sjeff	/* Pull in executable header into kernel_map */
309103941Sjeff	error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
310144501Sjhb	    VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp, 0);
31183221Smarcel	if (error)
31283221Smarcel		goto cleanup;
3139313Ssos
31483221Smarcel	/* Is it a Linux binary ? */
31583221Smarcel	if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
31683221Smarcel		error = ENOEXEC;
31783221Smarcel		goto cleanup;
31883221Smarcel	}
3199313Ssos
32083221Smarcel	/*
32183221Smarcel	 * While we are here, we should REALLY do some more checks
32283221Smarcel	 */
32314114Speter
32483221Smarcel	/* Set file/virtual offset based on a.out variant. */
32583221Smarcel	switch ((int)(a_out->a_magic & 0xffff)) {
32683221Smarcel	case 0413:	/* ZMAGIC */
32783221Smarcel		file_offset = 1024;
32883221Smarcel		break;
32983221Smarcel	case 0314:	/* QMAGIC */
33083221Smarcel		file_offset = 0;
33183221Smarcel		break;
33283221Smarcel	default:
33383221Smarcel		error = ENOEXEC;
33483221Smarcel		goto cleanup;
33583221Smarcel	}
3369313Ssos
33783221Smarcel	bss_size = round_page(a_out->a_bss);
33814114Speter
33983221Smarcel	/* Check various fields in header for validity/bounds. */
34083221Smarcel	if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
34183221Smarcel		error = ENOEXEC;
34283221Smarcel		goto cleanup;
34383221Smarcel	}
34414114Speter
34583221Smarcel	/* text + data can't exceed file size */
34683221Smarcel	if (a_out->a_data + a_out->a_text > attr.va_size) {
34783221Smarcel		error = EFAULT;
34883221Smarcel		goto cleanup;
34983221Smarcel	}
35014114Speter
35183221Smarcel	/*
35283221Smarcel	 * text/data/bss must not exceed limits
35383221Smarcel	 * XXX - this is not complete. it should check current usage PLUS
35483221Smarcel	 * the resources needed by this library.
35583221Smarcel	 */
356125454Sjhb	PROC_LOCK(td->td_proc);
35784783Sps	if (a_out->a_text > maxtsiz ||
358125454Sjhb	    a_out->a_data + bss_size > lim_cur(td->td_proc, RLIMIT_DATA)) {
359125454Sjhb		PROC_UNLOCK(td->td_proc);
36083221Smarcel		error = ENOMEM;
36183221Smarcel		goto cleanup;
36283221Smarcel	}
363125454Sjhb	PROC_UNLOCK(td->td_proc);
36414114Speter
365160555Sjhb	/*
366160555Sjhb	 * Prevent more writers.
367160555Sjhb	 * XXX: Note that if any of the VM operations fail below we don't
368160555Sjhb	 * clear this flag.
369160555Sjhb	 */
370101308Sjeff	vp->v_vflag |= VV_TEXT;
37114114Speter
37283221Smarcel	/*
373160555Sjhb	 * Lock no longer needed
374160555Sjhb	 */
375160555Sjhb	locked = 0;
376160555Sjhb	VOP_UNLOCK(vp, 0, td);
377160555Sjhb	VFS_UNLOCK_GIANT(vfslocked);
378160555Sjhb
379160555Sjhb	/*
38083221Smarcel	 * Check if file_offset page aligned. Currently we cannot handle
38183221Smarcel	 * misalinged file offsets, and so we read in the entire image
38283221Smarcel	 * (what a waste).
38383221Smarcel	 */
38483221Smarcel	if (file_offset & PAGE_MASK) {
3859313Ssos#ifdef DEBUG
38683221Smarcel		printf("uselib: Non page aligned binary %lu\n", file_offset);
3879313Ssos#endif
38883221Smarcel		/* Map text+data read/write/execute */
38914114Speter
39083221Smarcel		/* a_entry is the load address and is page aligned */
39183221Smarcel		vmaddr = trunc_page(a_out->a_entry);
39214114Speter
39383221Smarcel		/* get anon user mapping, read+write+execute */
39483366Sjulian		error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
39583366Sjulian		    &vmaddr, a_out->a_text + a_out->a_data, FALSE, VM_PROT_ALL,
39683221Smarcel		    VM_PROT_ALL, 0);
39783221Smarcel		if (error)
39883221Smarcel			goto cleanup;
3999313Ssos
40083221Smarcel		/* map file into kernel_map */
40183221Smarcel		error = vm_mmap(kernel_map, &buffer,
40283221Smarcel		    round_page(a_out->a_text + a_out->a_data + file_offset),
403144501Sjhb		    VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp,
40483221Smarcel		    trunc_page(file_offset));
40583221Smarcel		if (error)
40683221Smarcel			goto cleanup;
4079313Ssos
40883221Smarcel		/* copy from kernel VM space to user space */
409133816Stjr		error = copyout(PTRIN(buffer + file_offset),
410111797Sdes		    (void *)vmaddr, a_out->a_text + a_out->a_data);
4119313Ssos
41283221Smarcel		/* release temporary kernel space */
41383221Smarcel		vm_map_remove(kernel_map, buffer, buffer +
41483221Smarcel		    round_page(a_out->a_text + a_out->a_data + file_offset));
4159313Ssos
41683221Smarcel		if (error)
41783221Smarcel			goto cleanup;
41883221Smarcel	} else {
4199313Ssos#ifdef DEBUG
42083221Smarcel		printf("uselib: Page aligned binary %lu\n", file_offset);
4219313Ssos#endif
42283221Smarcel		/*
42383221Smarcel		 * for QMAGIC, a_entry is 20 bytes beyond the load address
42483221Smarcel		 * to skip the executable header
42583221Smarcel		 */
42683221Smarcel		vmaddr = trunc_page(a_out->a_entry);
42714114Speter
42883221Smarcel		/*
42983221Smarcel		 * Map it all into the process's space as a single
43083221Smarcel		 * copy-on-write "data" segment.
43183221Smarcel		 */
43283366Sjulian		error = vm_mmap(&td->td_proc->p_vmspace->vm_map, &vmaddr,
43383221Smarcel		    a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL,
434144501Sjhb		    MAP_PRIVATE | MAP_FIXED, OBJT_VNODE, vp, file_offset);
43583221Smarcel		if (error)
43683221Smarcel			goto cleanup;
43783221Smarcel	}
4389313Ssos#ifdef DEBUG
43983221Smarcel	printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long*)vmaddr)[0],
44083221Smarcel	    ((long*)vmaddr)[1]);
4419313Ssos#endif
44283221Smarcel	if (bss_size != 0) {
44383221Smarcel		/* Calculate BSS start address */
44483221Smarcel		vmaddr = trunc_page(a_out->a_entry) + a_out->a_text +
44583221Smarcel		    a_out->a_data;
44614114Speter
44783221Smarcel		/* allocate some 'anon' space */
44883366Sjulian		error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
44983366Sjulian		    &vmaddr, bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0);
45083221Smarcel		if (error)
45183221Smarcel			goto cleanup;
45283221Smarcel	}
45314114Speter
45414114Spetercleanup:
45583221Smarcel	/* Unlock vnode if needed */
456160555Sjhb	if (locked) {
45783366Sjulian		VOP_UNLOCK(vp, 0, td);
458160555Sjhb		VFS_UNLOCK_GIANT(vfslocked);
459160555Sjhb	}
46014114Speter
46183221Smarcel	/* Release the kernel mapping. */
46283221Smarcel	if (a_out)
46383221Smarcel		vm_map_remove(kernel_map, (vm_offset_t)a_out,
46483221Smarcel		    (vm_offset_t)a_out + PAGE_SIZE);
46514114Speter
46683221Smarcel	return error;
4679313Ssos}
4689313Ssos
469158415Snetchild#endif	/* __i386__ */
470133816Stjr
4719313Ssosint
47283366Sjulianlinux_select(struct thread *td, struct linux_select_args *args)
47314331Speter{
474133747Stjr	l_timeval ltv;
47583221Smarcel	struct timeval tv0, tv1, utv, *tvp;
47683221Smarcel	int error;
47714331Speter
4789313Ssos#ifdef DEBUG
47983221Smarcel	if (ldebug(select))
48083221Smarcel		printf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds,
48183221Smarcel		    (void *)args->readfds, (void *)args->writefds,
48283221Smarcel		    (void *)args->exceptfds, (void *)args->timeout);
4839313Ssos#endif
48414331Speter
48583221Smarcel	/*
48683221Smarcel	 * Store current time for computation of the amount of
48783221Smarcel	 * time left.
48883221Smarcel	 */
48983221Smarcel	if (args->timeout) {
490133747Stjr		if ((error = copyin(args->timeout, &ltv, sizeof(ltv))))
49183221Smarcel			goto select_out;
492133747Stjr		utv.tv_sec = ltv.tv_sec;
493133747Stjr		utv.tv_usec = ltv.tv_usec;
49414331Speter#ifdef DEBUG
49583221Smarcel		if (ldebug(select))
496153775Strhodes			printf(LMSG("incoming timeout (%jd/%ld)"),
497153775Strhodes			    (intmax_t)utv.tv_sec, utv.tv_usec);
49814331Speter#endif
49983221Smarcel
50083221Smarcel		if (itimerfix(&utv)) {
50183221Smarcel			/*
50283221Smarcel			 * The timeval was invalid.  Convert it to something
50383221Smarcel			 * valid that will act as it does under Linux.
50483221Smarcel			 */
50583221Smarcel			utv.tv_sec += utv.tv_usec / 1000000;
50683221Smarcel			utv.tv_usec %= 1000000;
50783221Smarcel			if (utv.tv_usec < 0) {
50883221Smarcel				utv.tv_sec -= 1;
50983221Smarcel				utv.tv_usec += 1000000;
51083221Smarcel			}
51183221Smarcel			if (utv.tv_sec < 0)
51283221Smarcel				timevalclear(&utv);
51383221Smarcel		}
51483221Smarcel		microtime(&tv0);
515102814Siedowse		tvp = &utv;
516102814Siedowse	} else
517102814Siedowse		tvp = NULL;
51814331Speter
519102814Siedowse	error = kern_select(td, args->nfds, args->readfds, args->writefds,
520102814Siedowse	    args->exceptfds, tvp);
521102814Siedowse
52214331Speter#ifdef DEBUG
52383221Smarcel	if (ldebug(select))
52472543Sjlemon		printf(LMSG("real select returns %d"), error);
52514331Speter#endif
52683221Smarcel	if (error) {
52783221Smarcel		/*
52883221Smarcel		 * See fs/select.c in the Linux kernel.  Without this,
52983221Smarcel		 * Maelstrom doesn't work.
53083221Smarcel		 */
53183221Smarcel		if (error == ERESTART)
53283221Smarcel			error = EINTR;
53383221Smarcel		goto select_out;
53483221Smarcel	}
53514331Speter
53683221Smarcel	if (args->timeout) {
53783366Sjulian		if (td->td_retval[0]) {
53883221Smarcel			/*
53983221Smarcel			 * Compute how much time was left of the timeout,
54083221Smarcel			 * by subtracting the current time and the time
54183221Smarcel			 * before we started the call, and subtracting
54283221Smarcel			 * that result from the user-supplied value.
54383221Smarcel			 */
54483221Smarcel			microtime(&tv1);
54583221Smarcel			timevalsub(&tv1, &tv0);
54683221Smarcel			timevalsub(&utv, &tv1);
54783221Smarcel			if (utv.tv_sec < 0)
54883221Smarcel				timevalclear(&utv);
54983221Smarcel		} else
55083221Smarcel			timevalclear(&utv);
55114331Speter#ifdef DEBUG
55283221Smarcel		if (ldebug(select))
553153775Strhodes			printf(LMSG("outgoing timeout (%jd/%ld)"),
554153775Strhodes			    (intmax_t)utv.tv_sec, utv.tv_usec);
55514331Speter#endif
556133747Stjr		ltv.tv_sec = utv.tv_sec;
557133747Stjr		ltv.tv_usec = utv.tv_usec;
558133747Stjr		if ((error = copyout(&ltv, args->timeout, sizeof(ltv))))
55983221Smarcel			goto select_out;
56083221Smarcel	}
56114331Speter
56214331Speterselect_out:
56314331Speter#ifdef DEBUG
56483221Smarcel	if (ldebug(select))
56583221Smarcel		printf(LMSG("select_out -> %d"), error);
56614331Speter#endif
56783221Smarcel	return error;
5689313Ssos}
5699313Ssos
570111798Sdesint
57183366Sjulianlinux_mremap(struct thread *td, struct linux_mremap_args *args)
57237548Sjkh{
57337548Sjkh	struct munmap_args /* {
57437548Sjkh		void *addr;
57537548Sjkh		size_t len;
576111798Sdes	} */ bsd_args;
57737548Sjkh	int error = 0;
578111798Sdes
57937548Sjkh#ifdef DEBUG
58072543Sjlemon	if (ldebug(mremap))
58172543Sjlemon		printf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"),
582133845Sobrien		    (void *)(uintptr_t)args->addr,
583111798Sdes		    (unsigned long)args->old_len,
58472543Sjlemon		    (unsigned long)args->new_len,
58572543Sjlemon		    (unsigned long)args->flags);
58637548Sjkh#endif
58737548Sjkh	args->new_len = round_page(args->new_len);
58837548Sjkh	args->old_len = round_page(args->old_len);
58937548Sjkh
59037548Sjkh	if (args->new_len > args->old_len) {
59183366Sjulian		td->td_retval[0] = 0;
59237548Sjkh		return ENOMEM;
59337548Sjkh	}
59437548Sjkh
59537548Sjkh	if (args->new_len < args->old_len) {
596133816Stjr		bsd_args.addr =
597133816Stjr		    (caddr_t)((uintptr_t)args->addr + args->new_len);
59837548Sjkh		bsd_args.len = args->old_len - args->new_len;
59983366Sjulian		error = munmap(td, &bsd_args);
60037548Sjkh	}
60137548Sjkh
602102963Sbde	td->td_retval[0] = error ? 0 : (uintptr_t)args->addr;
60337548Sjkh	return error;
60437548Sjkh}
60537548Sjkh
606103652Smdodd#define LINUX_MS_ASYNC       0x0001
607103652Smdodd#define LINUX_MS_INVALIDATE  0x0002
608103652Smdodd#define LINUX_MS_SYNC        0x0004
609103652Smdodd
61014331Speterint
61183366Sjulianlinux_msync(struct thread *td, struct linux_msync_args *args)
61214331Speter{
61314331Speter	struct msync_args bsd_args;
6149313Ssos
615133816Stjr	bsd_args.addr = (caddr_t)(uintptr_t)args->addr;
616133816Stjr	bsd_args.len = (uintptr_t)args->len;
617103652Smdodd	bsd_args.flags = args->fl & ~LINUX_MS_SYNC;
61814331Speter
61983366Sjulian	return msync(td, &bsd_args);
62014331Speter}
62114331Speter
6229313Ssosint
62383366Sjulianlinux_time(struct thread *td, struct linux_time_args *args)
6249313Ssos{
62583221Smarcel	struct timeval tv;
62683221Smarcel	l_time_t tm;
62783221Smarcel	int error;
6289313Ssos
6299313Ssos#ifdef DEBUG
63072543Sjlemon	if (ldebug(time))
63172543Sjlemon		printf(ARGS(time, "*"));
6329313Ssos#endif
63383221Smarcel
63483221Smarcel	microtime(&tv);
63583221Smarcel	tm = tv.tv_sec;
636111797Sdes	if (args->tm && (error = copyout(&tm, args->tm, sizeof(tm))))
63783221Smarcel		return error;
63883366Sjulian	td->td_retval[0] = tm;
63983221Smarcel	return 0;
6409313Ssos}
6419313Ssos
64283221Smarcelstruct l_times_argv {
64383221Smarcel	l_long		tms_utime;
64483221Smarcel	l_long		tms_stime;
64583221Smarcel	l_long		tms_cutime;
64683221Smarcel	l_long		tms_cstime;
6479313Ssos};
6489313Ssos
64914381Speter#define CLK_TCK 100	/* Linux uses 100 */
65074701Sgallatin
65114381Speter#define CONVTCK(r)	(r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
65214381Speter
6539313Ssosint
65483366Sjulianlinux_times(struct thread *td, struct linux_times_args *args)
6559313Ssos{
656136152Sjhb	struct timeval tv, utime, stime, cutime, cstime;
65783221Smarcel	struct l_times_argv tms;
658136152Sjhb	struct proc *p;
65983221Smarcel	int error;
6609313Ssos
6619313Ssos#ifdef DEBUG
66272543Sjlemon	if (ldebug(times))
66372543Sjlemon		printf(ARGS(times, "*"));
6649313Ssos#endif
66514381Speter
666159896Snetchild	if (args->buf != NULL) {
667159896Snetchild		p = td->td_proc;
668159896Snetchild		PROC_LOCK(p);
669159896Snetchild		calcru(p, &utime, &stime);
670159896Snetchild		calccru(p, &cutime, &cstime);
671159896Snetchild		PROC_UNLOCK(p);
67214381Speter
673159896Snetchild		tms.tms_utime = CONVTCK(utime);
674159896Snetchild		tms.tms_stime = CONVTCK(stime);
67514381Speter
676159896Snetchild		tms.tms_cutime = CONVTCK(cutime);
677159896Snetchild		tms.tms_cstime = CONVTCK(cstime);
67814381Speter
679159896Snetchild		if ((error = copyout(&tms, args->buf, sizeof(tms))))
680159896Snetchild			return error;
681159896Snetchild	}
68283221Smarcel
68383221Smarcel	microuptime(&tv);
68483366Sjulian	td->td_retval[0] = (int)CONVTCK(tv);
68583221Smarcel	return 0;
6869313Ssos}
6879313Ssos
6889313Ssosint
68983366Sjulianlinux_newuname(struct thread *td, struct linux_newuname_args *args)
6909313Ssos{
69183221Smarcel	struct l_new_utsname utsname;
69287275Srwatson	char osname[LINUX_MAX_UTSNAME];
69387275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
694118149Sdes	char *p;
6959313Ssos
6969313Ssos#ifdef DEBUG
69772543Sjlemon	if (ldebug(newuname))
69872543Sjlemon		printf(ARGS(newuname, "*"));
6999313Ssos#endif
70050345Smarcel
701112206Sjhb	linux_get_osname(td, osname);
702112206Sjhb	linux_get_osrelease(td, osrelease);
70350465Smarcel
70483221Smarcel	bzero(&utsname, sizeof(utsname));
705105359Srobert	strlcpy(utsname.sysname, osname, LINUX_MAX_UTSNAME);
706105359Srobert	getcredhostname(td->td_ucred, utsname.nodename, LINUX_MAX_UTSNAME);
707105359Srobert	strlcpy(utsname.release, osrelease, LINUX_MAX_UTSNAME);
708105359Srobert	strlcpy(utsname.version, version, LINUX_MAX_UTSNAME);
709118149Sdes	for (p = utsname.version; *p != '\0'; ++p)
710118149Sdes		if (*p == '\n') {
711118149Sdes			*p = '\0';
712118149Sdes			break;
713118149Sdes		}
714118149Sdes#ifdef __i386__
715118149Sdes	{
716118149Sdes		const char *class;
717118149Sdes		switch (cpu_class) {
718118149Sdes		case CPUCLASS_686:
719118149Sdes			class = "i686";
720118149Sdes			break;
721118149Sdes		case CPUCLASS_586:
722118149Sdes			class = "i586";
723118149Sdes			break;
724118149Sdes		case CPUCLASS_486:
725118149Sdes			class = "i486";
726118149Sdes			break;
727118149Sdes		default:
728118149Sdes			class = "i386";
729118149Sdes		}
730118149Sdes		strlcpy(utsname.machine, class, LINUX_MAX_UTSNAME);
731118149Sdes	}
732140213Sobrien#elif defined(__amd64__)	/* XXX: Linux can change 'personality'. */
733140213Sobrien#ifdef COMPAT_LINUX32
734140213Sobrien	strlcpy(utsname.machine, "i686", LINUX_MAX_UTSNAME);
735118149Sdes#else
736140213Sobrien	strlcpy(utsname.machine, "x86_64", LINUX_MAX_UTSNAME);
737140213Sobrien#endif /* COMPAT_LINUX32 */
738140213Sobrien#else /* something other than i386 or amd64 - assume we and Linux agree */
739105359Srobert	strlcpy(utsname.machine, machine, LINUX_MAX_UTSNAME);
740140213Sobrien#endif /* __i386__ */
741105359Srobert	strlcpy(utsname.domainname, domainname, LINUX_MAX_UTSNAME);
74250345Smarcel
743111797Sdes	return (copyout(&utsname, args->buf, sizeof(utsname)));
7449313Ssos}
7459313Ssos
746140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
74783221Smarcelstruct l_utimbuf {
74883221Smarcel	l_time_t l_actime;
74983221Smarcel	l_time_t l_modtime;
75014381Speter};
7519313Ssos
7529313Ssosint
75383366Sjulianlinux_utime(struct thread *td, struct linux_utime_args *args)
7549313Ssos{
75583221Smarcel	struct timeval tv[2], *tvp;
75683221Smarcel	struct l_utimbuf lut;
757102814Siedowse	char *fname;
75883221Smarcel	int error;
7599313Ssos
760102814Siedowse	LCONVPATHEXIST(td, args->fname, &fname);
76114331Speter
7629313Ssos#ifdef DEBUG
76372543Sjlemon	if (ldebug(utime))
764102814Siedowse		printf(ARGS(utime, "%s, *"), fname);
7659313Ssos#endif
76614381Speter
76783221Smarcel	if (args->times) {
768111797Sdes		if ((error = copyin(args->times, &lut, sizeof lut))) {
769102814Siedowse			LFREEPATH(fname);
77083221Smarcel			return error;
771102814Siedowse		}
77283221Smarcel		tv[0].tv_sec = lut.l_actime;
77383221Smarcel		tv[0].tv_usec = 0;
77483221Smarcel		tv[1].tv_sec = lut.l_modtime;
77583221Smarcel		tv[1].tv_usec = 0;
776102814Siedowse		tvp = tv;
77783221Smarcel	} else
778102814Siedowse		tvp = NULL;
77983221Smarcel
780102814Siedowse	error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE);
781102814Siedowse	LFREEPATH(fname);
782102814Siedowse	return (error);
7839313Ssos}
784133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
7859313Ssos
78644384Sjulian#define __WCLONE 0x80000000
78744384Sjulian
7889313Ssosint
78983366Sjulianlinux_waitpid(struct thread *td, struct linux_waitpid_args *args)
7909313Ssos{
791127140Sjhb	int error, options, tmpstat;
7929313Ssos
7939313Ssos#ifdef DEBUG
79472543Sjlemon	if (ldebug(waitpid))
79572543Sjlemon		printf(ARGS(waitpid, "%d, %p, %d"),
79672543Sjlemon		    args->pid, (void *)args->status, args->options);
7979313Ssos#endif
7989313Ssos
799127140Sjhb	options = (args->options & (WNOHANG | WUNTRACED));
80083221Smarcel	/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
80183221Smarcel	if (args->options & __WCLONE)
802127140Sjhb		options |= WLINUXCLONE;
80343208Sjulian
804127140Sjhb	error = kern_wait(td, args->pid, &tmpstat, options, NULL);
805127140Sjhb	if (error)
80683221Smarcel		return error;
80783221Smarcel
80883221Smarcel	if (args->status) {
80983221Smarcel		tmpstat &= 0xffff;
81083221Smarcel		if (WIFSIGNALED(tmpstat))
81183221Smarcel			tmpstat = (tmpstat & 0xffffff80) |
81283221Smarcel			    BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
81383221Smarcel		else if (WIFSTOPPED(tmpstat))
81483221Smarcel			tmpstat = (tmpstat & 0xffff00ff) |
81583221Smarcel			    (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
816111797Sdes		return copyout(&tmpstat, args->status, sizeof(int));
81783221Smarcel	}
81883221Smarcel
81914331Speter	return 0;
8209313Ssos}
8219313Ssos
82214331Speterint
82383366Sjulianlinux_wait4(struct thread *td, struct linux_wait4_args *args)
8249313Ssos{
825127140Sjhb	int error, options, tmpstat;
826136152Sjhb	struct rusage ru, *rup;
827113613Sjhb	struct proc *p;
8289313Ssos
8299313Ssos#ifdef DEBUG
83072543Sjlemon	if (ldebug(wait4))
83172543Sjlemon		printf(ARGS(wait4, "%d, %p, %d, %p"),
83272543Sjlemon		    args->pid, (void *)args->status, args->options,
83372543Sjlemon		    (void *)args->rusage);
8349313Ssos#endif
8359313Ssos
836127140Sjhb	options = (args->options & (WNOHANG | WUNTRACED));
83783221Smarcel	/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
83883221Smarcel	if (args->options & __WCLONE)
839127140Sjhb		options |= WLINUXCLONE;
84014331Speter
841136152Sjhb	if (args->rusage != NULL)
842136152Sjhb		rup = &ru;
843136152Sjhb	else
844136152Sjhb		rup = NULL;
845136152Sjhb	error = kern_wait(td, args->pid, &tmpstat, options, rup);
846127140Sjhb	if (error)
84783221Smarcel		return error;
84814331Speter
849113613Sjhb	p = td->td_proc;
850113613Sjhb	PROC_LOCK(p);
851151316Sdavidxu	sigqueue_delete(&p->p_sigqueue, SIGCHLD);
852113613Sjhb	PROC_UNLOCK(p);
85383221Smarcel
85483221Smarcel	if (args->status) {
85583221Smarcel		tmpstat &= 0xffff;
85683221Smarcel		if (WIFSIGNALED(tmpstat))
85783221Smarcel			tmpstat = (tmpstat & 0xffffff80) |
85883221Smarcel			    BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
85983221Smarcel		else if (WIFSTOPPED(tmpstat))
86083221Smarcel			tmpstat = (tmpstat & 0xffff00ff) |
86183221Smarcel			    (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
862127140Sjhb		error = copyout(&tmpstat, args->status, sizeof(int));
86383221Smarcel	}
864127140Sjhb	if (args->rusage != NULL && error == 0)
865127140Sjhb		error = copyout(&ru, args->rusage, sizeof(ru));
86683221Smarcel
867127140Sjhb	return (error);
8689313Ssos}
86913420Ssos
87014331Speterint
87183366Sjulianlinux_mknod(struct thread *td, struct linux_mknod_args *args)
87213420Ssos{
873102814Siedowse	char *path;
874102814Siedowse	int error;
87514331Speter
876102814Siedowse	LCONVPATHCREAT(td, args->path, &path);
87714331Speter
87814331Speter#ifdef DEBUG
87972543Sjlemon	if (ldebug(mknod))
880102814Siedowse		printf(ARGS(mknod, "%s, %d, %d"), path, args->mode, args->dev);
88114331Speter#endif
88214331Speter
883102814Siedowse	if (args->mode & S_IFIFO)
884102814Siedowse		error = kern_mkfifo(td, path, UIO_SYSSPACE, args->mode);
885102814Siedowse	else
886102814Siedowse		error = kern_mknod(td, path, UIO_SYSSPACE, args->mode,
887102814Siedowse		    args->dev);
888102814Siedowse	LFREEPATH(path);
889102814Siedowse	return (error);
89013420Ssos}
89114331Speter
89214331Speter/*
89314331Speter * UGH! This is just about the dumbest idea I've ever heard!!
89414331Speter */
89514331Speterint
89683366Sjulianlinux_personality(struct thread *td, struct linux_personality_args *args)
89714331Speter{
89814331Speter#ifdef DEBUG
89972543Sjlemon	if (ldebug(personality))
900113579Sjhb		printf(ARGS(personality, "%lu"), (unsigned long)args->per);
90114331Speter#endif
90214331Speter	if (args->per != 0)
90314331Speter		return EINVAL;
90414331Speter
90514331Speter	/* Yes Jim, it's still a Linux... */
90683366Sjulian	td->td_retval[0] = 0;
90714331Speter	return 0;
90814331Speter}
90914331Speter
910133749Stjrstruct l_itimerval {
911133749Stjr	l_timeval it_interval;
912133749Stjr	l_timeval it_value;
913133749Stjr};
914133749Stjr
915140832Ssobomax#define	B2L_ITIMERVAL(bip, lip) 					\
916140832Ssobomax	(bip)->it_interval.tv_sec = (lip)->it_interval.tv_sec;		\
917140832Ssobomax	(bip)->it_interval.tv_usec = (lip)->it_interval.tv_usec;	\
918140832Ssobomax	(bip)->it_value.tv_sec = (lip)->it_value.tv_sec;		\
919140832Ssobomax	(bip)->it_value.tv_usec = (lip)->it_value.tv_usec;
920140832Ssobomax
92114331Speterint
922133749Stjrlinux_setitimer(struct thread *td, struct linux_setitimer_args *uap)
92314331Speter{
92414331Speter	int error;
925140832Ssobomax	struct l_itimerval ls;
926140832Ssobomax	struct itimerval aitv, oitv;
92714331Speter
92814331Speter#ifdef DEBUG
92972543Sjlemon	if (ldebug(setitimer))
93072543Sjlemon		printf(ARGS(setitimer, "%p, %p"),
931133840Sobrien		    (void *)uap->itv, (void *)uap->oitv);
93214331Speter#endif
933140832Ssobomax
934140832Ssobomax	if (uap->itv == NULL) {
935140832Ssobomax		uap->itv = uap->oitv;
936140832Ssobomax		return (linux_getitimer(td, (struct linux_getitimer_args *)uap));
93714331Speter	}
938140832Ssobomax
939140832Ssobomax	error = copyin(uap->itv, &ls, sizeof(ls));
940133749Stjr	if (error != 0)
941133749Stjr		return (error);
942140832Ssobomax	B2L_ITIMERVAL(&aitv, &ls);
943140832Ssobomax#ifdef DEBUG
944140832Ssobomax	if (ldebug(setitimer)) {
945153775Strhodes		printf("setitimer: value: sec: %jd, usec: %ld\n",
946153775Strhodes		    (intmax_t)aitv.it_value.tv_sec, aitv.it_value.tv_usec);
947153775Strhodes		printf("setitimer: interval: sec: %jd, usec: %ld\n",
948153775Strhodes		    (intmax_t)aitv.it_interval.tv_sec, aitv.it_interval.tv_usec);
949133749Stjr	}
950140832Ssobomax#endif
951140832Ssobomax	error = kern_setitimer(td, uap->which, &aitv, &oitv);
952140832Ssobomax	if (error != 0 || uap->oitv == NULL)
953140832Ssobomax		return (error);
954140832Ssobomax	B2L_ITIMERVAL(&ls, &oitv);
955140832Ssobomax
956140832Ssobomax	return (copyout(&ls, uap->oitv, sizeof(ls)));
95714331Speter}
95814331Speter
95914331Speterint
960133749Stjrlinux_getitimer(struct thread *td, struct linux_getitimer_args *uap)
96114331Speter{
962133749Stjr	int error;
963140832Ssobomax	struct l_itimerval ls;
964140832Ssobomax	struct itimerval aitv;
965133749Stjr
96614331Speter#ifdef DEBUG
96772543Sjlemon	if (ldebug(getitimer))
968133840Sobrien		printf(ARGS(getitimer, "%p"), (void *)uap->itv);
96914331Speter#endif
970140832Ssobomax	error = kern_getitimer(td, uap->which, &aitv);
971133749Stjr	if (error != 0)
972133749Stjr		return (error);
973140832Ssobomax	B2L_ITIMERVAL(&ls, &aitv);
974140832Ssobomax	return (copyout(&ls, uap->itv, sizeof(ls)));
97514331Speter}
97630837Skato
97730837Skatoint
97883366Sjulianlinux_nice(struct thread *td, struct linux_nice_args *args)
97930837Skato{
98030837Skato	struct setpriority_args	bsd_args;
98130837Skato
98230837Skato	bsd_args.which = PRIO_PROCESS;
98330837Skato	bsd_args.who = 0;	/* current process */
98430837Skato	bsd_args.prio = args->inc;
98583366Sjulian	return setpriority(td, &bsd_args);
98630837Skato}
98730837Skato
98842185Ssosint
98983366Sjulianlinux_setgroups(struct thread *td, struct linux_setgroups_args *args)
99042185Ssos{
99177183Srwatson	struct ucred *newcred, *oldcred;
99283221Smarcel	l_gid_t linux_gidset[NGROUPS];
99350350Smarcel	gid_t *bsd_gidset;
99450350Smarcel	int ngrp, error;
99594621Sjhb	struct proc *p;
99642185Ssos
99783221Smarcel	ngrp = args->gidsetsize;
998121302Stjr	if (ngrp < 0 || ngrp >= NGROUPS)
99994621Sjhb		return (EINVAL);
1000111797Sdes	error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t));
100194621Sjhb	if (error)
100294621Sjhb		return (error);
100394621Sjhb	newcred = crget();
100494621Sjhb	p = td->td_proc;
100594621Sjhb	PROC_LOCK(p);
100694621Sjhb	oldcred = p->p_ucred;
100742185Ssos
100850350Smarcel	/*
100950350Smarcel	 * cr_groups[0] holds egid. Setting the whole set from
101050350Smarcel	 * the supplied set will cause egid to be changed too.
101150350Smarcel	 * Keep cr_groups[0] unchanged to prevent that.
101250350Smarcel	 */
101342185Ssos
1014132653Scperciva	if ((error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) {
101594621Sjhb		PROC_UNLOCK(p);
101694621Sjhb		crfree(newcred);
101750350Smarcel		return (error);
101894621Sjhb	}
101942185Ssos
102094621Sjhb	crcopy(newcred, oldcred);
102150350Smarcel	if (ngrp > 0) {
102277183Srwatson		newcred->cr_ngroups = ngrp + 1;
102350350Smarcel
102477183Srwatson		bsd_gidset = newcred->cr_groups;
102550350Smarcel		ngrp--;
102650350Smarcel		while (ngrp >= 0) {
102750350Smarcel			bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
102850350Smarcel			ngrp--;
102950350Smarcel		}
103050350Smarcel	}
103150350Smarcel	else
103277183Srwatson		newcred->cr_ngroups = 1;
103350350Smarcel
103494621Sjhb	setsugid(p);
103594621Sjhb	p->p_ucred = newcred;
103694621Sjhb	PROC_UNLOCK(p);
103777183Srwatson	crfree(oldcred);
103850350Smarcel	return (0);
103942185Ssos}
104042185Ssos
104142185Ssosint
104283366Sjulianlinux_getgroups(struct thread *td, struct linux_getgroups_args *args)
104342185Ssos{
104477183Srwatson	struct ucred *cred;
104583221Smarcel	l_gid_t linux_gidset[NGROUPS];
104650350Smarcel	gid_t *bsd_gidset;
104750350Smarcel	int bsd_gidsetsz, ngrp, error;
104842185Ssos
104994454Sjhb	cred = td->td_ucred;
105077183Srwatson	bsd_gidset = cred->cr_groups;
105177183Srwatson	bsd_gidsetsz = cred->cr_ngroups - 1;
105242185Ssos
105350350Smarcel	/*
105450350Smarcel	 * cr_groups[0] holds egid. Returning the whole set
105550350Smarcel	 * here will cause a duplicate. Exclude cr_groups[0]
105650350Smarcel	 * to prevent that.
105750350Smarcel	 */
105842185Ssos
105983221Smarcel	if ((ngrp = args->gidsetsize) == 0) {
106083366Sjulian		td->td_retval[0] = bsd_gidsetsz;
106150350Smarcel		return (0);
106250350Smarcel	}
106342185Ssos
106450546Smarcel	if (ngrp < bsd_gidsetsz)
106550350Smarcel		return (EINVAL);
106642185Ssos
106750546Smarcel	ngrp = 0;
106850350Smarcel	while (ngrp < bsd_gidsetsz) {
106950546Smarcel		linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
107050350Smarcel		ngrp++;
107150350Smarcel	}
107250350Smarcel
1073111797Sdes	if ((error = copyout(linux_gidset, args->grouplist,
107483221Smarcel	    ngrp * sizeof(l_gid_t))))
107550350Smarcel		return (error);
107650350Smarcel
107783366Sjulian	td->td_retval[0] = ngrp;
107850350Smarcel	return (0);
107942185Ssos}
108049626Smarcel
108149626Smarcelint
108283366Sjulianlinux_setrlimit(struct thread *td, struct linux_setrlimit_args *args)
108349626Smarcel{
1084102814Siedowse	struct rlimit bsd_rlim;
108583221Smarcel	struct l_rlimit rlim;
1086102814Siedowse	u_int which;
108765099Smarcel	int error;
108849842Smarcel
108949626Smarcel#ifdef DEBUG
109072543Sjlemon	if (ldebug(setrlimit))
109172543Sjlemon		printf(ARGS(setrlimit, "%d, %p"),
109283221Smarcel		    args->resource, (void *)args->rlim);
109349626Smarcel#endif
109449626Smarcel
109583221Smarcel	if (args->resource >= LINUX_RLIM_NLIMITS)
109665099Smarcel		return (EINVAL);
109749626Smarcel
1098102814Siedowse	which = linux_to_bsd_resource[args->resource];
1099102814Siedowse	if (which == -1)
110065099Smarcel		return (EINVAL);
110149626Smarcel
1102111797Sdes	error = copyin(args->rlim, &rlim, sizeof(rlim));
110365099Smarcel	if (error)
110465099Smarcel		return (error);
110549626Smarcel
1106102814Siedowse	bsd_rlim.rlim_cur = (rlim_t)rlim.rlim_cur;
1107102814Siedowse	bsd_rlim.rlim_max = (rlim_t)rlim.rlim_max;
1108125454Sjhb	return (kern_setrlimit(td, which, &bsd_rlim));
110949626Smarcel}
111049626Smarcel
111149626Smarcelint
111283366Sjulianlinux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args)
111349626Smarcel{
111483221Smarcel	struct l_rlimit rlim;
1115102814Siedowse	struct proc *p = td->td_proc;
1116125454Sjhb	struct rlimit bsd_rlim;
1117102814Siedowse	u_int which;
111849842Smarcel
111949626Smarcel#ifdef DEBUG
112083221Smarcel	if (ldebug(old_getrlimit))
112183221Smarcel		printf(ARGS(old_getrlimit, "%d, %p"),
112283221Smarcel		    args->resource, (void *)args->rlim);
112349626Smarcel#endif
112449626Smarcel
112583221Smarcel	if (args->resource >= LINUX_RLIM_NLIMITS)
112665099Smarcel		return (EINVAL);
112749626Smarcel
1128102814Siedowse	which = linux_to_bsd_resource[args->resource];
1129102814Siedowse	if (which == -1)
113065099Smarcel		return (EINVAL);
113149626Smarcel
1132125454Sjhb	PROC_LOCK(p);
1133125454Sjhb	lim_rlimit(p, which, &bsd_rlim);
1134125454Sjhb	PROC_UNLOCK(p);
1135125454Sjhb
1136140214Sobrien#ifdef COMPAT_LINUX32
1137140214Sobrien	rlim.rlim_cur = (unsigned int)bsd_rlim.rlim_cur;
1138140214Sobrien	if (rlim.rlim_cur == UINT_MAX)
1139140214Sobrien		rlim.rlim_cur = INT_MAX;
1140140214Sobrien	rlim.rlim_max = (unsigned int)bsd_rlim.rlim_max;
1141140214Sobrien	if (rlim.rlim_max == UINT_MAX)
1142140214Sobrien		rlim.rlim_max = INT_MAX;
1143140214Sobrien#else
1144125454Sjhb	rlim.rlim_cur = (unsigned long)bsd_rlim.rlim_cur;
114565106Smarcel	if (rlim.rlim_cur == ULONG_MAX)
114665106Smarcel		rlim.rlim_cur = LONG_MAX;
1147125454Sjhb	rlim.rlim_max = (unsigned long)bsd_rlim.rlim_max;
114865106Smarcel	if (rlim.rlim_max == ULONG_MAX)
114965106Smarcel		rlim.rlim_max = LONG_MAX;
1150133816Stjr#endif
1151111797Sdes	return (copyout(&rlim, args->rlim, sizeof(rlim)));
115249626Smarcel}
115383221Smarcel
115483221Smarcelint
115583366Sjulianlinux_getrlimit(struct thread *td, struct linux_getrlimit_args *args)
115683221Smarcel{
115783221Smarcel	struct l_rlimit rlim;
1158102814Siedowse	struct proc *p = td->td_proc;
1159125454Sjhb	struct rlimit bsd_rlim;
1160102814Siedowse	u_int which;
116183221Smarcel
116283221Smarcel#ifdef DEBUG
116383221Smarcel	if (ldebug(getrlimit))
116483221Smarcel		printf(ARGS(getrlimit, "%d, %p"),
116583221Smarcel		    args->resource, (void *)args->rlim);
116683221Smarcel#endif
116783221Smarcel
116883221Smarcel	if (args->resource >= LINUX_RLIM_NLIMITS)
116983221Smarcel		return (EINVAL);
117083221Smarcel
1171102814Siedowse	which = linux_to_bsd_resource[args->resource];
1172102814Siedowse	if (which == -1)
117383221Smarcel		return (EINVAL);
117483221Smarcel
1175125454Sjhb	PROC_LOCK(p);
1176125454Sjhb	lim_rlimit(p, which, &bsd_rlim);
1177125454Sjhb	PROC_UNLOCK(p);
1178125454Sjhb
1179125454Sjhb	rlim.rlim_cur = (l_ulong)bsd_rlim.rlim_cur;
1180125454Sjhb	rlim.rlim_max = (l_ulong)bsd_rlim.rlim_max;
1181111797Sdes	return (copyout(&rlim, args->rlim, sizeof(rlim)));
118283221Smarcel}
118349849Smarcel
118449849Smarcelint
118583366Sjulianlinux_sched_setscheduler(struct thread *td,
118683221Smarcel    struct linux_sched_setscheduler_args *args)
118749849Smarcel{
118849849Smarcel	struct sched_setscheduler_args bsd;
118949849Smarcel
119049849Smarcel#ifdef DEBUG
119172543Sjlemon	if (ldebug(sched_setscheduler))
119272543Sjlemon		printf(ARGS(sched_setscheduler, "%d, %d, %p"),
119383221Smarcel		    args->pid, args->policy, (const void *)args->param);
119449849Smarcel#endif
119549849Smarcel
119683221Smarcel	switch (args->policy) {
119749849Smarcel	case LINUX_SCHED_OTHER:
119849849Smarcel		bsd.policy = SCHED_OTHER;
119949849Smarcel		break;
120049849Smarcel	case LINUX_SCHED_FIFO:
120149849Smarcel		bsd.policy = SCHED_FIFO;
120249849Smarcel		break;
120349849Smarcel	case LINUX_SCHED_RR:
120449849Smarcel		bsd.policy = SCHED_RR;
120549849Smarcel		break;
120649849Smarcel	default:
120749849Smarcel		return EINVAL;
120849849Smarcel	}
120949849Smarcel
121083221Smarcel	bsd.pid = args->pid;
121183221Smarcel	bsd.param = (struct sched_param *)args->param;
121283366Sjulian	return sched_setscheduler(td, &bsd);
121349849Smarcel}
121449849Smarcel
121549849Smarcelint
121683366Sjulianlinux_sched_getscheduler(struct thread *td,
121783221Smarcel    struct linux_sched_getscheduler_args *args)
121849849Smarcel{
121949849Smarcel	struct sched_getscheduler_args bsd;
122049849Smarcel	int error;
122149849Smarcel
122249849Smarcel#ifdef DEBUG
122372543Sjlemon	if (ldebug(sched_getscheduler))
122483221Smarcel		printf(ARGS(sched_getscheduler, "%d"), args->pid);
122549849Smarcel#endif
122649849Smarcel
122783221Smarcel	bsd.pid = args->pid;
122883366Sjulian	error = sched_getscheduler(td, &bsd);
122949849Smarcel
123083366Sjulian	switch (td->td_retval[0]) {
123149849Smarcel	case SCHED_OTHER:
123283366Sjulian		td->td_retval[0] = LINUX_SCHED_OTHER;
123349849Smarcel		break;
123449849Smarcel	case SCHED_FIFO:
123583366Sjulian		td->td_retval[0] = LINUX_SCHED_FIFO;
123649849Smarcel		break;
123749849Smarcel	case SCHED_RR:
123883366Sjulian		td->td_retval[0] = LINUX_SCHED_RR;
123949849Smarcel		break;
124049849Smarcel	}
124149849Smarcel
124249849Smarcel	return error;
124349849Smarcel}
124472538Sjlemon
124575053Salcint
124683366Sjulianlinux_sched_get_priority_max(struct thread *td,
124783221Smarcel    struct linux_sched_get_priority_max_args *args)
124875053Salc{
124975053Salc	struct sched_get_priority_max_args bsd;
125075053Salc
125175053Salc#ifdef DEBUG
125275053Salc	if (ldebug(sched_get_priority_max))
125383221Smarcel		printf(ARGS(sched_get_priority_max, "%d"), args->policy);
125475053Salc#endif
125575053Salc
125683221Smarcel	switch (args->policy) {
125775053Salc	case LINUX_SCHED_OTHER:
125875053Salc		bsd.policy = SCHED_OTHER;
125975053Salc		break;
126075053Salc	case LINUX_SCHED_FIFO:
126175053Salc		bsd.policy = SCHED_FIFO;
126275053Salc		break;
126375053Salc	case LINUX_SCHED_RR:
126475053Salc		bsd.policy = SCHED_RR;
126575053Salc		break;
126675053Salc	default:
126775053Salc		return EINVAL;
126875053Salc	}
126983366Sjulian	return sched_get_priority_max(td, &bsd);
127075053Salc}
127175053Salc
127275053Salcint
127383366Sjulianlinux_sched_get_priority_min(struct thread *td,
127483221Smarcel    struct linux_sched_get_priority_min_args *args)
127575053Salc{
127675053Salc	struct sched_get_priority_min_args bsd;
127775053Salc
127875053Salc#ifdef DEBUG
127975053Salc	if (ldebug(sched_get_priority_min))
128083221Smarcel		printf(ARGS(sched_get_priority_min, "%d"), args->policy);
128175053Salc#endif
128275053Salc
128383221Smarcel	switch (args->policy) {
128475053Salc	case LINUX_SCHED_OTHER:
128575053Salc		bsd.policy = SCHED_OTHER;
128675053Salc		break;
128775053Salc	case LINUX_SCHED_FIFO:
128875053Salc		bsd.policy = SCHED_FIFO;
128975053Salc		break;
129075053Salc	case LINUX_SCHED_RR:
129175053Salc		bsd.policy = SCHED_RR;
129275053Salc		break;
129375053Salc	default:
129475053Salc		return EINVAL;
129575053Salc	}
129683366Sjulian	return sched_get_priority_min(td, &bsd);
129775053Salc}
129875053Salc
129972538Sjlemon#define REBOOT_CAD_ON	0x89abcdef
130072538Sjlemon#define REBOOT_CAD_OFF	0
130172538Sjlemon#define REBOOT_HALT	0xcdef0123
130272538Sjlemon
130372538Sjlemonint
130483366Sjulianlinux_reboot(struct thread *td, struct linux_reboot_args *args)
130572538Sjlemon{
130672538Sjlemon	struct reboot_args bsd_args;
130772538Sjlemon
130872538Sjlemon#ifdef DEBUG
130972538Sjlemon	if (ldebug(reboot))
131083221Smarcel		printf(ARGS(reboot, "0x%x"), args->cmd);
131172538Sjlemon#endif
131283221Smarcel	if (args->cmd == REBOOT_CAD_ON || args->cmd == REBOOT_CAD_OFF)
131372538Sjlemon		return (0);
131483221Smarcel	bsd_args.opt = (args->cmd == REBOOT_HALT) ? RB_HALT : 0;
131583366Sjulian	return (reboot(td, &bsd_args));
131672538Sjlemon}
131783221Smarcel
131889717Sgallatin
131983221Smarcel/*
132083221Smarcel * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify
1321130344Sphk * td->td_retval[1] when COMPAT_43 is defined. This
132283221Smarcel * globbers registers that are assumed to be preserved. The following
132383221Smarcel * lightweight syscalls fixes this. See also linux_getgid16() and
132483221Smarcel * linux_getuid16() in linux_uid16.c.
132583221Smarcel *
132683221Smarcel * linux_getpid() - MP SAFE
132783221Smarcel * linux_getgid() - MP SAFE
132883221Smarcel * linux_getuid() - MP SAFE
132983221Smarcel */
133083221Smarcel
133183221Smarcelint
133283366Sjulianlinux_getpid(struct thread *td, struct linux_getpid_args *args)
133383221Smarcel{
1334161317Snetchild#ifdef __i386__
1335161310Snetchild   	struct linux_emuldata *em;
1336161420Snetchild	char osrel[LINUX_MAX_UTSNAME];
133783366Sjulian
1338161420Snetchild	linux_get_osrelease(td, osrel);
1339161420Snetchild	if (strlen(osrel) >= 3 && osrel[2] == '6') {
1340161420Snetchild   	   	em = em_find(td->td_proc, EMUL_UNLOCKED);
1341161420Snetchild		KASSERT(em != NULL, ("getpid: emuldata not found.\n"));
1342161420Snetchild   		td->td_retval[0] = em->shared->group_pid;
1343161420Snetchild		EMUL_UNLOCK(&emul_lock);
1344161420Snetchild	} else {
1345161420Snetchild	   	PROC_LOCK(td->td_proc);
1346161420Snetchild   	   	td->td_retval[0] = td->td_proc->p_pid;
1347161420Snetchild	   	PROC_UNLOCK(td->td_proc);
1348161420Snetchild	}
1349161317Snetchild#else
1350161420Snetchild	PROC_LOCK(td->td_proc);
1351161317Snetchild	td->td_retval[0] = td->td_proc->p_pid;
1352161420Snetchild	PROC_UNLOCK(td->td_proc);
1353161317Snetchild#endif
1354161310Snetchild	return (0);
1355161310Snetchild}
1356161310Snetchild
1357161310Snetchildint
1358161310Snetchildlinux_gettid(struct thread *td, struct linux_gettid_args *args)
1359161310Snetchild{
1360161310Snetchild#ifdef DEBUG
1361161310Snetchild	if (ldebug(gettid))
1362161310Snetchild		printf(ARGS(gettid, ""));
1363161310Snetchild#endif
1364161310Snetchild
136583366Sjulian	td->td_retval[0] = td->td_proc->p_pid;
136683221Smarcel	return (0);
136783221Smarcel}
136883221Smarcel
1369161310Snetchild
137083221Smarcelint
1371161310Snetchildlinux_getppid(struct thread *td, struct linux_getppid_args *args)
1372161310Snetchild{
1373161420Snetchild#ifdef __i386__
1374161310Snetchild   	struct linux_emuldata *em;
1375161310Snetchild	struct proc *p, *pp;
1376161420Snetchild	char osrel[LINUX_MAX_UTSNAME];
1377161310Snetchild
1378161420Snetchild	linux_get_osrelease(td, osrel);
1379161420Snetchild	if (strlen(osrel) >= 3 && osrel[2] != '6') {
1380161420Snetchild	   	PROC_LOCK(td->td_proc);
1381161420Snetchild	   	td->td_retval[0] = td->td_proc->p_pptr->p_pid;
1382161420Snetchild	   	PROC_UNLOCK(td->td_proc);
1383161420Snetchild		return (0);
1384161420Snetchild	}
1385161420Snetchild
1386161310Snetchild	em = em_find(td->td_proc, EMUL_UNLOCKED);
1387161310Snetchild
1388161310Snetchild	KASSERT(em != NULL, ("getppid: process emuldata not found.\n"));
1389161310Snetchild
1390161310Snetchild	/* find the group leader */
1391161310Snetchild	p = pfind(em->shared->group_pid);
1392161310Snetchild
1393161310Snetchild	if (p == NULL) {
1394161310Snetchild#ifdef DEBUG
1395161310Snetchild	   	printf(LMSG("parent process not found.\n"));
1396161310Snetchild#endif
1397161310Snetchild		return (0);
1398161310Snetchild	}
1399161310Snetchild
1400161310Snetchild	pp = p->p_pptr;		/* switch to parent */
1401161310Snetchild	PROC_LOCK(pp);
1402161310Snetchild	PROC_UNLOCK(p);
1403161310Snetchild
1404161310Snetchild	/* if its also linux process */
1405161310Snetchild	if (pp->p_sysent == &elf_linux_sysvec) {
1406161310Snetchild   	   	em = em_find(pp, EMUL_LOCKED);
1407161310Snetchild		KASSERT(em != NULL, ("getppid: parent emuldata not found.\n"));
1408161310Snetchild
1409161420Snetchild		td->td_retval[0] = em->shared->group_pid;
1410161310Snetchild	} else
1411161310Snetchild	   	td->td_retval[0] = pp->p_pid;
1412161310Snetchild
1413161310Snetchild	EMUL_UNLOCK(&emul_lock);
1414161310Snetchild	PROC_UNLOCK(pp);
1415161317Snetchild#else
1416161317Snetchild	return getppid(td, (struct getppid_args *) args);
1417161317Snetchild#endif
1418161420Snetchild
1419161310Snetchild	return (0);
1420161310Snetchild}
1421161310Snetchild
1422161310Snetchildint
142383366Sjulianlinux_getgid(struct thread *td, struct linux_getgid_args *args)
142483221Smarcel{
142583366Sjulian
142694454Sjhb	td->td_retval[0] = td->td_ucred->cr_rgid;
142783221Smarcel	return (0);
142883221Smarcel}
142983221Smarcel
143083221Smarcelint
143183366Sjulianlinux_getuid(struct thread *td, struct linux_getuid_args *args)
143283221Smarcel{
143383366Sjulian
143494454Sjhb	td->td_retval[0] = td->td_ucred->cr_ruid;
143583221Smarcel	return (0);
143683221Smarcel}
143783503Smr
143889717Sgallatin
143983503Smrint
144083503Smrlinux_getsid(struct thread *td, struct linux_getsid_args *args)
144183503Smr{
144283503Smr	struct getsid_args bsd;
144383503Smr	bsd.pid = args->pid;
144483503Smr	return getsid(td, &bsd);
144583503Smr}
1446143197Ssobomax
1447143197Ssobomaxint
1448143197Ssobomaxlinux_nosys(struct thread *td, struct nosys_args *ignore)
1449143197Ssobomax{
1450143197Ssobomax
1451143197Ssobomax	return (ENOSYS);
1452143197Ssobomax}
1453147141Ssobomax
1454147141Ssobomaxint
1455147141Ssobomaxlinux_getpriority(struct thread *td, struct linux_getpriority_args *args)
1456147141Ssobomax{
1457147141Ssobomax	struct getpriority_args	bsd_args;
1458147141Ssobomax	int error;
1459147141Ssobomax
1460147141Ssobomax	bsd_args.which = args->which;
1461147141Ssobomax	bsd_args.who = args->who;
1462147141Ssobomax	error = getpriority(td, &bsd_args);
1463147141Ssobomax	td->td_retval[0] = 20 - td->td_retval[0];
1464147141Ssobomax	return error;
1465147141Ssobomax}
1466156842Snetchild
1467156842Snetchildint
1468156842Snetchildlinux_sethostname(struct thread *td, struct linux_sethostname_args *args)
1469156842Snetchild{
1470156842Snetchild	int name[2];
1471156842Snetchild	int error;
1472156842Snetchild
1473156842Snetchild	name[0] = CTL_KERN;
1474156842Snetchild	name[1] = KERN_HOSTNAME;
1475157183Sjhb	if ((error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL)))
1476156842Snetchild		return (error);
1477156842Snetchild	return (userland_sysctl(td, name, 2, 0, 0, 0, args->hostname,
1478156842Snetchild		 args->len, 0, 0));
1479156842Snetchild}
1480156842Snetchild
1481161310Snetchildint
1482161310Snetchildlinux_exit_group(struct thread *td, struct linux_exit_group_args *args)
1483161310Snetchild{
1484161420Snetchild#ifdef __i386__
1485161310Snetchild   	struct linux_emuldata *em, *td_em, *tmp_em;
1486161310Snetchild	struct proc *sp;
1487161420Snetchild	char osrel[LINUX_MAX_UTSNAME];
1488161310Snetchild
1489161310Snetchild#ifdef DEBUG
1490161310Snetchild	if (ldebug(exit_group))
1491161310Snetchild		printf(ARGS(exit_group, "%i"), args->error_code);
1492161310Snetchild#endif
1493161310Snetchild
1494161420Snetchild	linux_get_osrelease(td, osrel);
1495161420Snetchild	if (strlen(osrel) >= 3 && osrel[2] == '6') {
1496161420Snetchild   	   	td_em = em_find(td->td_proc, EMUL_UNLOCKED);
1497161310Snetchild
1498161420Snetchild		KASSERT(td_em != NULL, ("exit_group: emuldata not found.\n"));
1499161310Snetchild
1500161420Snetchild   		EMUL_SHARED_RLOCK(&emul_shared_lock);
1501161420Snetchild     		LIST_FOREACH_SAFE(em, &td_em->shared->threads, threads, tmp_em) {
1502161420Snetchild	   		if (em->pid == td_em->pid)
1503161420Snetchild		   		continue;
1504161310Snetchild
1505161420Snetchild			sp = pfind(em->pid);
1506161420Snetchild			psignal(sp, SIGKILL);
1507161420Snetchild			PROC_UNLOCK(sp);
1508161310Snetchild#ifdef DEBUG
1509161420Snetchild			printf(LMSG("linux_sys_exit_group: kill PID %d\n"), em->pid);
1510161310Snetchild#endif
1511161420Snetchild		}
1512161420Snetchild
1513161420Snetchild		EMUL_SHARED_RUNLOCK(&emul_shared_lock);
1514161420Snetchild		EMUL_UNLOCK(&emul_lock);
1515161310Snetchild	}
1516161420Snetchild#endif
1517161310Snetchild
1518161310Snetchild	exit1(td, W_EXITCODE(args->error_code,0));
1519161310Snetchild
1520161310Snetchild   	return (0);
1521161310Snetchild}
1522161310Snetchild
1523