linux_misc.c revision 218030
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 218030 2011-01-28 18:47:07Z dchagin $");
32116173Sobrien
33156874Sru#include "opt_compat.h"
3449842Smarcel
359313Ssos#include <sys/param.h>
36102954Sbde#include <sys/blist.h>
3776166Smarkm#include <sys/fcntl.h>
38158415Snetchild#if defined(__i386__)
3976166Smarkm#include <sys/imgact_aout.h>
40133816Stjr#endif
4191385Srobert#include <sys/jail.h>
4212458Sbde#include <sys/kernel.h>
43114216Skan#include <sys/limits.h>
4476166Smarkm#include <sys/lock.h>
45102954Sbde#include <sys/malloc.h>
469313Ssos#include <sys/mman.h>
479313Ssos#include <sys/mount.h>
4876166Smarkm#include <sys/mutex.h>
499313Ssos#include <sys/namei.h>
50164033Srwatson#include <sys/priv.h>
5176166Smarkm#include <sys/proc.h>
5272538Sjlemon#include <sys/reboot.h>
539313Ssos#include <sys/resourcevar.h>
54164184Strhodes#include <sys/sched.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>
65177257Srdivacky#include <sys/cpuset.h>
669313Ssos
67163606Srwatson#include <security/mac/mac_framework.h>
68163606Srwatson
6912652Sbde#include <vm/vm.h>
7012689Speter#include <vm/pmap.h>
7112458Sbde#include <vm/vm_kern.h>
7212689Speter#include <vm/vm_map.h>
7312842Sbde#include <vm/vm_extern.h>
7480180Spirzyk#include <vm/vm_object.h>
7580180Spirzyk#include <vm/swap_pager.h>
7612458Sbde
77140214Sobrien#ifdef COMPAT_LINUX32
78140214Sobrien#include <machine/../linux32/linux.h>
79140214Sobrien#include <machine/../linux32/linux32_proto.h>
80140214Sobrien#else
8164909Smarcel#include <machine/../linux/linux.h>
8268583Smarcel#include <machine/../linux/linux_proto.h>
83133816Stjr#endif
84102954Sbde
85177997Skib#include <compat/linux/linux_file.h>
8664909Smarcel#include <compat/linux/linux_mib.h>
87163734Snetchild#include <compat/linux/linux_signal.h>
8864909Smarcel#include <compat/linux/linux_util.h>
89178976Srdivacky#include <compat/linux/linux_sysproto.h>
90178976Srdivacky#include <compat/linux/linux_emul.h>
91178976Srdivacky#include <compat/linux/linux_misc.h>
9264909Smarcel
93191966Sdchaginint stclohz;				/* Statistics clock frequency */
94191966Sdchagin
9551793Smarcel#define BSD_TO_LINUX_SIGNAL(sig)	\
9651793Smarcel	(((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
9751793Smarcel
9883221Smarcelstatic unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = {
9983221Smarcel	RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK,
10083221Smarcel	RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE,
101165871Snetchild	RLIMIT_MEMLOCK, RLIMIT_AS
10249626Smarcel};
10349626Smarcel
10483221Smarcelstruct l_sysinfo {
10583221Smarcel	l_long		uptime;		/* Seconds since boot */
10683221Smarcel	l_ulong		loads[3];	/* 1, 5, and 15 minute load averages */
107122802Ssobomax#define LINUX_SYSINFO_LOADS_SCALE 65536
10883221Smarcel	l_ulong		totalram;	/* Total usable main memory size */
10983221Smarcel	l_ulong		freeram;	/* Available memory size */
11083221Smarcel	l_ulong		sharedram;	/* Amount of shared memory */
11183221Smarcel	l_ulong		bufferram;	/* Memory used by buffers */
11283221Smarcel	l_ulong		totalswap;	/* Total swap space size */
11383221Smarcel	l_ulong		freeswap;	/* swap space still available */
11483221Smarcel	l_ushort	procs;		/* Number of current processes */
115164380Skib	l_ushort	pads;
116122802Ssobomax	l_ulong		totalbig;
117122802Ssobomax	l_ulong		freebig;
118122802Ssobomax	l_uint		mem_unit;
119164380Skib	char		_f[20-2*sizeof(l_long)-sizeof(l_int)];	/* padding */
12080180Spirzyk};
1219313Ssosint
12283366Sjulianlinux_sysinfo(struct thread *td, struct linux_sysinfo_args *args)
12380180Spirzyk{
12483221Smarcel	struct l_sysinfo sysinfo;
12583221Smarcel	vm_object_t object;
126117723Sphk	int i, j;
12783221Smarcel	struct timespec ts;
12880180Spirzyk
12983221Smarcel	getnanouptime(&ts);
130147816Sjhb	if (ts.tv_nsec != 0)
131147816Sjhb		ts.tv_sec++;
132147816Sjhb	sysinfo.uptime = ts.tv_sec;
13380180Spirzyk
13483221Smarcel	/* Use the information from the mib to get our load averages */
13583221Smarcel	for (i = 0; i < 3; i++)
136122802Ssobomax		sysinfo.loads[i] = averunnable.ldavg[i] *
137122802Ssobomax		    LINUX_SYSINFO_LOADS_SCALE / averunnable.fscale;
13880180Spirzyk
13983221Smarcel	sysinfo.totalram = physmem * PAGE_SIZE;
140170170Sattilio	sysinfo.freeram = sysinfo.totalram - cnt.v_wire_count * PAGE_SIZE;
14180180Spirzyk
14283221Smarcel	sysinfo.sharedram = 0;
143124082Salc	mtx_lock(&vm_object_list_mtx);
144124082Salc	TAILQ_FOREACH(object, &vm_object_list, object_list)
14583221Smarcel		if (object->shadow_count > 1)
14683221Smarcel			sysinfo.sharedram += object->resident_page_count;
147124082Salc	mtx_unlock(&vm_object_list_mtx);
14880180Spirzyk
14983221Smarcel	sysinfo.sharedram *= PAGE_SIZE;
15083221Smarcel	sysinfo.bufferram = 0;
15180180Spirzyk
152117723Sphk	swap_pager_status(&i, &j);
153165686Snetchild	sysinfo.totalswap = i * PAGE_SIZE;
154117723Sphk	sysinfo.freeswap = (i - j) * PAGE_SIZE;
15580180Spirzyk
156122802Ssobomax	sysinfo.procs = nprocs;
15780180Spirzyk
158122802Ssobomax	/* The following are only present in newer Linux kernels. */
159122802Ssobomax	sysinfo.totalbig = 0;
160122802Ssobomax	sysinfo.freebig = 0;
161122802Ssobomax	sysinfo.mem_unit = 1;
162122802Ssobomax
163111797Sdes	return copyout(&sysinfo, args->info, sizeof(sysinfo));
16480180Spirzyk}
16580180Spirzyk
16680180Spirzykint
16783366Sjulianlinux_alarm(struct thread *td, struct linux_alarm_args *args)
1689313Ssos{
16983221Smarcel	struct itimerval it, old_it;
170180766Srdivacky	u_int secs;
171141467Sjhb	int error;
1729313Ssos
1739313Ssos#ifdef DEBUG
17472543Sjlemon	if (ldebug(alarm))
17572543Sjlemon		printf(ARGS(alarm, "%u"), args->secs);
1769313Ssos#endif
177180766Srdivacky
178180766Srdivacky	secs = args->secs;
17983221Smarcel
180180766Srdivacky	if (secs > INT_MAX)
181180766Srdivacky		secs = INT_MAX;
18283221Smarcel
183180766Srdivacky	it.it_value.tv_sec = (long) secs;
18483221Smarcel	it.it_value.tv_usec = 0;
18583221Smarcel	it.it_interval.tv_sec = 0;
18683221Smarcel	it.it_interval.tv_usec = 0;
187141467Sjhb	error = kern_setitimer(td, ITIMER_REAL, &it, &old_it);
188141467Sjhb	if (error)
189141467Sjhb		return (error);
190165686Snetchild	if (timevalisset(&old_it.it_value)) {
19183221Smarcel		if (old_it.it_value.tv_usec != 0)
19283221Smarcel			old_it.it_value.tv_sec++;
19383366Sjulian		td->td_retval[0] = old_it.it_value.tv_sec;
19483221Smarcel	}
195141467Sjhb	return (0);
1969313Ssos}
1979313Ssos
1989313Ssosint
19983366Sjulianlinux_brk(struct thread *td, struct linux_brk_args *args)
2009313Ssos{
20183366Sjulian	struct vmspace *vm = td->td_proc->p_vmspace;
20283221Smarcel	vm_offset_t new, old;
20383221Smarcel	struct obreak_args /* {
20483221Smarcel		char * nsize;
20583221Smarcel	} */ tmp;
2069313Ssos
2079313Ssos#ifdef DEBUG
20872543Sjlemon	if (ldebug(brk))
209133845Sobrien		printf(ARGS(brk, "%p"), (void *)(uintptr_t)args->dsend);
2109313Ssos#endif
21183221Smarcel	old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
21283221Smarcel	new = (vm_offset_t)args->dsend;
213165686Snetchild	tmp.nsize = (char *)new;
21483366Sjulian	if (((caddr_t)new > vm->vm_daddr) && !obreak(td, &tmp))
21583366Sjulian		td->td_retval[0] = (long)new;
21683221Smarcel	else
21783366Sjulian		td->td_retval[0] = (long)old;
2189313Ssos
21983221Smarcel	return 0;
2209313Ssos}
2219313Ssos
222158415Snetchild#if defined(__i386__)
223158415Snetchild/* XXX: what about amd64/linux32? */
224133816Stjr
2259313Ssosint
22683366Sjulianlinux_uselib(struct thread *td, struct linux_uselib_args *args)
2279313Ssos{
22883221Smarcel	struct nameidata ni;
22983221Smarcel	struct vnode *vp;
23083221Smarcel	struct exec *a_out;
23183221Smarcel	struct vattr attr;
23283221Smarcel	vm_offset_t vmaddr;
23383221Smarcel	unsigned long file_offset;
23483221Smarcel	vm_offset_t buffer;
23583221Smarcel	unsigned long bss_size;
236102814Siedowse	char *library;
23783221Smarcel	int error;
238160555Sjhb	int locked, vfslocked;
2399313Ssos
240102814Siedowse	LCONVPATHEXIST(td, args->library, &library);
24114331Speter
2429313Ssos#ifdef DEBUG
24372543Sjlemon	if (ldebug(uselib))
244102814Siedowse		printf(ARGS(uselib, "%s"), library);
2459313Ssos#endif
2469313Ssos
24783221Smarcel	a_out = NULL;
248160555Sjhb	vfslocked = 0;
24983221Smarcel	locked = 0;
25083221Smarcel	vp = NULL;
25114114Speter
252160555Sjhb	NDINIT(&ni, LOOKUP, ISOPEN | FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
253160555Sjhb	    UIO_SYSSPACE, library, td);
25483221Smarcel	error = namei(&ni);
255102814Siedowse	LFREEPATH(library);
25683221Smarcel	if (error)
25783221Smarcel		goto cleanup;
2589313Ssos
25983221Smarcel	vp = ni.ni_vp;
260160555Sjhb	vfslocked = NDHASGIANT(&ni);
26183221Smarcel	NDFREE(&ni, NDF_ONLY_PNBUF);
2629313Ssos
26383221Smarcel	/*
26483221Smarcel	 * From here on down, we have a locked vnode that must be unlocked.
265160555Sjhb	 * XXX: The code below largely duplicates exec_check_permissions().
26683221Smarcel	 */
267160555Sjhb	locked = 1;
26814114Speter
26983221Smarcel	/* Writable? */
27083221Smarcel	if (vp->v_writecount) {
27183221Smarcel		error = ETXTBSY;
27283221Smarcel		goto cleanup;
27383221Smarcel	}
2749313Ssos
27583221Smarcel	/* Executable? */
276182371Sattilio	error = VOP_GETATTR(vp, &attr, td->td_ucred);
27783221Smarcel	if (error)
27883221Smarcel		goto cleanup;
2799313Ssos
28083221Smarcel	if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
28183221Smarcel	    ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) {
282160555Sjhb		/* EACCESS is what exec(2) returns. */
28383221Smarcel		error = ENOEXEC;
28483221Smarcel		goto cleanup;
28583221Smarcel	}
2869313Ssos
28783221Smarcel	/* Sensible size? */
28883221Smarcel	if (attr.va_size == 0) {
28983221Smarcel		error = ENOEXEC;
29083221Smarcel		goto cleanup;
29183221Smarcel	}
2929313Ssos
29383221Smarcel	/* Can we access it? */
29491406Sjhb	error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
29583221Smarcel	if (error)
29683221Smarcel		goto cleanup;
2979313Ssos
29898209Srwatson	/*
29998209Srwatson	 * XXX: This should use vn_open() so that it is properly authorized,
30098209Srwatson	 * and to reduce code redundancy all over the place here.
301160555Sjhb	 * XXX: Not really, it duplicates far more of exec_check_permissions()
302160555Sjhb	 * than vn_open().
30398209Srwatson	 */
304101189Srwatson#ifdef MAC
305183275Strasz	error = mac_vnode_check_open(td->td_ucred, vp, VREAD);
306101189Srwatson	if (error)
307101189Srwatson		goto cleanup;
308101189Srwatson#endif
309170152Skib	error = VOP_OPEN(vp, FREAD, td->td_ucred, td, NULL);
31083221Smarcel	if (error)
31183221Smarcel		goto cleanup;
3129313Ssos
313103941Sjeff	/* Pull in executable header into kernel_map */
314103941Sjeff	error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
315144501Sjhb	    VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp, 0);
31683221Smarcel	if (error)
31783221Smarcel		goto cleanup;
3189313Ssos
31983221Smarcel	/* Is it a Linux binary ? */
32083221Smarcel	if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
32183221Smarcel		error = ENOEXEC;
32283221Smarcel		goto cleanup;
32383221Smarcel	}
3249313Ssos
32583221Smarcel	/*
32683221Smarcel	 * While we are here, we should REALLY do some more checks
32783221Smarcel	 */
32814114Speter
32983221Smarcel	/* Set file/virtual offset based on a.out variant. */
33083221Smarcel	switch ((int)(a_out->a_magic & 0xffff)) {
331165686Snetchild	case 0413:			/* ZMAGIC */
33283221Smarcel		file_offset = 1024;
33383221Smarcel		break;
334165686Snetchild	case 0314:			/* QMAGIC */
33583221Smarcel		file_offset = 0;
33683221Smarcel		break;
33783221Smarcel	default:
33883221Smarcel		error = ENOEXEC;
33983221Smarcel		goto cleanup;
34083221Smarcel	}
3419313Ssos
34283221Smarcel	bss_size = round_page(a_out->a_bss);
34314114Speter
34483221Smarcel	/* Check various fields in header for validity/bounds. */
34583221Smarcel	if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
34683221Smarcel		error = ENOEXEC;
34783221Smarcel		goto cleanup;
34883221Smarcel	}
34914114Speter
35083221Smarcel	/* text + data can't exceed file size */
35183221Smarcel	if (a_out->a_data + a_out->a_text > attr.va_size) {
35283221Smarcel		error = EFAULT;
35383221Smarcel		goto cleanup;
35483221Smarcel	}
35514114Speter
35683221Smarcel	/*
35783221Smarcel	 * text/data/bss must not exceed limits
35883221Smarcel	 * XXX - this is not complete. it should check current usage PLUS
35983221Smarcel	 * the resources needed by this library.
36083221Smarcel	 */
361125454Sjhb	PROC_LOCK(td->td_proc);
36284783Sps	if (a_out->a_text > maxtsiz ||
363125454Sjhb	    a_out->a_data + bss_size > lim_cur(td->td_proc, RLIMIT_DATA)) {
364125454Sjhb		PROC_UNLOCK(td->td_proc);
36583221Smarcel		error = ENOMEM;
36683221Smarcel		goto cleanup;
36783221Smarcel	}
368125454Sjhb	PROC_UNLOCK(td->td_proc);
36914114Speter
370160555Sjhb	/*
371160555Sjhb	 * Prevent more writers.
372160555Sjhb	 * XXX: Note that if any of the VM operations fail below we don't
373160555Sjhb	 * clear this flag.
374160555Sjhb	 */
375101308Sjeff	vp->v_vflag |= VV_TEXT;
37614114Speter
37783221Smarcel	/*
378160555Sjhb	 * Lock no longer needed
379160555Sjhb	 */
380160555Sjhb	locked = 0;
381175294Sattilio	VOP_UNLOCK(vp, 0);
382160555Sjhb	VFS_UNLOCK_GIANT(vfslocked);
383160555Sjhb
384160555Sjhb	/*
38583221Smarcel	 * Check if file_offset page aligned. Currently we cannot handle
38683221Smarcel	 * misalinged file offsets, and so we read in the entire image
38783221Smarcel	 * (what a waste).
38883221Smarcel	 */
38983221Smarcel	if (file_offset & PAGE_MASK) {
3909313Ssos#ifdef DEBUG
39183221Smarcel		printf("uselib: Non page aligned binary %lu\n", file_offset);
3929313Ssos#endif
39383221Smarcel		/* Map text+data read/write/execute */
39414114Speter
39583221Smarcel		/* a_entry is the load address and is page aligned */
39683221Smarcel		vmaddr = trunc_page(a_out->a_entry);
39714114Speter
39883221Smarcel		/* get anon user mapping, read+write+execute */
39983366Sjulian		error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
40083366Sjulian		    &vmaddr, a_out->a_text + a_out->a_data, FALSE, VM_PROT_ALL,
40183221Smarcel		    VM_PROT_ALL, 0);
40283221Smarcel		if (error)
40383221Smarcel			goto cleanup;
4049313Ssos
40583221Smarcel		/* map file into kernel_map */
40683221Smarcel		error = vm_mmap(kernel_map, &buffer,
40783221Smarcel		    round_page(a_out->a_text + a_out->a_data + file_offset),
408144501Sjhb		    VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp,
40983221Smarcel		    trunc_page(file_offset));
41083221Smarcel		if (error)
41183221Smarcel			goto cleanup;
4129313Ssos
41383221Smarcel		/* copy from kernel VM space to user space */
414133816Stjr		error = copyout(PTRIN(buffer + file_offset),
415111797Sdes		    (void *)vmaddr, a_out->a_text + a_out->a_data);
4169313Ssos
41783221Smarcel		/* release temporary kernel space */
41883221Smarcel		vm_map_remove(kernel_map, buffer, buffer +
41983221Smarcel		    round_page(a_out->a_text + a_out->a_data + file_offset));
4209313Ssos
42183221Smarcel		if (error)
42283221Smarcel			goto cleanup;
42383221Smarcel	} else {
4249313Ssos#ifdef DEBUG
42583221Smarcel		printf("uselib: Page aligned binary %lu\n", file_offset);
4269313Ssos#endif
42783221Smarcel		/*
42883221Smarcel		 * for QMAGIC, a_entry is 20 bytes beyond the load address
42983221Smarcel		 * to skip the executable header
43083221Smarcel		 */
43183221Smarcel		vmaddr = trunc_page(a_out->a_entry);
43214114Speter
43383221Smarcel		/*
43483221Smarcel		 * Map it all into the process's space as a single
43583221Smarcel		 * copy-on-write "data" segment.
43683221Smarcel		 */
43783366Sjulian		error = vm_mmap(&td->td_proc->p_vmspace->vm_map, &vmaddr,
43883221Smarcel		    a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL,
439144501Sjhb		    MAP_PRIVATE | MAP_FIXED, OBJT_VNODE, vp, file_offset);
44083221Smarcel		if (error)
44183221Smarcel			goto cleanup;
44283221Smarcel	}
4439313Ssos#ifdef DEBUG
444165686Snetchild	printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long *)vmaddr)[0],
445165686Snetchild	    ((long *)vmaddr)[1]);
4469313Ssos#endif
44783221Smarcel	if (bss_size != 0) {
44883221Smarcel		/* Calculate BSS start address */
44983221Smarcel		vmaddr = trunc_page(a_out->a_entry) + a_out->a_text +
45083221Smarcel		    a_out->a_data;
45114114Speter
45283221Smarcel		/* allocate some 'anon' space */
45383366Sjulian		error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
45483366Sjulian		    &vmaddr, bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0);
45583221Smarcel		if (error)
45683221Smarcel			goto cleanup;
45783221Smarcel	}
45814114Speter
45914114Spetercleanup:
46083221Smarcel	/* Unlock vnode if needed */
461160555Sjhb	if (locked) {
462175294Sattilio		VOP_UNLOCK(vp, 0);
463160555Sjhb		VFS_UNLOCK_GIANT(vfslocked);
464160555Sjhb	}
46514114Speter
46683221Smarcel	/* Release the kernel mapping. */
46783221Smarcel	if (a_out)
46883221Smarcel		vm_map_remove(kernel_map, (vm_offset_t)a_out,
46983221Smarcel		    (vm_offset_t)a_out + PAGE_SIZE);
47014114Speter
47183221Smarcel	return error;
4729313Ssos}
4739313Ssos
474158415Snetchild#endif	/* __i386__ */
475133816Stjr
4769313Ssosint
47783366Sjulianlinux_select(struct thread *td, struct linux_select_args *args)
47814331Speter{
479133747Stjr	l_timeval ltv;
48083221Smarcel	struct timeval tv0, tv1, utv, *tvp;
48183221Smarcel	int error;
48214331Speter
4839313Ssos#ifdef DEBUG
48483221Smarcel	if (ldebug(select))
48583221Smarcel		printf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds,
48683221Smarcel		    (void *)args->readfds, (void *)args->writefds,
48783221Smarcel		    (void *)args->exceptfds, (void *)args->timeout);
4889313Ssos#endif
48914331Speter
49083221Smarcel	/*
49183221Smarcel	 * Store current time for computation of the amount of
49283221Smarcel	 * time left.
49383221Smarcel	 */
49483221Smarcel	if (args->timeout) {
495133747Stjr		if ((error = copyin(args->timeout, &ltv, sizeof(ltv))))
49683221Smarcel			goto select_out;
497133747Stjr		utv.tv_sec = ltv.tv_sec;
498133747Stjr		utv.tv_usec = ltv.tv_usec;
49914331Speter#ifdef DEBUG
50083221Smarcel		if (ldebug(select))
501153775Strhodes			printf(LMSG("incoming timeout (%jd/%ld)"),
502153775Strhodes			    (intmax_t)utv.tv_sec, utv.tv_usec);
50314331Speter#endif
50483221Smarcel
50583221Smarcel		if (itimerfix(&utv)) {
50683221Smarcel			/*
50783221Smarcel			 * The timeval was invalid.  Convert it to something
50883221Smarcel			 * valid that will act as it does under Linux.
50983221Smarcel			 */
51083221Smarcel			utv.tv_sec += utv.tv_usec / 1000000;
51183221Smarcel			utv.tv_usec %= 1000000;
51283221Smarcel			if (utv.tv_usec < 0) {
51383221Smarcel				utv.tv_sec -= 1;
51483221Smarcel				utv.tv_usec += 1000000;
51583221Smarcel			}
51683221Smarcel			if (utv.tv_sec < 0)
51783221Smarcel				timevalclear(&utv);
51883221Smarcel		}
51983221Smarcel		microtime(&tv0);
520102814Siedowse		tvp = &utv;
521102814Siedowse	} else
522102814Siedowse		tvp = NULL;
52314331Speter
524102814Siedowse	error = kern_select(td, args->nfds, args->readfds, args->writefds,
525197049Skib	    args->exceptfds, tvp, sizeof(l_int) * 8);
526102814Siedowse
52714331Speter#ifdef DEBUG
52883221Smarcel	if (ldebug(select))
52972543Sjlemon		printf(LMSG("real select returns %d"), error);
53014331Speter#endif
531182935Srdivacky	if (error)
53283221Smarcel		goto select_out;
53314331Speter
53483221Smarcel	if (args->timeout) {
53583366Sjulian		if (td->td_retval[0]) {
53683221Smarcel			/*
53783221Smarcel			 * Compute how much time was left of the timeout,
53883221Smarcel			 * by subtracting the current time and the time
53983221Smarcel			 * before we started the call, and subtracting
54083221Smarcel			 * that result from the user-supplied value.
54183221Smarcel			 */
54283221Smarcel			microtime(&tv1);
54383221Smarcel			timevalsub(&tv1, &tv0);
54483221Smarcel			timevalsub(&utv, &tv1);
54583221Smarcel			if (utv.tv_sec < 0)
54683221Smarcel				timevalclear(&utv);
54783221Smarcel		} else
54883221Smarcel			timevalclear(&utv);
54914331Speter#ifdef DEBUG
55083221Smarcel		if (ldebug(select))
551153775Strhodes			printf(LMSG("outgoing timeout (%jd/%ld)"),
552153775Strhodes			    (intmax_t)utv.tv_sec, utv.tv_usec);
55314331Speter#endif
554133747Stjr		ltv.tv_sec = utv.tv_sec;
555133747Stjr		ltv.tv_usec = utv.tv_usec;
556133747Stjr		if ((error = copyout(&ltv, args->timeout, sizeof(ltv))))
55783221Smarcel			goto select_out;
55883221Smarcel	}
55914331Speter
56014331Speterselect_out:
56114331Speter#ifdef DEBUG
56283221Smarcel	if (ldebug(select))
56383221Smarcel		printf(LMSG("select_out -> %d"), error);
56414331Speter#endif
56583221Smarcel	return error;
5669313Ssos}
5679313Ssos
568111798Sdesint
56983366Sjulianlinux_mremap(struct thread *td, struct linux_mremap_args *args)
57037548Sjkh{
57137548Sjkh	struct munmap_args /* {
57237548Sjkh		void *addr;
57337548Sjkh		size_t len;
574111798Sdes	} */ bsd_args;
57537548Sjkh	int error = 0;
576111798Sdes
57737548Sjkh#ifdef DEBUG
57872543Sjlemon	if (ldebug(mremap))
57972543Sjlemon		printf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"),
580133845Sobrien		    (void *)(uintptr_t)args->addr,
581111798Sdes		    (unsigned long)args->old_len,
58272543Sjlemon		    (unsigned long)args->new_len,
58372543Sjlemon		    (unsigned long)args->flags);
58437548Sjkh#endif
585176460Skib
586176460Skib	if (args->flags & ~(LINUX_MREMAP_FIXED | LINUX_MREMAP_MAYMOVE)) {
587176460Skib		td->td_retval[0] = 0;
588176460Skib		return (EINVAL);
589176460Skib	}
590176460Skib
591176460Skib	/*
592176460Skib	 * Check for the page alignment.
593176460Skib	 * Linux defines PAGE_MASK to be FreeBSD ~PAGE_MASK.
594176460Skib	 */
595176460Skib	if (args->addr & PAGE_MASK) {
596176460Skib		td->td_retval[0] = 0;
597176460Skib		return (EINVAL);
598176460Skib	}
599176460Skib
60037548Sjkh	args->new_len = round_page(args->new_len);
60137548Sjkh	args->old_len = round_page(args->old_len);
60237548Sjkh
60337548Sjkh	if (args->new_len > args->old_len) {
60483366Sjulian		td->td_retval[0] = 0;
60537548Sjkh		return ENOMEM;
60637548Sjkh	}
60737548Sjkh
60837548Sjkh	if (args->new_len < args->old_len) {
609133816Stjr		bsd_args.addr =
610133816Stjr		    (caddr_t)((uintptr_t)args->addr + args->new_len);
61137548Sjkh		bsd_args.len = args->old_len - args->new_len;
61283366Sjulian		error = munmap(td, &bsd_args);
61337548Sjkh	}
61437548Sjkh
615102963Sbde	td->td_retval[0] = error ? 0 : (uintptr_t)args->addr;
61637548Sjkh	return error;
61737548Sjkh}
61837548Sjkh
619103652Smdodd#define LINUX_MS_ASYNC       0x0001
620103652Smdodd#define LINUX_MS_INVALIDATE  0x0002
621103652Smdodd#define LINUX_MS_SYNC        0x0004
622103652Smdodd
62314331Speterint
62483366Sjulianlinux_msync(struct thread *td, struct linux_msync_args *args)
62514331Speter{
62614331Speter	struct msync_args bsd_args;
6279313Ssos
628133816Stjr	bsd_args.addr = (caddr_t)(uintptr_t)args->addr;
629133816Stjr	bsd_args.len = (uintptr_t)args->len;
630103652Smdodd	bsd_args.flags = args->fl & ~LINUX_MS_SYNC;
63114331Speter
63283366Sjulian	return msync(td, &bsd_args);
63314331Speter}
63414331Speter
6359313Ssosint
63683366Sjulianlinux_time(struct thread *td, struct linux_time_args *args)
6379313Ssos{
63883221Smarcel	struct timeval tv;
63983221Smarcel	l_time_t tm;
64083221Smarcel	int error;
6419313Ssos
6429313Ssos#ifdef DEBUG
64372543Sjlemon	if (ldebug(time))
64472543Sjlemon		printf(ARGS(time, "*"));
6459313Ssos#endif
64683221Smarcel
64783221Smarcel	microtime(&tv);
64883221Smarcel	tm = tv.tv_sec;
649111797Sdes	if (args->tm && (error = copyout(&tm, args->tm, sizeof(tm))))
65083221Smarcel		return error;
65183366Sjulian	td->td_retval[0] = tm;
65283221Smarcel	return 0;
6539313Ssos}
6549313Ssos
65583221Smarcelstruct l_times_argv {
656191880Sdchagin	l_clock_t	tms_utime;
657191880Sdchagin	l_clock_t	tms_stime;
658191880Sdchagin	l_clock_t	tms_cutime;
659191880Sdchagin	l_clock_t	tms_cstime;
6609313Ssos};
6619313Ssos
66274701Sgallatin
663191973Sdchagin/*
664191973Sdchagin * Glibc versions prior to 2.2.1 always use hard-coded CLK_TCK value.
665191973Sdchagin * Since 2.2.1 Glibc uses value exported from kernel via AT_CLKTCK
666191973Sdchagin * auxiliary vector entry.
667191973Sdchagin */
668191973Sdchagin#define	CLK_TCK		100
669191973Sdchagin
670191973Sdchagin#define	CONVOTCK(r)	(r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
671191973Sdchagin#define	CONVNTCK(r)	(r.tv_sec * stclohz + r.tv_usec / (1000000 / stclohz))
672191973Sdchagin
673191973Sdchagin#define	CONVTCK(r)	(linux_kernver(td) >= LINUX_KERNVER_2004000 ?		\
674191973Sdchagin			    CONVNTCK(r) : CONVOTCK(r))
675191973Sdchagin
6769313Ssosint
67783366Sjulianlinux_times(struct thread *td, struct linux_times_args *args)
6789313Ssos{
679136152Sjhb	struct timeval tv, utime, stime, cutime, cstime;
68083221Smarcel	struct l_times_argv tms;
681136152Sjhb	struct proc *p;
68283221Smarcel	int error;
6839313Ssos
6849313Ssos#ifdef DEBUG
68572543Sjlemon	if (ldebug(times))
68672543Sjlemon		printf(ARGS(times, "*"));
6879313Ssos#endif
68814381Speter
689159896Snetchild	if (args->buf != NULL) {
690159896Snetchild		p = td->td_proc;
691159896Snetchild		PROC_LOCK(p);
692170472Sattilio		PROC_SLOCK(p);
693159896Snetchild		calcru(p, &utime, &stime);
694170472Sattilio		PROC_SUNLOCK(p);
695159896Snetchild		calccru(p, &cutime, &cstime);
696159896Snetchild		PROC_UNLOCK(p);
69714381Speter
698159896Snetchild		tms.tms_utime = CONVTCK(utime);
699159896Snetchild		tms.tms_stime = CONVTCK(stime);
70014381Speter
701159896Snetchild		tms.tms_cutime = CONVTCK(cutime);
702159896Snetchild		tms.tms_cstime = CONVTCK(cstime);
70314381Speter
704159896Snetchild		if ((error = copyout(&tms, args->buf, sizeof(tms))))
705159896Snetchild			return error;
706159896Snetchild	}
70783221Smarcel
70883221Smarcel	microuptime(&tv);
70983366Sjulian	td->td_retval[0] = (int)CONVTCK(tv);
71083221Smarcel	return 0;
7119313Ssos}
7129313Ssos
7139313Ssosint
71483366Sjulianlinux_newuname(struct thread *td, struct linux_newuname_args *args)
7159313Ssos{
71683221Smarcel	struct l_new_utsname utsname;
71787275Srwatson	char osname[LINUX_MAX_UTSNAME];
71887275Srwatson	char osrelease[LINUX_MAX_UTSNAME];
719118149Sdes	char *p;
7209313Ssos
7219313Ssos#ifdef DEBUG
72272543Sjlemon	if (ldebug(newuname))
72372543Sjlemon		printf(ARGS(newuname, "*"));
7249313Ssos#endif
72550345Smarcel
726112206Sjhb	linux_get_osname(td, osname);
727112206Sjhb	linux_get_osrelease(td, osrelease);
72850465Smarcel
72983221Smarcel	bzero(&utsname, sizeof(utsname));
730105359Srobert	strlcpy(utsname.sysname, osname, LINUX_MAX_UTSNAME);
731105359Srobert	getcredhostname(td->td_ucred, utsname.nodename, LINUX_MAX_UTSNAME);
732194090Sjamie	getcreddomainname(td->td_ucred, utsname.domainname, LINUX_MAX_UTSNAME);
733105359Srobert	strlcpy(utsname.release, osrelease, LINUX_MAX_UTSNAME);
734105359Srobert	strlcpy(utsname.version, version, LINUX_MAX_UTSNAME);
735118149Sdes	for (p = utsname.version; *p != '\0'; ++p)
736118149Sdes		if (*p == '\n') {
737118149Sdes			*p = '\0';
738118149Sdes			break;
739118149Sdes		}
740189362Sdchagin	strlcpy(utsname.machine, linux_platform, LINUX_MAX_UTSNAME);
741165686Snetchild
742111797Sdes	return (copyout(&utsname, args->buf, sizeof(utsname)));
7439313Ssos}
7449313Ssos
745140214Sobrien#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
74683221Smarcelstruct l_utimbuf {
74783221Smarcel	l_time_t l_actime;
74883221Smarcel	l_time_t l_modtime;
74914381Speter};
7509313Ssos
7519313Ssosint
75283366Sjulianlinux_utime(struct thread *td, struct linux_utime_args *args)
7539313Ssos{
75483221Smarcel	struct timeval tv[2], *tvp;
75583221Smarcel	struct l_utimbuf lut;
756102814Siedowse	char *fname;
75783221Smarcel	int error;
7589313Ssos
759102814Siedowse	LCONVPATHEXIST(td, args->fname, &fname);
76014331Speter
7619313Ssos#ifdef DEBUG
76272543Sjlemon	if (ldebug(utime))
763102814Siedowse		printf(ARGS(utime, "%s, *"), fname);
7649313Ssos#endif
76514381Speter
76683221Smarcel	if (args->times) {
767111797Sdes		if ((error = copyin(args->times, &lut, sizeof lut))) {
768102814Siedowse			LFREEPATH(fname);
76983221Smarcel			return error;
770102814Siedowse		}
77183221Smarcel		tv[0].tv_sec = lut.l_actime;
77283221Smarcel		tv[0].tv_usec = 0;
77383221Smarcel		tv[1].tv_sec = lut.l_modtime;
77483221Smarcel		tv[1].tv_usec = 0;
775102814Siedowse		tvp = tv;
77683221Smarcel	} else
777102814Siedowse		tvp = NULL;
77883221Smarcel
779102814Siedowse	error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE);
780102814Siedowse	LFREEPATH(fname);
781102814Siedowse	return (error);
7829313Ssos}
783165689Snetchild
784165689Snetchildint
785165689Snetchildlinux_utimes(struct thread *td, struct linux_utimes_args *args)
786165689Snetchild{
787165689Snetchild	l_timeval ltv[2];
788165689Snetchild	struct timeval tv[2], *tvp = NULL;
789165689Snetchild	char *fname;
790165689Snetchild	int error;
791165689Snetchild
792165689Snetchild	LCONVPATHEXIST(td, args->fname, &fname);
793165689Snetchild
794165689Snetchild#ifdef DEBUG
795165689Snetchild	if (ldebug(utimes))
796165689Snetchild		printf(ARGS(utimes, "%s, *"), fname);
797165689Snetchild#endif
798165689Snetchild
799165689Snetchild	if (args->tptr != NULL) {
800165689Snetchild		if ((error = copyin(args->tptr, ltv, sizeof ltv))) {
801165689Snetchild			LFREEPATH(fname);
802165689Snetchild			return (error);
803165689Snetchild		}
804165689Snetchild		tv[0].tv_sec = ltv[0].tv_sec;
805165689Snetchild		tv[0].tv_usec = ltv[0].tv_usec;
806165689Snetchild		tv[1].tv_sec = ltv[1].tv_sec;
807165689Snetchild		tv[1].tv_usec = ltv[1].tv_usec;
808165689Snetchild		tvp = tv;
809165689Snetchild	}
810165689Snetchild
811165689Snetchild	error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE);
812165689Snetchild	LFREEPATH(fname);
813165689Snetchild	return (error);
814165689Snetchild}
815177997Skib
816177997Skibint
817177997Skiblinux_futimesat(struct thread *td, struct linux_futimesat_args *args)
818177997Skib{
819177997Skib	l_timeval ltv[2];
820177997Skib	struct timeval tv[2], *tvp = NULL;
821177997Skib	char *fname;
822177997Skib	int error, dfd;
823177997Skib
824177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
825177997Skib	LCONVPATHEXIST_AT(td, args->filename, &fname, dfd);
826177997Skib
827177997Skib#ifdef DEBUG
828177997Skib	if (ldebug(futimesat))
829177997Skib		printf(ARGS(futimesat, "%s, *"), fname);
830177997Skib#endif
831177997Skib
832177997Skib	if (args->utimes != NULL) {
833177997Skib		if ((error = copyin(args->utimes, ltv, sizeof ltv))) {
834177997Skib			LFREEPATH(fname);
835177997Skib			return (error);
836177997Skib		}
837177997Skib		tv[0].tv_sec = ltv[0].tv_sec;
838177997Skib		tv[0].tv_usec = ltv[0].tv_usec;
839177997Skib		tv[1].tv_sec = ltv[1].tv_sec;
840177997Skib		tv[1].tv_usec = ltv[1].tv_usec;
841177997Skib		tvp = tv;
842177997Skib	}
843177997Skib
844177997Skib	error = kern_utimesat(td, dfd, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE);
845177997Skib	LFREEPATH(fname);
846177997Skib	return (error);
847177997Skib}
848133816Stjr#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
8499313Ssos
8509313Ssosint
851218030Sdchaginlinux_common_wait(struct thread *td, int pid, int *status,
852218030Sdchagin    int options, struct rusage *ru)
8539313Ssos{
854218030Sdchagin	int error, tmpstat;
8559313Ssos
856218030Sdchagin	error = kern_wait(td, pid, &tmpstat, options, ru);
857127140Sjhb	if (error)
858218030Sdchagin		return (error);
85983221Smarcel
860218030Sdchagin	if (status) {
86183221Smarcel		tmpstat &= 0xffff;
86283221Smarcel		if (WIFSIGNALED(tmpstat))
86383221Smarcel			tmpstat = (tmpstat & 0xffffff80) |
86483221Smarcel			    BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
86583221Smarcel		else if (WIFSTOPPED(tmpstat))
86683221Smarcel			tmpstat = (tmpstat & 0xffff00ff) |
86783221Smarcel			    (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
868218030Sdchagin		error = copyout(&tmpstat, status, sizeof(int));
86983221Smarcel	}
87083221Smarcel
871218030Sdchagin	return (error);
8729313Ssos}
8739313Ssos
87414331Speterint
875218030Sdchaginlinux_waitpid(struct thread *td, struct linux_waitpid_args *args)
8769313Ssos{
877218030Sdchagin	int options;
878218030Sdchagin
8799313Ssos#ifdef DEBUG
880218030Sdchagin	if (ldebug(waitpid))
881218030Sdchagin		printf(ARGS(waitpid, "%d, %p, %d"),
882218030Sdchagin		    args->pid, (void *)args->status, args->options);
8839313Ssos#endif
884218030Sdchagin	/*
885218030Sdchagin	 * this is necessary because the test in kern_wait doesn't work
886218030Sdchagin	 * because we mess with the options here
887218030Sdchagin	 */
888218030Sdchagin	if (args->options & ~(WUNTRACED | WNOHANG | WCONTINUED | __WCLONE))
889218030Sdchagin		return (EINVAL);
890218030Sdchagin
891127140Sjhb	options = (args->options & (WNOHANG | WUNTRACED));
89283221Smarcel	/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
89383221Smarcel	if (args->options & __WCLONE)
894127140Sjhb		options |= WLINUXCLONE;
89514331Speter
896218030Sdchagin	return (linux_common_wait(td, args->pid, args->status, options, NULL));
897218030Sdchagin}
89814331Speter
89983221Smarcel
90014331Speterint
90183366Sjulianlinux_mknod(struct thread *td, struct linux_mknod_args *args)
90213420Ssos{
903102814Siedowse	char *path;
904102814Siedowse	int error;
90514331Speter
906102814Siedowse	LCONVPATHCREAT(td, args->path, &path);
90714331Speter
90814331Speter#ifdef DEBUG
90972543Sjlemon	if (ldebug(mknod))
910102814Siedowse		printf(ARGS(mknod, "%s, %d, %d"), path, args->mode, args->dev);
91114331Speter#endif
91214331Speter
913164893Sjkim	switch (args->mode & S_IFMT) {
914164893Sjkim	case S_IFIFO:
915164893Sjkim	case S_IFSOCK:
916102814Siedowse		error = kern_mkfifo(td, path, UIO_SYSSPACE, args->mode);
917164893Sjkim		break;
918164893Sjkim
919164893Sjkim	case S_IFCHR:
920164893Sjkim	case S_IFBLK:
921102814Siedowse		error = kern_mknod(td, path, UIO_SYSSPACE, args->mode,
922102814Siedowse		    args->dev);
923164893Sjkim		break;
924164893Sjkim
925164893Sjkim	case S_IFDIR:
926164893Sjkim		error = EPERM;
927164893Sjkim		break;
928164893Sjkim
929164893Sjkim	case 0:
930164893Sjkim		args->mode |= S_IFREG;
931165686Snetchild		/* FALLTHROUGH */
932164893Sjkim	case S_IFREG:
933164893Sjkim		error = kern_open(td, path, UIO_SYSSPACE,
934164893Sjkim		    O_WRONLY | O_CREAT | O_TRUNC, args->mode);
935177997Skib		if (error == 0)
936177997Skib			kern_close(td, td->td_retval[0]);
937164893Sjkim		break;
938164893Sjkim
939164893Sjkim	default:
940164893Sjkim		error = EINVAL;
941164893Sjkim		break;
942164893Sjkim	}
943102814Siedowse	LFREEPATH(path);
944102814Siedowse	return (error);
94513420Ssos}
94614331Speter
947177997Skibint
948177997Skiblinux_mknodat(struct thread *td, struct linux_mknodat_args *args)
949177997Skib{
950177997Skib	char *path;
951177997Skib	int error, dfd;
952177997Skib
953177997Skib	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
954177997Skib	LCONVPATHCREAT_AT(td, args->filename, &path, dfd);
955177997Skib
956177997Skib#ifdef DEBUG
957177997Skib	if (ldebug(mknodat))
958177997Skib		printf(ARGS(mknodat, "%s, %d, %d"), path, args->mode, args->dev);
959177997Skib#endif
960177997Skib
961177997Skib	switch (args->mode & S_IFMT) {
962177997Skib	case S_IFIFO:
963177997Skib	case S_IFSOCK:
964177997Skib		error = kern_mkfifoat(td, dfd, path, UIO_SYSSPACE, args->mode);
965177997Skib		break;
966177997Skib
967177997Skib	case S_IFCHR:
968177997Skib	case S_IFBLK:
969177997Skib		error = kern_mknodat(td, dfd, path, UIO_SYSSPACE, args->mode,
970177997Skib		    args->dev);
971177997Skib		break;
972177997Skib
973177997Skib	case S_IFDIR:
974177997Skib		error = EPERM;
975177997Skib		break;
976177997Skib
977177997Skib	case 0:
978177997Skib		args->mode |= S_IFREG;
979177997Skib		/* FALLTHROUGH */
980177997Skib	case S_IFREG:
981177997Skib		error = kern_openat(td, dfd, path, UIO_SYSSPACE,
982177997Skib		    O_WRONLY | O_CREAT | O_TRUNC, args->mode);
983177997Skib		if (error == 0)
984177997Skib			kern_close(td, td->td_retval[0]);
985177997Skib		break;
986177997Skib
987177997Skib	default:
988177997Skib		error = EINVAL;
989177997Skib		break;
990177997Skib	}
991177997Skib	LFREEPATH(path);
992177997Skib	return (error);
993177997Skib}
994177997Skib
99514331Speter/*
99614331Speter * UGH! This is just about the dumbest idea I've ever heard!!
99714331Speter */
99814331Speterint
99983366Sjulianlinux_personality(struct thread *td, struct linux_personality_args *args)
100014331Speter{
100114331Speter#ifdef DEBUG
100272543Sjlemon	if (ldebug(personality))
1003113579Sjhb		printf(ARGS(personality, "%lu"), (unsigned long)args->per);
100414331Speter#endif
100514331Speter	if (args->per != 0)
100614331Speter		return EINVAL;
100714331Speter
100814331Speter	/* Yes Jim, it's still a Linux... */
100983366Sjulian	td->td_retval[0] = 0;
101014331Speter	return 0;
101114331Speter}
101214331Speter
1013133749Stjrstruct l_itimerval {
1014133749Stjr	l_timeval it_interval;
1015133749Stjr	l_timeval it_value;
1016133749Stjr};
1017133749Stjr
1018140832Ssobomax#define	B2L_ITIMERVAL(bip, lip) 					\
1019140832Ssobomax	(bip)->it_interval.tv_sec = (lip)->it_interval.tv_sec;		\
1020140832Ssobomax	(bip)->it_interval.tv_usec = (lip)->it_interval.tv_usec;	\
1021140832Ssobomax	(bip)->it_value.tv_sec = (lip)->it_value.tv_sec;		\
1022140832Ssobomax	(bip)->it_value.tv_usec = (lip)->it_value.tv_usec;
1023140832Ssobomax
102414331Speterint
1025133749Stjrlinux_setitimer(struct thread *td, struct linux_setitimer_args *uap)
102614331Speter{
102714331Speter	int error;
1028140832Ssobomax	struct l_itimerval ls;
1029140832Ssobomax	struct itimerval aitv, oitv;
103014331Speter
103114331Speter#ifdef DEBUG
103272543Sjlemon	if (ldebug(setitimer))
103372543Sjlemon		printf(ARGS(setitimer, "%p, %p"),
1034133840Sobrien		    (void *)uap->itv, (void *)uap->oitv);
103514331Speter#endif
1036140832Ssobomax
1037140832Ssobomax	if (uap->itv == NULL) {
1038140832Ssobomax		uap->itv = uap->oitv;
1039140832Ssobomax		return (linux_getitimer(td, (struct linux_getitimer_args *)uap));
104014331Speter	}
1041140832Ssobomax
1042140832Ssobomax	error = copyin(uap->itv, &ls, sizeof(ls));
1043133749Stjr	if (error != 0)
1044133749Stjr		return (error);
1045140832Ssobomax	B2L_ITIMERVAL(&aitv, &ls);
1046140832Ssobomax#ifdef DEBUG
1047140832Ssobomax	if (ldebug(setitimer)) {
1048153775Strhodes		printf("setitimer: value: sec: %jd, usec: %ld\n",
1049153775Strhodes		    (intmax_t)aitv.it_value.tv_sec, aitv.it_value.tv_usec);
1050153775Strhodes		printf("setitimer: interval: sec: %jd, usec: %ld\n",
1051153775Strhodes		    (intmax_t)aitv.it_interval.tv_sec, aitv.it_interval.tv_usec);
1052133749Stjr	}
1053140832Ssobomax#endif
1054140832Ssobomax	error = kern_setitimer(td, uap->which, &aitv, &oitv);
1055140832Ssobomax	if (error != 0 || uap->oitv == NULL)
1056140832Ssobomax		return (error);
1057140832Ssobomax	B2L_ITIMERVAL(&ls, &oitv);
1058140832Ssobomax
1059140832Ssobomax	return (copyout(&ls, uap->oitv, sizeof(ls)));
106014331Speter}
106114331Speter
106214331Speterint
1063133749Stjrlinux_getitimer(struct thread *td, struct linux_getitimer_args *uap)
106414331Speter{
1065133749Stjr	int error;
1066140832Ssobomax	struct l_itimerval ls;
1067140832Ssobomax	struct itimerval aitv;
1068133749Stjr
106914331Speter#ifdef DEBUG
107072543Sjlemon	if (ldebug(getitimer))
1071133840Sobrien		printf(ARGS(getitimer, "%p"), (void *)uap->itv);
107214331Speter#endif
1073140832Ssobomax	error = kern_getitimer(td, uap->which, &aitv);
1074133749Stjr	if (error != 0)
1075133749Stjr		return (error);
1076140832Ssobomax	B2L_ITIMERVAL(&ls, &aitv);
1077140832Ssobomax	return (copyout(&ls, uap->itv, sizeof(ls)));
107814331Speter}
107930837Skato
108030837Skatoint
108183366Sjulianlinux_nice(struct thread *td, struct linux_nice_args *args)
108230837Skato{
1083165686Snetchild	struct setpriority_args bsd_args;
108430837Skato
108530837Skato	bsd_args.which = PRIO_PROCESS;
1086165686Snetchild	bsd_args.who = 0;		/* current process */
108730837Skato	bsd_args.prio = args->inc;
108883366Sjulian	return setpriority(td, &bsd_args);
108930837Skato}
109030837Skato
109142185Ssosint
109283366Sjulianlinux_setgroups(struct thread *td, struct linux_setgroups_args *args)
109342185Ssos{
109477183Srwatson	struct ucred *newcred, *oldcred;
1095194498Sbrooks	l_gid_t *linux_gidset;
109650350Smarcel	gid_t *bsd_gidset;
109750350Smarcel	int ngrp, error;
109894621Sjhb	struct proc *p;
109942185Ssos
110083221Smarcel	ngrp = args->gidsetsize;
1101202341Sbrooks	if (ngrp < 0 || ngrp >= ngroups_max + 1)
110294621Sjhb		return (EINVAL);
1103194498Sbrooks	linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_TEMP, M_WAITOK);
1104111797Sdes	error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t));
110594621Sjhb	if (error)
1106194498Sbrooks		goto out;
110794621Sjhb	newcred = crget();
110894621Sjhb	p = td->td_proc;
110994621Sjhb	PROC_LOCK(p);
1110194498Sbrooks	oldcred = crcopysafe(p, newcred);
111142185Ssos
111250350Smarcel	/*
111350350Smarcel	 * cr_groups[0] holds egid. Setting the whole set from
111450350Smarcel	 * the supplied set will cause egid to be changed too.
111550350Smarcel	 * Keep cr_groups[0] unchanged to prevent that.
111650350Smarcel	 */
111742185Ssos
1118170587Srwatson	if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0)) != 0) {
111994621Sjhb		PROC_UNLOCK(p);
112094621Sjhb		crfree(newcred);
1121194498Sbrooks		goto out;
112294621Sjhb	}
112342185Ssos
112450350Smarcel	if (ngrp > 0) {
112577183Srwatson		newcred->cr_ngroups = ngrp + 1;
112650350Smarcel
112777183Srwatson		bsd_gidset = newcred->cr_groups;
112850350Smarcel		ngrp--;
112950350Smarcel		while (ngrp >= 0) {
113050350Smarcel			bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
113150350Smarcel			ngrp--;
113250350Smarcel		}
1133165686Snetchild	} else
113477183Srwatson		newcred->cr_ngroups = 1;
113550350Smarcel
113694621Sjhb	setsugid(p);
113794621Sjhb	p->p_ucred = newcred;
113894621Sjhb	PROC_UNLOCK(p);
113977183Srwatson	crfree(oldcred);
1140194498Sbrooks	error = 0;
1141194498Sbrooksout:
1142194498Sbrooks	free(linux_gidset, M_TEMP);
1143194498Sbrooks	return (error);
114442185Ssos}
114542185Ssos
114642185Ssosint
114783366Sjulianlinux_getgroups(struct thread *td, struct linux_getgroups_args *args)
114842185Ssos{
114977183Srwatson	struct ucred *cred;
1150194498Sbrooks	l_gid_t *linux_gidset;
115150350Smarcel	gid_t *bsd_gidset;
115250350Smarcel	int bsd_gidsetsz, ngrp, error;
115342185Ssos
115494454Sjhb	cred = td->td_ucred;
115577183Srwatson	bsd_gidset = cred->cr_groups;
115677183Srwatson	bsd_gidsetsz = cred->cr_ngroups - 1;
115742185Ssos
115850350Smarcel	/*
115950350Smarcel	 * cr_groups[0] holds egid. Returning the whole set
116050350Smarcel	 * here will cause a duplicate. Exclude cr_groups[0]
116150350Smarcel	 * to prevent that.
116250350Smarcel	 */
116342185Ssos
116483221Smarcel	if ((ngrp = args->gidsetsize) == 0) {
116583366Sjulian		td->td_retval[0] = bsd_gidsetsz;
116650350Smarcel		return (0);
116750350Smarcel	}
116842185Ssos
116950546Smarcel	if (ngrp < bsd_gidsetsz)
117050350Smarcel		return (EINVAL);
117142185Ssos
117250546Smarcel	ngrp = 0;
1173194498Sbrooks	linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset),
1174194498Sbrooks	    M_TEMP, M_WAITOK);
117550350Smarcel	while (ngrp < bsd_gidsetsz) {
117650546Smarcel		linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
117750350Smarcel		ngrp++;
117850350Smarcel	}
117950350Smarcel
1180194498Sbrooks	error = copyout(linux_gidset, args->grouplist, ngrp * sizeof(l_gid_t));
1181194498Sbrooks	free(linux_gidset, M_TEMP);
1182194498Sbrooks	if (error)
118350350Smarcel		return (error);
118450350Smarcel
118583366Sjulian	td->td_retval[0] = ngrp;
118650350Smarcel	return (0);
118742185Ssos}
118849626Smarcel
118949626Smarcelint
119083366Sjulianlinux_setrlimit(struct thread *td, struct linux_setrlimit_args *args)
119149626Smarcel{
1192102814Siedowse	struct rlimit bsd_rlim;
119383221Smarcel	struct l_rlimit rlim;
1194102814Siedowse	u_int which;
119565099Smarcel	int error;
119649842Smarcel
119749626Smarcel#ifdef DEBUG
119872543Sjlemon	if (ldebug(setrlimit))
119972543Sjlemon		printf(ARGS(setrlimit, "%d, %p"),
120083221Smarcel		    args->resource, (void *)args->rlim);
120149626Smarcel#endif
120249626Smarcel
120383221Smarcel	if (args->resource >= LINUX_RLIM_NLIMITS)
120465099Smarcel		return (EINVAL);
120549626Smarcel
1206102814Siedowse	which = linux_to_bsd_resource[args->resource];
1207102814Siedowse	if (which == -1)
120865099Smarcel		return (EINVAL);
120949626Smarcel
1210111797Sdes	error = copyin(args->rlim, &rlim, sizeof(rlim));
121165099Smarcel	if (error)
121265099Smarcel		return (error);
121349626Smarcel
1214102814Siedowse	bsd_rlim.rlim_cur = (rlim_t)rlim.rlim_cur;
1215102814Siedowse	bsd_rlim.rlim_max = (rlim_t)rlim.rlim_max;
1216125454Sjhb	return (kern_setrlimit(td, which, &bsd_rlim));
121749626Smarcel}
121849626Smarcel
121949626Smarcelint
122083366Sjulianlinux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args)
122149626Smarcel{
122283221Smarcel	struct l_rlimit rlim;
1223102814Siedowse	struct proc *p = td->td_proc;
1224125454Sjhb	struct rlimit bsd_rlim;
1225102814Siedowse	u_int which;
122649842Smarcel
122749626Smarcel#ifdef DEBUG
122883221Smarcel	if (ldebug(old_getrlimit))
122983221Smarcel		printf(ARGS(old_getrlimit, "%d, %p"),
123083221Smarcel		    args->resource, (void *)args->rlim);
123149626Smarcel#endif
123249626Smarcel
123383221Smarcel	if (args->resource >= LINUX_RLIM_NLIMITS)
123465099Smarcel		return (EINVAL);
123549626Smarcel
1236102814Siedowse	which = linux_to_bsd_resource[args->resource];
1237102814Siedowse	if (which == -1)
123865099Smarcel		return (EINVAL);
123949626Smarcel
1240125454Sjhb	PROC_LOCK(p);
1241125454Sjhb	lim_rlimit(p, which, &bsd_rlim);
1242125454Sjhb	PROC_UNLOCK(p);
1243125454Sjhb
1244140214Sobrien#ifdef COMPAT_LINUX32
1245140214Sobrien	rlim.rlim_cur = (unsigned int)bsd_rlim.rlim_cur;
1246140214Sobrien	if (rlim.rlim_cur == UINT_MAX)
1247140214Sobrien		rlim.rlim_cur = INT_MAX;
1248140214Sobrien	rlim.rlim_max = (unsigned int)bsd_rlim.rlim_max;
1249140214Sobrien	if (rlim.rlim_max == UINT_MAX)
1250140214Sobrien		rlim.rlim_max = INT_MAX;
1251140214Sobrien#else
1252125454Sjhb	rlim.rlim_cur = (unsigned long)bsd_rlim.rlim_cur;
125365106Smarcel	if (rlim.rlim_cur == ULONG_MAX)
125465106Smarcel		rlim.rlim_cur = LONG_MAX;
1255125454Sjhb	rlim.rlim_max = (unsigned long)bsd_rlim.rlim_max;
125665106Smarcel	if (rlim.rlim_max == ULONG_MAX)
125765106Smarcel		rlim.rlim_max = LONG_MAX;
1258133816Stjr#endif
1259111797Sdes	return (copyout(&rlim, args->rlim, sizeof(rlim)));
126049626Smarcel}
126183221Smarcel
126283221Smarcelint
126383366Sjulianlinux_getrlimit(struct thread *td, struct linux_getrlimit_args *args)
126483221Smarcel{
126583221Smarcel	struct l_rlimit rlim;
1266102814Siedowse	struct proc *p = td->td_proc;
1267125454Sjhb	struct rlimit bsd_rlim;
1268102814Siedowse	u_int which;
126983221Smarcel
127083221Smarcel#ifdef DEBUG
127183221Smarcel	if (ldebug(getrlimit))
127283221Smarcel		printf(ARGS(getrlimit, "%d, %p"),
127383221Smarcel		    args->resource, (void *)args->rlim);
127483221Smarcel#endif
127583221Smarcel
127683221Smarcel	if (args->resource >= LINUX_RLIM_NLIMITS)
127783221Smarcel		return (EINVAL);
127883221Smarcel
1279102814Siedowse	which = linux_to_bsd_resource[args->resource];
1280102814Siedowse	if (which == -1)
128183221Smarcel		return (EINVAL);
128283221Smarcel
1283125454Sjhb	PROC_LOCK(p);
1284125454Sjhb	lim_rlimit(p, which, &bsd_rlim);
1285125454Sjhb	PROC_UNLOCK(p);
1286125454Sjhb
1287125454Sjhb	rlim.rlim_cur = (l_ulong)bsd_rlim.rlim_cur;
1288125454Sjhb	rlim.rlim_max = (l_ulong)bsd_rlim.rlim_max;
1289111797Sdes	return (copyout(&rlim, args->rlim, sizeof(rlim)));
129083221Smarcel}
129149849Smarcel
129249849Smarcelint
129383366Sjulianlinux_sched_setscheduler(struct thread *td,
129483221Smarcel    struct linux_sched_setscheduler_args *args)
129549849Smarcel{
129649849Smarcel	struct sched_setscheduler_args bsd;
129749849Smarcel
129849849Smarcel#ifdef DEBUG
129972543Sjlemon	if (ldebug(sched_setscheduler))
130072543Sjlemon		printf(ARGS(sched_setscheduler, "%d, %d, %p"),
130183221Smarcel		    args->pid, args->policy, (const void *)args->param);
130249849Smarcel#endif
130349849Smarcel
130483221Smarcel	switch (args->policy) {
130549849Smarcel	case LINUX_SCHED_OTHER:
130649849Smarcel		bsd.policy = SCHED_OTHER;
130749849Smarcel		break;
130849849Smarcel	case LINUX_SCHED_FIFO:
130949849Smarcel		bsd.policy = SCHED_FIFO;
131049849Smarcel		break;
131149849Smarcel	case LINUX_SCHED_RR:
131249849Smarcel		bsd.policy = SCHED_RR;
131349849Smarcel		break;
131449849Smarcel	default:
131549849Smarcel		return EINVAL;
131649849Smarcel	}
131749849Smarcel
131883221Smarcel	bsd.pid = args->pid;
131983221Smarcel	bsd.param = (struct sched_param *)args->param;
132083366Sjulian	return sched_setscheduler(td, &bsd);
132149849Smarcel}
132249849Smarcel
132349849Smarcelint
132483366Sjulianlinux_sched_getscheduler(struct thread *td,
132583221Smarcel    struct linux_sched_getscheduler_args *args)
132649849Smarcel{
132749849Smarcel	struct sched_getscheduler_args bsd;
132849849Smarcel	int error;
132949849Smarcel
133049849Smarcel#ifdef DEBUG
133172543Sjlemon	if (ldebug(sched_getscheduler))
133283221Smarcel		printf(ARGS(sched_getscheduler, "%d"), args->pid);
133349849Smarcel#endif
133449849Smarcel
133583221Smarcel	bsd.pid = args->pid;
133683366Sjulian	error = sched_getscheduler(td, &bsd);
133749849Smarcel
133883366Sjulian	switch (td->td_retval[0]) {
133949849Smarcel	case SCHED_OTHER:
134083366Sjulian		td->td_retval[0] = LINUX_SCHED_OTHER;
134149849Smarcel		break;
134249849Smarcel	case SCHED_FIFO:
134383366Sjulian		td->td_retval[0] = LINUX_SCHED_FIFO;
134449849Smarcel		break;
134549849Smarcel	case SCHED_RR:
134683366Sjulian		td->td_retval[0] = LINUX_SCHED_RR;
134749849Smarcel		break;
134849849Smarcel	}
134949849Smarcel
135049849Smarcel	return error;
135149849Smarcel}
135272538Sjlemon
135375053Salcint
135483366Sjulianlinux_sched_get_priority_max(struct thread *td,
135583221Smarcel    struct linux_sched_get_priority_max_args *args)
135675053Salc{
135775053Salc	struct sched_get_priority_max_args bsd;
135875053Salc
135975053Salc#ifdef DEBUG
136075053Salc	if (ldebug(sched_get_priority_max))
136183221Smarcel		printf(ARGS(sched_get_priority_max, "%d"), args->policy);
136275053Salc#endif
136375053Salc
136483221Smarcel	switch (args->policy) {
136575053Salc	case LINUX_SCHED_OTHER:
136675053Salc		bsd.policy = SCHED_OTHER;
136775053Salc		break;
136875053Salc	case LINUX_SCHED_FIFO:
136975053Salc		bsd.policy = SCHED_FIFO;
137075053Salc		break;
137175053Salc	case LINUX_SCHED_RR:
137275053Salc		bsd.policy = SCHED_RR;
137375053Salc		break;
137475053Salc	default:
137575053Salc		return EINVAL;
137675053Salc	}
137783366Sjulian	return sched_get_priority_max(td, &bsd);
137875053Salc}
137975053Salc
138075053Salcint
138183366Sjulianlinux_sched_get_priority_min(struct thread *td,
138283221Smarcel    struct linux_sched_get_priority_min_args *args)
138375053Salc{
138475053Salc	struct sched_get_priority_min_args bsd;
138575053Salc
138675053Salc#ifdef DEBUG
138775053Salc	if (ldebug(sched_get_priority_min))
138883221Smarcel		printf(ARGS(sched_get_priority_min, "%d"), args->policy);
138975053Salc#endif
139075053Salc
139183221Smarcel	switch (args->policy) {
139275053Salc	case LINUX_SCHED_OTHER:
139375053Salc		bsd.policy = SCHED_OTHER;
139475053Salc		break;
139575053Salc	case LINUX_SCHED_FIFO:
139675053Salc		bsd.policy = SCHED_FIFO;
139775053Salc		break;
139875053Salc	case LINUX_SCHED_RR:
139975053Salc		bsd.policy = SCHED_RR;
140075053Salc		break;
140175053Salc	default:
140275053Salc		return EINVAL;
140375053Salc	}
140483366Sjulian	return sched_get_priority_min(td, &bsd);
140575053Salc}
140675053Salc
140772538Sjlemon#define REBOOT_CAD_ON	0x89abcdef
140872538Sjlemon#define REBOOT_CAD_OFF	0
140972538Sjlemon#define REBOOT_HALT	0xcdef0123
1410162358Snetchild#define REBOOT_RESTART	0x01234567
1411162358Snetchild#define REBOOT_RESTART2	0xA1B2C3D4
1412162358Snetchild#define REBOOT_POWEROFF	0x4321FEDC
1413162358Snetchild#define REBOOT_MAGIC1	0xfee1dead
1414162358Snetchild#define REBOOT_MAGIC2	0x28121969
1415162358Snetchild#define REBOOT_MAGIC2A	0x05121996
1416162358Snetchild#define REBOOT_MAGIC2B	0x16041998
141772538Sjlemon
141872538Sjlemonint
141983366Sjulianlinux_reboot(struct thread *td, struct linux_reboot_args *args)
142072538Sjlemon{
142172538Sjlemon	struct reboot_args bsd_args;
142272538Sjlemon
142372538Sjlemon#ifdef DEBUG
142472538Sjlemon	if (ldebug(reboot))
142583221Smarcel		printf(ARGS(reboot, "0x%x"), args->cmd);
142672538Sjlemon#endif
1427162358Snetchild
1428162358Snetchild	if (args->magic1 != REBOOT_MAGIC1)
1429162358Snetchild		return EINVAL;
1430162358Snetchild
1431162358Snetchild	switch (args->magic2) {
1432162358Snetchild	case REBOOT_MAGIC2:
1433162358Snetchild	case REBOOT_MAGIC2A:
1434162358Snetchild	case REBOOT_MAGIC2B:
1435162358Snetchild		break;
1436162358Snetchild	default:
1437162358Snetchild		return EINVAL;
1438162358Snetchild	}
1439162358Snetchild
1440162358Snetchild	switch (args->cmd) {
1441162358Snetchild	case REBOOT_CAD_ON:
1442162358Snetchild	case REBOOT_CAD_OFF:
1443164033Srwatson		return (priv_check(td, PRIV_REBOOT));
1444162358Snetchild	case REBOOT_HALT:
1445162358Snetchild		bsd_args.opt = RB_HALT;
1446162358Snetchild		break;
1447162358Snetchild	case REBOOT_RESTART:
1448162358Snetchild	case REBOOT_RESTART2:
1449162358Snetchild		bsd_args.opt = 0;
1450162358Snetchild		break;
1451162358Snetchild	case REBOOT_POWEROFF:
1452162358Snetchild		bsd_args.opt = RB_POWEROFF;
1453162358Snetchild		break;
1454162358Snetchild	default:
1455162358Snetchild		return EINVAL;
1456162358Snetchild	}
1457162358Snetchild	return reboot(td, &bsd_args);
145872538Sjlemon}
145983221Smarcel
146089717Sgallatin
146183221Smarcel/*
146283221Smarcel * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify
1463166944Snetchild * td->td_retval[1] when COMPAT_43 is defined. This clobbers registers that
1464166944Snetchild * are assumed to be preserved. The following lightweight syscalls fixes
1465166944Snetchild * this. See also linux_getgid16() and linux_getuid16() in linux_uid16.c
146683221Smarcel *
146783221Smarcel * linux_getpid() - MP SAFE
146883221Smarcel * linux_getgid() - MP SAFE
146983221Smarcel * linux_getuid() - MP SAFE
147083221Smarcel */
147183221Smarcel
147283221Smarcelint
147383366Sjulianlinux_getpid(struct thread *td, struct linux_getpid_args *args)
147483221Smarcel{
1475165686Snetchild	struct linux_emuldata *em;
147683366Sjulian
1477164378Skib#ifdef DEBUG
1478164378Skib	if (ldebug(getpid))
1479164378Skib		printf(ARGS(getpid, ""));
1480164378Skib#endif
1481164378Skib
1482165687Snetchild	if (linux_use26(td)) {
1483165869Snetchild		em = em_find(td->td_proc, EMUL_DONTLOCK);
1484161420Snetchild		KASSERT(em != NULL, ("getpid: emuldata not found.\n"));
1485165686Snetchild		td->td_retval[0] = em->shared->group_pid;
1486161420Snetchild	} else {
1487165686Snetchild		td->td_retval[0] = td->td_proc->p_pid;
1488161420Snetchild	}
1489161474Snetchild
1490161310Snetchild	return (0);
1491161310Snetchild}
1492161310Snetchild
1493161310Snetchildint
1494161310Snetchildlinux_gettid(struct thread *td, struct linux_gettid_args *args)
1495161310Snetchild{
1496170152Skib
1497161310Snetchild#ifdef DEBUG
1498161310Snetchild	if (ldebug(gettid))
1499161310Snetchild		printf(ARGS(gettid, ""));
1500161310Snetchild#endif
1501161310Snetchild
150283366Sjulian	td->td_retval[0] = td->td_proc->p_pid;
150383221Smarcel	return (0);
150483221Smarcel}
150583221Smarcel
1506161310Snetchild
150783221Smarcelint
1508161310Snetchildlinux_getppid(struct thread *td, struct linux_getppid_args *args)
1509161310Snetchild{
1510165686Snetchild	struct linux_emuldata *em;
1511161310Snetchild	struct proc *p, *pp;
1512161310Snetchild
1513164378Skib#ifdef DEBUG
1514164378Skib	if (ldebug(getppid))
1515164378Skib		printf(ARGS(getppid, ""));
1516164378Skib#endif
1517164378Skib
1518165687Snetchild	if (!linux_use26(td)) {
1519165686Snetchild		PROC_LOCK(td->td_proc);
1520165686Snetchild		td->td_retval[0] = td->td_proc->p_pptr->p_pid;
1521165686Snetchild		PROC_UNLOCK(td->td_proc);
1522161420Snetchild		return (0);
1523161420Snetchild	}
1524161420Snetchild
1525165869Snetchild	em = em_find(td->td_proc, EMUL_DONTLOCK);
1526161310Snetchild
1527161310Snetchild	KASSERT(em != NULL, ("getppid: process emuldata not found.\n"));
1528161310Snetchild
1529161310Snetchild	/* find the group leader */
1530161310Snetchild	p = pfind(em->shared->group_pid);
1531161310Snetchild
1532161310Snetchild	if (p == NULL) {
1533161310Snetchild#ifdef DEBUG
1534161310Snetchild	   	printf(LMSG("parent process not found.\n"));
1535161310Snetchild#endif
1536161310Snetchild		return (0);
1537161310Snetchild	}
1538161310Snetchild
1539161310Snetchild	pp = p->p_pptr;		/* switch to parent */
1540161310Snetchild	PROC_LOCK(pp);
1541161310Snetchild	PROC_UNLOCK(p);
1542161310Snetchild
1543161310Snetchild	/* if its also linux process */
1544161310Snetchild	if (pp->p_sysent == &elf_linux_sysvec) {
1545165867Snetchild		em = em_find(pp, EMUL_DONTLOCK);
1546161310Snetchild		KASSERT(em != NULL, ("getppid: parent emuldata not found.\n"));
1547161310Snetchild
1548161420Snetchild		td->td_retval[0] = em->shared->group_pid;
1549161310Snetchild	} else
1550165686Snetchild		td->td_retval[0] = pp->p_pid;
1551161310Snetchild
1552161310Snetchild	PROC_UNLOCK(pp);
1553161420Snetchild
1554161310Snetchild	return (0);
1555161310Snetchild}
1556161310Snetchild
1557161310Snetchildint
155883366Sjulianlinux_getgid(struct thread *td, struct linux_getgid_args *args)
155983221Smarcel{
156083366Sjulian
1561164378Skib#ifdef DEBUG
1562164378Skib	if (ldebug(getgid))
1563164378Skib		printf(ARGS(getgid, ""));
1564164378Skib#endif
1565164378Skib
156694454Sjhb	td->td_retval[0] = td->td_ucred->cr_rgid;
156783221Smarcel	return (0);
156883221Smarcel}
156983221Smarcel
157083221Smarcelint
157183366Sjulianlinux_getuid(struct thread *td, struct linux_getuid_args *args)
157283221Smarcel{
157383366Sjulian
1574164378Skib#ifdef DEBUG
1575164378Skib	if (ldebug(getuid))
1576164378Skib		printf(ARGS(getuid, ""));
1577164378Skib#endif
1578164378Skib
157994454Sjhb	td->td_retval[0] = td->td_ucred->cr_ruid;
158083221Smarcel	return (0);
158183221Smarcel}
158283503Smr
158389717Sgallatin
158483503Smrint
158583503Smrlinux_getsid(struct thread *td, struct linux_getsid_args *args)
158683503Smr{
158783503Smr	struct getsid_args bsd;
1588164378Skib
1589164378Skib#ifdef DEBUG
1590164378Skib	if (ldebug(getsid))
1591164378Skib		printf(ARGS(getsid, "%i"), args->pid);
1592164378Skib#endif
1593164378Skib
159483503Smr	bsd.pid = args->pid;
159583503Smr	return getsid(td, &bsd);
159683503Smr}
1597143197Ssobomax
1598143197Ssobomaxint
1599143197Ssobomaxlinux_nosys(struct thread *td, struct nosys_args *ignore)
1600143197Ssobomax{
1601143197Ssobomax
1602143197Ssobomax	return (ENOSYS);
1603143197Ssobomax}
1604147141Ssobomax
1605147141Ssobomaxint
1606147141Ssobomaxlinux_getpriority(struct thread *td, struct linux_getpriority_args *args)
1607147141Ssobomax{
1608165686Snetchild	struct getpriority_args bsd_args;
1609147141Ssobomax	int error;
1610147141Ssobomax
1611164378Skib#ifdef DEBUG
1612164378Skib	if (ldebug(getpriority))
1613164378Skib		printf(ARGS(getpriority, "%i, %i"), args->which, args->who);
1614164378Skib#endif
1615164378Skib
1616147141Ssobomax	bsd_args.which = args->which;
1617147141Ssobomax	bsd_args.who = args->who;
1618147141Ssobomax	error = getpriority(td, &bsd_args);
1619147141Ssobomax	td->td_retval[0] = 20 - td->td_retval[0];
1620147141Ssobomax	return error;
1621147141Ssobomax}
1622156842Snetchild
1623156842Snetchildint
1624156842Snetchildlinux_sethostname(struct thread *td, struct linux_sethostname_args *args)
1625156842Snetchild{
1626156842Snetchild	int name[2];
1627156842Snetchild
1628164378Skib#ifdef DEBUG
1629164378Skib	if (ldebug(sethostname))
1630164378Skib		printf(ARGS(sethostname, "*, %i"), args->len);
1631164378Skib#endif
1632164378Skib
1633156842Snetchild	name[0] = CTL_KERN;
1634156842Snetchild	name[1] = KERN_HOSTNAME;
1635186564Sed	return (userland_sysctl(td, name, 2, 0, 0, 0, args->hostname,
1636186564Sed	    args->len, 0, 0));
1637156842Snetchild}
1638156842Snetchild
1639161310Snetchildint
1640184789Sedlinux_setdomainname(struct thread *td, struct linux_setdomainname_args *args)
1641184789Sed{
1642184789Sed	int name[2];
1643184789Sed
1644184789Sed#ifdef DEBUG
1645184789Sed	if (ldebug(setdomainname))
1646184789Sed		printf(ARGS(setdomainname, "*, %i"), args->len);
1647184789Sed#endif
1648184789Sed
1649184789Sed	name[0] = CTL_KERN;
1650184789Sed	name[1] = KERN_NISDOMAINNAME;
1651186564Sed	return (userland_sysctl(td, name, 2, 0, 0, 0, args->name,
1652186564Sed	    args->len, 0, 0));
1653184789Sed}
1654184789Sed
1655184789Sedint
1656161310Snetchildlinux_exit_group(struct thread *td, struct linux_exit_group_args *args)
1657161310Snetchild{
1658215664Snetchild	struct linux_emuldata *em;
1659161310Snetchild
1660161310Snetchild#ifdef DEBUG
1661161310Snetchild	if (ldebug(exit_group))
1662161310Snetchild		printf(ARGS(exit_group, "%i"), args->error_code);
1663161310Snetchild#endif
1664161310Snetchild
1665215664Snetchild	em = em_find(td->td_proc, EMUL_DONTLOCK);
1666215664Snetchild	if (em->shared->refs > 1) {
1667215664Snetchild		EMUL_SHARED_WLOCK(&emul_shared_lock);
1668215664Snetchild		em->shared->flags |= EMUL_SHARED_HASXSTAT;
1669215664Snetchild		em->shared->xstat = W_EXITCODE(args->error_code, 0);
1670215664Snetchild		EMUL_SHARED_WUNLOCK(&emul_shared_lock);
1671215664Snetchild		if (linux_use26(td))
1672215664Snetchild			linux_kill_threads(td, SIGKILL);
1673215664Snetchild	}
1674161310Snetchild
1675165686Snetchild	/*
1676165686Snetchild	 * XXX: we should send a signal to the parent if
1677166397Skib	 * SIGNAL_EXIT_GROUP is set. We ignore that (temporarily?)
1678165686Snetchild	 * as it doesnt occur often.
1679165686Snetchild	 */
1680165686Snetchild	exit1(td, W_EXITCODE(args->error_code, 0));
1681161310Snetchild
1682165686Snetchild	return (0);
1683161310Snetchild}
1684163734Snetchild
1685163734Snetchildint
1686163734Snetchildlinux_prctl(struct thread *td, struct linux_prctl_args *args)
1687163734Snetchild{
1688165686Snetchild	int error = 0, max_size;
1689163734Snetchild	struct proc *p = td->td_proc;
1690163734Snetchild	char comm[LINUX_MAX_COMM_LEN];
1691163734Snetchild	struct linux_emuldata *em;
1692166931Snetchild	int pdeath_signal;
1693163734Snetchild
1694163734Snetchild#ifdef DEBUG
1695163734Snetchild	if (ldebug(prctl))
1696165686Snetchild		printf(ARGS(prctl, "%d, %d, %d, %d, %d"), args->option,
1697165686Snetchild		    args->arg2, args->arg3, args->arg4, args->arg5);
1698163734Snetchild#endif
1699165686Snetchild
1700165686Snetchild	switch (args->option) {
1701165686Snetchild	case LINUX_PR_SET_PDEATHSIG:
1702165686Snetchild		if (!LINUX_SIG_VALID(args->arg2))
1703165686Snetchild			return (EINVAL);
1704165867Snetchild		em = em_find(p, EMUL_DOLOCK);
1705163740Snetchild		KASSERT(em != NULL, ("prctl: emuldata not found.\n"));
1706163740Snetchild		em->pdeath_signal = args->arg2;
1707163740Snetchild		EMUL_UNLOCK(&emul_lock);
1708165686Snetchild		break;
1709163740Snetchild	case LINUX_PR_GET_PDEATHSIG:
1710165867Snetchild		em = em_find(p, EMUL_DOLOCK);
1711163740Snetchild		KASSERT(em != NULL, ("prctl: emuldata not found.\n"));
1712166931Snetchild		pdeath_signal = em->pdeath_signal;
1713166931Snetchild		EMUL_UNLOCK(&emul_lock);
1714166931Snetchild		error = copyout(&pdeath_signal,
1715165686Snetchild		    (void *)(register_t)args->arg2,
1716166931Snetchild		    sizeof(pdeath_signal));
1717163740Snetchild		break;
1718163740Snetchild	case LINUX_PR_SET_NAME:
1719164826Snetchild		/*
1720164826Snetchild		 * To be on the safe side we need to make sure to not
1721164826Snetchild		 * overflow the size a linux program expects. We already
1722164826Snetchild		 * do this here in the copyin, so that we don't need to
1723164826Snetchild		 * check on copyout.
1724164826Snetchild		 */
1725164826Snetchild		max_size = MIN(sizeof(comm), sizeof(p->p_comm));
1726165686Snetchild		error = copyinstr((void *)(register_t)args->arg2, comm,
1727164826Snetchild		    max_size, NULL);
1728164826Snetchild
1729164826Snetchild		/* Linux silently truncates the name if it is too long. */
1730164826Snetchild		if (error == ENAMETOOLONG) {
1731164826Snetchild			/*
1732164826Snetchild			 * XXX: copyinstr() isn't documented to populate the
1733164826Snetchild			 * array completely, so do a copyin() to be on the
1734164826Snetchild			 * safe side. This should be changed in case
1735164826Snetchild			 * copyinstr() is changed to guarantee this.
1736164826Snetchild			 */
1737164826Snetchild			error = copyin((void *)(register_t)args->arg2, comm,
1738164826Snetchild			    max_size - 1);
1739164826Snetchild			comm[max_size - 1] = '\0';
1740164826Snetchild		}
1741163740Snetchild		if (error)
1742165686Snetchild			return (error);
1743164826Snetchild
1744163740Snetchild		PROC_LOCK(p);
1745164826Snetchild		strlcpy(p->p_comm, comm, sizeof(p->p_comm));
1746163740Snetchild		PROC_UNLOCK(p);
1747163740Snetchild		break;
1748163740Snetchild	case LINUX_PR_GET_NAME:
1749164826Snetchild		PROC_LOCK(p);
1750164826Snetchild		strlcpy(comm, p->p_comm, sizeof(comm));
1751164826Snetchild		PROC_UNLOCK(p);
1752165686Snetchild		error = copyout(comm, (void *)(register_t)args->arg2,
1753165686Snetchild		    strlen(comm) + 1);
1754163740Snetchild		break;
1755163740Snetchild	default:
1756163740Snetchild		error = EINVAL;
1757163740Snetchild		break;
1758163734Snetchild	}
1759163734Snetchild
1760163734Snetchild	return (error);
1761163734Snetchild}
1762171998Skib
1763171998Skib/*
1764177257Srdivacky * Get affinity of a process.
1765171998Skib */
1766171998Skibint
1767171998Skiblinux_sched_getaffinity(struct thread *td,
1768171998Skib    struct linux_sched_getaffinity_args *args)
1769171998Skib{
1770171998Skib	int error;
1771177257Srdivacky	struct cpuset_getaffinity_args cga;
1772171998Skib
1773177257Srdivacky#ifdef DEBUG
1774177257Srdivacky	if (ldebug(sched_getaffinity))
1775177257Srdivacky		printf(ARGS(sched_getaffinity, "%d, %d, *"), args->pid,
1776177257Srdivacky		    args->len);
1777177257Srdivacky#endif
1778183612Skib	if (args->len < sizeof(cpuset_t))
1779183612Skib		return (EINVAL);
1780171998Skib
1781177257Srdivacky	cga.level = CPU_LEVEL_WHICH;
1782177257Srdivacky	cga.which = CPU_WHICH_PID;
1783177257Srdivacky	cga.id = args->pid;
1784183612Skib	cga.cpusetsize = sizeof(cpuset_t);
1785177604Sru	cga.mask = (cpuset_t *) args->user_mask_ptr;
1786183612Skib
1787177257Srdivacky	if ((error = cpuset_getaffinity(td, &cga)) == 0)
1788183612Skib		td->td_retval[0] = sizeof(cpuset_t);
1789171998Skib
1790177257Srdivacky	return (error);
1791171998Skib}
1792177257Srdivacky
1793177257Srdivacky/*
1794177257Srdivacky *  Set affinity of a process.
1795177257Srdivacky */
1796177257Srdivackyint
1797177257Srdivackylinux_sched_setaffinity(struct thread *td,
1798177257Srdivacky    struct linux_sched_setaffinity_args *args)
1799177257Srdivacky{
1800177257Srdivacky	struct cpuset_setaffinity_args csa;
1801177257Srdivacky
1802177257Srdivacky#ifdef DEBUG
1803177257Srdivacky	if (ldebug(sched_setaffinity))
1804177257Srdivacky		printf(ARGS(sched_setaffinity, "%d, %d, *"), args->pid,
1805177257Srdivacky		    args->len);
1806177257Srdivacky#endif
1807183612Skib	if (args->len < sizeof(cpuset_t))
1808183612Skib		return (EINVAL);
1809183612Skib
1810177257Srdivacky	csa.level = CPU_LEVEL_WHICH;
1811177257Srdivacky	csa.which = CPU_WHICH_PID;
1812177257Srdivacky	csa.id = args->pid;
1813183612Skib	csa.cpusetsize = sizeof(cpuset_t);
1814177604Sru	csa.mask = (cpuset_t *) args->user_mask_ptr;
1815177257Srdivacky
1816177257Srdivacky	return (cpuset_setaffinity(td, &csa));
1817177257Srdivacky}
1818