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