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