1 /* $NetBSD: linux32_unistd.c,v 1.1 2006/02/09 19:18:57 manu Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 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. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Emmanuel Dreyfus 17 * 4. The name of the author may not be used to endorse or promote 18 * products derived from this software without specific prior written 19 * permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS'' 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 36 __KERNEL_RCSID(0, "$NetBSD: linux32_unistd.c,v 1.1 2006/02/09 19:18:57 manu Exp $"); 37 38 #include <sys/types.h> 39 #include <sys/param.h> 40 #include <sys/fstypes.h> 41 #include <sys/signal.h> 42 #include <sys/dirent.h> 43 #include <sys/kernel.h> 44 #include <sys/fcntl.h> 45 #include <sys/select.h> 46 #include <sys/sa.h> 47 #include <sys/proc.h> 48 #include <sys/ucred.h> 49 #include <sys/swap.h> 50 51 #include <machine/types.h> 52 53 #include <sys/syscallargs.h> 54 55 #include <compat/netbsd32/netbsd32.h> 56 #include <compat/netbsd32/netbsd32_conv.h> 57 #include <compat/netbsd32/netbsd32_syscallargs.h> 58 59 #include <compat/linux/common/linux_types.h> 60 #include <compat/linux/common/linux_signal.h> 61 #include <compat/linux/common/linux_machdep.h> 62 #include <compat/linux/common/linux_misc.h> 63 #include <compat/linux/common/linux_oldolduname.h> 64 #include <compat/linux/linux_syscallargs.h> 65 66 #include <compat/linux32/common/linux32_types.h> 67 #include <compat/linux32/common/linux32_signal.h> 68 #include <compat/linux32/common/linux32_machdep.h> 69 #include <compat/linux32/common/linux32_sysctl.h> 70 #include <compat/linux32/common/linux32_socketcall.h> 71 #include <compat/linux32/linux32_syscallargs.h> 72 73 static int linux32_select1(struct lwp *, register_t *, 74 int, fd_set *, fd_set *, fd_set *, struct timeval *); 75 76 int 77 linux32_sys_brk(l, v, retval) 78 struct lwp *l; 79 void *v; 80 register_t *retval; 81 { 82 struct linux32_sys_brk_args /* { 83 syscallarg(netbsd32_charp) nsize; 84 } */ *uap = v; 85 struct linux_sys_brk_args ua; 86 87 NETBSD32TOP_UAP(nsize, char); 88 return linux_sys_brk(l, &ua, retval); 89 } 90 91 int 92 linux32_sys_access(l, v, retval) 93 struct lwp *l; 94 void *v; 95 register_t *retval; 96 { 97 struct linux32_sys_access_args /* { 98 syscallarg(const netbsd32_charp) path; 99 syscallarg(int) flags; 100 } */ *uap = v; 101 struct sys_access_args ua; 102 caddr_t sg; 103 104 NETBSD32TOP_UAP(path, const char); 105 NETBSD32TO64_UAP(flags); 106 107 sg = stackgap_init(l->l_proc, 0); 108 CHECK_ALT_EXIST(l, &sg, SCARG(&ua, path)); 109 110 return sys_access(l, &ua, retval); 111 } 112 113 int 114 linux32_sys_llseek(l, v, retval) 115 struct lwp *l; 116 void *v; 117 register_t *retval; 118 { 119 struct linux32_sys_llseek_args /* { 120 syscallcarg(int) fd; 121 syscallarg(u_int32_t) ohigh; 122 syscallarg(u_int32_t) olow; 123 syscallarg(netbsd32_caddr_t) res; 124 syscallcarg(int) whence; 125 } */ *uap = v; 126 struct linux_sys_llseek_args ua; 127 128 NETBSD32TO64_UAP(fd); 129 NETBSD32TO64_UAP(ohigh); 130 NETBSD32TO64_UAP(olow); 131 NETBSD32TOP_UAP(res, char); 132 NETBSD32TO64_UAP(whence); 133 134 return linux_sys_llseek(l, &ua, retval); 135 } 136 137 int 138 linux32_sys_readlink(l, v, retval) 139 struct lwp *l; 140 void *v; 141 register_t *retval; 142 { 143 struct linux32_sys_readlink_args /* { 144 syscallarg(const netbsd32_charp) name; 145 syscallarg(netbsd32_charp) buf; 146 syscallarg(int) count; 147 } */ *uap = v; 148 struct linux_sys_readlink_args ua; 149 150 NETBSD32TOP_UAP(name, const char); 151 NETBSD32TOP_UAP(buf, char) 152 NETBSD32TO64_UAP(count); 153 154 return linux_sys_readlink(l, &ua, retval); 155 } 156 157 158 int 159 linux32_sys_select(l, v, retval) 160 struct lwp *l; 161 void *v; 162 register_t *retval; 163 { 164 struct linux32_sys_select_args /* { 165 syscallarg(int) nfds; 166 syscallarg(netbsd32_fd_setp_t) readfds; 167 syscallarg(netbsd32_fd_setp_t) writefds; 168 syscallarg(netbsd32_fd_setp_t) exceptfds; 169 syscallarg(netbsd32_timevalp_t) timeout; 170 } */ *uap = v; 171 172 return linux32_select1(l, retval, SCARG(uap, nfds), 173 NETBSD32PTR64(SCARG(uap, readfds)), 174 NETBSD32PTR64(SCARG(uap, writefds)), 175 NETBSD32PTR64(SCARG(uap, exceptfds)), 176 NETBSD32PTR64(SCARG(uap, timeout))); 177 } 178 179 int 180 linux32_sys_oldselect(l, v, retval) 181 struct lwp *l; 182 void *v; 183 register_t *retval; 184 { 185 struct linux32_sys_oldselect_args /* { 186 syscallarg(linux32_oldselectp_t) lsp; 187 } */ *uap = v; 188 struct linux32_oldselect lsp32; 189 int error; 190 191 if ((error = copyin(NETBSD32PTR64(SCARG(uap, lsp)), 192 &lsp32, sizeof(lsp32))) != 0) 193 return error; 194 195 return linux32_select1(l, retval, lsp32.nfds, 196 NETBSD32PTR64(lsp32.readfds), NETBSD32PTR64(lsp32.writefds), 197 NETBSD32PTR64(lsp32.exceptfds), NETBSD32PTR64(lsp32.timeout)); 198 } 199 200 static int 201 linux32_select1(l, retval, nfds, readfds, writefds, exceptfds, timeout) 202 struct lwp *l; 203 register_t *retval; 204 int nfds; 205 fd_set *readfds, *writefds, *exceptfds; 206 struct timeval *timeout; 207 { 208 struct timeval tv0, tv1, utv, otv; 209 struct netbsd32_timeval utv32; 210 int error; 211 212 /* 213 * Store current time for computation of the amount of 214 * time left. 215 */ 216 if (timeout) { 217 if ((error = copyin(timeout, &utv32, sizeof(utv32)))) 218 return error; 219 220 netbsd32_to_timeval(&utv32, &utv); 221 otv = utv; 222 223 if (itimerfix(&utv)) { 224 /* 225 * The timeval was invalid. Convert it to something 226 * valid that will act as it does under Linux. 227 */ 228 utv.tv_sec += utv.tv_usec / 1000000; 229 utv.tv_usec %= 1000000; 230 if (utv.tv_usec < 0) { 231 utv.tv_sec -= 1; 232 utv.tv_usec += 1000000; 233 } 234 if (utv.tv_sec < 0) 235 timerclear(&utv); 236 } 237 microtime(&tv0); 238 } else { 239 timerclear(&utv); 240 } 241 242 error = selcommon(l, retval, nfds, 243 readfds, writefds, exceptfds, &utv, NULL); 244 245 if (error) { 246 /* 247 * See fs/select.c in the Linux kernel. Without this, 248 * Maelstrom doesn't work. 249 */ 250 if (error == ERESTART) 251 error = EINTR; 252 return error; 253 } 254 255 if (timeout) { 256 if (*retval) { 257 /* 258 * Compute how much time was left of the timeout, 259 * by subtracting the current time and the time 260 * before we started the call, and subtracting 261 * that result from the user-supplied value. 262 */ 263 microtime(&tv1); 264 timersub(&tv1, &tv0, &tv1); 265 timersub(&otv, &tv1, &utv); 266 if (utv.tv_sec < 0) 267 timerclear(&utv); 268 } else { 269 timerclear(&utv); 270 } 271 272 netbsd32_from_timeval(&utv, &utv32); 273 274 if ((error = copyout(&utv32, timeout, sizeof(utv32)))) 275 return error; 276 } 277 278 return 0; 279 } 280 281 int 282 linux32_sys_pipe(l, v, retval) 283 struct lwp *l; 284 void *v; 285 register_t *retval; 286 { 287 struct linux32_sys_pipe_args /* { 288 syscallarg(netbsd32_intp) fd; 289 } */ *uap = v; 290 int error; 291 int pfds[2]; 292 293 if ((error = sys_pipe(l, 0, retval))) 294 return error; 295 296 pfds[0] = (int)retval[0]; 297 pfds[1] = (int)retval[1]; 298 299 if ((error = copyout(pfds, NETBSD32PTR64(SCARG(uap, fd)), 300 2 * sizeof (int))) != 0) 301 return error; 302 303 retval[0] = 0; 304 retval[1] = 0; 305 306 return 0; 307 } 308 309 310 int 311 linux32_sys_unlink(l, v, retval) 312 struct lwp *l; 313 void *v; 314 register_t *retval; 315 { 316 struct linux32_sys_unlink_args /* { 317 syscallarg(const netbsd32_charp) path; 318 } */ *uap = v; 319 struct linux_sys_unlink_args ua; 320 321 NETBSD32TOP_UAP(path, const char); 322 323 return linux_sys_unlink(l, &ua, retval); 324 } 325 326 int 327 linux32_sys_chdir(l, v, retval) 328 struct lwp *l; 329 void *v; 330 register_t *retval; 331 { 332 struct linux32_sys_chdir_args /* { 333 syscallarg(const netbsd32_charp) path; 334 } */ *uap = v; 335 struct sys_chdir_args ua; 336 caddr_t sg = stackgap_init(l->l_proc, 0); 337 338 NETBSD32TOP_UAP(path, const char); 339 340 CHECK_ALT_EXIST(l, &sg, SCARG(&ua, path)); 341 342 return sys_chdir(l, &ua, retval); 343 } 344 345 int 346 linux32_sys_link(l, v, retval) 347 struct lwp *l; 348 void *v; 349 register_t *retval; 350 { 351 struct linux32_sys_link_args /* { 352 syscallarg(const netbsd32_charp) path; 353 syscallarg(const netbsd32_charp) link; 354 } */ *uap = v; 355 struct sys_link_args ua; 356 caddr_t sg = stackgap_init(l->l_proc, 0); 357 358 NETBSD32TOP_UAP(path, const char); 359 NETBSD32TOP_UAP(link, const char); 360 361 CHECK_ALT_EXIST(l, &sg, SCARG(&ua, path)); 362 CHECK_ALT_CREAT(l, &sg, SCARG(&ua, link)); 363 364 return sys_link(l, &ua, retval); 365 } 366 367 int 368 linux32_sys_creat(l, v, retval) 369 struct lwp *l; 370 void *v; 371 register_t *retval; 372 { 373 struct linux32_sys_creat_args /* { 374 syscallarg(const netbsd32_charp) path; 375 syscallarg(int) mode; 376 } */ *uap = v; 377 struct sys_open_args ua; 378 caddr_t sg = stackgap_init(l->l_proc, 0); 379 380 NETBSD32TOP_UAP(path, const char); 381 SCARG(&ua, flags) = O_CREAT | O_TRUNC | O_WRONLY; 382 NETBSD32TO64_UAP(mode); 383 384 CHECK_ALT_EXIST(l, &sg, SCARG(&ua, path)); 385 386 return sys_open(l, &ua, retval); 387 } 388 389 int 390 linux32_sys_mknod(l, v, retval) 391 struct lwp *l; 392 void *v; 393 register_t *retval; 394 { 395 struct linux32_sys_mknod_args /* { 396 syscallarg(const netbsd32_charp) path; 397 syscallarg(int) mode; 398 syscallarg(int) dev; 399 } */ *uap = v; 400 struct linux_sys_mknod_args ua; 401 402 NETBSD32TOP_UAP(path, const char); 403 NETBSD32TO64_UAP(mode); 404 NETBSD32TO64_UAP(dev); 405 406 return linux_sys_mknod(l, &ua, retval); 407 } 408 409 int 410 linux32_sys_chmod(l, v, retval) 411 struct lwp *l; 412 void *v; 413 register_t *retval; 414 { 415 struct linux32_sys_chmod_args /* { 416 syscallarg(const netbsd32_charp) path; 417 syscallarg(int) mode; 418 } */ *uap = v; 419 struct sys_chmod_args ua; 420 caddr_t sg = stackgap_init(l->l_proc, 0); 421 422 NETBSD32TOP_UAP(path, const char); 423 NETBSD32TO64_UAP(mode); 424 425 CHECK_ALT_EXIST(l, &sg, SCARG(&ua, path)); 426 427 return sys_chmod(l, &ua, retval); 428 } 429 430 int 431 linux32_sys_lchown16(l, v, retval) 432 struct lwp *l; 433 void *v; 434 register_t *retval; 435 { 436 struct linux32_sys_lchown16_args /* { 437 syscallarg(const netbsd32_charp) path; 438 syscallarg(int) uid; 439 syscallarg(int) gid; 440 } */ *uap = v; 441 struct sys___posix_lchown_args ua; 442 caddr_t sg = stackgap_init(l->l_proc, 0); 443 444 NETBSD32TOP_UAP(path, const char); 445 CHECK_ALT_SYMLINK(l, &sg, SCARG(&ua, path)); 446 447 if ((linux32_uid_t)SCARG(uap, uid) == (linux32_uid_t)-1) 448 SCARG(&ua, uid) = (uid_t)-1; 449 else 450 SCARG(&ua, uid) = SCARG(uap, uid); 451 452 if ((linux32_gid_t)SCARG(uap, gid) == (linux32_gid_t)-1) 453 SCARG(&ua, gid) = (gid_t)-1; 454 else 455 SCARG(&ua, gid) = SCARG(uap, gid); 456 457 return sys___posix_lchown(l, &ua, retval); 458 } 459 460 int 461 linux32_sys_break(l, v, retval) 462 struct lwp *l; 463 void *v; 464 register_t *retval; 465 { 466 #if 0 467 struct linux32_sys_break_args /* { 468 syscallarg(const netbsd32_charp) nsize; 469 } */ *uap = v; 470 #endif 471 472 return ENOSYS; 473 } 474 475 int 476 linux32_sys_rename(l, v, retval) 477 struct lwp *l; 478 void *v; 479 register_t *retval; 480 { 481 struct linux32_sys_rename_args /* { 482 syscallarg(const netbsd32_charp) from; 483 syscallarg(const netbsd32_charp) to; 484 } */ *uap = v; 485 struct sys_rename_args ua; 486 caddr_t sg = stackgap_init(l->l_proc, 0); 487 488 NETBSD32TOP_UAP(from, const char); 489 NETBSD32TOP_UAP(to, const char); 490 491 CHECK_ALT_EXIST(l, &sg, SCARG(&ua, from)); 492 CHECK_ALT_CREAT(l, &sg, SCARG(&ua, to)); 493 494 return sys___posix_rename(l, &ua, retval); 495 } 496 497 int 498 linux32_sys_mkdir(l, v, retval) 499 struct lwp *l; 500 void *v; 501 register_t *retval; 502 { 503 struct linux32_sys_mkdir_args /* { 504 syscallarg(const netbsd32_charp) path; 505 syscallarg(int) mode; 506 } */ *uap = v; 507 struct sys_mkdir_args ua; 508 caddr_t sg = stackgap_init(l->l_proc, 0); 509 510 NETBSD32TOP_UAP(path, const char); 511 NETBSD32TO64_UAP(mode); 512 513 CHECK_ALT_CREAT(l, &sg, SCARG(&ua, path)); 514 515 return sys_mkdir(l, &ua, retval); 516 } 517 518 int 519 linux32_sys_rmdir(l, v, retval) 520 struct lwp *l; 521 void *v; 522 register_t *retval; 523 { 524 struct linux32_sys_rmdir_args /* { 525 syscallarg(const netbsd32_charp) path; 526 } */ *uap = v; 527 struct sys_rmdir_args ua; 528 caddr_t sg = stackgap_init(l->l_proc, 0); 529 530 NETBSD32TOP_UAP(path, const char); 531 532 CHECK_ALT_EXIST(l, &sg, SCARG(&ua, path)); 533 534 return sys_rmdir(l, &ua, retval); 535 } 536 537 int 538 linux32_sys_getgroups16(l, v, retval) 539 struct lwp *l; 540 void *v; 541 register_t *retval; 542 { 543 struct linux32_sys_getgroups16_args /* { 544 syscallarg(int) gidsetsize; 545 syscallarg(linux32_gidp_t) gidset; 546 } */ *uap = v; 547 struct linux_sys_getgroups16_args ua; 548 549 NETBSD32TO64_UAP(gidsetsize); 550 NETBSD32TOP_UAP(gidset, linux32_gid_t); 551 552 return linux_sys_getgroups16(l, &ua, retval); 553 } 554 555 int 556 linux32_sys_setgroups16(l, v, retval) 557 struct lwp *l; 558 void *v; 559 register_t *retval; 560 { 561 struct linux32_sys_setgroups16_args /* { 562 syscallarg(int) gidsetsize; 563 syscallarg(linux32_gidp_t) gidset; 564 } */ *uap = v; 565 struct linux_sys_setgroups16_args ua; 566 567 NETBSD32TO64_UAP(gidsetsize); 568 NETBSD32TOP_UAP(gidset, linux32_gid_t); 569 570 return linux_sys_setgroups16(l, &ua, retval); 571 } 572 573 int 574 linux32_sys_symlink(l, v, retval) 575 struct lwp *l; 576 void *v; 577 register_t *retval; 578 { 579 struct linux32_sys_symlink_args /* { 580 syscallarg(const netbsd32_charp) path; 581 syscallarg(const netbsd32_charp) link; 582 } */ *uap = v; 583 struct sys_symlink_args ua; 584 caddr_t sg = stackgap_init(l->l_proc, 0); 585 586 NETBSD32TOP_UAP(path, const char); 587 NETBSD32TOP_UAP(link, const char); 588 589 CHECK_ALT_EXIST(l, &sg, SCARG(&ua, path)); 590 CHECK_ALT_CREAT(l, &sg, SCARG(&ua, link)); 591 592 return sys_symlink(l, &ua, retval); 593 } 594 595 596 int 597 linux32_sys_swapon(l, v, retval) 598 struct lwp *l; 599 void *v; 600 register_t *retval; 601 { 602 struct linux32_sys_swapon_args /* { 603 syscallarg(const netbsd32_charp) name; 604 } */ *uap = v; 605 struct sys_swapctl_args ua; 606 607 SCARG(&ua, cmd) = SWAP_ON; 608 SCARG(&ua, arg) = (void *)__UNCONST(NETBSD32PTR64(SCARG(uap, name))); 609 SCARG(&ua, misc) = 0; /* priority */ 610 return (sys_swapctl(l, &ua, retval)); 611 } 612 613 int 614 linux32_sys_swapoff(l, v, retval) 615 struct lwp *l; 616 void *v; 617 register_t *retval; 618 { 619 struct linux32_sys_swapoff_args /* { 620 syscallarg(const netbsd32_charp) path; 621 } */ *uap = v; 622 struct sys_swapctl_args ua; 623 624 SCARG(&ua, cmd) = SWAP_OFF; 625 SCARG(&ua, arg) = (void *)__UNCONST(NETBSD32PTR64(SCARG(uap, path))); 626 SCARG(&ua, misc) = 0; /* priority */ 627 return (sys_swapctl(l, &ua, retval)); 628 } 629 630 631 int 632 linux32_sys_reboot(l, v, retval) 633 struct lwp *l; 634 void *v; 635 register_t *retval; 636 { 637 struct linux32_sys_reboot_args /* { 638 syscallarg(int) magic1; 639 syscallarg(int) magic2; 640 syscallarg(int) cmd; 641 syscallarg(netbsd32_voidp) arg; 642 } */ *uap = v; 643 struct linux_sys_reboot_args ua; 644 645 NETBSD32TO64_UAP(magic1); 646 NETBSD32TO64_UAP(magic2); 647 NETBSD32TO64_UAP(cmd); 648 NETBSD32TOP_UAP(arg, void); 649 650 return linux_sys_reboot(l, &ua, retval); 651 } 652 653 int 654 linux32_sys_truncate(l, v, retval) 655 struct lwp *l; 656 void *v; 657 register_t *retval; 658 { 659 struct linux32_sys_truncate_args /* { 660 syscallarg(const netbsd32_charp) path; 661 syscallarg(netbsd32_charp) buf; 662 syscallarg(int) count; 663 } */ *uap = v; 664 struct compat_43_sys_truncate_args ua; 665 666 NETBSD32TOP_UAP(path, const char); 667 NETBSD32TO64_UAP(length); 668 669 return compat_43_sys_truncate(l, &ua, retval); 670 } 671 672 int 673 linux32_sys_fchown16(l, v, retval) 674 struct lwp *l; 675 void *v; 676 register_t *retval; 677 { 678 struct linux32_sys_fchown16_args /* { 679 syscallarg(int) fd; 680 syscallarg(int) uid; 681 syscallarg(int) gid; 682 } */ *uap = v; 683 struct sys___posix_fchown_args ua; 684 685 SCARG(&ua, fd) = SCARG(uap, fd); 686 687 if ((linux32_uid_t)SCARG(uap, uid) == (linux32_uid_t)-1) 688 SCARG(&ua, uid) = (uid_t)-1; 689 else 690 SCARG(&ua, uid) = SCARG(uap, uid); 691 692 if ((linux32_gid_t)SCARG(uap, gid) == (linux32_gid_t)-1) 693 SCARG(&ua, gid) = (gid_t)-1; 694 else 695 SCARG(&ua, gid) = SCARG(uap, gid); 696 697 return sys___posix_fchown(l, &ua, retval); 698 } 699