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