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