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.19 1996/05/02 10:43:13 phk 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 #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); 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); 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