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