xref: /freebsd-13.1/sys/compat/linux/linux_misc.c (revision e08ac58b)
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.10 1996/01/14 10:59:57 sos 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 = 0;
177     struct vattr attr;
178     unsigned long vmaddr, virtual_offset, 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 
186 #ifdef DEBUG
187     printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, args->library);
188 #endif
189 
190     for (ptr = path; (*ptr = *prefix) != '\0'; ptr++, prefix++) ;
191     sz = MAXPATHLEN - (ptr - path);
192     if (error = copyinstr(args->library, ptr, sz, &len))
193 	return error;
194     if (*ptr != '/')
195 	return EINVAL;
196 
197 #ifdef DEBUG
198     printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, path);
199 #endif
200 
201     NDINIT(&ni, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, path, p);
202     if (error = namei(&ni))
203 	return error;
204 
205     vp = ni.ni_vp;
206     if (vp == NULL)
207 	    return ENOEXEC;
208 
209     if (vp->v_writecount) {
210 	    VOP_UNLOCK(vp);
211 	    return ETXTBSY;
212     }
213 
214     if (error = VOP_GETATTR(vp, &attr, p->p_ucred, p)) {
215 	    VOP_UNLOCK(vp);
216 	    return error;
217     }
218 
219     if ((vp->v_mount->mnt_flag & MNT_NOEXEC)
220 	|| ((attr.va_mode & 0111) == 0)
221 	|| (attr.va_type != VREG)) {
222 	    VOP_UNLOCK(vp);
223 	    return ENOEXEC;
224     }
225 
226     if (attr.va_size == 0) {
227 	    VOP_UNLOCK(vp);
228 	    return ENOEXEC;
229     }
230 
231     if (error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p)) {
232 	VOP_UNLOCK(vp);
233 	return error;
234     }
235 
236     if (error = VOP_OPEN(vp, FREAD, p->p_ucred, p)) {
237 	VOP_UNLOCK(vp);
238 	return error;
239     }
240 
241     VOP_UNLOCK(vp);	/* lock no longer needed */
242 
243     error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, 1024,
244 	    	    VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
245     if (error)
246 	return (error);
247 
248     /*
249      * Is it a Linux binary ?
250      */
251     if (((a_out->a_magic >> 16) & 0xff) != 0x64)
252 	return ENOEXEC;
253 
254     /*
255      * Set file/virtual offset based on a.out variant.
256      */
257     switch ((int)(a_out->a_magic & 0xffff)) {
258     case 0413:	/* ZMAGIC */
259 	virtual_offset = 0;	/* actually aout->a_entry */
260 	file_offset = 1024;
261 	break;
262     case 0314:	/* QMAGIC */
263 	virtual_offset = 0;	/* actually aout->a_entry */
264 	file_offset = 0;
265 	break;
266     default:
267 	return ENOEXEC;
268     }
269 
270     vp->v_flag |= VTEXT;
271     bss_size = round_page(a_out->a_bss);
272     /*
273      * Check if file_offset page aligned,.
274      * Currently we cannot handle misalinged file offsets,
275      * and so we read in the entire image (what a waste).
276      */
277     if (file_offset & PGOFSET) {
278 #ifdef DEBUG
279 printf("uselib: Non page aligned binary %d\n", file_offset);
280 #endif
281 	/*
282 	 * Map text+data read/write/execute
283 	 */
284 	vmaddr = virtual_offset + round_page(a_out->a_entry);
285 	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
286 		    	    round_page(a_out->a_text + a_out->a_data), FALSE,
287 				VM_PROT_ALL, VM_PROT_ALL, 0);
288 	if (error)
289 	    return error;
290 
291 	error = vm_mmap(kernel_map, &buffer,
292 			round_page(a_out->a_text + a_out->a_data + file_offset),
293 		   	VM_PROT_READ, VM_PROT_READ, MAP_FILE,
294 			(caddr_t)vp, trunc_page(file_offset));
295 	if (error)
296 	    return error;
297 
298 	error = copyout((caddr_t)(buffer + file_offset), (caddr_t)vmaddr,
299 			a_out->a_text + a_out->a_data);
300 	if (error)
301 	    return error;
302 
303 	vm_map_remove(kernel_map, trunc_page(vmaddr),
304 		      round_page(a_out->a_text + a_out->a_data + file_offset));
305 
306 	error = vm_map_protect(&p->p_vmspace->vm_map, vmaddr,
307 		   	       round_page(a_out->a_text + a_out->a_data),
308 		   	       VM_PROT_ALL, TRUE);
309 	if (error)
310 	    return error;
311     }
312     else {
313 #ifdef DEBUG
314 printf("uselib: Page aligned binary %d\n", file_offset);
315 #endif
316 	vmaddr = virtual_offset + trunc_page(a_out->a_entry);
317 	error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr,
318 			a_out->a_text + a_out->a_data,
319 			VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
320 			(caddr_t)vp, file_offset);
321 	if (error)
322 	    return (error);
323     }
324 #ifdef DEBUG
325 printf("mem=%08x = %08x %08x\n", vmaddr, ((int*)vmaddr)[0], ((int*)vmaddr)[1]);
326 #endif
327     if (bss_size != 0) {
328 	vmaddr = virtual_offset + round_page(a_out->a_entry) +
329 		 round_page(a_out->a_text + a_out->a_data);
330 	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
331 			    bss_size, FALSE,
332 				VM_PROT_ALL, VM_PROT_ALL, 0);
333 	if (error)
334 	    return error;
335 	error = vm_map_protect(&p->p_vmspace->vm_map, vmaddr, bss_size,
336 		   	       VM_PROT_ALL, TRUE);
337 	if (error)
338 	    return error;
339     }
340     return 0;
341 }
342 
343 struct linux_select_args {
344     void *ptr;
345 };
346 
347 int
348 linux_select(struct proc *p, struct linux_select_args *args, int *retval)
349 {
350     struct {
351 	int nfds;
352 	fd_set *readfds;
353 	fd_set *writefds;
354 	fd_set *exceptfds;
355 	struct timeval *timeout;
356     } linux_args;
357     struct select_args /* {
358 	unsigned int nd;
359 	fd_set *in;
360 	fd_set *ou;
361 	fd_set *ex;
362 	struct timeval *tv;
363     } */ bsd_args;
364     int error;
365 
366     if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args,
367 			sizeof(linux_args))))
368 	return error;
369 #ifdef DEBUG
370     printf("Linux-emul(%d): select(%d, %d, %d, %d, %d)\n",
371 	   p->p_pid, linux_args.nfds, linux_args.readfds,
372 	   linux_args.writefds, linux_args.exceptfds,
373 	   linux_args.timeout);
374 #endif
375     bsd_args.nd = linux_args.nfds;
376     bsd_args.in = linux_args.readfds;
377     bsd_args.ou = linux_args.writefds;
378     bsd_args.ex = linux_args.exceptfds;
379     bsd_args.tv = linux_args.timeout;
380     return select(p, &bsd_args, retval);
381 }
382 
383 struct linux_getpgid_args {
384     int pid;
385 };
386 
387 int
388 linux_getpgid(struct proc *p, struct linux_getpgid_args *args, int *retval)
389 {
390     struct proc *curproc;
391 
392 #ifdef DEBUG
393     printf("Linux-emul(%d): getpgid(%d)\n", p->p_pid, args->pid);
394 #endif
395     if (args->pid != p->p_pid) {
396 	if (!(curproc = pfind(args->pid)))
397 	    return ESRCH;
398     }
399     else
400 	curproc = p;
401     *retval = curproc->p_pgid;
402     return 0;
403 }
404 
405 int
406 linux_fork(struct proc *p, void *args, int *retval)
407 {
408     int error;
409 
410 #ifdef DEBUG
411     printf("Linux-emul(%d): fork()\n", p->p_pid);
412 #endif
413     if (error = fork(p, args, retval))
414 	return error;
415     if (retval[1] == 1)
416 	retval[0] = 0;
417     return 0;
418 }
419 
420 struct linux_mmap_args {
421     void *ptr;
422 };
423 
424 int
425 linux_mmap(struct proc *p, struct linux_mmap_args *args, int *retval)
426 {
427     struct {
428 	linux_caddr_t addr;
429 	int len;
430 	int prot;
431 	int flags;
432 	int fd;
433 	int pos;
434     } linux_args;
435     struct mmap_args /* {
436 	caddr_t addr;
437 	size_t len;
438 	int prot;
439 	int flags;
440 	int fd;
441 	long pad;
442 	off_t pos;
443     } */ bsd_args;
444     int error;
445 
446     if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args,
447 			sizeof(linux_args))))
448 	return error;
449 #ifdef DEBUG
450     printf("Linux-emul(%d): mmap(%08x, %d, %d, %08x, %d, %d)\n",
451 	   p->p_pid, linux_args.addr, linux_args.len, linux_args.prot,
452 	   linux_args.flags, linux_args.fd, linux_args.pos);
453 #endif
454     bsd_args.flags = 0;
455     if (linux_args.flags & LINUX_MAP_SHARED)
456 	bsd_args.flags |= MAP_SHARED;
457     if (linux_args.flags & LINUX_MAP_PRIVATE)
458 	bsd_args.flags |= MAP_PRIVATE;
459     if (linux_args.flags & LINUX_MAP_FIXED)
460 	bsd_args.flags |= MAP_FIXED;
461     if (linux_args.flags & LINUX_MAP_ANON)
462 	bsd_args.flags |= MAP_ANON;
463     bsd_args.addr = linux_args.addr;
464     bsd_args.len = linux_args.len;
465     bsd_args.prot = linux_args.prot;
466     bsd_args.fd = linux_args.fd;
467     bsd_args.pos = linux_args.pos;
468     bsd_args.pad = 0;
469     return mmap(p, &bsd_args, retval);
470 }
471 
472 struct linux_pipe_args {
473     int *pipefds;
474 };
475 
476 int
477 linux_pipe(struct proc *p, struct linux_pipe_args *args, int *retval)
478 {
479     int error;
480 
481 #ifdef DEBUG
482     printf("Linux-emul(%d): pipe(*)\n", p->p_pid);
483 #endif
484     if (error = pipe(p, 0, retval))
485 	return error;
486     if (error = copyout(retval, args->pipefds, 2*sizeof(int)))
487 	return error;
488     *retval = 0;
489     return 0;
490 }
491 
492 struct linux_time_args {
493     linux_time_t *tm;
494 };
495 
496 int
497 linux_time(struct proc *p, struct linux_time_args *args, int *retval)
498 {
499     struct timeval tv;
500     linux_time_t tm;
501     int error;
502 
503 #ifdef DEBUG
504     printf("Linux-emul(%d): time(*)\n", p->p_pid);
505 #endif
506     microtime(&tv);
507     tm = tv.tv_sec;
508     if (error = copyout(&tm, args->tm, sizeof(linux_time_t)))
509 	return error;
510     *retval = tv.tv_sec;
511     return 0;
512 }
513 
514 struct linux_tms {
515     long    tms_utime;
516     long    tms_stime;
517     long    tms_cutime;
518     long    tms_cstime;
519 };
520 
521 struct linux_tms_args {
522     char *buf;
523 };
524 
525 int
526 linux_times(struct proc *p, struct linux_tms_args *args, int *retval)
527 {
528     struct timeval tv;
529     struct linux_tms tms;
530 
531 #ifdef DEBUG
532     printf("Linux-emul(%d): times(*)\n", p->p_pid);
533 #endif
534     tms.tms_utime = p->p_uticks;
535     tms.tms_stime = p->p_sticks;
536     tms.tms_cutime = p->p_stats->p_cru.ru_utime.tv_sec * hz +
537 	    ((p->p_stats->p_cru.ru_utime.tv_usec * hz)/1000000);
538     tms.tms_cstime = p->p_stats->p_cru.ru_stime.tv_sec * hz +
539 	    ((p->p_stats->p_cru.ru_stime.tv_usec * hz)/1000000);
540     microtime(&tv);
541     *retval = tv.tv_sec * hz + (tv.tv_usec * hz)/1000000;
542     return (copyout((caddr_t)&tms, (caddr_t)args->buf,
543 	    	    sizeof(struct linux_tms)));
544 }
545 
546 struct linux_newuname_t {
547     char sysname[65];
548     char nodename[65];
549     char release[65];
550     char version[65];
551     char machine[65];
552     char domainname[65];
553 };
554 
555 struct linux_newuname_args {
556     char *buf;
557 };
558 
559 int
560 linux_newuname(struct proc *p, struct linux_newuname_args *args, int *retval)
561 {
562     struct linux_newuname_t linux_newuname;
563 
564 #ifdef DEBUG
565     printf("Linux-emul(%d): newuname(*)\n", p->p_pid);
566 #endif
567     bzero(&linux_newuname, sizeof(struct linux_newuname_args));
568     strncpy(linux_newuname.sysname, ostype, 64);
569     strncpy(linux_newuname.nodename, hostname, 64);
570     strncpy(linux_newuname.release, osrelease, 64);
571     strncpy(linux_newuname.version, version, 64);
572     strncpy(linux_newuname.machine, machine, 64);
573     strncpy(linux_newuname.domainname, domainname, 64);
574     return (copyout((caddr_t)&linux_newuname, (caddr_t)args->buf,
575 	    	    sizeof(struct linux_newuname_t)));
576 }
577 
578 struct linux_utime_args {
579     char	*fname;
580     linux_time_t    *timeptr;
581 };
582 
583 int
584 linux_utime(struct proc *p, struct linux_utime_args *args, int *retval)
585 {
586     struct utimes_args /* {
587 	char	*path;
588 	struct	timeval *tptr;
589     } */ bsdutimes;
590     struct timeval tv;
591 
592 #ifdef DEBUG
593     printf("Linux-emul(%d): utime(%s, *)\n", p->p_pid, args->fname);
594 #endif
595     tv.tv_sec = (long)args->timeptr;
596     tv.tv_usec = 0;
597     bsdutimes.tptr = &tv;
598     bsdutimes.path = args->fname;
599     return utimes(p, &bsdutimes, retval);
600 }
601 
602 struct linux_waitpid_args {
603     int pid;
604     int *status;
605     int options;
606 };
607 
608 int
609 linux_waitpid(struct proc *p, struct linux_waitpid_args *args, int *retval)
610 {
611     struct wait_args /* {
612 	int pid;
613 	int *status;
614 	int options;
615 	struct	rusage *rusage;
616     } */ tmp;
617     int error, tmpstat;
618 
619 #ifdef DEBUG
620     printf("Linux-emul(%d): waitpid(%d, *, %d)\n",
621 	   p->p_pid, args->pid, args->options);
622 #endif
623     tmp.pid = args->pid;
624     tmp.status = args->status;
625     tmp.options = args->options;
626     tmp.rusage = NULL;
627 
628     if (error = wait4(p, &tmp, retval))
629 	return error;
630     if (error = copyin(args->status, &tmpstat, sizeof(int)))
631 	return error;
632     if (WIFSIGNALED(tmpstat))
633 	tmpstat = (tmpstat & 0xffffff80) |
634 		  bsd_to_linux_signal[WTERMSIG(tmpstat)];
635     else if (WIFSTOPPED(tmpstat))
636 	tmpstat = (tmpstat & 0xffff00ff) |
637 	      	  (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8);
638     return copyout(&tmpstat, args->status, sizeof(int));
639 }
640 
641 struct linux_wait4_args {
642     int pid;
643     int *status;
644     int options;
645     struct rusage *rusage;
646 };
647 
648 int
649 linux_wait4(struct proc *p, struct linux_wait4_args *args, int *retval)
650 {
651     struct wait_args /* {
652 	int pid;
653 	int *status;
654 	int options;
655 	struct	rusage *rusage;
656     } */ tmp;
657     int error, tmpstat;
658 
659 #ifdef DEBUG
660     printf("Linux-emul(%d): wait4(%d, *, %d, *)\n",
661 	   p->p_pid, args->pid, args->options);
662 #endif
663     tmp.pid = args->pid;
664     tmp.status = args->status;
665     tmp.options = args->options;
666     tmp.rusage = args->rusage;
667 
668     if (error = wait4(p, &tmp, retval))
669 	return error;
670     if (error = copyin(args->status, &tmpstat, sizeof(int)))
671 	return error;
672     if (WIFSIGNALED(tmpstat))
673 	tmpstat = (tmpstat & 0xffffff80) |
674 	      bsd_to_linux_signal[WTERMSIG(tmpstat)];
675     else if (WIFSTOPPED(tmpstat))
676 	tmpstat = (tmpstat & 0xffff00ff) |
677 	      (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8);
678     return copyout(&tmpstat, args->status, sizeof(int));
679 }
680 
681 struct linux_mknod_args {
682 	char *path;
683 	int mode;
684 	int dev;
685 };
686 
687 int
688 linux_mknod(struct proc *p, struct linux_mknod_args *args, int *retval)
689 {
690 	if (args->mode & S_IFIFO)
691 		return mkfifo(p, (struct mkfifo_args *)args, retval);
692 	else
693 		return mknod(p, (struct mknod_args *)args, retval);
694 }
695