linux_misc.c revision 161317
1/*-
2 * Copyright (c) 2002 Doug Rabson
3 * Copyright (c) 1994-1995 S�ren Schmidt
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer
11 *    in this position and unchanged.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/compat/linux/linux_misc.c 161317 2006-08-15 15:15:17Z netchild $");
32
33#include "opt_compat.h"
34#include "opt_mac.h"
35
36#include <sys/param.h>
37#include <sys/blist.h>
38#include <sys/fcntl.h>
39#if defined(__i386__)
40#include <sys/imgact_aout.h>
41#endif
42#include <sys/jail.h>
43#include <sys/kernel.h>
44#include <sys/limits.h>
45#include <sys/lock.h>
46#include <sys/mac.h>
47#include <sys/malloc.h>
48#include <sys/mman.h>
49#include <sys/mount.h>
50#include <sys/mutex.h>
51#include <sys/namei.h>
52#include <sys/proc.h>
53#include <sys/reboot.h>
54#include <sys/resourcevar.h>
55#include <sys/signalvar.h>
56#include <sys/stat.h>
57#include <sys/syscallsubr.h>
58#include <sys/sysctl.h>
59#include <sys/sysproto.h>
60#include <sys/systm.h>
61#include <sys/time.h>
62#include <sys/vmmeter.h>
63#include <sys/vnode.h>
64#include <sys/wait.h>
65
66#include <vm/vm.h>
67#include <vm/pmap.h>
68#include <vm/vm_kern.h>
69#include <vm/vm_map.h>
70#include <vm/vm_extern.h>
71#include <vm/vm_object.h>
72#include <vm/swap_pager.h>
73
74#include <posix4/sched.h>
75
76#include <compat/linux/linux_sysproto.h>
77#include <compat/linux/linux_emul.h>
78
79#ifdef COMPAT_LINUX32
80#include <machine/../linux32/linux.h>
81#include <machine/../linux32/linux32_proto.h>
82#else
83#include <machine/../linux/linux.h>
84#include <machine/../linux/linux_proto.h>
85#endif
86
87#include <compat/linux/linux_mib.h>
88#include <compat/linux/linux_util.h>
89
90#ifdef __i386__
91#include <machine/cputypes.h>
92#endif
93
94#define BSD_TO_LINUX_SIGNAL(sig)	\
95	(((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
96
97extern struct sx emul_shared_lock;
98extern struct sx emul_lock;
99
100static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = {
101	RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK,
102	RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE,
103	RLIMIT_MEMLOCK, -1
104};
105
106struct l_sysinfo {
107	l_long		uptime;		/* Seconds since boot */
108	l_ulong		loads[3];	/* 1, 5, and 15 minute load averages */
109#define LINUX_SYSINFO_LOADS_SCALE 65536
110	l_ulong		totalram;	/* Total usable main memory size */
111	l_ulong		freeram;	/* Available memory size */
112	l_ulong		sharedram;	/* Amount of shared memory */
113	l_ulong		bufferram;	/* Memory used by buffers */
114	l_ulong		totalswap;	/* Total swap space size */
115	l_ulong		freeswap;	/* swap space still available */
116	l_ushort	procs;		/* Number of current processes */
117	l_ulong		totalbig;
118	l_ulong		freebig;
119	l_uint		mem_unit;
120	char		_f[6];		/* Pads structure to 64 bytes */
121};
122int
123linux_sysinfo(struct thread *td, struct linux_sysinfo_args *args)
124{
125	struct l_sysinfo sysinfo;
126	vm_object_t object;
127	int i, j;
128	struct timespec ts;
129
130	getnanouptime(&ts);
131	if (ts.tv_nsec != 0)
132		ts.tv_sec++;
133	sysinfo.uptime = ts.tv_sec;
134
135	/* Use the information from the mib to get our load averages */
136	for (i = 0; i < 3; i++)
137		sysinfo.loads[i] = averunnable.ldavg[i] *
138		    LINUX_SYSINFO_LOADS_SCALE / averunnable.fscale;
139
140	sysinfo.totalram = physmem * PAGE_SIZE;
141	sysinfo.freeram = sysinfo.totalram - cnt.v_wire_count * PAGE_SIZE;
142
143	sysinfo.sharedram = 0;
144	mtx_lock(&vm_object_list_mtx);
145	TAILQ_FOREACH(object, &vm_object_list, object_list)
146		if (object->shadow_count > 1)
147			sysinfo.sharedram += object->resident_page_count;
148	mtx_unlock(&vm_object_list_mtx);
149
150	sysinfo.sharedram *= PAGE_SIZE;
151	sysinfo.bufferram = 0;
152
153	swap_pager_status(&i, &j);
154	sysinfo.totalswap= i * PAGE_SIZE;
155	sysinfo.freeswap = (i - j) * PAGE_SIZE;
156
157	sysinfo.procs = nprocs;
158
159	/* The following are only present in newer Linux kernels. */
160	sysinfo.totalbig = 0;
161	sysinfo.freebig = 0;
162	sysinfo.mem_unit = 1;
163
164	return copyout(&sysinfo, args->info, sizeof(sysinfo));
165}
166
167int
168linux_alarm(struct thread *td, struct linux_alarm_args *args)
169{
170	struct itimerval it, old_it;
171	int error;
172
173#ifdef DEBUG
174	if (ldebug(alarm))
175		printf(ARGS(alarm, "%u"), args->secs);
176#endif
177
178	if (args->secs > 100000000)
179		return (EINVAL);
180
181	it.it_value.tv_sec = (long)args->secs;
182	it.it_value.tv_usec = 0;
183	it.it_interval.tv_sec = 0;
184	it.it_interval.tv_usec = 0;
185	error = kern_setitimer(td, ITIMER_REAL, &it, &old_it);
186	if (error)
187		return (error);
188	if (timevalisset(&old_it.it_value)) {
189		if (old_it.it_value.tv_usec != 0)
190			old_it.it_value.tv_sec++;
191		td->td_retval[0] = old_it.it_value.tv_sec;
192	}
193	return (0);
194}
195
196int
197linux_brk(struct thread *td, struct linux_brk_args *args)
198{
199	struct vmspace *vm = td->td_proc->p_vmspace;
200	vm_offset_t new, old;
201	struct obreak_args /* {
202		char * nsize;
203	} */ tmp;
204
205#ifdef DEBUG
206	if (ldebug(brk))
207		printf(ARGS(brk, "%p"), (void *)(uintptr_t)args->dsend);
208#endif
209	old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
210	new = (vm_offset_t)args->dsend;
211	tmp.nsize = (char *) new;
212	if (((caddr_t)new > vm->vm_daddr) && !obreak(td, &tmp))
213		td->td_retval[0] = (long)new;
214	else
215		td->td_retval[0] = (long)old;
216
217	return 0;
218}
219
220#if defined(__i386__)
221/* XXX: what about amd64/linux32? */
222
223int
224linux_uselib(struct thread *td, struct linux_uselib_args *args)
225{
226	struct nameidata ni;
227	struct vnode *vp;
228	struct exec *a_out;
229	struct vattr attr;
230	vm_offset_t vmaddr;
231	unsigned long file_offset;
232	vm_offset_t buffer;
233	unsigned long bss_size;
234	char *library;
235	int error;
236	int locked, vfslocked;
237
238	LCONVPATHEXIST(td, args->library, &library);
239
240#ifdef DEBUG
241	if (ldebug(uselib))
242		printf(ARGS(uselib, "%s"), library);
243#endif
244
245	a_out = NULL;
246	vfslocked = 0;
247	locked = 0;
248	vp = NULL;
249
250	NDINIT(&ni, LOOKUP, ISOPEN | FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
251	    UIO_SYSSPACE, library, td);
252	error = namei(&ni);
253	LFREEPATH(library);
254	if (error)
255		goto cleanup;
256
257	vp = ni.ni_vp;
258	vfslocked = NDHASGIANT(&ni);
259	NDFREE(&ni, NDF_ONLY_PNBUF);
260
261	/*
262	 * From here on down, we have a locked vnode that must be unlocked.
263	 * XXX: The code below largely duplicates exec_check_permissions().
264	 */
265	locked = 1;
266
267	/* Writable? */
268	if (vp->v_writecount) {
269		error = ETXTBSY;
270		goto cleanup;
271	}
272
273	/* Executable? */
274	error = VOP_GETATTR(vp, &attr, td->td_ucred, td);
275	if (error)
276		goto cleanup;
277
278	if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
279	    ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) {
280		/* EACCESS is what exec(2) returns. */
281		error = ENOEXEC;
282		goto cleanup;
283	}
284
285	/* Sensible size? */
286	if (attr.va_size == 0) {
287		error = ENOEXEC;
288		goto cleanup;
289	}
290
291	/* Can we access it? */
292	error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
293	if (error)
294		goto cleanup;
295
296	/*
297	 * XXX: This should use vn_open() so that it is properly authorized,
298	 * and to reduce code redundancy all over the place here.
299	 * XXX: Not really, it duplicates far more of exec_check_permissions()
300	 * than vn_open().
301	 */
302#ifdef MAC
303	error = mac_check_vnode_open(td->td_ucred, vp, FREAD);
304	if (error)
305		goto cleanup;
306#endif
307	error = VOP_OPEN(vp, FREAD, td->td_ucred, td, -1);
308	if (error)
309		goto cleanup;
310
311	/* Pull in executable header into kernel_map */
312	error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
313	    VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp, 0);
314	if (error)
315		goto cleanup;
316
317	/* Is it a Linux binary ? */
318	if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
319		error = ENOEXEC;
320		goto cleanup;
321	}
322
323	/*
324	 * While we are here, we should REALLY do some more checks
325	 */
326
327	/* Set file/virtual offset based on a.out variant. */
328	switch ((int)(a_out->a_magic & 0xffff)) {
329	case 0413:	/* ZMAGIC */
330		file_offset = 1024;
331		break;
332	case 0314:	/* QMAGIC */
333		file_offset = 0;
334		break;
335	default:
336		error = ENOEXEC;
337		goto cleanup;
338	}
339
340	bss_size = round_page(a_out->a_bss);
341
342	/* Check various fields in header for validity/bounds. */
343	if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
344		error = ENOEXEC;
345		goto cleanup;
346	}
347
348	/* text + data can't exceed file size */
349	if (a_out->a_data + a_out->a_text > attr.va_size) {
350		error = EFAULT;
351		goto cleanup;
352	}
353
354	/*
355	 * text/data/bss must not exceed limits
356	 * XXX - this is not complete. it should check current usage PLUS
357	 * the resources needed by this library.
358	 */
359	PROC_LOCK(td->td_proc);
360	if (a_out->a_text > maxtsiz ||
361	    a_out->a_data + bss_size > lim_cur(td->td_proc, RLIMIT_DATA)) {
362		PROC_UNLOCK(td->td_proc);
363		error = ENOMEM;
364		goto cleanup;
365	}
366	PROC_UNLOCK(td->td_proc);
367
368	/*
369	 * Prevent more writers.
370	 * XXX: Note that if any of the VM operations fail below we don't
371	 * clear this flag.
372	 */
373	vp->v_vflag |= VV_TEXT;
374
375	/*
376	 * Lock no longer needed
377	 */
378	locked = 0;
379	VOP_UNLOCK(vp, 0, td);
380	VFS_UNLOCK_GIANT(vfslocked);
381
382	/*
383	 * Check if file_offset page aligned. Currently we cannot handle
384	 * misalinged file offsets, and so we read in the entire image
385	 * (what a waste).
386	 */
387	if (file_offset & PAGE_MASK) {
388#ifdef DEBUG
389		printf("uselib: Non page aligned binary %lu\n", file_offset);
390#endif
391		/* Map text+data read/write/execute */
392
393		/* a_entry is the load address and is page aligned */
394		vmaddr = trunc_page(a_out->a_entry);
395
396		/* get anon user mapping, read+write+execute */
397		error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
398		    &vmaddr, a_out->a_text + a_out->a_data, FALSE, VM_PROT_ALL,
399		    VM_PROT_ALL, 0);
400		if (error)
401			goto cleanup;
402
403		/* map file into kernel_map */
404		error = vm_mmap(kernel_map, &buffer,
405		    round_page(a_out->a_text + a_out->a_data + file_offset),
406		    VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp,
407		    trunc_page(file_offset));
408		if (error)
409			goto cleanup;
410
411		/* copy from kernel VM space to user space */
412		error = copyout(PTRIN(buffer + file_offset),
413		    (void *)vmaddr, a_out->a_text + a_out->a_data);
414
415		/* release temporary kernel space */
416		vm_map_remove(kernel_map, buffer, buffer +
417		    round_page(a_out->a_text + a_out->a_data + file_offset));
418
419		if (error)
420			goto cleanup;
421	} else {
422#ifdef DEBUG
423		printf("uselib: Page aligned binary %lu\n", file_offset);
424#endif
425		/*
426		 * for QMAGIC, a_entry is 20 bytes beyond the load address
427		 * to skip the executable header
428		 */
429		vmaddr = trunc_page(a_out->a_entry);
430
431		/*
432		 * Map it all into the process's space as a single
433		 * copy-on-write "data" segment.
434		 */
435		error = vm_mmap(&td->td_proc->p_vmspace->vm_map, &vmaddr,
436		    a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL,
437		    MAP_PRIVATE | MAP_FIXED, OBJT_VNODE, vp, file_offset);
438		if (error)
439			goto cleanup;
440	}
441#ifdef DEBUG
442	printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long*)vmaddr)[0],
443	    ((long*)vmaddr)[1]);
444#endif
445	if (bss_size != 0) {
446		/* Calculate BSS start address */
447		vmaddr = trunc_page(a_out->a_entry) + a_out->a_text +
448		    a_out->a_data;
449
450		/* allocate some 'anon' space */
451		error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
452		    &vmaddr, bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0);
453		if (error)
454			goto cleanup;
455	}
456
457cleanup:
458	/* Unlock vnode if needed */
459	if (locked) {
460		VOP_UNLOCK(vp, 0, td);
461		VFS_UNLOCK_GIANT(vfslocked);
462	}
463
464	/* Release the kernel mapping. */
465	if (a_out)
466		vm_map_remove(kernel_map, (vm_offset_t)a_out,
467		    (vm_offset_t)a_out + PAGE_SIZE);
468
469	return error;
470}
471
472#endif	/* __i386__ */
473
474int
475linux_select(struct thread *td, struct linux_select_args *args)
476{
477	l_timeval ltv;
478	struct timeval tv0, tv1, utv, *tvp;
479	int error;
480
481#ifdef DEBUG
482	if (ldebug(select))
483		printf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds,
484		    (void *)args->readfds, (void *)args->writefds,
485		    (void *)args->exceptfds, (void *)args->timeout);
486#endif
487
488	/*
489	 * Store current time for computation of the amount of
490	 * time left.
491	 */
492	if (args->timeout) {
493		if ((error = copyin(args->timeout, &ltv, sizeof(ltv))))
494			goto select_out;
495		utv.tv_sec = ltv.tv_sec;
496		utv.tv_usec = ltv.tv_usec;
497#ifdef DEBUG
498		if (ldebug(select))
499			printf(LMSG("incoming timeout (%jd/%ld)"),
500			    (intmax_t)utv.tv_sec, utv.tv_usec);
501#endif
502
503		if (itimerfix(&utv)) {
504			/*
505			 * The timeval was invalid.  Convert it to something
506			 * valid that will act as it does under Linux.
507			 */
508			utv.tv_sec += utv.tv_usec / 1000000;
509			utv.tv_usec %= 1000000;
510			if (utv.tv_usec < 0) {
511				utv.tv_sec -= 1;
512				utv.tv_usec += 1000000;
513			}
514			if (utv.tv_sec < 0)
515				timevalclear(&utv);
516		}
517		microtime(&tv0);
518		tvp = &utv;
519	} else
520		tvp = NULL;
521
522	error = kern_select(td, args->nfds, args->readfds, args->writefds,
523	    args->exceptfds, tvp);
524
525#ifdef DEBUG
526	if (ldebug(select))
527		printf(LMSG("real select returns %d"), error);
528#endif
529	if (error) {
530		/*
531		 * See fs/select.c in the Linux kernel.  Without this,
532		 * Maelstrom doesn't work.
533		 */
534		if (error == ERESTART)
535			error = EINTR;
536		goto select_out;
537	}
538
539	if (args->timeout) {
540		if (td->td_retval[0]) {
541			/*
542			 * Compute how much time was left of the timeout,
543			 * by subtracting the current time and the time
544			 * before we started the call, and subtracting
545			 * that result from the user-supplied value.
546			 */
547			microtime(&tv1);
548			timevalsub(&tv1, &tv0);
549			timevalsub(&utv, &tv1);
550			if (utv.tv_sec < 0)
551				timevalclear(&utv);
552		} else
553			timevalclear(&utv);
554#ifdef DEBUG
555		if (ldebug(select))
556			printf(LMSG("outgoing timeout (%jd/%ld)"),
557			    (intmax_t)utv.tv_sec, utv.tv_usec);
558#endif
559		ltv.tv_sec = utv.tv_sec;
560		ltv.tv_usec = utv.tv_usec;
561		if ((error = copyout(&ltv, args->timeout, sizeof(ltv))))
562			goto select_out;
563	}
564
565select_out:
566#ifdef DEBUG
567	if (ldebug(select))
568		printf(LMSG("select_out -> %d"), error);
569#endif
570	return error;
571}
572
573int
574linux_mremap(struct thread *td, struct linux_mremap_args *args)
575{
576	struct munmap_args /* {
577		void *addr;
578		size_t len;
579	} */ bsd_args;
580	int error = 0;
581
582#ifdef DEBUG
583	if (ldebug(mremap))
584		printf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"),
585		    (void *)(uintptr_t)args->addr,
586		    (unsigned long)args->old_len,
587		    (unsigned long)args->new_len,
588		    (unsigned long)args->flags);
589#endif
590	args->new_len = round_page(args->new_len);
591	args->old_len = round_page(args->old_len);
592
593	if (args->new_len > args->old_len) {
594		td->td_retval[0] = 0;
595		return ENOMEM;
596	}
597
598	if (args->new_len < args->old_len) {
599		bsd_args.addr =
600		    (caddr_t)((uintptr_t)args->addr + args->new_len);
601		bsd_args.len = args->old_len - args->new_len;
602		error = munmap(td, &bsd_args);
603	}
604
605	td->td_retval[0] = error ? 0 : (uintptr_t)args->addr;
606	return error;
607}
608
609#define LINUX_MS_ASYNC       0x0001
610#define LINUX_MS_INVALIDATE  0x0002
611#define LINUX_MS_SYNC        0x0004
612
613int
614linux_msync(struct thread *td, struct linux_msync_args *args)
615{
616	struct msync_args bsd_args;
617
618	bsd_args.addr = (caddr_t)(uintptr_t)args->addr;
619	bsd_args.len = (uintptr_t)args->len;
620	bsd_args.flags = args->fl & ~LINUX_MS_SYNC;
621
622	return msync(td, &bsd_args);
623}
624
625int
626linux_time(struct thread *td, struct linux_time_args *args)
627{
628	struct timeval tv;
629	l_time_t tm;
630	int error;
631
632#ifdef DEBUG
633	if (ldebug(time))
634		printf(ARGS(time, "*"));
635#endif
636
637	microtime(&tv);
638	tm = tv.tv_sec;
639	if (args->tm && (error = copyout(&tm, args->tm, sizeof(tm))))
640		return error;
641	td->td_retval[0] = tm;
642	return 0;
643}
644
645struct l_times_argv {
646	l_long		tms_utime;
647	l_long		tms_stime;
648	l_long		tms_cutime;
649	l_long		tms_cstime;
650};
651
652#define CLK_TCK 100	/* Linux uses 100 */
653
654#define CONVTCK(r)	(r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
655
656int
657linux_times(struct thread *td, struct linux_times_args *args)
658{
659	struct timeval tv, utime, stime, cutime, cstime;
660	struct l_times_argv tms;
661	struct proc *p;
662	int error;
663
664#ifdef DEBUG
665	if (ldebug(times))
666		printf(ARGS(times, "*"));
667#endif
668
669	if (args->buf != NULL) {
670		p = td->td_proc;
671		PROC_LOCK(p);
672		calcru(p, &utime, &stime);
673		calccru(p, &cutime, &cstime);
674		PROC_UNLOCK(p);
675
676		tms.tms_utime = CONVTCK(utime);
677		tms.tms_stime = CONVTCK(stime);
678
679		tms.tms_cutime = CONVTCK(cutime);
680		tms.tms_cstime = CONVTCK(cstime);
681
682		if ((error = copyout(&tms, args->buf, sizeof(tms))))
683			return error;
684	}
685
686	microuptime(&tv);
687	td->td_retval[0] = (int)CONVTCK(tv);
688	return 0;
689}
690
691int
692linux_newuname(struct thread *td, struct linux_newuname_args *args)
693{
694	struct l_new_utsname utsname;
695	char osname[LINUX_MAX_UTSNAME];
696	char osrelease[LINUX_MAX_UTSNAME];
697	char *p;
698
699#ifdef DEBUG
700	if (ldebug(newuname))
701		printf(ARGS(newuname, "*"));
702#endif
703
704	linux_get_osname(td, osname);
705	linux_get_osrelease(td, osrelease);
706
707	bzero(&utsname, sizeof(utsname));
708	strlcpy(utsname.sysname, osname, LINUX_MAX_UTSNAME);
709	getcredhostname(td->td_ucred, utsname.nodename, LINUX_MAX_UTSNAME);
710	strlcpy(utsname.release, osrelease, LINUX_MAX_UTSNAME);
711	strlcpy(utsname.version, version, LINUX_MAX_UTSNAME);
712	for (p = utsname.version; *p != '\0'; ++p)
713		if (*p == '\n') {
714			*p = '\0';
715			break;
716		}
717#ifdef __i386__
718	{
719		const char *class;
720		switch (cpu_class) {
721		case CPUCLASS_686:
722			class = "i686";
723			break;
724		case CPUCLASS_586:
725			class = "i586";
726			break;
727		case CPUCLASS_486:
728			class = "i486";
729			break;
730		default:
731			class = "i386";
732		}
733		strlcpy(utsname.machine, class, LINUX_MAX_UTSNAME);
734	}
735#elif defined(__amd64__)	/* XXX: Linux can change 'personality'. */
736#ifdef COMPAT_LINUX32
737	strlcpy(utsname.machine, "i686", LINUX_MAX_UTSNAME);
738#else
739	strlcpy(utsname.machine, "x86_64", LINUX_MAX_UTSNAME);
740#endif /* COMPAT_LINUX32 */
741#else /* something other than i386 or amd64 - assume we and Linux agree */
742	strlcpy(utsname.machine, machine, LINUX_MAX_UTSNAME);
743#endif /* __i386__ */
744	strlcpy(utsname.domainname, domainname, LINUX_MAX_UTSNAME);
745
746	return (copyout(&utsname, args->buf, sizeof(utsname)));
747}
748
749#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
750struct l_utimbuf {
751	l_time_t l_actime;
752	l_time_t l_modtime;
753};
754
755int
756linux_utime(struct thread *td, struct linux_utime_args *args)
757{
758	struct timeval tv[2], *tvp;
759	struct l_utimbuf lut;
760	char *fname;
761	int error;
762
763	LCONVPATHEXIST(td, args->fname, &fname);
764
765#ifdef DEBUG
766	if (ldebug(utime))
767		printf(ARGS(utime, "%s, *"), fname);
768#endif
769
770	if (args->times) {
771		if ((error = copyin(args->times, &lut, sizeof lut))) {
772			LFREEPATH(fname);
773			return error;
774		}
775		tv[0].tv_sec = lut.l_actime;
776		tv[0].tv_usec = 0;
777		tv[1].tv_sec = lut.l_modtime;
778		tv[1].tv_usec = 0;
779		tvp = tv;
780	} else
781		tvp = NULL;
782
783	error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE);
784	LFREEPATH(fname);
785	return (error);
786}
787#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
788
789#define __WCLONE 0x80000000
790
791int
792linux_waitpid(struct thread *td, struct linux_waitpid_args *args)
793{
794	int error, options, tmpstat;
795
796#ifdef DEBUG
797	if (ldebug(waitpid))
798		printf(ARGS(waitpid, "%d, %p, %d"),
799		    args->pid, (void *)args->status, args->options);
800#endif
801
802	options = (args->options & (WNOHANG | WUNTRACED));
803	/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
804	if (args->options & __WCLONE)
805		options |= WLINUXCLONE;
806
807	error = kern_wait(td, args->pid, &tmpstat, options, NULL);
808	if (error)
809		return error;
810
811	if (args->status) {
812		tmpstat &= 0xffff;
813		if (WIFSIGNALED(tmpstat))
814			tmpstat = (tmpstat & 0xffffff80) |
815			    BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
816		else if (WIFSTOPPED(tmpstat))
817			tmpstat = (tmpstat & 0xffff00ff) |
818			    (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
819		return copyout(&tmpstat, args->status, sizeof(int));
820	}
821
822	return 0;
823}
824
825int
826linux_wait4(struct thread *td, struct linux_wait4_args *args)
827{
828	int error, options, tmpstat;
829	struct rusage ru, *rup;
830	struct proc *p;
831
832#ifdef DEBUG
833	if (ldebug(wait4))
834		printf(ARGS(wait4, "%d, %p, %d, %p"),
835		    args->pid, (void *)args->status, args->options,
836		    (void *)args->rusage);
837#endif
838
839	options = (args->options & (WNOHANG | WUNTRACED));
840	/* WLINUXCLONE should be equal to __WCLONE, but we make sure */
841	if (args->options & __WCLONE)
842		options |= WLINUXCLONE;
843
844	if (args->rusage != NULL)
845		rup = &ru;
846	else
847		rup = NULL;
848	error = kern_wait(td, args->pid, &tmpstat, options, rup);
849	if (error)
850		return error;
851
852	p = td->td_proc;
853	PROC_LOCK(p);
854	sigqueue_delete(&p->p_sigqueue, SIGCHLD);
855	PROC_UNLOCK(p);
856
857	if (args->status) {
858		tmpstat &= 0xffff;
859		if (WIFSIGNALED(tmpstat))
860			tmpstat = (tmpstat & 0xffffff80) |
861			    BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
862		else if (WIFSTOPPED(tmpstat))
863			tmpstat = (tmpstat & 0xffff00ff) |
864			    (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
865		error = copyout(&tmpstat, args->status, sizeof(int));
866	}
867	if (args->rusage != NULL && error == 0)
868		error = copyout(&ru, args->rusage, sizeof(ru));
869
870	return (error);
871}
872
873int
874linux_mknod(struct thread *td, struct linux_mknod_args *args)
875{
876	char *path;
877	int error;
878
879	LCONVPATHCREAT(td, args->path, &path);
880
881#ifdef DEBUG
882	if (ldebug(mknod))
883		printf(ARGS(mknod, "%s, %d, %d"), path, args->mode, args->dev);
884#endif
885
886	if (args->mode & S_IFIFO)
887		error = kern_mkfifo(td, path, UIO_SYSSPACE, args->mode);
888	else
889		error = kern_mknod(td, path, UIO_SYSSPACE, args->mode,
890		    args->dev);
891	LFREEPATH(path);
892	return (error);
893}
894
895/*
896 * UGH! This is just about the dumbest idea I've ever heard!!
897 */
898int
899linux_personality(struct thread *td, struct linux_personality_args *args)
900{
901#ifdef DEBUG
902	if (ldebug(personality))
903		printf(ARGS(personality, "%lu"), (unsigned long)args->per);
904#endif
905	if (args->per != 0)
906		return EINVAL;
907
908	/* Yes Jim, it's still a Linux... */
909	td->td_retval[0] = 0;
910	return 0;
911}
912
913struct l_itimerval {
914	l_timeval it_interval;
915	l_timeval it_value;
916};
917
918#define	B2L_ITIMERVAL(bip, lip) 					\
919	(bip)->it_interval.tv_sec = (lip)->it_interval.tv_sec;		\
920	(bip)->it_interval.tv_usec = (lip)->it_interval.tv_usec;	\
921	(bip)->it_value.tv_sec = (lip)->it_value.tv_sec;		\
922	(bip)->it_value.tv_usec = (lip)->it_value.tv_usec;
923
924int
925linux_setitimer(struct thread *td, struct linux_setitimer_args *uap)
926{
927	int error;
928	struct l_itimerval ls;
929	struct itimerval aitv, oitv;
930
931#ifdef DEBUG
932	if (ldebug(setitimer))
933		printf(ARGS(setitimer, "%p, %p"),
934		    (void *)uap->itv, (void *)uap->oitv);
935#endif
936
937	if (uap->itv == NULL) {
938		uap->itv = uap->oitv;
939		return (linux_getitimer(td, (struct linux_getitimer_args *)uap));
940	}
941
942	error = copyin(uap->itv, &ls, sizeof(ls));
943	if (error != 0)
944		return (error);
945	B2L_ITIMERVAL(&aitv, &ls);
946#ifdef DEBUG
947	if (ldebug(setitimer)) {
948		printf("setitimer: value: sec: %jd, usec: %ld\n",
949		    (intmax_t)aitv.it_value.tv_sec, aitv.it_value.tv_usec);
950		printf("setitimer: interval: sec: %jd, usec: %ld\n",
951		    (intmax_t)aitv.it_interval.tv_sec, aitv.it_interval.tv_usec);
952	}
953#endif
954	error = kern_setitimer(td, uap->which, &aitv, &oitv);
955	if (error != 0 || uap->oitv == NULL)
956		return (error);
957	B2L_ITIMERVAL(&ls, &oitv);
958
959	return (copyout(&ls, uap->oitv, sizeof(ls)));
960}
961
962int
963linux_getitimer(struct thread *td, struct linux_getitimer_args *uap)
964{
965	int error;
966	struct l_itimerval ls;
967	struct itimerval aitv;
968
969#ifdef DEBUG
970	if (ldebug(getitimer))
971		printf(ARGS(getitimer, "%p"), (void *)uap->itv);
972#endif
973	error = kern_getitimer(td, uap->which, &aitv);
974	if (error != 0)
975		return (error);
976	B2L_ITIMERVAL(&ls, &aitv);
977	return (copyout(&ls, uap->itv, sizeof(ls)));
978}
979
980int
981linux_nice(struct thread *td, struct linux_nice_args *args)
982{
983	struct setpriority_args	bsd_args;
984
985	bsd_args.which = PRIO_PROCESS;
986	bsd_args.who = 0;	/* current process */
987	bsd_args.prio = args->inc;
988	return setpriority(td, &bsd_args);
989}
990
991int
992linux_setgroups(struct thread *td, struct linux_setgroups_args *args)
993{
994	struct ucred *newcred, *oldcred;
995	l_gid_t linux_gidset[NGROUPS];
996	gid_t *bsd_gidset;
997	int ngrp, error;
998	struct proc *p;
999
1000	ngrp = args->gidsetsize;
1001	if (ngrp < 0 || ngrp >= NGROUPS)
1002		return (EINVAL);
1003	error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t));
1004	if (error)
1005		return (error);
1006	newcred = crget();
1007	p = td->td_proc;
1008	PROC_LOCK(p);
1009	oldcred = p->p_ucred;
1010
1011	/*
1012	 * cr_groups[0] holds egid. Setting the whole set from
1013	 * the supplied set will cause egid to be changed too.
1014	 * Keep cr_groups[0] unchanged to prevent that.
1015	 */
1016
1017	if ((error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) {
1018		PROC_UNLOCK(p);
1019		crfree(newcred);
1020		return (error);
1021	}
1022
1023	crcopy(newcred, oldcred);
1024	if (ngrp > 0) {
1025		newcred->cr_ngroups = ngrp + 1;
1026
1027		bsd_gidset = newcred->cr_groups;
1028		ngrp--;
1029		while (ngrp >= 0) {
1030			bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
1031			ngrp--;
1032		}
1033	}
1034	else
1035		newcred->cr_ngroups = 1;
1036
1037	setsugid(p);
1038	p->p_ucred = newcred;
1039	PROC_UNLOCK(p);
1040	crfree(oldcred);
1041	return (0);
1042}
1043
1044int
1045linux_getgroups(struct thread *td, struct linux_getgroups_args *args)
1046{
1047	struct ucred *cred;
1048	l_gid_t linux_gidset[NGROUPS];
1049	gid_t *bsd_gidset;
1050	int bsd_gidsetsz, ngrp, error;
1051
1052	cred = td->td_ucred;
1053	bsd_gidset = cred->cr_groups;
1054	bsd_gidsetsz = cred->cr_ngroups - 1;
1055
1056	/*
1057	 * cr_groups[0] holds egid. Returning the whole set
1058	 * here will cause a duplicate. Exclude cr_groups[0]
1059	 * to prevent that.
1060	 */
1061
1062	if ((ngrp = args->gidsetsize) == 0) {
1063		td->td_retval[0] = bsd_gidsetsz;
1064		return (0);
1065	}
1066
1067	if (ngrp < bsd_gidsetsz)
1068		return (EINVAL);
1069
1070	ngrp = 0;
1071	while (ngrp < bsd_gidsetsz) {
1072		linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
1073		ngrp++;
1074	}
1075
1076	if ((error = copyout(linux_gidset, args->grouplist,
1077	    ngrp * sizeof(l_gid_t))))
1078		return (error);
1079
1080	td->td_retval[0] = ngrp;
1081	return (0);
1082}
1083
1084int
1085linux_setrlimit(struct thread *td, struct linux_setrlimit_args *args)
1086{
1087	struct rlimit bsd_rlim;
1088	struct l_rlimit rlim;
1089	u_int which;
1090	int error;
1091
1092#ifdef DEBUG
1093	if (ldebug(setrlimit))
1094		printf(ARGS(setrlimit, "%d, %p"),
1095		    args->resource, (void *)args->rlim);
1096#endif
1097
1098	if (args->resource >= LINUX_RLIM_NLIMITS)
1099		return (EINVAL);
1100
1101	which = linux_to_bsd_resource[args->resource];
1102	if (which == -1)
1103		return (EINVAL);
1104
1105	error = copyin(args->rlim, &rlim, sizeof(rlim));
1106	if (error)
1107		return (error);
1108
1109	bsd_rlim.rlim_cur = (rlim_t)rlim.rlim_cur;
1110	bsd_rlim.rlim_max = (rlim_t)rlim.rlim_max;
1111	return (kern_setrlimit(td, which, &bsd_rlim));
1112}
1113
1114int
1115linux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args)
1116{
1117	struct l_rlimit rlim;
1118	struct proc *p = td->td_proc;
1119	struct rlimit bsd_rlim;
1120	u_int which;
1121
1122#ifdef DEBUG
1123	if (ldebug(old_getrlimit))
1124		printf(ARGS(old_getrlimit, "%d, %p"),
1125		    args->resource, (void *)args->rlim);
1126#endif
1127
1128	if (args->resource >= LINUX_RLIM_NLIMITS)
1129		return (EINVAL);
1130
1131	which = linux_to_bsd_resource[args->resource];
1132	if (which == -1)
1133		return (EINVAL);
1134
1135	PROC_LOCK(p);
1136	lim_rlimit(p, which, &bsd_rlim);
1137	PROC_UNLOCK(p);
1138
1139#ifdef COMPAT_LINUX32
1140	rlim.rlim_cur = (unsigned int)bsd_rlim.rlim_cur;
1141	if (rlim.rlim_cur == UINT_MAX)
1142		rlim.rlim_cur = INT_MAX;
1143	rlim.rlim_max = (unsigned int)bsd_rlim.rlim_max;
1144	if (rlim.rlim_max == UINT_MAX)
1145		rlim.rlim_max = INT_MAX;
1146#else
1147	rlim.rlim_cur = (unsigned long)bsd_rlim.rlim_cur;
1148	if (rlim.rlim_cur == ULONG_MAX)
1149		rlim.rlim_cur = LONG_MAX;
1150	rlim.rlim_max = (unsigned long)bsd_rlim.rlim_max;
1151	if (rlim.rlim_max == ULONG_MAX)
1152		rlim.rlim_max = LONG_MAX;
1153#endif
1154	return (copyout(&rlim, args->rlim, sizeof(rlim)));
1155}
1156
1157int
1158linux_getrlimit(struct thread *td, struct linux_getrlimit_args *args)
1159{
1160	struct l_rlimit rlim;
1161	struct proc *p = td->td_proc;
1162	struct rlimit bsd_rlim;
1163	u_int which;
1164
1165#ifdef DEBUG
1166	if (ldebug(getrlimit))
1167		printf(ARGS(getrlimit, "%d, %p"),
1168		    args->resource, (void *)args->rlim);
1169#endif
1170
1171	if (args->resource >= LINUX_RLIM_NLIMITS)
1172		return (EINVAL);
1173
1174	which = linux_to_bsd_resource[args->resource];
1175	if (which == -1)
1176		return (EINVAL);
1177
1178	PROC_LOCK(p);
1179	lim_rlimit(p, which, &bsd_rlim);
1180	PROC_UNLOCK(p);
1181
1182	rlim.rlim_cur = (l_ulong)bsd_rlim.rlim_cur;
1183	rlim.rlim_max = (l_ulong)bsd_rlim.rlim_max;
1184	return (copyout(&rlim, args->rlim, sizeof(rlim)));
1185}
1186
1187int
1188linux_sched_setscheduler(struct thread *td,
1189    struct linux_sched_setscheduler_args *args)
1190{
1191	struct sched_setscheduler_args bsd;
1192
1193#ifdef DEBUG
1194	if (ldebug(sched_setscheduler))
1195		printf(ARGS(sched_setscheduler, "%d, %d, %p"),
1196		    args->pid, args->policy, (const void *)args->param);
1197#endif
1198
1199	switch (args->policy) {
1200	case LINUX_SCHED_OTHER:
1201		bsd.policy = SCHED_OTHER;
1202		break;
1203	case LINUX_SCHED_FIFO:
1204		bsd.policy = SCHED_FIFO;
1205		break;
1206	case LINUX_SCHED_RR:
1207		bsd.policy = SCHED_RR;
1208		break;
1209	default:
1210		return EINVAL;
1211	}
1212
1213	bsd.pid = args->pid;
1214	bsd.param = (struct sched_param *)args->param;
1215	return sched_setscheduler(td, &bsd);
1216}
1217
1218int
1219linux_sched_getscheduler(struct thread *td,
1220    struct linux_sched_getscheduler_args *args)
1221{
1222	struct sched_getscheduler_args bsd;
1223	int error;
1224
1225#ifdef DEBUG
1226	if (ldebug(sched_getscheduler))
1227		printf(ARGS(sched_getscheduler, "%d"), args->pid);
1228#endif
1229
1230	bsd.pid = args->pid;
1231	error = sched_getscheduler(td, &bsd);
1232
1233	switch (td->td_retval[0]) {
1234	case SCHED_OTHER:
1235		td->td_retval[0] = LINUX_SCHED_OTHER;
1236		break;
1237	case SCHED_FIFO:
1238		td->td_retval[0] = LINUX_SCHED_FIFO;
1239		break;
1240	case SCHED_RR:
1241		td->td_retval[0] = LINUX_SCHED_RR;
1242		break;
1243	}
1244
1245	return error;
1246}
1247
1248int
1249linux_sched_get_priority_max(struct thread *td,
1250    struct linux_sched_get_priority_max_args *args)
1251{
1252	struct sched_get_priority_max_args bsd;
1253
1254#ifdef DEBUG
1255	if (ldebug(sched_get_priority_max))
1256		printf(ARGS(sched_get_priority_max, "%d"), args->policy);
1257#endif
1258
1259	switch (args->policy) {
1260	case LINUX_SCHED_OTHER:
1261		bsd.policy = SCHED_OTHER;
1262		break;
1263	case LINUX_SCHED_FIFO:
1264		bsd.policy = SCHED_FIFO;
1265		break;
1266	case LINUX_SCHED_RR:
1267		bsd.policy = SCHED_RR;
1268		break;
1269	default:
1270		return EINVAL;
1271	}
1272	return sched_get_priority_max(td, &bsd);
1273}
1274
1275int
1276linux_sched_get_priority_min(struct thread *td,
1277    struct linux_sched_get_priority_min_args *args)
1278{
1279	struct sched_get_priority_min_args bsd;
1280
1281#ifdef DEBUG
1282	if (ldebug(sched_get_priority_min))
1283		printf(ARGS(sched_get_priority_min, "%d"), args->policy);
1284#endif
1285
1286	switch (args->policy) {
1287	case LINUX_SCHED_OTHER:
1288		bsd.policy = SCHED_OTHER;
1289		break;
1290	case LINUX_SCHED_FIFO:
1291		bsd.policy = SCHED_FIFO;
1292		break;
1293	case LINUX_SCHED_RR:
1294		bsd.policy = SCHED_RR;
1295		break;
1296	default:
1297		return EINVAL;
1298	}
1299	return sched_get_priority_min(td, &bsd);
1300}
1301
1302#define REBOOT_CAD_ON	0x89abcdef
1303#define REBOOT_CAD_OFF	0
1304#define REBOOT_HALT	0xcdef0123
1305
1306int
1307linux_reboot(struct thread *td, struct linux_reboot_args *args)
1308{
1309	struct reboot_args bsd_args;
1310
1311#ifdef DEBUG
1312	if (ldebug(reboot))
1313		printf(ARGS(reboot, "0x%x"), args->cmd);
1314#endif
1315	if (args->cmd == REBOOT_CAD_ON || args->cmd == REBOOT_CAD_OFF)
1316		return (0);
1317	bsd_args.opt = (args->cmd == REBOOT_HALT) ? RB_HALT : 0;
1318	return (reboot(td, &bsd_args));
1319}
1320
1321
1322/*
1323 * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify
1324 * td->td_retval[1] when COMPAT_43 is defined. This
1325 * globbers registers that are assumed to be preserved. The following
1326 * lightweight syscalls fixes this. See also linux_getgid16() and
1327 * linux_getuid16() in linux_uid16.c.
1328 *
1329 * linux_getpid() - MP SAFE
1330 * linux_getgid() - MP SAFE
1331 * linux_getuid() - MP SAFE
1332 */
1333
1334int
1335linux_getpid(struct thread *td, struct linux_getpid_args *args)
1336{
1337#ifdef __i386__
1338   	struct linux_emuldata *em;
1339
1340	em = em_find(td->td_proc, EMUL_UNLOCKED);
1341
1342	KASSERT(em != NULL, ("getpid: emuldata not found.\n"));
1343
1344	td->td_retval[0] = em->shared->group_pid;
1345	EMUL_UNLOCK(&emul_lock);
1346#else
1347	td->td_retval[0] = td->td_proc->p_pid;
1348#endif
1349	return (0);
1350}
1351
1352int
1353linux_gettid(struct thread *td, struct linux_gettid_args *args)
1354{
1355#ifdef DEBUG
1356	if (ldebug(gettid))
1357		printf(ARGS(gettid, ""));
1358#endif
1359
1360	td->td_retval[0] = td->td_proc->p_pid;
1361	return (0);
1362}
1363
1364
1365int
1366linux_getppid(struct thread *td, struct linux_getppid_args *args)
1367{
1368#ifdef	__i386__
1369   	struct linux_emuldata *em;
1370	struct proc *p, *pp;
1371
1372	em = em_find(td->td_proc, EMUL_UNLOCKED);
1373
1374	KASSERT(em != NULL, ("getppid: process emuldata not found.\n"));
1375
1376	/* find the group leader */
1377	p = pfind(em->shared->group_pid);
1378
1379	if (p == NULL) {
1380#ifdef DEBUG
1381	   	printf(LMSG("parent process not found.\n"));
1382#endif
1383		return (0);
1384	}
1385
1386	pp = p->p_pptr;		/* switch to parent */
1387	PROC_LOCK(pp);
1388	PROC_UNLOCK(p);
1389
1390	/* if its also linux process */
1391	if (pp->p_sysent == &elf_linux_sysvec) {
1392   	   	em = em_find(pp, EMUL_LOCKED);
1393		KASSERT(em != NULL, ("getppid: parent emuldata not found.\n"));
1394
1395	   	td->td_retval[0] = em->shared->group_pid;
1396	} else
1397	   	td->td_retval[0] = pp->p_pid;
1398
1399	EMUL_UNLOCK(&emul_lock);
1400	PROC_UNLOCK(pp);
1401#else
1402	return getppid(td, (struct getppid_args *) args);
1403#endif
1404	return (0);
1405}
1406
1407int
1408linux_getgid(struct thread *td, struct linux_getgid_args *args)
1409{
1410
1411	td->td_retval[0] = td->td_ucred->cr_rgid;
1412	return (0);
1413}
1414
1415int
1416linux_getuid(struct thread *td, struct linux_getuid_args *args)
1417{
1418
1419	td->td_retval[0] = td->td_ucred->cr_ruid;
1420	return (0);
1421}
1422
1423
1424int
1425linux_getsid(struct thread *td, struct linux_getsid_args *args)
1426{
1427	struct getsid_args bsd;
1428	bsd.pid = args->pid;
1429	return getsid(td, &bsd);
1430}
1431
1432int
1433linux_nosys(struct thread *td, struct nosys_args *ignore)
1434{
1435
1436	return (ENOSYS);
1437}
1438
1439int
1440linux_getpriority(struct thread *td, struct linux_getpriority_args *args)
1441{
1442	struct getpriority_args	bsd_args;
1443	int error;
1444
1445	bsd_args.which = args->which;
1446	bsd_args.who = args->who;
1447	error = getpriority(td, &bsd_args);
1448	td->td_retval[0] = 20 - td->td_retval[0];
1449	return error;
1450}
1451
1452int
1453linux_sethostname(struct thread *td, struct linux_sethostname_args *args)
1454{
1455	int name[2];
1456	int error;
1457
1458	name[0] = CTL_KERN;
1459	name[1] = KERN_HOSTNAME;
1460	if ((error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL)))
1461		return (error);
1462	return (userland_sysctl(td, name, 2, 0, 0, 0, args->hostname,
1463		 args->len, 0, 0));
1464}
1465
1466int
1467linux_exit_group(struct thread *td, struct linux_exit_group_args *args)
1468{
1469   	struct linux_emuldata *em, *td_em, *tmp_em;
1470	struct proc *sp;
1471
1472#ifdef DEBUG
1473	if (ldebug(exit_group))
1474		printf(ARGS(exit_group, "%i"), args->error_code);
1475#endif
1476
1477	td_em = em_find(td->td_proc, EMUL_UNLOCKED);
1478
1479	KASSERT(td_em != NULL, ("exit_group: emuldata not found.\n"));
1480
1481	EMUL_SHARED_RLOCK(&emul_shared_lock);
1482     	LIST_FOREACH_SAFE(em, &td_em->shared->threads, threads, tmp_em) {
1483	   	if (em->pid == td_em->pid)
1484		   	continue;
1485
1486		sp = pfind(em->pid);
1487		psignal(sp, SIGKILL);
1488		PROC_UNLOCK(sp);
1489#ifdef DEBUG
1490		printf(LMSG("linux_sys_exit_group: kill PID %d\n"), em->pid);
1491#endif
1492	}
1493
1494	EMUL_SHARED_RUNLOCK(&emul_shared_lock);
1495	EMUL_UNLOCK(&emul_lock);
1496
1497	exit1(td, W_EXITCODE(args->error_code,0));
1498
1499   	return (0);
1500}
1501
1502