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