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