xref: /freebsd/sys/compat/linux/linux_misc.c (revision 11afcc8f9f96d657b8e6f7547c02c1957331fc96)
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  *  $Id: linux_misc.c,v 1.40 1998/07/29 16:43:00 bde Exp $
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/sysproto.h>
34 #include <sys/kernel.h>
35 #include <sys/mman.h>
36 #include <sys/proc.h>
37 #include <sys/fcntl.h>
38 #include <sys/imgact_aout.h>
39 #include <sys/mount.h>
40 #include <sys/namei.h>
41 #include <sys/resourcevar.h>
42 #include <sys/stat.h>
43 #include <sys/sysctl.h>
44 #include <sys/vnode.h>
45 #include <sys/wait.h>
46 #include <sys/time.h>
47 
48 #include <vm/vm.h>
49 #include <vm/pmap.h>
50 #include <vm/vm_kern.h>
51 #include <vm/vm_prot.h>
52 #include <vm/vm_map.h>
53 #include <vm/vm_extern.h>
54 
55 #include <machine/frame.h>
56 #include <machine/psl.h>
57 
58 #include <i386/linux/linux.h>
59 #include <i386/linux/linux_proto.h>
60 #include <i386/linux/linux_util.h>
61 
62 int
63 linux_alarm(struct proc *p, struct linux_alarm_args *args)
64 {
65     struct itimerval it, old_it;
66     struct timeval tv;
67     int s;
68 
69 #ifdef DEBUG
70     printf("Linux-emul(%ld): alarm(%u)\n", (long)p->p_pid, args->secs);
71 #endif
72     if (args->secs > 100000000)
73 	return EINVAL;
74     it.it_value.tv_sec = (long)args->secs;
75     it.it_value.tv_usec = 0;
76     it.it_interval.tv_sec = 0;
77     it.it_interval.tv_usec = 0;
78     s = splsoftclock();
79     old_it = p->p_realtimer;
80     getmicrouptime(&tv);
81     if (timevalisset(&old_it.it_value))
82 	untimeout(realitexpire, (caddr_t)p, p->p_ithandle);
83     if (it.it_value.tv_sec != 0) {
84 	p->p_ithandle = timeout(realitexpire, (caddr_t)p, tvtohz(&it.it_value));
85 	timevaladd(&it.it_value, &tv);
86     }
87     p->p_realtimer = it;
88     splx(s);
89     if (timevalcmp(&old_it.it_value, &tv, >)) {
90 	timevalsub(&old_it.it_value, &tv);
91 	if (old_it.it_value.tv_usec != 0)
92 	    old_it.it_value.tv_sec++;
93 	p->p_retval[0] = old_it.it_value.tv_sec;
94     }
95     return 0;
96 }
97 
98 int
99 linux_brk(struct proc *p, struct linux_brk_args *args)
100 {
101 #if 0
102     struct vmspace *vm = p->p_vmspace;
103     vm_offset_t new, old;
104     int error;
105 
106     if ((vm_offset_t)args->dsend < (vm_offset_t)vm->vm_daddr)
107 	return EINVAL;
108     if (((caddr_t)args->dsend - (caddr_t)vm->vm_daddr)
109 	> p->p_rlimit[RLIMIT_DATA].rlim_cur)
110 	return ENOMEM;
111 
112     old = round_page((vm_offset_t)vm->vm_daddr) + ctob(vm->vm_dsize);
113     new = round_page((vm_offset_t)args->dsend);
114     p->p_retval[0] = old;
115     if ((new-old) > 0) {
116 	if (swap_pager_full)
117 	    return ENOMEM;
118 	error = vm_map_find(&vm->vm_map, NULL, 0, &old, (new-old), FALSE,
119 			VM_PROT_ALL, VM_PROT_ALL, 0);
120 	if (error)
121 	    return error;
122 	vm->vm_dsize += btoc((new-old));
123 	p->p_retval[0] = (int)(vm->vm_daddr + ctob(vm->vm_dsize));
124     }
125     return 0;
126 #else
127     struct vmspace *vm = p->p_vmspace;
128     vm_offset_t new, old;
129     struct obreak_args /* {
130 	char * nsize;
131     } */ tmp;
132 
133 #ifdef DEBUG
134     printf("Linux-emul(%ld): brk(%p)\n", (long)p->p_pid, (void *)args->dsend);
135 #endif
136     old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
137     new = (vm_offset_t)args->dsend;
138     tmp.nsize = (char *) new;
139     if (((caddr_t)new > vm->vm_daddr) && !obreak(p, &tmp))
140 	p->p_retval[0] = (int)new;
141     else
142 	p->p_retval[0] = (int)old;
143 
144     return 0;
145 #endif
146 }
147 
148 int
149 linux_uselib(struct proc *p, struct linux_uselib_args *args)
150 {
151     struct nameidata ni;
152     struct vnode *vp;
153     struct exec *a_out;
154     struct vattr attr;
155     vm_offset_t vmaddr;
156     unsigned long file_offset;
157     vm_offset_t buffer;
158     unsigned long bss_size;
159     int error;
160     caddr_t sg;
161     int locked;
162 
163     sg = stackgap_init();
164     CHECKALTEXIST(p, &sg, args->library);
165 
166 #ifdef DEBUG
167     printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, args->library);
168 #endif
169 
170     a_out = NULL;
171     locked = 0;
172     vp = NULL;
173 
174     NDINIT(&ni, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, args->library, p);
175     if (error = namei(&ni))
176 	goto cleanup;
177 
178     vp = ni.ni_vp;
179     if (vp == NULL) {
180 	error = ENOEXEC;	/* ?? */
181 	goto cleanup;
182     }
183 
184     /*
185      * From here on down, we have a locked vnode that must be unlocked.
186      */
187     locked++;
188 
189     /*
190      * Writable?
191      */
192     if (vp->v_writecount) {
193 	error = ETXTBSY;
194 	goto cleanup;
195     }
196 
197     /*
198      * Executable?
199      */
200     if (error = VOP_GETATTR(vp, &attr, p->p_ucred, p))
201 	goto cleanup;
202 
203     if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
204 	((attr.va_mode & 0111) == 0) ||
205 	(attr.va_type != VREG)) {
206 	    error = ENOEXEC;
207 	    goto cleanup;
208     }
209 
210     /*
211      * Sensible size?
212      */
213     if (attr.va_size == 0) {
214 	error = ENOEXEC;
215 	goto cleanup;
216     }
217 
218     /*
219      * Can we access it?
220      */
221     if (error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p))
222 	goto cleanup;
223 
224     if (error = VOP_OPEN(vp, FREAD, p->p_ucred, p))
225 	goto cleanup;
226 
227     /*
228      * Lock no longer needed
229      */
230     VOP_UNLOCK(vp, 0, p);
231     locked = 0;
232 
233     /*
234      * Pull in executable header into kernel_map
235      */
236     error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
237 	    	    VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
238     if (error)
239 	goto cleanup;
240 
241     /*
242      * Is it a Linux binary ?
243      */
244     if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
245 	error = ENOEXEC;
246 	goto cleanup;
247     }
248 
249     /* While we are here, we should REALLY do some more checks */
250 
251     /*
252      * Set file/virtual offset based on a.out variant.
253      */
254     switch ((int)(a_out->a_magic & 0xffff)) {
255     case 0413:	/* ZMAGIC */
256 	file_offset = 1024;
257 	break;
258     case 0314:	/* QMAGIC */
259 	file_offset = 0;
260 	break;
261     default:
262 	error = ENOEXEC;
263 	goto cleanup;
264     }
265 
266     bss_size = round_page(a_out->a_bss);
267 
268     /*
269      * Check various fields in header for validity/bounds.
270      */
271     if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
272 	error = ENOEXEC;
273 	goto cleanup;
274     }
275 
276     /* text + data can't exceed file size */
277     if (a_out->a_data + a_out->a_text > attr.va_size) {
278 	error = EFAULT;
279 	goto cleanup;
280     }
281 
282     /*
283      * text/data/bss must not exceed limits
284      * XXX: this is not complete. it should check current usage PLUS
285      * the resources needed by this library.
286      */
287     if (a_out->a_text > MAXTSIZ ||
288 	a_out->a_data + bss_size > p->p_rlimit[RLIMIT_DATA].rlim_cur) {
289 	error = ENOMEM;
290 	goto cleanup;
291     }
292 
293     /*
294      * prevent more writers
295      */
296     vp->v_flag |= VTEXT;
297 
298     /*
299      * Check if file_offset page aligned,.
300      * Currently we cannot handle misalinged file offsets,
301      * and so we read in the entire image (what a waste).
302      */
303     if (file_offset & PAGE_MASK) {
304 #ifdef DEBUG
305 printf("uselib: Non page aligned binary %lu\n", file_offset);
306 #endif
307 	/*
308 	 * Map text+data read/write/execute
309 	 */
310 
311 	/* a_entry is the load address and is page aligned */
312 	vmaddr = trunc_page(a_out->a_entry);
313 
314 	/* get anon user mapping, read+write+execute */
315 	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
316 		    	    a_out->a_text + a_out->a_data, FALSE,
317 			    VM_PROT_ALL, VM_PROT_ALL, 0);
318 	if (error)
319 	    goto cleanup;
320 
321 	/* map file into kernel_map */
322 	error = vm_mmap(kernel_map, &buffer,
323 			round_page(a_out->a_text + a_out->a_data + file_offset),
324 		   	VM_PROT_READ, VM_PROT_READ, 0,
325 			(caddr_t)vp, trunc_page(file_offset));
326 	if (error)
327 	    goto cleanup;
328 
329 	/* copy from kernel VM space to user space */
330 	error = copyout((caddr_t)(buffer + file_offset), (caddr_t)vmaddr,
331 			a_out->a_text + a_out->a_data);
332 
333 	/* release temporary kernel space */
334 	vm_map_remove(kernel_map, buffer,
335 		      buffer + round_page(a_out->a_text + a_out->a_data + file_offset));
336 
337 	if (error)
338 	    goto cleanup;
339     }
340     else {
341 #ifdef DEBUG
342 printf("uselib: Page aligned binary %lu\n", file_offset);
343 #endif
344 	/*
345 	 * for QMAGIC, a_entry is 20 bytes beyond the load address
346 	 * to skip the executable header
347 	 */
348 	vmaddr = trunc_page(a_out->a_entry);
349 
350 	/*
351 	 * Map it all into the process's space as a single copy-on-write
352 	 * "data" segment.
353 	 */
354 	error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr,
355 		   	a_out->a_text + a_out->a_data,
356 			VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
357 			(caddr_t)vp, file_offset);
358 	if (error)
359 	    goto cleanup;
360     }
361 #ifdef DEBUG
362 printf("mem=%08x = %08x %08x\n", vmaddr, ((int*)vmaddr)[0], ((int*)vmaddr)[1]);
363 #endif
364     if (bss_size != 0) {
365         /*
366 	 * Calculate BSS start address
367 	 */
368 	vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + a_out->a_data;
369 
370 	/*
371 	 * allocate some 'anon' space
372 	 */
373 	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
374 			    bss_size, FALSE,
375 			    VM_PROT_ALL, VM_PROT_ALL, 0);
376 	if (error)
377 	    goto cleanup;
378     }
379 
380 cleanup:
381     /*
382      * Unlock vnode if needed
383      */
384     if (locked)
385 	VOP_UNLOCK(vp, 0, p);
386 
387     /*
388      * Release the kernel mapping.
389      */
390     if (a_out)
391 	vm_map_remove(kernel_map, (vm_offset_t)a_out, (vm_offset_t)a_out + PAGE_SIZE);
392 
393     return error;
394 }
395 
396 /* XXX move */
397 struct linux_select_argv {
398 	int nfds;
399 	fd_set *readfds;
400 	fd_set *writefds;
401 	fd_set *exceptfds;
402 	struct timeval *timeout;
403 };
404 
405 int
406 linux_select(struct proc *p, struct linux_select_args *args)
407 {
408     struct linux_select_argv linux_args;
409     struct linux_newselect_args newsel;
410     int error;
411 
412 #ifdef SELECT_DEBUG
413     printf("Linux-emul(%d): select(%x)\n",
414 	   p->p_pid, args->ptr);
415 #endif
416     if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args,
417 			sizeof(linux_args))))
418 	return error;
419 
420     newsel.nfds = linux_args.nfds;
421     newsel.readfds = linux_args.readfds;
422     newsel.writefds = linux_args.writefds;
423     newsel.exceptfds = linux_args.exceptfds;
424     newsel.timeout = linux_args.timeout;
425 
426     return linux_newselect(p, &newsel);
427 }
428 
429 int
430 linux_newselect(struct proc *p, struct linux_newselect_args *args)
431 {
432     struct select_args bsa;
433     struct timeval tv0, tv1, utv, *tvp;
434     caddr_t sg;
435     int error;
436 
437 #ifdef DEBUG
438     printf("Linux-emul(%ld): newselect(%d, %p, %p, %p, %p)\n",
439   	(long)p->p_pid, args->nfds, (void *)args->readfds,
440 	(void *)args->writefds, (void *)args->exceptfds,
441 	(void *)args->timeout);
442 #endif
443     error = 0;
444     bsa.nd = args->nfds;
445     bsa.in = args->readfds;
446     bsa.ou = args->writefds;
447     bsa.ex = args->exceptfds;
448     bsa.tv = args->timeout;
449 
450     /*
451      * Store current time for computation of the amount of
452      * time left.
453      */
454     if (args->timeout) {
455 	if ((error = copyin(args->timeout, &utv, sizeof(utv))))
456 	    goto select_out;
457 #ifdef DEBUG
458 	printf("Linux-emul(%ld): incoming timeout (%ld/%ld)\n",
459 	    (long)p->p_pid, utv.tv_sec, utv.tv_usec);
460 #endif
461 	if (itimerfix(&utv)) {
462 	    /*
463 	     * The timeval was invalid.  Convert it to something
464 	     * valid that will act as it does under Linux.
465 	     */
466 	    sg = stackgap_init();
467 	    tvp = stackgap_alloc(&sg, sizeof(utv));
468 	    utv.tv_sec += utv.tv_usec / 1000000;
469 	    utv.tv_usec %= 1000000;
470 	    if (utv.tv_usec < 0) {
471 		utv.tv_sec -= 1;
472 		utv.tv_usec += 1000000;
473 	    }
474 	    if (utv.tv_sec < 0)
475 		timevalclear(&utv);
476 	    if ((error = copyout(&utv, tvp, sizeof(utv))))
477 		goto select_out;
478 	    bsa.tv = tvp;
479 	}
480 	microtime(&tv0);
481     }
482 
483     error = select(p, &bsa);
484 #ifdef DEBUG
485     printf("Linux-emul(%d): real select returns %d\n",
486 	       p->p_pid, error);
487 #endif
488 
489     if (error) {
490 	/*
491 	 * See fs/select.c in the Linux kernel.  Without this,
492 	 * Maelstrom doesn't work.
493 	 */
494 	if (error == ERESTART)
495 	    error = EINTR;
496 	goto select_out;
497     }
498 
499     if (args->timeout) {
500 	if (p->p_retval[0]) {
501 	    /*
502 	     * Compute how much time was left of the timeout,
503 	     * by subtracting the current time and the time
504 	     * before we started the call, and subtracting
505 	     * that result from the user-supplied value.
506 	     */
507 	    microtime(&tv1);
508 	    timevalsub(&tv1, &tv0);
509 	    timevalsub(&utv, &tv1);
510 	    if (utv.tv_sec < 0)
511 		timevalclear(&utv);
512 	} else
513 	    timevalclear(&utv);
514 #ifdef DEBUG
515 	printf("Linux-emul(%ld): outgoing timeout (%ld/%ld)\n",
516 	    (long)p->p_pid, utv.tv_sec, utv.tv_usec);
517 #endif
518 	if ((error = copyout(&utv, args->timeout, sizeof(utv))))
519 	    goto select_out;
520     }
521 
522 select_out:
523 #ifdef DEBUG
524     printf("Linux-emul(%d): newselect_out -> %d\n",
525 	       p->p_pid, error);
526 #endif
527     return error;
528 }
529 
530 int
531 linux_getpgid(struct proc *p, struct linux_getpgid_args *args)
532 {
533     struct proc *curproc;
534 
535 #ifdef DEBUG
536     printf("Linux-emul(%d): getpgid(%d)\n", p->p_pid, args->pid);
537 #endif
538     if (args->pid != p->p_pid) {
539 	if (!(curproc = pfind(args->pid)))
540 	    return ESRCH;
541     }
542     else
543 	curproc = p;
544     p->p_retval[0] = curproc->p_pgid;
545     return 0;
546 }
547 
548 int
549 linux_fork(struct proc *p, struct linux_fork_args *args)
550 {
551     int error;
552 
553 #ifdef DEBUG
554     printf("Linux-emul(%d): fork()\n", p->p_pid);
555 #endif
556     if (error = fork(p, (struct fork_args *)args))
557 	return error;
558     if (p->p_retval[1] == 1)
559 	p->p_retval[0] = 0;
560     return 0;
561 }
562 
563 /* XXX move */
564 struct linux_mmap_argv {
565 	linux_caddr_t addr;
566 	int len;
567 	int prot;
568 	int flags;
569 	int fd;
570 	int pos;
571 };
572 
573 int
574 linux_mmap(struct proc *p, struct linux_mmap_args *args)
575 {
576     struct mmap_args /* {
577 	caddr_t addr;
578 	size_t len;
579 	int prot;
580 	int flags;
581 	int fd;
582 	long pad;
583 	off_t pos;
584     } */ bsd_args;
585     int error;
586     struct linux_mmap_argv linux_args;
587 
588     if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args,
589 			sizeof(linux_args))))
590 	return error;
591 #ifdef DEBUG
592     printf("Linux-emul(%ld): mmap(%p, %d, %d, %08x, %d, %d)\n",
593 	(long)p->p_pid, (void *)linux_args.addr, linux_args.len,
594 	linux_args.prot, linux_args.flags, linux_args.fd, linux_args.pos);
595 #endif
596     bsd_args.flags = 0;
597     if (linux_args.flags & LINUX_MAP_SHARED)
598 	bsd_args.flags |= MAP_SHARED;
599     if (linux_args.flags & LINUX_MAP_PRIVATE)
600 	bsd_args.flags |= MAP_PRIVATE;
601     if (linux_args.flags & LINUX_MAP_FIXED)
602 	bsd_args.flags |= MAP_FIXED;
603     if (linux_args.flags & LINUX_MAP_ANON)
604 	bsd_args.flags |= MAP_ANON;
605     bsd_args.addr = linux_args.addr;
606     bsd_args.len = linux_args.len;
607     bsd_args.prot = linux_args.prot | PROT_READ;	/* always required */
608     bsd_args.fd = linux_args.fd;
609     bsd_args.pos = linux_args.pos;
610     bsd_args.pad = 0;
611     return mmap(p, &bsd_args);
612 }
613 
614 int
615 linux_mremap(struct proc *p, struct linux_mremap_args *args)
616 {
617 	struct munmap_args /* {
618 		void *addr;
619 		size_t len;
620 	} */ bsd_args;
621 	int error = 0;
622 
623 #ifdef DEBUG
624 	printf("Linux-emul(%ld): mremap(%p, %08x, %08x, %08x)\n",
625 	    (long)p->p_pid, (void *)args->addr, args->old_len, args->new_len,
626 	    args->flags);
627 #endif
628 	args->new_len = round_page(args->new_len);
629 	args->old_len = round_page(args->old_len);
630 
631 	if (args->new_len > args->old_len) {
632 		p->p_retval[0] = 0;
633 		return ENOMEM;
634 	}
635 
636 	if (args->new_len < args->old_len) {
637 		bsd_args.addr = args->addr + args->new_len;
638 		bsd_args.len = args->old_len - args->new_len;
639 		error = munmap(p, &bsd_args);
640 	}
641 
642 	p->p_retval[0] = error ? 0 : (int)args->addr;
643 	return error;
644 }
645 
646 int
647 linux_msync(struct proc *p, struct linux_msync_args *args)
648 {
649 	struct msync_args bsd_args;
650 
651 	bsd_args.addr = args->addr;
652 	bsd_args.len = args->len;
653 	bsd_args.flags = 0;	/* XXX ignore */
654 
655 	return msync(p, &bsd_args);
656 }
657 
658 int
659 linux_pipe(struct proc *p, struct linux_pipe_args *args)
660 {
661     int error;
662 
663 #ifdef DEBUG
664     printf("Linux-emul(%d): pipe(*)\n", p->p_pid);
665 #endif
666     if (error = pipe(p, 0))
667 	return error;
668     if (error = copyout(p->p_retval, args->pipefds, 2*sizeof(int)))
669 	return error;
670     p->p_retval[0] = 0;
671     return 0;
672 }
673 
674 int
675 linux_time(struct proc *p, struct linux_time_args *args)
676 {
677     struct timeval tv;
678     linux_time_t tm;
679     int error;
680 
681 #ifdef DEBUG
682     printf("Linux-emul(%d): time(*)\n", p->p_pid);
683 #endif
684     microtime(&tv);
685     tm = tv.tv_sec;
686     if (args->tm && (error = copyout(&tm, args->tm, sizeof(linux_time_t))))
687 	return error;
688     p->p_retval[0] = tm;
689     return 0;
690 }
691 
692 struct linux_times_argv {
693     long    tms_utime;
694     long    tms_stime;
695     long    tms_cutime;
696     long    tms_cstime;
697 };
698 
699 #define CLK_TCK 100	/* Linux uses 100 */
700 #define CONVTCK(r)	(r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
701 
702 int
703 linux_times(struct proc *p, struct linux_times_args *args)
704 {
705     struct timeval tv;
706     struct linux_times_argv tms;
707     struct rusage ru;
708     int error;
709 
710 #ifdef DEBUG
711     printf("Linux-emul(%d): times(*)\n", p->p_pid);
712 #endif
713     calcru(p, &ru.ru_utime, &ru.ru_stime, NULL);
714 
715     tms.tms_utime = CONVTCK(ru.ru_utime);
716     tms.tms_stime = CONVTCK(ru.ru_stime);
717 
718     tms.tms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime);
719     tms.tms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime);
720 
721     if ((error = copyout((caddr_t)&tms, (caddr_t)args->buf,
722 	    	    sizeof(struct linux_times_argv))))
723 	return error;
724 
725     microuptime(&tv);
726     p->p_retval[0] = (int)CONVTCK(tv);
727     return 0;
728 }
729 
730 /* XXX move */
731 struct linux_newuname_t {
732     char sysname[65];
733     char nodename[65];
734     char release[65];
735     char version[65];
736     char machine[65];
737     char domainname[65];
738 };
739 
740 int
741 linux_newuname(struct proc *p, struct linux_newuname_args *args)
742 {
743     struct linux_newuname_t linux_newuname;
744 
745 #ifdef DEBUG
746     printf("Linux-emul(%d): newuname(*)\n", p->p_pid);
747 #endif
748     bzero(&linux_newuname, sizeof(struct linux_newuname_args));
749     strncpy(linux_newuname.sysname, ostype, 64);
750     strncpy(linux_newuname.nodename, hostname, 64);
751     strncpy(linux_newuname.release, osrelease, 64);
752     strncpy(linux_newuname.version, version, 64);
753     strncpy(linux_newuname.machine, machine, 64);
754     strncpy(linux_newuname.domainname, domainname, 64);
755     return (copyout((caddr_t)&linux_newuname, (caddr_t)args->buf,
756 	    	    sizeof(struct linux_newuname_t)));
757 }
758 
759 struct linux_utimbuf {
760 	linux_time_t l_actime;
761 	linux_time_t l_modtime;
762 };
763 
764 int
765 linux_utime(struct proc *p, struct linux_utime_args *args)
766 {
767     struct utimes_args /* {
768 	char	*path;
769 	struct	timeval *tptr;
770     } */ bsdutimes;
771     struct timeval tv[2], *tvp;
772     struct linux_utimbuf lut;
773     int error;
774     caddr_t sg;
775 
776     sg = stackgap_init();
777     CHECKALTEXIST(p, &sg, args->fname);
778 
779 #ifdef DEBUG
780     printf("Linux-emul(%d): utime(%s, *)\n", p->p_pid, args->fname);
781 #endif
782     if (args->times) {
783 	if ((error = copyin(args->times, &lut, sizeof lut)))
784 	    return error;
785 	tv[0].tv_sec = lut.l_actime;
786 	tv[0].tv_usec = 0;
787 	tv[1].tv_sec = lut.l_modtime;
788 	tv[1].tv_usec = 0;
789 	/* so that utimes can copyin */
790 	tvp = (struct timeval *)stackgap_alloc(&sg, sizeof(tv));
791 	if ((error = copyout(tv, tvp, sizeof(tv))))
792 	    return error;
793 	bsdutimes.tptr = tvp;
794     } else
795 	bsdutimes.tptr = NULL;
796 
797     bsdutimes.path = args->fname;
798     return utimes(p, &bsdutimes);
799 }
800 
801 int
802 linux_waitpid(struct proc *p, struct linux_waitpid_args *args)
803 {
804     struct wait_args /* {
805 	int pid;
806 	int *status;
807 	int options;
808 	struct	rusage *rusage;
809     } */ tmp;
810     int error, tmpstat;
811 
812 #ifdef DEBUG
813     printf("Linux-emul(%ld): waitpid(%d, %p, %d)\n",
814 	(long)p->p_pid, args->pid, (void *)args->status, args->options);
815 #endif
816     tmp.pid = args->pid;
817     tmp.status = args->status;
818     tmp.options = args->options;
819     tmp.rusage = NULL;
820 
821     if (error = wait4(p, &tmp))
822 	return error;
823     if (args->status) {
824 	if (error = copyin(args->status, &tmpstat, sizeof(int)))
825 	    return error;
826 	if (WIFSIGNALED(tmpstat))
827 	    tmpstat = (tmpstat & 0xffffff80) |
828 		      bsd_to_linux_signal[WTERMSIG(tmpstat)];
829 	else if (WIFSTOPPED(tmpstat))
830 	    tmpstat = (tmpstat & 0xffff00ff) |
831 		      (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8);
832 	return copyout(&tmpstat, args->status, sizeof(int));
833     } else
834 	return 0;
835 }
836 
837 int
838 linux_wait4(struct proc *p, struct linux_wait4_args *args)
839 {
840     struct wait_args /* {
841 	int pid;
842 	int *status;
843 	int options;
844 	struct	rusage *rusage;
845     } */ tmp;
846     int error, tmpstat;
847 
848 #ifdef DEBUG
849     printf("Linux-emul(%ld): wait4(%d, %p, %d, %p)\n",
850 	(long)p->p_pid, args->pid, (void *)args->status, args->options,
851 	(void *)args->rusage);
852 #endif
853     tmp.pid = args->pid;
854     tmp.status = args->status;
855     tmp.options = args->options;
856     tmp.rusage = args->rusage;
857 
858     if (error = wait4(p, &tmp))
859 	return error;
860 
861     p->p_siglist &= ~sigmask(SIGCHLD);
862 
863     if (args->status) {
864 	if (error = copyin(args->status, &tmpstat, sizeof(int)))
865 	    return error;
866 	if (WIFSIGNALED(tmpstat))
867 	    tmpstat = (tmpstat & 0xffffff80) |
868 		  bsd_to_linux_signal[WTERMSIG(tmpstat)];
869 	else if (WIFSTOPPED(tmpstat))
870 	    tmpstat = (tmpstat & 0xffff00ff) |
871 		  (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8);
872 	return copyout(&tmpstat, args->status, sizeof(int));
873     } else
874 	return 0;
875 }
876 
877 int
878 linux_mknod(struct proc *p, struct linux_mknod_args *args)
879 {
880 	caddr_t sg;
881 	struct mknod_args bsd_mknod;
882 	struct mkfifo_args bsd_mkfifo;
883 
884 	sg = stackgap_init();
885 
886 	CHECKALTCREAT(p, &sg, args->path);
887 
888 #ifdef DEBUG
889 	printf("Linux-emul(%d): mknod(%s, %d, %d)\n",
890 	   p->p_pid, args->path, args->mode, args->dev);
891 #endif
892 
893 	if (args->mode & S_IFIFO) {
894 		bsd_mkfifo.path = args->path;
895 		bsd_mkfifo.mode = args->mode;
896 		return mkfifo(p, &bsd_mkfifo);
897 	} else {
898 		bsd_mknod.path = args->path;
899 		bsd_mknod.mode = args->mode;
900 		bsd_mknod.dev = args->dev;
901 		return mknod(p, &bsd_mknod);
902 	}
903 }
904 
905 /*
906  * UGH! This is just about the dumbest idea I've ever heard!!
907  */
908 int
909 linux_personality(struct proc *p, struct linux_personality_args *args)
910 {
911 #ifdef DEBUG
912 	printf("Linux-emul(%d): personality(%d)\n",
913 	   p->p_pid, args->per);
914 #endif
915 	if (args->per != 0)
916 		return EINVAL;
917 
918 	/* Yes Jim, it's still a Linux... */
919 	p->p_retval[0] = 0;
920 	return 0;
921 }
922 
923 /*
924  * Wrappers for get/setitimer for debugging..
925  */
926 int
927 linux_setitimer(struct proc *p, struct linux_setitimer_args *args)
928 {
929 	struct setitimer_args bsa;
930 	struct itimerval foo;
931 	int error;
932 
933 #ifdef DEBUG
934 	printf("Linux-emul(%ld): setitimer(%p, %p)\n",
935 	    (long)p->p_pid, (void *)args->itv, (void *)args->oitv);
936 #endif
937 	bsa.which = args->which;
938 	bsa.itv = args->itv;
939 	bsa.oitv = args->oitv;
940 	if (args->itv) {
941 	    if ((error = copyin((caddr_t)args->itv, (caddr_t)&foo,
942 			sizeof(foo))))
943 		return error;
944 #ifdef DEBUG
945 	    printf("setitimer: value: sec: %ld, usec: %ld\n",
946 		foo.it_value.tv_sec, foo.it_value.tv_usec);
947 	    printf("setitimer: interval: sec: %ld, usec: %ld\n",
948 		foo.it_interval.tv_sec, foo.it_interval.tv_usec);
949 #endif
950 	}
951 	return setitimer(p, &bsa);
952 }
953 
954 int
955 linux_getitimer(struct proc *p, struct linux_getitimer_args *args)
956 {
957 	struct getitimer_args bsa;
958 #ifdef DEBUG
959 	printf("Linux-emul(%ld): getitimer(%p)\n",
960 	    (long)p->p_pid, (void *)args->itv);
961 #endif
962 	bsa.which = args->which;
963 	bsa.itv = args->itv;
964 	return getitimer(p, &bsa);
965 }
966 
967 int
968 linux_iopl(struct proc *p, struct linux_iopl_args *args)
969 {
970 	int error;
971 
972 	error = suser(p->p_ucred, &p->p_acflag);
973 	if (error != 0)
974 		return error;
975 	if (securelevel > 0)
976 		return EPERM;
977 	p->p_md.md_regs->tf_eflags |= PSL_IOPL;
978 	return 0;
979 }
980 
981 int
982 linux_nice(struct proc *p, struct linux_nice_args *args)
983 {
984 	struct setpriority_args	bsd_args;
985 
986 	bsd_args.which = PRIO_PROCESS;
987 	bsd_args.who = 0;	/* current process */
988 	bsd_args.prio = args->inc;
989 	return setpriority(p, &bsd_args);
990 }
991 
992