1 /* $NetBSD: netbsd32_fs.c,v 1.60 2011/01/22 22:26:10 matt Exp $ */ 2 3 /* 4 * Copyright (c) 1998, 2001 Matthew R. Green 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: netbsd32_fs.c,v 1.60 2011/01/22 22:26:10 matt Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/mount.h> 35 #include <sys/socket.h> 36 #include <sys/socketvar.h> 37 #include <sys/stat.h> 38 #include <sys/time.h> 39 #include <sys/ktrace.h> 40 #include <sys/resourcevar.h> 41 #include <sys/vnode.h> 42 #include <sys/file.h> 43 #include <sys/filedesc.h> 44 #include <sys/namei.h> 45 #include <sys/statvfs.h> 46 #include <sys/syscallargs.h> 47 #include <sys/proc.h> 48 #include <sys/dirent.h> 49 #include <sys/kauth.h> 50 #include <sys/vfs_syscalls.h> 51 52 #include <fs/cd9660/cd9660_mount.h> 53 #include <ufs/ufs/ufsmount.h> 54 55 #define NFS_ARGS_ONLY 56 #include <nfs/nfsmount.h> 57 58 #include <compat/netbsd32/netbsd32.h> 59 #include <compat/netbsd32/netbsd32_syscallargs.h> 60 #include <compat/netbsd32/netbsd32_conv.h> 61 #include <compat/sys/mount.h> 62 63 64 static int dofilereadv32(int, struct file *, struct netbsd32_iovec *, 65 int, off_t *, int, register_t *); 66 static int dofilewritev32(int, struct file *, struct netbsd32_iovec *, 67 int, off_t *, int, register_t *); 68 69 struct iovec * 70 netbsd32_get_iov(struct netbsd32_iovec *iov32, int iovlen, struct iovec *aiov, 71 int aiov_len) 72 { 73 #define N_IOV32 8 74 struct netbsd32_iovec aiov32[N_IOV32]; 75 struct iovec *iov = aiov; 76 struct iovec *iovp; 77 int i, n, j; 78 int error; 79 80 if (iovlen < 0 || iovlen > IOV_MAX) 81 return NULL; 82 83 if (iovlen > aiov_len) 84 iov = kmem_alloc(iovlen * sizeof(*iov), KM_SLEEP); 85 86 iovp = iov; 87 for (i = 0; i < iovlen; iov32 += N_IOV32, i += N_IOV32) { 88 n = iovlen - i; 89 if (n > N_IOV32) 90 n = N_IOV32; 91 error = copyin(iov32, aiov32, n * sizeof (*iov32)); 92 if (error != 0) { 93 if (iov != aiov) 94 kmem_free(iov, iovlen * sizeof(*iov)); 95 return NULL; 96 } 97 for (j = 0; j < n; iovp++, j++) { 98 iovp->iov_base = NETBSD32PTR64(aiov32[j].iov_base); 99 iovp->iov_len = aiov32[j].iov_len; 100 } 101 } 102 return iov; 103 #undef N_IOV32 104 } 105 106 int 107 netbsd32_readv(struct lwp *l, const struct netbsd32_readv_args *uap, register_t *retval) 108 { 109 /* { 110 syscallarg(int) fd; 111 syscallarg(const netbsd32_iovecp_t) iovp; 112 syscallarg(int) iovcnt; 113 } */ 114 int fd = SCARG(uap, fd); 115 file_t *fp; 116 117 if ((fp = fd_getfile(fd)) == NULL) 118 return (EBADF); 119 120 if ((fp->f_flag & FREAD) == 0) { 121 fd_putfile(fd); 122 return (EBADF); 123 } 124 125 return (dofilereadv32(fd, fp, 126 (struct netbsd32_iovec *)SCARG_P32(uap, iovp), 127 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval)); 128 } 129 130 /* Damn thing copies in the iovec! */ 131 int 132 dofilereadv32(int fd, struct file *fp, struct netbsd32_iovec *iovp, int iovcnt, off_t *offset, int flags, register_t *retval) 133 { 134 struct uio auio; 135 struct iovec *iov; 136 struct iovec *needfree; 137 struct iovec aiov[UIO_SMALLIOV]; 138 long i, cnt, error = 0; 139 u_int iovlen; 140 struct iovec *ktriov = NULL; 141 142 /* note: can't use iovlen until iovcnt is validated */ 143 iovlen = iovcnt * sizeof(struct iovec); 144 if ((u_int)iovcnt > UIO_SMALLIOV) { 145 if ((u_int)iovcnt > IOV_MAX) { 146 error = EINVAL; 147 goto out; 148 } 149 iov = kmem_alloc(iovlen, KM_SLEEP); 150 needfree = iov; 151 } else if ((u_int)iovcnt > 0) { 152 iov = aiov; 153 needfree = NULL; 154 } else { 155 error = EINVAL; 156 goto out; 157 } 158 159 auio.uio_iov = iov; 160 auio.uio_iovcnt = iovcnt; 161 auio.uio_rw = UIO_READ; 162 auio.uio_vmspace = curproc->p_vmspace; 163 error = netbsd32_to_iovecin(iovp, iov, iovcnt); 164 if (error) 165 goto done; 166 auio.uio_resid = 0; 167 for (i = 0; i < iovcnt; i++) { 168 auio.uio_resid += iov->iov_len; 169 /* 170 * Reads return ssize_t because -1 is returned on error. 171 * Therefore we must restrict the length to SSIZE_MAX to 172 * avoid garbage return values. 173 */ 174 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { 175 error = EINVAL; 176 goto done; 177 } 178 iov++; 179 } 180 181 /* 182 * if tracing, save a copy of iovec 183 */ 184 if (ktrpoint(KTR_GENIO)) { 185 ktriov = kmem_alloc(iovlen, KM_SLEEP); 186 memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen); 187 } 188 189 cnt = auio.uio_resid; 190 error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred, flags); 191 if (error) 192 if (auio.uio_resid != cnt && (error == ERESTART || 193 error == EINTR || error == EWOULDBLOCK)) 194 error = 0; 195 cnt -= auio.uio_resid; 196 197 if (ktriov != NULL) { 198 ktrgeniov(fd, UIO_READ, ktriov, cnt, error); 199 kmem_free(ktriov, iovlen); 200 } 201 202 *retval = cnt; 203 done: 204 if (needfree) 205 kmem_free(needfree, iovlen); 206 out: 207 fd_putfile(fd); 208 return (error); 209 } 210 211 int 212 netbsd32_writev(struct lwp *l, const struct netbsd32_writev_args *uap, register_t *retval) 213 { 214 /* { 215 syscallarg(int) fd; 216 syscallarg(const netbsd32_iovecp_t) iovp; 217 syscallarg(int) iovcnt; 218 } */ 219 int fd = SCARG(uap, fd); 220 file_t *fp; 221 222 if ((fp = fd_getfile(fd)) == NULL) 223 return (EBADF); 224 225 if ((fp->f_flag & FWRITE) == 0) { 226 fd_putfile(fd); 227 return (EBADF); 228 } 229 230 return (dofilewritev32(fd, fp, 231 (struct netbsd32_iovec *)SCARG_P32(uap, iovp), 232 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval)); 233 } 234 235 int 236 dofilewritev32(int fd, struct file *fp, struct netbsd32_iovec *iovp, int iovcnt, off_t *offset, int flags, register_t *retval) 237 { 238 struct uio auio; 239 struct iovec *iov; 240 struct iovec *needfree; 241 struct iovec aiov[UIO_SMALLIOV]; 242 long i, cnt, error = 0; 243 u_int iovlen; 244 struct iovec *ktriov = NULL; 245 246 /* note: can't use iovlen until iovcnt is validated */ 247 iovlen = iovcnt * sizeof(struct iovec); 248 if ((u_int)iovcnt > UIO_SMALLIOV) { 249 if ((u_int)iovcnt > IOV_MAX) { 250 error = EINVAL; 251 goto out; 252 } 253 iov = kmem_alloc(iovlen, KM_SLEEP); 254 needfree = iov; 255 } else if ((u_int)iovcnt > 0) { 256 iov = aiov; 257 needfree = NULL; 258 } else { 259 error = EINVAL; 260 goto out; 261 } 262 263 auio.uio_iov = iov; 264 auio.uio_iovcnt = iovcnt; 265 auio.uio_rw = UIO_WRITE; 266 auio.uio_vmspace = curproc->p_vmspace; 267 error = netbsd32_to_iovecin(iovp, iov, iovcnt); 268 if (error) 269 goto done; 270 auio.uio_resid = 0; 271 for (i = 0; i < iovcnt; i++) { 272 auio.uio_resid += iov->iov_len; 273 /* 274 * Writes return ssize_t because -1 is returned on error. 275 * Therefore we must restrict the length to SSIZE_MAX to 276 * avoid garbage return values. 277 */ 278 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { 279 error = EINVAL; 280 goto done; 281 } 282 iov++; 283 } 284 285 /* 286 * if tracing, save a copy of iovec 287 */ 288 if (ktrpoint(KTR_GENIO)) { 289 ktriov = kmem_alloc(iovlen, KM_SLEEP); 290 memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen); 291 } 292 293 cnt = auio.uio_resid; 294 error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred, flags); 295 if (error) { 296 if (auio.uio_resid != cnt && (error == ERESTART || 297 error == EINTR || error == EWOULDBLOCK)) 298 error = 0; 299 if (error == EPIPE) { 300 mutex_enter(proc_lock); 301 psignal(curproc, SIGPIPE); 302 mutex_exit(proc_lock); 303 } 304 } 305 cnt -= auio.uio_resid; 306 if (ktriov != NULL) { 307 ktrgenio(fd, UIO_WRITE, ktriov, cnt, error); 308 kmem_free(ktriov, iovlen); 309 } 310 *retval = cnt; 311 done: 312 if (needfree) 313 kmem_free(needfree, iovlen); 314 out: 315 fd_putfile(fd); 316 return (error); 317 } 318 319 /* 320 * Common routine to set access and modification times given a vnode. 321 */ 322 static int 323 get_utimes32(const netbsd32_timevalp_t *tptr, struct timeval *tv, 324 struct timeval **tvp) 325 { 326 int error; 327 struct netbsd32_timeval tv32[2]; 328 329 if (tptr == NULL) { 330 *tvp = NULL; 331 return 0; 332 } 333 334 error = copyin(tptr, tv32, sizeof(tv32)); 335 if (error) 336 return error; 337 netbsd32_to_timeval(&tv32[0], &tv[0]); 338 netbsd32_to_timeval(&tv32[1], &tv[1]); 339 340 *tvp = tv; 341 return 0; 342 } 343 344 int 345 netbsd32___utimes50(struct lwp *l, const struct netbsd32___utimes50_args *uap, register_t *retval) 346 { 347 /* { 348 syscallarg(const netbsd32_charp) path; 349 syscallarg(const netbsd32_timevalp_t) tptr; 350 } */ 351 int error; 352 struct timeval tv[2], *tvp; 353 354 error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp); 355 if (error != 0) 356 return error; 357 358 return do_sys_utimes(l, NULL, SCARG_P32(uap, path), FOLLOW, 359 tvp, UIO_SYSSPACE); 360 } 361 362 static int 363 netbds32_copyout_statvfs(const void *kp, void *up, size_t len) 364 { 365 struct netbsd32_statvfs *sbuf_32; 366 int error; 367 368 sbuf_32 = kmem_alloc(sizeof(*sbuf_32), KM_SLEEP); 369 netbsd32_from_statvfs(kp, sbuf_32); 370 error = copyout(sbuf_32, up, sizeof(*sbuf_32)); 371 kmem_free(sbuf_32, sizeof(*sbuf_32)); 372 373 return error; 374 } 375 376 int 377 netbsd32_statvfs1(struct lwp *l, const struct netbsd32_statvfs1_args *uap, register_t *retval) 378 { 379 /* { 380 syscallarg(const netbsd32_charp) path; 381 syscallarg(netbsd32_statvfsp_t) buf; 382 syscallarg(int) flags; 383 } */ 384 struct statvfs *sb; 385 int error; 386 387 sb = STATVFSBUF_GET(); 388 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), SCARG(uap, flags), sb); 389 if (error == 0) 390 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0); 391 STATVFSBUF_PUT(sb); 392 return error; 393 } 394 395 int 396 netbsd32_fstatvfs1(struct lwp *l, const struct netbsd32_fstatvfs1_args *uap, register_t *retval) 397 { 398 /* { 399 syscallarg(int) fd; 400 syscallarg(netbsd32_statvfsp_t) buf; 401 syscallarg(int) flags; 402 } */ 403 struct statvfs *sb; 404 int error; 405 406 sb = STATVFSBUF_GET(); 407 error = do_sys_fstatvfs(l, SCARG(uap, fd), SCARG(uap, flags), sb); 408 if (error == 0) 409 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0); 410 STATVFSBUF_PUT(sb); 411 return error; 412 } 413 414 int 415 netbsd32_getvfsstat(struct lwp *l, const struct netbsd32_getvfsstat_args *uap, register_t *retval) 416 { 417 /* { 418 syscallarg(netbsd32_statvfsp_t) buf; 419 syscallarg(netbsd32_size_t) bufsize; 420 syscallarg(int) flags; 421 } */ 422 423 return do_sys_getvfsstat(l, SCARG_P32(uap, buf), SCARG(uap, bufsize), 424 SCARG(uap, flags), netbds32_copyout_statvfs, 425 sizeof (struct netbsd32_statvfs), retval); 426 } 427 428 int 429 netbsd32___fhstatvfs140(struct lwp *l, const struct netbsd32___fhstatvfs140_args *uap, register_t *retval) 430 { 431 /* { 432 syscallarg(const netbsd32_pointer_t) fhp; 433 syscallarg(netbsd32_size_t) fh_size; 434 syscallarg(netbsd32_statvfsp_t) buf; 435 syscallarg(int) flags; 436 } */ 437 struct statvfs *sb; 438 int error; 439 440 sb = STATVFSBUF_GET(); 441 error = do_fhstatvfs(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), sb, 442 SCARG(uap, flags)); 443 444 if (error == 0) 445 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0); 446 STATVFSBUF_PUT(sb); 447 448 return error; 449 } 450 451 int 452 netbsd32___futimes50(struct lwp *l, const struct netbsd32___futimes50_args *uap, register_t *retval) 453 { 454 /* { 455 syscallarg(int) fd; 456 syscallarg(const netbsd32_timevalp_t) tptr; 457 } */ 458 int error; 459 file_t *fp; 460 struct timeval tv[2], *tvp; 461 462 error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp); 463 if (error != 0) 464 return error; 465 466 /* fd_getvnode() will use the descriptor for us */ 467 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 468 return (error); 469 470 error = do_sys_utimes(l, fp->f_data, NULL, 0, tvp, UIO_SYSSPACE); 471 472 fd_putfile(SCARG(uap, fd)); 473 return (error); 474 } 475 476 int 477 netbsd32___getdents30(struct lwp *l, 478 const struct netbsd32___getdents30_args *uap, register_t *retval) 479 { 480 /* { 481 syscallarg(int) fd; 482 syscallarg(netbsd32_charp) buf; 483 syscallarg(netbsd32_size_t) count; 484 } */ 485 file_t *fp; 486 int error, done; 487 488 /* fd_getvnode() will use the descriptor for us */ 489 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 490 return (error); 491 if ((fp->f_flag & FREAD) == 0) { 492 error = EBADF; 493 goto out; 494 } 495 error = vn_readdir(fp, SCARG_P32(uap, buf), 496 UIO_USERSPACE, SCARG(uap, count), &done, l, 0, 0); 497 *retval = done; 498 out: 499 fd_putfile(SCARG(uap, fd)); 500 return (error); 501 } 502 503 int 504 netbsd32___lutimes50(struct lwp *l, 505 const struct netbsd32___lutimes50_args *uap, register_t *retval) 506 { 507 /* { 508 syscallarg(const netbsd32_charp) path; 509 syscallarg(const netbsd32_timevalp_t) tptr; 510 } */ 511 int error; 512 struct timeval tv[2], *tvp; 513 514 error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp); 515 if (error != 0) 516 return error; 517 518 return do_sys_utimes(l, NULL, SCARG_P32(uap, path), NOFOLLOW, 519 tvp, UIO_SYSSPACE); 520 } 521 522 int 523 netbsd32___stat50(struct lwp *l, const struct netbsd32___stat50_args *uap, register_t *retval) 524 { 525 /* { 526 syscallarg(const netbsd32_charp) path; 527 syscallarg(netbsd32_statp_t) ub; 528 } */ 529 struct netbsd32_stat sb32; 530 struct stat sb; 531 int error; 532 const char *path; 533 534 path = SCARG_P32(uap, path); 535 536 error = do_sys_stat(path, FOLLOW, &sb); 537 if (error) 538 return (error); 539 netbsd32_from_stat(&sb, &sb32); 540 error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32)); 541 return (error); 542 } 543 544 int 545 netbsd32___fstat50(struct lwp *l, const struct netbsd32___fstat50_args *uap, register_t *retval) 546 { 547 /* { 548 syscallarg(int) fd; 549 syscallarg(netbsd32_statp_t) sb; 550 } */ 551 struct netbsd32_stat sb32; 552 struct stat ub; 553 int error; 554 555 error = do_sys_fstat(SCARG(uap, fd), &ub); 556 if (error == 0) { 557 netbsd32_from_stat(&ub, &sb32); 558 error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb32)); 559 } 560 return (error); 561 } 562 563 int 564 netbsd32___lstat50(struct lwp *l, const struct netbsd32___lstat50_args *uap, register_t *retval) 565 { 566 /* { 567 syscallarg(const netbsd32_charp) path; 568 syscallarg(netbsd32_statp_t) ub; 569 } */ 570 struct netbsd32_stat sb32; 571 struct stat sb; 572 int error; 573 const char *path; 574 575 path = SCARG_P32(uap, path); 576 577 error = do_sys_stat(path, NOFOLLOW, &sb); 578 if (error) 579 return (error); 580 netbsd32_from_stat(&sb, &sb32); 581 error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32)); 582 return (error); 583 } 584 585 int 586 netbsd32___fhstat50(struct lwp *l, const struct netbsd32___fhstat50_args *uap, register_t *retval) 587 { 588 /* { 589 syscallarg(const netbsd32_pointer_t) fhp; 590 syscallarg(netbsd32_size_t) fh_size; 591 syscallarg(netbsd32_statp_t) sb; 592 } */ 593 struct stat sb; 594 struct netbsd32_stat sb32; 595 int error; 596 597 error = do_fhstat(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), &sb); 598 if (error != 0) { 599 netbsd32_from_stat(&sb, &sb32); 600 error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb)); 601 } 602 return error; 603 } 604 605 int 606 netbsd32_preadv(struct lwp *l, const struct netbsd32_preadv_args *uap, register_t *retval) 607 { 608 /* { 609 syscallarg(int) fd; 610 syscallarg(const netbsd32_iovecp_t) iovp; 611 syscallarg(int) iovcnt; 612 syscallarg(int) pad; 613 syscallarg(off_t) offset; 614 } */ 615 file_t *fp; 616 struct vnode *vp; 617 off_t offset; 618 int error, fd = SCARG(uap, fd); 619 620 if ((fp = fd_getfile(fd)) == NULL) 621 return (EBADF); 622 623 if ((fp->f_flag & FREAD) == 0) { 624 fd_putfile(fd); 625 return (EBADF); 626 } 627 628 vp = fp->f_data; 629 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 630 error = ESPIPE; 631 goto out; 632 } 633 634 offset = SCARG(uap, offset); 635 636 /* 637 * XXX This works because no file systems actually 638 * XXX take any action on the seek operation. 639 */ 640 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0) 641 goto out; 642 643 return (dofilereadv32(fd, fp, SCARG_P32(uap, iovp), 644 SCARG(uap, iovcnt), &offset, 0, retval)); 645 646 out: 647 fd_putfile(fd); 648 return (error); 649 } 650 651 int 652 netbsd32_pwritev(struct lwp *l, const struct netbsd32_pwritev_args *uap, register_t *retval) 653 { 654 /* { 655 syscallarg(int) fd; 656 syscallarg(const netbsd32_iovecp_t) iovp; 657 syscallarg(int) iovcnt; 658 syscallarg(int) pad; 659 syscallarg(off_t) offset; 660 } */ 661 file_t *fp; 662 struct vnode *vp; 663 off_t offset; 664 int error, fd = SCARG(uap, fd); 665 666 if ((fp = fd_getfile(fd)) == NULL) 667 return (EBADF); 668 669 if ((fp->f_flag & FWRITE) == 0) { 670 fd_putfile(fd); 671 return (EBADF); 672 } 673 674 vp = fp->f_data; 675 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 676 error = ESPIPE; 677 goto out; 678 } 679 680 offset = SCARG(uap, offset); 681 682 /* 683 * XXX This works because no file systems actually 684 * XXX take any action on the seek operation. 685 */ 686 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0) 687 goto out; 688 689 return (dofilewritev32(fd, fp, SCARG_P32(uap, iovp), 690 SCARG(uap, iovcnt), &offset, 0, retval)); 691 692 out: 693 fd_putfile(fd); 694 return (error); 695 } 696 697 /* 698 * Find pathname of process's current directory. 699 * 700 * Use vfs vnode-to-name reverse cache; if that fails, fall back 701 * to reading directory contents. 702 */ 703 /* XXX NH Why does this exist */ 704 int 705 getcwd_common(struct vnode *, struct vnode *, 706 char **, char *, int, int, struct lwp *); 707 708 int 709 netbsd32___getcwd(struct lwp *l, const struct netbsd32___getcwd_args *uap, register_t *retval) 710 { 711 /* { 712 syscallarg(char *) bufp; 713 syscallarg(size_t) length; 714 } */ 715 struct proc *p = l->l_proc; 716 int error; 717 char *path; 718 char *bp, *bend; 719 int len = (int)SCARG(uap, length); 720 int lenused; 721 struct cwdinfo *cwdi; 722 723 if (len > MAXPATHLEN*4) 724 len = MAXPATHLEN*4; 725 else if (len < 2) 726 return ERANGE; 727 728 path = kmem_alloc(len, KM_SLEEP); 729 if (!path) 730 return ENOMEM; 731 732 bp = &path[len]; 733 bend = bp; 734 *(--bp) = '\0'; 735 736 /* 737 * 5th argument here is "max number of vnodes to traverse". 738 * Since each entry takes up at least 2 bytes in the output buffer, 739 * limit it to N/2 vnodes for an N byte buffer. 740 */ 741 #define GETCWD_CHECK_ACCESS 0x0001 742 cwdi = p->p_cwdi; 743 rw_enter(&cwdi->cwdi_lock, RW_READER); 744 error = getcwd_common (cwdi->cwdi_cdir, NULL, &bp, path, len/2, 745 GETCWD_CHECK_ACCESS, l); 746 rw_exit(&cwdi->cwdi_lock); 747 748 if (error) 749 goto out; 750 lenused = bend - bp; 751 *retval = lenused; 752 /* put the result into user buffer */ 753 error = copyout(bp, SCARG_P32(uap, bufp), lenused); 754 755 out: 756 kmem_free(path, len); 757 return error; 758 } 759 760 int 761 netbsd32___mount50(struct lwp *l, const struct netbsd32___mount50_args *uap, 762 register_t *retval) 763 { 764 /* { 765 syscallarg(netbsd32_charp) type; 766 syscallarg(netbsd32_charp) path; 767 syscallarg(int) flags; 768 syscallarg(netbsd32_voidp) data; 769 syscallarg(netbsd32_size_t) data_len; 770 } */ 771 char mtype[MNAMELEN]; 772 union { 773 struct netbsd32_ufs_args ufs_args; 774 struct netbsd32_mfs_args mfs_args; 775 struct netbsd32_iso_args iso_args; 776 struct netbsd32_nfs_args nfs_args; 777 } fs_args32; 778 union { 779 struct ufs_args ufs_args; 780 struct mfs_args mfs_args; 781 struct iso_args iso_args; 782 struct nfs_args nfs_args; 783 } fs_args; 784 const char *type = SCARG_P32(uap, type); 785 const char *path = SCARG_P32(uap, path); 786 int flags = SCARG(uap, flags); 787 void *data = SCARG_P32(uap, data); 788 size_t data_len = SCARG(uap, data_len); 789 enum uio_seg data_seg; 790 size_t len; 791 int error; 792 793 error = copyinstr(type, mtype, sizeof(mtype), &len); 794 if (error) 795 return error; 796 if (strcmp(mtype, MOUNT_MFS) == 0) { 797 if (data_len != sizeof(fs_args32.mfs_args)) 798 return EINVAL; 799 if ((flags & MNT_GETARGS) == 0) { 800 error = copyin(data, &fs_args32.mfs_args, 801 sizeof(fs_args32.mfs_args)); 802 if (error) 803 return error; 804 fs_args.mfs_args.fspec = 805 NETBSD32PTR64(fs_args32.mfs_args.fspec); 806 memset(&fs_args.mfs_args._pad1, 0, 807 sizeof(fs_args.mfs_args._pad1)); 808 fs_args.mfs_args.base = 809 NETBSD32PTR64(fs_args32.mfs_args.base); 810 fs_args.mfs_args.size = fs_args32.mfs_args.size; 811 } 812 data_seg = UIO_SYSSPACE; 813 data = &fs_args.mfs_args; 814 data_len = sizeof(fs_args.mfs_args); 815 } else if (strcmp(mtype, MOUNT_UFS) == 0) { 816 if (data_len > sizeof(fs_args32.ufs_args)) 817 return EINVAL; 818 if ((flags & MNT_GETARGS) == 0) { 819 error = copyin(data, &fs_args32.ufs_args, 820 sizeof(fs_args32.ufs_args)); 821 if (error) 822 return error; 823 fs_args.ufs_args.fspec = 824 NETBSD32PTR64(fs_args32.ufs_args.fspec); 825 } 826 data_seg = UIO_SYSSPACE; 827 data = &fs_args.ufs_args; 828 data_len = sizeof(fs_args.ufs_args); 829 } else if (strcmp(mtype, MOUNT_CD9660) == 0) { 830 if (data_len != sizeof(fs_args32.iso_args)) 831 return EINVAL; 832 if ((flags & MNT_GETARGS) == 0) { 833 error = copyin(data, &fs_args32.iso_args, 834 sizeof(fs_args32.iso_args)); 835 if (error) 836 return error; 837 fs_args.iso_args.fspec = 838 NETBSD32PTR64(fs_args32.iso_args.fspec); 839 memset(&fs_args.iso_args._pad1, 0, 840 sizeof(fs_args.iso_args._pad1)); 841 fs_args.iso_args.flags = fs_args32.iso_args.flags; 842 } 843 data_seg = UIO_SYSSPACE; 844 data = &fs_args.iso_args; 845 data_len = sizeof(fs_args.iso_args); 846 } else if (strcmp(mtype, MOUNT_NFS) == 0) { 847 if (data_len != sizeof(fs_args32.nfs_args)) 848 return EINVAL; 849 if ((flags & MNT_GETARGS) == 0) { 850 error = copyin(data, &fs_args32.nfs_args, 851 sizeof(fs_args32.nfs_args)); 852 if (error) 853 return error; 854 fs_args.nfs_args.version = fs_args32.nfs_args.version; 855 fs_args.nfs_args.addr = 856 NETBSD32PTR64(fs_args32.nfs_args.addr); 857 memcpy(&fs_args.nfs_args.addrlen, 858 &fs_args32.nfs_args.addrlen, 859 offsetof(struct nfs_args, fh) 860 - offsetof(struct nfs_args, addrlen)); 861 fs_args.nfs_args.fh = 862 NETBSD32PTR64(fs_args32.nfs_args.fh); 863 memcpy(&fs_args.nfs_args.fhsize, 864 &fs_args32.nfs_args.fhsize, 865 offsetof(struct nfs_args, hostname) 866 - offsetof(struct nfs_args, fhsize)); 867 fs_args.nfs_args.hostname = 868 NETBSD32PTR64(fs_args32.nfs_args.hostname); 869 } 870 data_seg = UIO_SYSSPACE; 871 data = &fs_args.nfs_args; 872 data_len = sizeof(fs_args.nfs_args); 873 } else { 874 data_seg = UIO_USERSPACE; 875 } 876 error = do_sys_mount(l, NULL, type, path, flags, data, data_seg, 877 data_len, retval); 878 if (error) 879 return error; 880 if (flags & MNT_GETARGS) { 881 data_len = *retval; 882 if (strcmp(mtype, MOUNT_MFS) == 0) { 883 if (data_len != sizeof(fs_args.mfs_args)) 884 return EINVAL; 885 NETBSD32PTR32(fs_args32.mfs_args.fspec, 886 fs_args.mfs_args.fspec); 887 memset(&fs_args32.mfs_args._pad1, 0, 888 sizeof(fs_args32.mfs_args._pad1)); 889 NETBSD32PTR32(fs_args32.mfs_args.base, 890 fs_args.mfs_args.base); 891 fs_args32.mfs_args.size = fs_args.mfs_args.size; 892 error = copyout(&fs_args32.mfs_args, data, 893 sizeof(fs_args32.mfs_args)); 894 } else if (strcmp(mtype, MOUNT_UFS) == 0) { 895 if (data_len != sizeof(fs_args.ufs_args)) 896 return EINVAL; 897 NETBSD32PTR32(fs_args32.ufs_args.fspec, 898 fs_args.ufs_args.fspec); 899 error = copyout(&fs_args32.ufs_args, data, 900 sizeof(fs_args32.ufs_args)); 901 } else if (strcmp(mtype, MOUNT_CD9660) == 0) { 902 if (data_len != sizeof(fs_args.iso_args)) 903 return EINVAL; 904 NETBSD32PTR32(fs_args32.iso_args.fspec, 905 fs_args.iso_args.fspec); 906 memset(&fs_args32.iso_args._pad1, 0, 907 sizeof(fs_args32.iso_args._pad1)); 908 fs_args32.iso_args.flags = fs_args.iso_args.flags; 909 error = copyout(&fs_args32.iso_args, data, 910 sizeof(fs_args32.iso_args)); 911 } else if (strcmp(mtype, MOUNT_NFS) == 0) { 912 if (data_len != sizeof(fs_args.nfs_args)) 913 return EINVAL; 914 error = copyin(data, &fs_args32.nfs_args, 915 sizeof(fs_args32.nfs_args)); 916 if (error) 917 return error; 918 fs_args.nfs_args.version = fs_args32.nfs_args.version; 919 NETBSD32PTR32(fs_args32.nfs_args.addr, 920 fs_args.nfs_args.addr); 921 memcpy(&fs_args32.nfs_args.addrlen, 922 &fs_args.nfs_args.addrlen, 923 offsetof(struct nfs_args, fh) 924 - offsetof(struct nfs_args, addrlen)); 925 NETBSD32PTR32(fs_args32.nfs_args.fh, 926 fs_args.nfs_args.fh); 927 memcpy(&fs_args32.nfs_args.fhsize, 928 &fs_args.nfs_args.fhsize, 929 offsetof(struct nfs_args, hostname) 930 - offsetof(struct nfs_args, fhsize)); 931 NETBSD32PTR32(fs_args32.nfs_args.hostname, 932 fs_args.nfs_args.hostname); 933 error = copyout(&fs_args32.nfs_args, data, 934 sizeof(fs_args32.nfs_args)); 935 } 936 } 937 return error; 938 } 939