xref: /freebsd/sys/compat/linux/linux_misc.c (revision 04c9749ff0148ec8f73b150cec8bc2c094a5d31a)
1 /*-
2  * Copyright (c) 1994-1995 S�ren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software withough specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #include "opt_compat.h"
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/sysproto.h>
36 #include <sys/kernel.h>
37 #include <sys/mman.h>
38 #include <sys/proc.h>
39 #include <sys/fcntl.h>
40 #include <sys/imgact_aout.h>
41 #include <sys/mount.h>
42 #include <sys/namei.h>
43 #include <sys/resourcevar.h>
44 #include <sys/stat.h>
45 #include <sys/sysctl.h>
46 #include <sys/unistd.h>
47 #include <sys/vnode.h>
48 #include <sys/wait.h>
49 #include <sys/time.h>
50 #include <sys/signalvar.h>
51 
52 #include <vm/vm.h>
53 #include <vm/pmap.h>
54 #include <vm/vm_kern.h>
55 #include <vm/vm_map.h>
56 #include <vm/vm_extern.h>
57 
58 #include <machine/frame.h>
59 #include <machine/psl.h>
60 #include <machine/sysarch.h>
61 #include <machine/segments.h>
62 
63 #include <posix4/sched.h>
64 
65 #include <machine/../linux/linux.h>
66 #include <machine/../linux/linux_proto.h>
67 #include <compat/linux/linux_mib.h>
68 #include <compat/linux/linux_util.h>
69 
70 #define BSD_TO_LINUX_SIGNAL(sig)	\
71 	(((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
72 
73 static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] =
74 { RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK,
75   RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE,
76   RLIMIT_MEMLOCK, -1
77 };
78 
79 int
80 linux_alarm(struct proc *p, struct linux_alarm_args *args)
81 {
82     struct itimerval it, old_it;
83     struct timeval tv;
84     int s;
85 
86 #ifdef DEBUG
87     printf("Linux-emul(%ld): alarm(%u)\n", (long)p->p_pid, args->secs);
88 #endif
89     if (args->secs > 100000000)
90 	return EINVAL;
91     it.it_value.tv_sec = (long)args->secs;
92     it.it_value.tv_usec = 0;
93     it.it_interval.tv_sec = 0;
94     it.it_interval.tv_usec = 0;
95     s = splsoftclock();
96     old_it = p->p_realtimer;
97     getmicrouptime(&tv);
98     if (timevalisset(&old_it.it_value))
99 	untimeout(realitexpire, (caddr_t)p, p->p_ithandle);
100     if (it.it_value.tv_sec != 0) {
101 	p->p_ithandle = timeout(realitexpire, (caddr_t)p, tvtohz(&it.it_value));
102 	timevaladd(&it.it_value, &tv);
103     }
104     p->p_realtimer = it;
105     splx(s);
106     if (timevalcmp(&old_it.it_value, &tv, >)) {
107 	timevalsub(&old_it.it_value, &tv);
108 	if (old_it.it_value.tv_usec != 0)
109 	    old_it.it_value.tv_sec++;
110 	p->p_retval[0] = old_it.it_value.tv_sec;
111     }
112     return 0;
113 }
114 
115 int
116 linux_brk(struct proc *p, struct linux_brk_args *args)
117 {
118 #if 0
119     struct vmspace *vm = p->p_vmspace;
120     vm_offset_t new, old;
121     int error;
122 
123     if ((vm_offset_t)args->dsend < (vm_offset_t)vm->vm_daddr)
124 	return EINVAL;
125     if (((caddr_t)args->dsend - (caddr_t)vm->vm_daddr)
126 	> p->p_rlimit[RLIMIT_DATA].rlim_cur)
127 	return ENOMEM;
128 
129     old = round_page((vm_offset_t)vm->vm_daddr) + ctob(vm->vm_dsize);
130     new = round_page((vm_offset_t)args->dsend);
131     p->p_retval[0] = old;
132     if ((new-old) > 0) {
133 	if (swap_pager_full)
134 	    return ENOMEM;
135 	error = vm_map_find(&vm->vm_map, NULL, 0, &old, (new-old), FALSE,
136 			VM_PROT_ALL, VM_PROT_ALL, 0);
137 	if (error)
138 	    return error;
139 	vm->vm_dsize += btoc((new-old));
140 	p->p_retval[0] = (int)(vm->vm_daddr + ctob(vm->vm_dsize));
141     }
142     return 0;
143 #else
144     struct vmspace *vm = p->p_vmspace;
145     vm_offset_t new, old;
146     struct obreak_args /* {
147 	char * nsize;
148     } */ tmp;
149 
150 #ifdef DEBUG
151     printf("Linux-emul(%ld): brk(%p)\n", (long)p->p_pid, (void *)args->dsend);
152 #endif
153     old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
154     new = (vm_offset_t)args->dsend;
155     tmp.nsize = (char *) new;
156     if (((caddr_t)new > vm->vm_daddr) && !obreak(p, &tmp))
157 	p->p_retval[0] = (int)new;
158     else
159 	p->p_retval[0] = (int)old;
160 
161     return 0;
162 #endif
163 }
164 
165 int
166 linux_uselib(struct proc *p, struct linux_uselib_args *args)
167 {
168     struct nameidata ni;
169     struct vnode *vp;
170     struct exec *a_out;
171     struct vattr attr;
172     vm_offset_t vmaddr;
173     unsigned long file_offset;
174     vm_offset_t buffer;
175     unsigned long bss_size;
176     int error;
177     caddr_t sg;
178     int locked;
179 
180     sg = stackgap_init();
181     CHECKALTEXIST(p, &sg, args->library);
182 
183 #ifdef DEBUG
184     printf("Linux-emul(%ld): uselib(%s)\n", (long)p->p_pid, args->library);
185 #endif
186 
187     a_out = NULL;
188     locked = 0;
189     vp = NULL;
190 
191     NDINIT(&ni, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, args->library, p);
192     error = namei(&ni);
193     if (error)
194 	goto cleanup;
195 
196     vp = ni.ni_vp;
197     /*
198      * XXX This looks like a bogus check - a LOCKLEAF namei should not succeed
199      * without returning a vnode.
200      */
201     if (vp == NULL) {
202 	error = ENOEXEC;	/* ?? */
203 	goto cleanup;
204     }
205     NDFREE(&ni, NDF_ONLY_PNBUF);
206 
207     /*
208      * From here on down, we have a locked vnode that must be unlocked.
209      */
210     locked++;
211 
212     /*
213      * Writable?
214      */
215     if (vp->v_writecount) {
216 	error = ETXTBSY;
217 	goto cleanup;
218     }
219 
220     /*
221      * Executable?
222      */
223     error = VOP_GETATTR(vp, &attr, p->p_ucred, p);
224     if (error)
225 	goto cleanup;
226 
227     if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
228 	((attr.va_mode & 0111) == 0) ||
229 	(attr.va_type != VREG)) {
230 	    error = ENOEXEC;
231 	    goto cleanup;
232     }
233 
234     /*
235      * Sensible size?
236      */
237     if (attr.va_size == 0) {
238 	error = ENOEXEC;
239 	goto cleanup;
240     }
241 
242     /*
243      * Can we access it?
244      */
245     error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
246     if (error)
247 	goto cleanup;
248 
249     error = VOP_OPEN(vp, FREAD, p->p_ucred, p);
250     if (error)
251 	goto cleanup;
252 
253     /*
254      * Lock no longer needed
255      */
256     VOP_UNLOCK(vp, 0, p);
257     locked = 0;
258 
259     /*
260      * Pull in executable header into kernel_map
261      */
262     error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
263 	    	    VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
264     if (error)
265 	goto cleanup;
266 
267     /*
268      * Is it a Linux binary ?
269      */
270     if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
271 	error = ENOEXEC;
272 	goto cleanup;
273     }
274 
275     /* While we are here, we should REALLY do some more checks */
276 
277     /*
278      * Set file/virtual offset based on a.out variant.
279      */
280     switch ((int)(a_out->a_magic & 0xffff)) {
281     case 0413:	/* ZMAGIC */
282 	file_offset = 1024;
283 	break;
284     case 0314:	/* QMAGIC */
285 	file_offset = 0;
286 	break;
287     default:
288 	error = ENOEXEC;
289 	goto cleanup;
290     }
291 
292     bss_size = round_page(a_out->a_bss);
293 
294     /*
295      * Check various fields in header for validity/bounds.
296      */
297     if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
298 	error = ENOEXEC;
299 	goto cleanup;
300     }
301 
302     /* text + data can't exceed file size */
303     if (a_out->a_data + a_out->a_text > attr.va_size) {
304 	error = EFAULT;
305 	goto cleanup;
306     }
307 
308     /*
309      * text/data/bss must not exceed limits
310      * XXX: this is not complete. it should check current usage PLUS
311      * the resources needed by this library.
312      */
313     if (a_out->a_text > MAXTSIZ ||
314 	a_out->a_data + bss_size > p->p_rlimit[RLIMIT_DATA].rlim_cur) {
315 	error = ENOMEM;
316 	goto cleanup;
317     }
318 
319     /*
320      * prevent more writers
321      */
322     vp->v_flag |= VTEXT;
323 
324     /*
325      * Check if file_offset page aligned,.
326      * Currently we cannot handle misalinged file offsets,
327      * and so we read in the entire image (what a waste).
328      */
329     if (file_offset & PAGE_MASK) {
330 #ifdef DEBUG
331 printf("uselib: Non page aligned binary %lu\n", file_offset);
332 #endif
333 	/*
334 	 * Map text+data read/write/execute
335 	 */
336 
337 	/* a_entry is the load address and is page aligned */
338 	vmaddr = trunc_page(a_out->a_entry);
339 
340 	/* get anon user mapping, read+write+execute */
341 	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
342 		    	    a_out->a_text + a_out->a_data, FALSE,
343 			    VM_PROT_ALL, VM_PROT_ALL, 0);
344 	if (error)
345 	    goto cleanup;
346 
347 	/* map file into kernel_map */
348 	error = vm_mmap(kernel_map, &buffer,
349 			round_page(a_out->a_text + a_out->a_data + file_offset),
350 		   	VM_PROT_READ, VM_PROT_READ, 0,
351 			(caddr_t)vp, trunc_page(file_offset));
352 	if (error)
353 	    goto cleanup;
354 
355 	/* copy from kernel VM space to user space */
356 	error = copyout((caddr_t)(void *)(uintptr_t)(buffer + file_offset),
357 			(caddr_t)vmaddr, a_out->a_text + a_out->a_data);
358 
359 	/* release temporary kernel space */
360 	vm_map_remove(kernel_map, buffer,
361 		      buffer + round_page(a_out->a_text + a_out->a_data + file_offset));
362 
363 	if (error)
364 	    goto cleanup;
365     }
366     else {
367 #ifdef DEBUG
368 printf("uselib: Page aligned binary %lu\n", file_offset);
369 #endif
370 	/*
371 	 * for QMAGIC, a_entry is 20 bytes beyond the load address
372 	 * to skip the executable header
373 	 */
374 	vmaddr = trunc_page(a_out->a_entry);
375 
376 	/*
377 	 * Map it all into the process's space as a single copy-on-write
378 	 * "data" segment.
379 	 */
380 	error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr,
381 		   	a_out->a_text + a_out->a_data,
382 			VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
383 			(caddr_t)vp, file_offset);
384 	if (error)
385 	    goto cleanup;
386     }
387 #ifdef DEBUG
388 printf("mem=%08x = %08x %08x\n", vmaddr, ((int*)vmaddr)[0], ((int*)vmaddr)[1]);
389 #endif
390     if (bss_size != 0) {
391         /*
392 	 * Calculate BSS start address
393 	 */
394 	vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + a_out->a_data;
395 
396 	/*
397 	 * allocate some 'anon' space
398 	 */
399 	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
400 			    bss_size, FALSE,
401 			    VM_PROT_ALL, VM_PROT_ALL, 0);
402 	if (error)
403 	    goto cleanup;
404     }
405 
406 cleanup:
407     /*
408      * Unlock vnode if needed
409      */
410     if (locked)
411 	VOP_UNLOCK(vp, 0, p);
412 
413     /*
414      * Release the kernel mapping.
415      */
416     if (a_out)
417 	vm_map_remove(kernel_map, (vm_offset_t)a_out, (vm_offset_t)a_out + PAGE_SIZE);
418 
419     return error;
420 }
421 
422 int
423 linux_newselect(struct proc *p, struct linux_newselect_args *args)
424 {
425     struct select_args bsa;
426     struct timeval tv0, tv1, utv, *tvp;
427     caddr_t sg;
428     int error;
429 
430 #ifdef DEBUG
431     printf("Linux-emul(%ld): newselect(%d, %p, %p, %p, %p)\n",
432   	(long)p->p_pid, args->nfds, (void *)args->readfds,
433 	(void *)args->writefds, (void *)args->exceptfds,
434 	(void *)args->timeout);
435 #endif
436     error = 0;
437     bsa.nd = args->nfds;
438     bsa.in = args->readfds;
439     bsa.ou = args->writefds;
440     bsa.ex = args->exceptfds;
441     bsa.tv = args->timeout;
442 
443     /*
444      * Store current time for computation of the amount of
445      * time left.
446      */
447     if (args->timeout) {
448 	if ((error = copyin(args->timeout, &utv, sizeof(utv))))
449 	    goto select_out;
450 #ifdef DEBUG
451 	printf("Linux-emul(%ld): incoming timeout (%ld/%ld)\n",
452 	    (long)p->p_pid, utv.tv_sec, utv.tv_usec);
453 #endif
454 	if (itimerfix(&utv)) {
455 	    /*
456 	     * The timeval was invalid.  Convert it to something
457 	     * valid that will act as it does under Linux.
458 	     */
459 	    sg = stackgap_init();
460 	    tvp = stackgap_alloc(&sg, sizeof(utv));
461 	    utv.tv_sec += utv.tv_usec / 1000000;
462 	    utv.tv_usec %= 1000000;
463 	    if (utv.tv_usec < 0) {
464 		utv.tv_sec -= 1;
465 		utv.tv_usec += 1000000;
466 	    }
467 	    if (utv.tv_sec < 0)
468 		timevalclear(&utv);
469 	    if ((error = copyout(&utv, tvp, sizeof(utv))))
470 		goto select_out;
471 	    bsa.tv = tvp;
472 	}
473 	microtime(&tv0);
474     }
475 
476     error = select(p, &bsa);
477 #ifdef DEBUG
478     printf("Linux-emul(%ld): real select returns %d\n", (long)p->p_pid, error);
479 #endif
480 
481     if (error) {
482 	/*
483 	 * See fs/select.c in the Linux kernel.  Without this,
484 	 * Maelstrom doesn't work.
485 	 */
486 	if (error == ERESTART)
487 	    error = EINTR;
488 	goto select_out;
489     }
490 
491     if (args->timeout) {
492 	if (p->p_retval[0]) {
493 	    /*
494 	     * Compute how much time was left of the timeout,
495 	     * by subtracting the current time and the time
496 	     * before we started the call, and subtracting
497 	     * that result from the user-supplied value.
498 	     */
499 	    microtime(&tv1);
500 	    timevalsub(&tv1, &tv0);
501 	    timevalsub(&utv, &tv1);
502 	    if (utv.tv_sec < 0)
503 		timevalclear(&utv);
504 	} else
505 	    timevalclear(&utv);
506 #ifdef DEBUG
507 	printf("Linux-emul(%ld): outgoing timeout (%ld/%ld)\n",
508 	    (long)p->p_pid, utv.tv_sec, utv.tv_usec);
509 #endif
510 	if ((error = copyout(&utv, args->timeout, sizeof(utv))))
511 	    goto select_out;
512     }
513 
514 select_out:
515 #ifdef DEBUG
516     printf("Linux-emul(%ld): newselect_out -> %d\n", (long)p->p_pid, error);
517 #endif
518     return error;
519 }
520 
521 int
522 linux_getpgid(struct proc *p, struct linux_getpgid_args *args)
523 {
524     struct proc *curp;
525 
526 #ifdef DEBUG
527     printf("Linux-emul(%ld): getpgid(%d)\n", (long)p->p_pid, args->pid);
528 #endif
529     if (args->pid != p->p_pid) {
530 	if (!(curp = pfind(args->pid)))
531 	    return ESRCH;
532     }
533     else
534 	curp = p;
535     p->p_retval[0] = curp->p_pgid;
536     return 0;
537 }
538 
539 int
540 linux_mremap(struct proc *p, struct linux_mremap_args *args)
541 {
542 	struct munmap_args /* {
543 		void *addr;
544 		size_t len;
545 	} */ bsd_args;
546 	int error = 0;
547 
548 #ifdef DEBUG
549 	printf("Linux-emul(%ld): mremap(%p, %08x, %08x, %08x)\n",
550 	    (long)p->p_pid, (void *)args->addr, args->old_len, args->new_len,
551 	    args->flags);
552 #endif
553 	args->new_len = round_page(args->new_len);
554 	args->old_len = round_page(args->old_len);
555 
556 	if (args->new_len > args->old_len) {
557 		p->p_retval[0] = 0;
558 		return ENOMEM;
559 	}
560 
561 	if (args->new_len < args->old_len) {
562 		bsd_args.addr = args->addr + args->new_len;
563 		bsd_args.len = args->old_len - args->new_len;
564 		error = munmap(p, &bsd_args);
565 	}
566 
567 	p->p_retval[0] = error ? 0 : (int)args->addr;
568 	return error;
569 }
570 
571 int
572 linux_msync(struct proc *p, struct linux_msync_args *args)
573 {
574 	struct msync_args bsd_args;
575 
576 	bsd_args.addr = args->addr;
577 	bsd_args.len = args->len;
578 	bsd_args.flags = 0;	/* XXX ignore */
579 
580 	return msync(p, &bsd_args);
581 }
582 
583 int
584 linux_time(struct proc *p, struct linux_time_args *args)
585 {
586     struct timeval tv;
587     linux_time_t tm;
588     int error;
589 
590 #ifdef DEBUG
591     printf("Linux-emul(%ld): time(*)\n", (long)p->p_pid);
592 #endif
593     microtime(&tv);
594     tm = tv.tv_sec;
595     if (args->tm && (error = copyout(&tm, args->tm, sizeof(linux_time_t))))
596 	return error;
597     p->p_retval[0] = tm;
598     return 0;
599 }
600 
601 struct linux_times_argv {
602     long    tms_utime;
603     long    tms_stime;
604     long    tms_cutime;
605     long    tms_cstime;
606 };
607 
608 #define CLK_TCK 100	/* Linux uses 100 */
609 #define CONVTCK(r)	(r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
610 
611 int
612 linux_times(struct proc *p, struct linux_times_args *args)
613 {
614     struct timeval tv;
615     struct linux_times_argv tms;
616     struct rusage ru;
617     int error;
618 
619 #ifdef DEBUG
620     printf("Linux-emul(%ld): times(*)\n", (long)p->p_pid);
621 #endif
622     calcru(p, &ru.ru_utime, &ru.ru_stime, NULL);
623 
624     tms.tms_utime = CONVTCK(ru.ru_utime);
625     tms.tms_stime = CONVTCK(ru.ru_stime);
626 
627     tms.tms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime);
628     tms.tms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime);
629 
630     if ((error = copyout((caddr_t)&tms, (caddr_t)args->buf,
631 	    	    sizeof(struct linux_times_argv))))
632 	return error;
633 
634     microuptime(&tv);
635     p->p_retval[0] = (int)CONVTCK(tv);
636     return 0;
637 }
638 
639 int
640 linux_newuname(struct proc *p, struct linux_newuname_args *args)
641 {
642 	struct linux_new_utsname utsname;
643 	char *osrelease, *osname;
644 
645 #ifdef DEBUG
646 	printf("Linux-emul(%ld): newuname(*)\n", (long)p->p_pid);
647 #endif
648 
649 	osname = linux_get_osname(p);
650 	osrelease = linux_get_osrelease(p);
651 
652 	bzero(&utsname, sizeof(struct linux_new_utsname));
653 	strncpy(utsname.sysname, osname, LINUX_MAX_UTSNAME-1);
654 	strncpy(utsname.nodename, hostname, LINUX_MAX_UTSNAME-1);
655 	strncpy(utsname.release, osrelease, LINUX_MAX_UTSNAME-1);
656 	strncpy(utsname.version, version, LINUX_MAX_UTSNAME-1);
657 	strncpy(utsname.machine, machine, LINUX_MAX_UTSNAME-1);
658 	strncpy(utsname.domainname, domainname, LINUX_MAX_UTSNAME-1);
659 
660 	return (copyout((caddr_t)&utsname, (caddr_t)args->buf,
661 			sizeof(struct linux_new_utsname)));
662 }
663 
664 struct linux_utimbuf {
665 	linux_time_t l_actime;
666 	linux_time_t l_modtime;
667 };
668 
669 int
670 linux_utime(struct proc *p, struct linux_utime_args *args)
671 {
672     struct utimes_args /* {
673 	char	*path;
674 	struct	timeval *tptr;
675     } */ bsdutimes;
676     struct timeval tv[2], *tvp;
677     struct linux_utimbuf lut;
678     int error;
679     caddr_t sg;
680 
681     sg = stackgap_init();
682     CHECKALTEXIST(p, &sg, args->fname);
683 
684 #ifdef DEBUG
685     printf("Linux-emul(%ld): utime(%s, *)\n", (long)p->p_pid, args->fname);
686 #endif
687     if (args->times) {
688 	if ((error = copyin(args->times, &lut, sizeof lut)))
689 	    return error;
690 	tv[0].tv_sec = lut.l_actime;
691 	tv[0].tv_usec = 0;
692 	tv[1].tv_sec = lut.l_modtime;
693 	tv[1].tv_usec = 0;
694 	/* so that utimes can copyin */
695 	tvp = (struct timeval *)stackgap_alloc(&sg, sizeof(tv));
696 	if (tvp == NULL)
697 		return (ENAMETOOLONG);
698 	if ((error = copyout(tv, tvp, sizeof(tv))))
699 	    return error;
700 	bsdutimes.tptr = tvp;
701     } else
702 	bsdutimes.tptr = NULL;
703 
704     bsdutimes.path = args->fname;
705     return utimes(p, &bsdutimes);
706 }
707 
708 #define __WCLONE 0x80000000
709 
710 int
711 linux_waitpid(struct proc *p, struct linux_waitpid_args *args)
712 {
713     struct wait_args /* {
714 	int pid;
715 	int *status;
716 	int options;
717 	struct	rusage *rusage;
718     } */ tmp;
719     int error, tmpstat;
720 
721 #ifdef DEBUG
722     printf("Linux-emul(%ld): waitpid(%d, %p, %d)\n",
723 	(long)p->p_pid, args->pid, (void *)args->status, args->options);
724 #endif
725     tmp.pid = args->pid;
726     tmp.status = args->status;
727     tmp.options = (args->options & (WNOHANG | WUNTRACED));
728     /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
729     if (args->options & __WCLONE)
730 	tmp.options |= WLINUXCLONE;
731     tmp.rusage = NULL;
732 
733     if ((error = wait4(p, &tmp)) != 0)
734 	return error;
735 
736     if (args->status) {
737 	if ((error = copyin(args->status, &tmpstat, sizeof(int))) != 0)
738 	    return error;
739 	tmpstat &= 0xffff;
740 	if (WIFSIGNALED(tmpstat))
741 	    tmpstat = (tmpstat & 0xffffff80) |
742 		      BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
743 	else if (WIFSTOPPED(tmpstat))
744 	    tmpstat = (tmpstat & 0xffff00ff) |
745 		      (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
746 	return copyout(&tmpstat, args->status, sizeof(int));
747     } else
748 	return 0;
749 }
750 
751 int
752 linux_wait4(struct proc *p, struct linux_wait4_args *args)
753 {
754     struct wait_args /* {
755 	int pid;
756 	int *status;
757 	int options;
758 	struct	rusage *rusage;
759     } */ tmp;
760     int error, tmpstat;
761 
762 #ifdef DEBUG
763     printf("Linux-emul(%ld): wait4(%d, %p, %d, %p)\n",
764 	(long)p->p_pid, args->pid, (void *)args->status, args->options,
765 	(void *)args->rusage);
766 #endif
767     tmp.pid = args->pid;
768     tmp.status = args->status;
769     tmp.options = (args->options & (WNOHANG | WUNTRACED));
770     /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
771     if (args->options & __WCLONE)
772 	tmp.options |= WLINUXCLONE;
773     tmp.rusage = args->rusage;
774 
775     if ((error = wait4(p, &tmp)) != 0)
776 	return error;
777 
778     SIGDELSET(p->p_siglist, SIGCHLD);
779 
780     if (args->status) {
781 	if ((error = copyin(args->status, &tmpstat, sizeof(int))) != 0)
782 	    return error;
783 	tmpstat &= 0xffff;
784 	if (WIFSIGNALED(tmpstat))
785 	    tmpstat = (tmpstat & 0xffffff80) |
786 		  BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
787 	else if (WIFSTOPPED(tmpstat))
788 	    tmpstat = (tmpstat & 0xffff00ff) |
789 		  (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
790 	return copyout(&tmpstat, args->status, sizeof(int));
791     } else
792 	return 0;
793 }
794 
795 int
796 linux_mknod(struct proc *p, struct linux_mknod_args *args)
797 {
798 	caddr_t sg;
799 	struct mknod_args bsd_mknod;
800 	struct mkfifo_args bsd_mkfifo;
801 
802 	sg = stackgap_init();
803 
804 	CHECKALTCREAT(p, &sg, args->path);
805 
806 #ifdef DEBUG
807 	printf("Linux-emul(%ld): mknod(%s, %d, %d)\n",
808 	   (long)p->p_pid, args->path, args->mode, args->dev);
809 #endif
810 
811 	if (args->mode & S_IFIFO) {
812 		bsd_mkfifo.path = args->path;
813 		bsd_mkfifo.mode = args->mode;
814 		return mkfifo(p, &bsd_mkfifo);
815 	} else {
816 		bsd_mknod.path = args->path;
817 		bsd_mknod.mode = args->mode;
818 		bsd_mknod.dev = args->dev;
819 		return mknod(p, &bsd_mknod);
820 	}
821 }
822 
823 /*
824  * UGH! This is just about the dumbest idea I've ever heard!!
825  */
826 int
827 linux_personality(struct proc *p, struct linux_personality_args *args)
828 {
829 #ifdef DEBUG
830 	printf("Linux-emul(%ld): personality(%d)\n",
831 	   (long)p->p_pid, args->per);
832 #endif
833 	if (args->per != 0)
834 		return EINVAL;
835 
836 	/* Yes Jim, it's still a Linux... */
837 	p->p_retval[0] = 0;
838 	return 0;
839 }
840 
841 /*
842  * Wrappers for get/setitimer for debugging..
843  */
844 int
845 linux_setitimer(struct proc *p, struct linux_setitimer_args *args)
846 {
847 	struct setitimer_args bsa;
848 	struct itimerval foo;
849 	int error;
850 
851 #ifdef DEBUG
852 	printf("Linux-emul(%ld): setitimer(%p, %p)\n",
853 	    (long)p->p_pid, (void *)args->itv, (void *)args->oitv);
854 #endif
855 	bsa.which = args->which;
856 	bsa.itv = args->itv;
857 	bsa.oitv = args->oitv;
858 	if (args->itv) {
859 	    if ((error = copyin((caddr_t)args->itv, (caddr_t)&foo,
860 			sizeof(foo))))
861 		return error;
862 #ifdef DEBUG
863 	    printf("setitimer: value: sec: %ld, usec: %ld\n",
864 		foo.it_value.tv_sec, foo.it_value.tv_usec);
865 	    printf("setitimer: interval: sec: %ld, usec: %ld\n",
866 		foo.it_interval.tv_sec, foo.it_interval.tv_usec);
867 #endif
868 	}
869 	return setitimer(p, &bsa);
870 }
871 
872 int
873 linux_getitimer(struct proc *p, struct linux_getitimer_args *args)
874 {
875 	struct getitimer_args bsa;
876 #ifdef DEBUG
877 	printf("Linux-emul(%ld): getitimer(%p)\n",
878 	    (long)p->p_pid, (void *)args->itv);
879 #endif
880 	bsa.which = args->which;
881 	bsa.itv = args->itv;
882 	return getitimer(p, &bsa);
883 }
884 
885 int
886 linux_nice(struct proc *p, struct linux_nice_args *args)
887 {
888 	struct setpriority_args	bsd_args;
889 
890 	bsd_args.which = PRIO_PROCESS;
891 	bsd_args.who = 0;	/* current process */
892 	bsd_args.prio = args->inc;
893 	return setpriority(p, &bsd_args);
894 }
895 
896 int
897 linux_setgroups(p, uap)
898 	struct proc *p;
899 	struct linux_setgroups_args *uap;
900 {
901 	struct pcred *pc;
902 	linux_gid_t linux_gidset[NGROUPS];
903 	gid_t *bsd_gidset;
904 	int ngrp, error;
905 
906 	pc = p->p_cred;
907 	ngrp = uap->gidsetsize;
908 
909 	/*
910 	 * cr_groups[0] holds egid. Setting the whole set from
911 	 * the supplied set will cause egid to be changed too.
912 	 * Keep cr_groups[0] unchanged to prevent that.
913 	 */
914 
915 	if ((error = suser(p)) != 0)
916 		return (error);
917 
918 	if (ngrp >= NGROUPS)
919 		return (EINVAL);
920 
921 	pc->pc_ucred = crcopy(pc->pc_ucred);
922 	if (ngrp > 0) {
923 		error = copyin((caddr_t)uap->gidset, (caddr_t)linux_gidset,
924 			       ngrp * sizeof(linux_gid_t));
925 		if (error)
926 			return (error);
927 
928 		pc->pc_ucred->cr_ngroups = ngrp + 1;
929 
930 		bsd_gidset = pc->pc_ucred->cr_groups;
931 		ngrp--;
932 		while (ngrp >= 0) {
933 			bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
934 			ngrp--;
935 		}
936 	}
937 	else
938 		pc->pc_ucred->cr_ngroups = 1;
939 
940 	setsugid(p);
941 	return (0);
942 }
943 
944 int
945 linux_getgroups(p, uap)
946 	struct proc *p;
947 	struct linux_getgroups_args *uap;
948 {
949 	struct pcred *pc;
950 	linux_gid_t linux_gidset[NGROUPS];
951 	gid_t *bsd_gidset;
952 	int bsd_gidsetsz, ngrp, error;
953 
954 	pc = p->p_cred;
955 	bsd_gidset = pc->pc_ucred->cr_groups;
956 	bsd_gidsetsz = pc->pc_ucred->cr_ngroups - 1;
957 
958 	/*
959 	 * cr_groups[0] holds egid. Returning the whole set
960 	 * here will cause a duplicate. Exclude cr_groups[0]
961 	 * to prevent that.
962 	 */
963 
964 	if ((ngrp = uap->gidsetsize) == 0) {
965 		p->p_retval[0] = bsd_gidsetsz;
966 		return (0);
967 	}
968 
969 	if (ngrp < bsd_gidsetsz)
970 		return (EINVAL);
971 
972 	ngrp = 0;
973 	while (ngrp < bsd_gidsetsz) {
974 		linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
975 		ngrp++;
976 	}
977 
978 	if ((error = copyout((caddr_t)linux_gidset, (caddr_t)uap->gidset,
979 	    ngrp * sizeof(linux_gid_t))))
980 		return (error);
981 
982 	p->p_retval[0] = ngrp;
983 	return (0);
984 }
985 
986 int
987 linux_setrlimit(p, uap)
988      struct proc *p;
989      struct linux_setrlimit_args *uap;
990 {
991     struct osetrlimit_args bsd;
992 
993 #ifdef DEBUG
994     printf("Linux-emul(%ld): setrlimit(%d, %p)\n",
995 	   (long)p->p_pid, uap->resource, (void *)uap->rlim);
996 #endif
997 
998     if (uap->resource >= LINUX_RLIM_NLIMITS)
999 	return EINVAL;
1000 
1001     bsd.which = linux_to_bsd_resource[uap->resource];
1002 
1003     if (bsd.which == -1)
1004 	return EINVAL;
1005 
1006     bsd.rlp = uap->rlim;
1007     return osetrlimit(p, &bsd);
1008 }
1009 
1010 int
1011 linux_getrlimit(p, uap)
1012      struct proc *p;
1013      struct linux_getrlimit_args *uap;
1014 {
1015     struct ogetrlimit_args bsd;
1016 
1017 #ifdef DEBUG
1018     printf("Linux-emul(%ld): getrlimit(%d, %p)\n",
1019 	   (long)p->p_pid, uap->resource, (void *)uap->rlim);
1020 #endif
1021 
1022     if (uap->resource >= LINUX_RLIM_NLIMITS)
1023 	return EINVAL;
1024 
1025     bsd.which = linux_to_bsd_resource[uap->resource];
1026 
1027     if (bsd.which == -1)
1028 	return EINVAL;
1029 
1030     bsd.rlp = uap->rlim;
1031     return ogetrlimit(p, &bsd);
1032 }
1033 
1034 int
1035 linux_sched_setscheduler(p, uap)
1036 	struct proc *p;
1037 	struct linux_sched_setscheduler_args *uap;
1038 {
1039 	struct sched_setscheduler_args bsd;
1040 
1041 #ifdef DEBUG
1042 	printf("Linux-emul(%ld): sched_setscheduler(%d, %d, %p)\n",
1043 	    (long)p->p_pid, uap->pid, uap->policy, (const void *)uap->param);
1044 #endif
1045 
1046 	switch (uap->policy) {
1047 	case LINUX_SCHED_OTHER:
1048 		bsd.policy = SCHED_OTHER;
1049 		break;
1050 	case LINUX_SCHED_FIFO:
1051 		bsd.policy = SCHED_FIFO;
1052 		break;
1053 	case LINUX_SCHED_RR:
1054 		bsd.policy = SCHED_RR;
1055 		break;
1056 	default:
1057 		return EINVAL;
1058 	}
1059 
1060 	bsd.pid = uap->pid;
1061 	bsd.param = uap->param;
1062 	return sched_setscheduler(p, &bsd);
1063 }
1064 
1065 int
1066 linux_sched_getscheduler(p, uap)
1067 	struct proc *p;
1068 	struct linux_sched_getscheduler_args *uap;
1069 {
1070 	struct sched_getscheduler_args bsd;
1071 	int error;
1072 
1073 #ifdef DEBUG
1074 	printf("Linux-emul(%ld): sched_getscheduler(%d)\n",
1075 	       (long)p->p_pid, uap->pid);
1076 #endif
1077 
1078 	bsd.pid = uap->pid;
1079 	error = sched_getscheduler(p, &bsd);
1080 
1081 	switch (p->p_retval[0]) {
1082 	case SCHED_OTHER:
1083 		p->p_retval[0] = LINUX_SCHED_OTHER;
1084 		break;
1085 	case SCHED_FIFO:
1086 		p->p_retval[0] = LINUX_SCHED_FIFO;
1087 		break;
1088 	case SCHED_RR:
1089 		p->p_retval[0] = LINUX_SCHED_RR;
1090 		break;
1091 	}
1092 
1093 	return error;
1094 }
1095