xref: /freebsd-14.2/sys/compat/linux/linux_misc.c (revision ef5d438e)
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.11 1996/01/19 22:59:24 dyson 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 
54 #include <vm/vm.h>
55 #include <vm/vm_param.h>
56 #include <vm/pmap.h>
57 #include <vm/lock.h>
58 #include <vm/vm_kern.h>
59 #include <vm/vm_prot.h>
60 #include <vm/vm_map.h>
61 #include <vm/vm_extern.h>
62 
63 #include <machine/cpu.h>
64 #include <machine/psl.h>
65 
66 #include <i386/linux/linux.h>
67 #include <i386/linux/sysproto.h>
68 
69 struct linux_alarm_args {
70     unsigned int secs;
71 };
72 
73 int
74 linux_alarm(struct proc *p, struct linux_alarm_args *args, int *retval)
75 {
76     struct itimerval it, old_it;
77     struct timeval tv;
78     int s;
79 
80 #ifdef DEBUG
81     printf("Linux-emul(%d): alarm(%d)\n", p->p_pid, args->secs);
82 #endif
83     it.it_value.tv_sec = (long)args->secs;
84     it.it_value.tv_usec = 0;
85     it.it_interval.tv_sec = 0;
86     it.it_interval.tv_usec = 0;
87     s = splclock();
88     old_it = p->p_realtimer;
89     tv = time;
90     if (timerisset(&old_it.it_value))
91 	if (timercmp(&old_it.it_value, &tv, <))
92 	    timerclear(&old_it.it_value);
93 	else
94 	    timevalsub(&old_it.it_value, &tv);
95     splx(s);
96     if (itimerfix(&it.it_value) || itimerfix(&it.it_interval))
97 	return EINVAL;
98     s = splclock();
99     untimeout(realitexpire, (caddr_t)p);
100     tv = time;
101     if (timerisset(&it.it_value)) {
102 	timevaladd(&it.it_value, &tv);
103 	timeout(realitexpire, (caddr_t)p, hzto(&it.it_value));
104     }
105     p->p_realtimer = it;
106     splx(s);
107     if (old_it.it_value.tv_usec)
108 	old_it.it_value.tv_sec++;
109     *retval = old_it.it_value.tv_sec;
110     return 0;
111 }
112 
113 struct linux_brk_args {
114     linux_caddr_t dsend;
115 };
116 
117 int
118 linux_brk(struct proc *p, struct linux_brk_args *args, int *retval)
119 {
120 #if 0
121     struct vmspace *vm = p->p_vmspace;
122     vm_offset_t new, old;
123     int error;
124 
125     if ((vm_offset_t)args->dsend < (vm_offset_t)vm->vm_daddr)
126 	return EINVAL;
127     if (((caddr_t)args->dsend - (caddr_t)vm->vm_daddr)
128 	> p->p_rlimit[RLIMIT_DATA].rlim_cur)
129 	return ENOMEM;
130 
131     old = round_page((vm_offset_t)vm->vm_daddr) + ctob(vm->vm_dsize);
132     new = round_page((vm_offset_t)args->dsend);
133     *retval = old;
134     if ((new-old) > 0) {
135 	if (swap_pager_full)
136 	    return ENOMEM;
137 	error = vm_map_find(&vm->vm_map, NULL, 0, &old, (new-old), FALSE,
138 			VM_PROT_ALL, VM_PROT_ALL, 0);
139 	if (error)
140 	    return error;
141 	vm->vm_dsize += btoc((new-old));
142 	*retval = (int)(vm->vm_daddr + ctob(vm->vm_dsize));
143     }
144     return 0;
145 #else
146     struct vmspace *vm = p->p_vmspace;
147     vm_offset_t new, old;
148     struct obreak_args /* {
149 	char * nsize;
150     } */ tmp;
151 
152 #ifdef DEBUG
153     printf("Linux-emul(%d): brk(%08x)\n", p->p_pid, args->dsend);
154 #endif
155     old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
156     new = (vm_offset_t)args->dsend;
157     tmp.nsize = (char *) new;
158     if (((caddr_t)new > vm->vm_daddr) && !obreak(p, &tmp, retval))
159 	retval[0] = (int)new;
160     else
161 	retval[0] = (int)old;
162 
163     return 0;
164 #endif
165 }
166 
167 struct linux_uselib_args {
168     char *library;
169 };
170 
171 int
172 linux_uselib(struct proc *p, struct linux_uselib_args *args, int *retval)
173 {
174     struct nameidata ni;
175     struct vnode *vp;
176     struct exec *a_out;
177     struct vattr attr;
178     unsigned long vmaddr, file_offset;
179     unsigned long buffer, bss_size;
180     char *ptr;
181     char path[MAXPATHLEN];
182     const char *prefix = "/compat/linux";
183     size_t sz, len;
184     int error;
185     int locked;
186 
187 #ifdef DEBUG
188     printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, args->library);
189 #endif
190 
191     a_out = NULL;
192     locked = 0;
193     vp = NULL;
194 
195     for (ptr = path; (*ptr = *prefix) != '\0'; ptr++, prefix++) ;
196     sz = MAXPATHLEN - (ptr - path);
197     if (error = copyinstr(args->library, ptr, sz, &len))
198 	goto cleanup;
199     if (*ptr != '/') {
200 	error = EINVAL;
201 	goto cleanup;
202     }
203 
204 #ifdef DEBUG
205     printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, path);
206 #endif
207 
208     NDINIT(&ni, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, path, p);
209     if (error = namei(&ni))
210 	goto cleanup;
211 
212     vp = ni.ni_vp;
213     if (vp == NULL) {
214 	error = ENOEXEC;	/* ?? */
215 	goto cleanup;
216     }
217 
218     /*
219      * From here on down, we have a locked vnode that must be unlocked.
220      */
221     locked++;
222 
223     /*
224      * Writable?
225      */
226     if (vp->v_writecount) {
227 	error = ETXTBSY;
228 	goto cleanup;
229     }
230 
231     /*
232      * Executable?
233      */
234     if (error = VOP_GETATTR(vp, &attr, p->p_ucred, p))
235 	goto cleanup;
236 
237     if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
238 	((attr.va_mode & 0111) == 0) ||
239 	(attr.va_type != VREG)) {
240 	    error = ENOEXEC;
241 	    goto cleanup;
242     }
243 
244     /*
245      * Sensible size?
246      */
247     if (attr.va_size == 0) {
248 	error = ENOEXEC;
249 	goto cleanup;
250     }
251 
252     /*
253      * Can we access it?
254      */
255     if (error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p))
256 	goto cleanup;
257 
258     if (error = VOP_OPEN(vp, FREAD, p->p_ucred, p))
259 	goto cleanup;
260 
261     /*
262      * Lock no longer needed
263      */
264     VOP_UNLOCK(vp);
265     locked = 0;
266 
267     /*
268      * Pull in executable header into kernel_map
269      */
270     error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
271 	    	    VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
272     if (error)
273 	goto cleanup;
274 
275     /*
276      * Is it a Linux binary ?
277      */
278     if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
279 	error = ENOEXEC;
280 	goto cleanup;
281     }
282 
283     /* While we are here, we should REALLY do some more checks */
284 
285     /*
286      * Set file/virtual offset based on a.out variant.
287      */
288     switch ((int)(a_out->a_magic & 0xffff)) {
289     case 0413:	/* ZMAGIC */
290 	file_offset = 1024;
291 	break;
292     case 0314:	/* QMAGIC */
293 	file_offset = 0;
294 	break;
295     default:
296 	error = ENOEXEC;
297 	goto cleanup;
298     }
299 
300     bss_size = round_page(a_out->a_bss);
301 
302     /*
303      * Check various fields in header for validity/bounds.
304      */
305     if (a_out->a_text % NBPG || a_out->a_data % NBPG) {
306 	error = ENOEXEC;
307 	goto cleanup;
308     }
309 
310     /* text + data can't exceed file size */
311     if (a_out->a_data + a_out->a_text > attr.va_size) {
312 	error = EFAULT;
313 	goto cleanup;
314     }
315 
316     /*
317      * text/data/bss must not exceed limits
318      * XXX: this is not complete. it should check current usage PLUS
319      * the resources needed by this library.
320      */
321     if (a_out->a_text > MAXTSIZ || a_out->a_data + bss_size > MAXDSIZ ||
322 	a_out->a_data+bss_size > p->p_rlimit[RLIMIT_DATA].rlim_cur) {
323 	error = ENOMEM;
324 	goto cleanup;
325     }
326 
327     /*
328      * prevent more writers
329      */
330     vp->v_flag |= VTEXT;
331 
332     /*
333      * Check if file_offset page aligned,.
334      * Currently we cannot handle misalinged file offsets,
335      * and so we read in the entire image (what a waste).
336      */
337     if (file_offset & PGOFSET) {
338 #ifdef DEBUG
339 printf("uselib: Non page aligned binary %d\n", file_offset);
340 #endif
341 	/*
342 	 * Map text+data read/write/execute
343 	 */
344 
345 	/* a_entry is the load address and is page aligned */
346 	vmaddr = trunc_page(a_out->a_entry);
347 
348 	/* get anon user mapping, read+write+execute */
349 	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
350 		    	    a_out->a_text + a_out->a_data, FALSE,
351 			    VM_PROT_ALL, VM_PROT_ALL, 0);
352 	if (error)
353 	    goto cleanup;
354 
355 	/* map file into kernel_map */
356 	error = vm_mmap(kernel_map, &buffer,
357 			round_page(a_out->a_text + a_out->a_data + file_offset),
358 		   	VM_PROT_READ, VM_PROT_READ, MAP_FILE,
359 			(caddr_t)vp, trunc_page(file_offset));
360 	if (error)
361 	    goto cleanup;
362 
363 	/* copy from kernel VM space to user space */
364 	error = copyout((caddr_t)(buffer + file_offset), (caddr_t)vmaddr,
365 			a_out->a_text + a_out->a_data);
366 
367 	/* release temporary kernel space */
368 	vm_map_remove(kernel_map, buffer,
369 		      round_page(a_out->a_text + a_out->a_data + file_offset));
370 
371 	if (error)
372 	    goto cleanup;
373     }
374     else {
375 #ifdef DEBUG
376 printf("uselib: Page aligned binary %d\n", file_offset);
377 #endif
378 	/*
379 	 * for QMAGIC, a_entry is 20 bytes beyond the load address
380 	 * to skip the executable header
381 	 */
382 	vmaddr = trunc_page(a_out->a_entry);
383 
384 	/*
385 	 * Map it all into the process's space as a single copy-on-write
386 	 * "data" segment.
387 	 */
388 	error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr,
389 		   	a_out->a_text + a_out->a_data,
390 			VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
391 			(caddr_t)vp, file_offset);
392 	if (error)
393 	    goto cleanup;
394     }
395 #ifdef DEBUG
396 printf("mem=%08x = %08x %08x\n", vmaddr, ((int*)vmaddr)[0], ((int*)vmaddr)[1]);
397 #endif
398     if (bss_size != 0) {
399         /*
400 	 * Calculate BSS start address
401 	 */
402 	vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + a_out->a_data;
403 
404 	/*
405 	 * allocate some 'anon' space
406 	 */
407 	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
408 			    bss_size, FALSE,
409 			    VM_PROT_ALL, VM_PROT_ALL, 0);
410 	if (error)
411 	    goto cleanup;
412     }
413 
414 cleanup:
415     /*
416      * Unlock vnode if needed
417      */
418     if (locked)
419 	VOP_UNLOCK(vp);
420 
421     /*
422      * Release the kernel mapping.
423      */
424     if (a_out)
425 	vm_map_remove(kernel_map, (vm_offset_t)a_out, PAGE_SIZE);
426 
427     return error;
428 }
429 
430 struct linux_select_args {
431     void *ptr;
432 };
433 
434 int
435 linux_select(struct proc *p, struct linux_select_args *args, int *retval)
436 {
437     struct {
438 	int nfds;
439 	fd_set *readfds;
440 	fd_set *writefds;
441 	fd_set *exceptfds;
442 	struct timeval *timeout;
443     } linux_args;
444     struct select_args /* {
445 	unsigned int nd;
446 	fd_set *in;
447 	fd_set *ou;
448 	fd_set *ex;
449 	struct timeval *tv;
450     } */ bsd_args;
451     int error;
452 
453     if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args,
454 			sizeof(linux_args))))
455 	return error;
456 #ifdef DEBUG
457     printf("Linux-emul(%d): select(%d, %d, %d, %d, %d)\n",
458 	   p->p_pid, linux_args.nfds, linux_args.readfds,
459 	   linux_args.writefds, linux_args.exceptfds,
460 	   linux_args.timeout);
461 #endif
462     bsd_args.nd = linux_args.nfds;
463     bsd_args.in = linux_args.readfds;
464     bsd_args.ou = linux_args.writefds;
465     bsd_args.ex = linux_args.exceptfds;
466     bsd_args.tv = linux_args.timeout;
467     return select(p, &bsd_args, retval);
468 }
469 
470 struct linux_getpgid_args {
471     int pid;
472 };
473 
474 int
475 linux_getpgid(struct proc *p, struct linux_getpgid_args *args, int *retval)
476 {
477     struct proc *curproc;
478 
479 #ifdef DEBUG
480     printf("Linux-emul(%d): getpgid(%d)\n", p->p_pid, args->pid);
481 #endif
482     if (args->pid != p->p_pid) {
483 	if (!(curproc = pfind(args->pid)))
484 	    return ESRCH;
485     }
486     else
487 	curproc = p;
488     *retval = curproc->p_pgid;
489     return 0;
490 }
491 
492 int
493 linux_fork(struct proc *p, void *args, int *retval)
494 {
495     int error;
496 
497 #ifdef DEBUG
498     printf("Linux-emul(%d): fork()\n", p->p_pid);
499 #endif
500     if (error = fork(p, args, retval))
501 	return error;
502     if (retval[1] == 1)
503 	retval[0] = 0;
504     return 0;
505 }
506 
507 struct linux_mmap_args {
508     void *ptr;
509 };
510 
511 int
512 linux_mmap(struct proc *p, struct linux_mmap_args *args, int *retval)
513 {
514     struct {
515 	linux_caddr_t addr;
516 	int len;
517 	int prot;
518 	int flags;
519 	int fd;
520 	int pos;
521     } linux_args;
522     struct mmap_args /* {
523 	caddr_t addr;
524 	size_t len;
525 	int prot;
526 	int flags;
527 	int fd;
528 	long pad;
529 	off_t pos;
530     } */ bsd_args;
531     int error;
532 
533     if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args,
534 			sizeof(linux_args))))
535 	return error;
536 #ifdef DEBUG
537     printf("Linux-emul(%d): mmap(%08x, %d, %d, %08x, %d, %d)\n",
538 	   p->p_pid, linux_args.addr, linux_args.len, linux_args.prot,
539 	   linux_args.flags, linux_args.fd, linux_args.pos);
540 #endif
541     bsd_args.flags = 0;
542     if (linux_args.flags & LINUX_MAP_SHARED)
543 	bsd_args.flags |= MAP_SHARED;
544     if (linux_args.flags & LINUX_MAP_PRIVATE)
545 	bsd_args.flags |= MAP_PRIVATE;
546     if (linux_args.flags & LINUX_MAP_FIXED)
547 	bsd_args.flags |= MAP_FIXED;
548     if (linux_args.flags & LINUX_MAP_ANON)
549 	bsd_args.flags |= MAP_ANON;
550     bsd_args.addr = linux_args.addr;
551     bsd_args.len = linux_args.len;
552     bsd_args.prot = linux_args.prot;
553     bsd_args.fd = linux_args.fd;
554     bsd_args.pos = linux_args.pos;
555     bsd_args.pad = 0;
556     return mmap(p, &bsd_args, retval);
557 }
558 
559 struct linux_pipe_args {
560     int *pipefds;
561 };
562 
563 int
564 linux_pipe(struct proc *p, struct linux_pipe_args *args, int *retval)
565 {
566     int error;
567 
568 #ifdef DEBUG
569     printf("Linux-emul(%d): pipe(*)\n", p->p_pid);
570 #endif
571     if (error = pipe(p, 0, retval))
572 	return error;
573     if (error = copyout(retval, args->pipefds, 2*sizeof(int)))
574 	return error;
575     *retval = 0;
576     return 0;
577 }
578 
579 struct linux_time_args {
580     linux_time_t *tm;
581 };
582 
583 int
584 linux_time(struct proc *p, struct linux_time_args *args, int *retval)
585 {
586     struct timeval tv;
587     linux_time_t tm;
588     int error;
589 
590 #ifdef DEBUG
591     printf("Linux-emul(%d): time(*)\n", p->p_pid);
592 #endif
593     microtime(&tv);
594     tm = tv.tv_sec;
595     if (error = copyout(&tm, args->tm, sizeof(linux_time_t)))
596 	return error;
597     *retval = tv.tv_sec;
598     return 0;
599 }
600 
601 struct linux_tms {
602     long    tms_utime;
603     long    tms_stime;
604     long    tms_cutime;
605     long    tms_cstime;
606 };
607 
608 struct linux_tms_args {
609     char *buf;
610 };
611 
612 int
613 linux_times(struct proc *p, struct linux_tms_args *args, int *retval)
614 {
615     struct timeval tv;
616     struct linux_tms tms;
617 
618 #ifdef DEBUG
619     printf("Linux-emul(%d): times(*)\n", p->p_pid);
620 #endif
621     tms.tms_utime = p->p_uticks;
622     tms.tms_stime = p->p_sticks;
623     tms.tms_cutime = p->p_stats->p_cru.ru_utime.tv_sec * hz +
624 	    ((p->p_stats->p_cru.ru_utime.tv_usec * hz)/1000000);
625     tms.tms_cstime = p->p_stats->p_cru.ru_stime.tv_sec * hz +
626 	    ((p->p_stats->p_cru.ru_stime.tv_usec * hz)/1000000);
627     microtime(&tv);
628     *retval = tv.tv_sec * hz + (tv.tv_usec * hz)/1000000;
629     return (copyout((caddr_t)&tms, (caddr_t)args->buf,
630 	    	    sizeof(struct linux_tms)));
631 }
632 
633 struct linux_newuname_t {
634     char sysname[65];
635     char nodename[65];
636     char release[65];
637     char version[65];
638     char machine[65];
639     char domainname[65];
640 };
641 
642 struct linux_newuname_args {
643     char *buf;
644 };
645 
646 int
647 linux_newuname(struct proc *p, struct linux_newuname_args *args, int *retval)
648 {
649     struct linux_newuname_t linux_newuname;
650 
651 #ifdef DEBUG
652     printf("Linux-emul(%d): newuname(*)\n", p->p_pid);
653 #endif
654     bzero(&linux_newuname, sizeof(struct linux_newuname_args));
655     strncpy(linux_newuname.sysname, ostype, 64);
656     strncpy(linux_newuname.nodename, hostname, 64);
657     strncpy(linux_newuname.release, osrelease, 64);
658     strncpy(linux_newuname.version, version, 64);
659     strncpy(linux_newuname.machine, machine, 64);
660     strncpy(linux_newuname.domainname, domainname, 64);
661     return (copyout((caddr_t)&linux_newuname, (caddr_t)args->buf,
662 	    	    sizeof(struct linux_newuname_t)));
663 }
664 
665 struct linux_utime_args {
666     char	*fname;
667     linux_time_t    *timeptr;
668 };
669 
670 int
671 linux_utime(struct proc *p, struct linux_utime_args *args, int *retval)
672 {
673     struct utimes_args /* {
674 	char	*path;
675 	struct	timeval *tptr;
676     } */ bsdutimes;
677     struct timeval tv;
678 
679 #ifdef DEBUG
680     printf("Linux-emul(%d): utime(%s, *)\n", p->p_pid, args->fname);
681 #endif
682     tv.tv_sec = (long)args->timeptr;
683     tv.tv_usec = 0;
684     bsdutimes.tptr = &tv;
685     bsdutimes.path = args->fname;
686     return utimes(p, &bsdutimes, retval);
687 }
688 
689 struct linux_waitpid_args {
690     int pid;
691     int *status;
692     int options;
693 };
694 
695 int
696 linux_waitpid(struct proc *p, struct linux_waitpid_args *args, int *retval)
697 {
698     struct wait_args /* {
699 	int pid;
700 	int *status;
701 	int options;
702 	struct	rusage *rusage;
703     } */ tmp;
704     int error, tmpstat;
705 
706 #ifdef DEBUG
707     printf("Linux-emul(%d): waitpid(%d, *, %d)\n",
708 	   p->p_pid, args->pid, args->options);
709 #endif
710     tmp.pid = args->pid;
711     tmp.status = args->status;
712     tmp.options = args->options;
713     tmp.rusage = NULL;
714 
715     if (error = wait4(p, &tmp, retval))
716 	return error;
717     if (error = copyin(args->status, &tmpstat, sizeof(int)))
718 	return error;
719     if (WIFSIGNALED(tmpstat))
720 	tmpstat = (tmpstat & 0xffffff80) |
721 		  bsd_to_linux_signal[WTERMSIG(tmpstat)];
722     else if (WIFSTOPPED(tmpstat))
723 	tmpstat = (tmpstat & 0xffff00ff) |
724 	      	  (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8);
725     return copyout(&tmpstat, args->status, sizeof(int));
726 }
727 
728 struct linux_wait4_args {
729     int pid;
730     int *status;
731     int options;
732     struct rusage *rusage;
733 };
734 
735 int
736 linux_wait4(struct proc *p, struct linux_wait4_args *args, int *retval)
737 {
738     struct wait_args /* {
739 	int pid;
740 	int *status;
741 	int options;
742 	struct	rusage *rusage;
743     } */ tmp;
744     int error, tmpstat;
745 
746 #ifdef DEBUG
747     printf("Linux-emul(%d): wait4(%d, *, %d, *)\n",
748 	   p->p_pid, args->pid, args->options);
749 #endif
750     tmp.pid = args->pid;
751     tmp.status = args->status;
752     tmp.options = args->options;
753     tmp.rusage = args->rusage;
754 
755     if (error = wait4(p, &tmp, retval))
756 	return error;
757     if (error = copyin(args->status, &tmpstat, sizeof(int)))
758 	return error;
759     if (WIFSIGNALED(tmpstat))
760 	tmpstat = (tmpstat & 0xffffff80) |
761 	      bsd_to_linux_signal[WTERMSIG(tmpstat)];
762     else if (WIFSTOPPED(tmpstat))
763 	tmpstat = (tmpstat & 0xffff00ff) |
764 	      (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8);
765     return copyout(&tmpstat, args->status, sizeof(int));
766 }
767 
768 struct linux_mknod_args {
769 	char *path;
770 	int mode;
771 	int dev;
772 };
773 
774 int
775 linux_mknod(struct proc *p, struct linux_mknod_args *args, int *retval)
776 {
777 	if (args->mode & S_IFIFO)
778 		return mkfifo(p, (struct mkfifo_args *)args, retval);
779 	else
780 		return mknod(p, (struct mknod_args *)args, retval);
781 }
782