1 /* $NetBSD: netbsd32_fs.c,v 1.55 2008/06/24 11:18:15 ad 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.55 2008/06/24 11:18:15 ad Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/malloc.h> 35 #include <sys/mount.h> 36 #include <sys/socket.h> 37 #include <sys/socketvar.h> 38 #include <sys/stat.h> 39 #include <sys/time.h> 40 #include <sys/ktrace.h> 41 #include <sys/resourcevar.h> 42 #include <sys/vnode.h> 43 #include <sys/file.h> 44 #include <sys/filedesc.h> 45 #include <sys/namei.h> 46 #include <sys/statvfs.h> 47 #include <sys/syscallargs.h> 48 #include <sys/proc.h> 49 #include <sys/dirent.h> 50 #include <sys/kauth.h> 51 #include <sys/vfs_syscalls.h> 52 53 #include <compat/netbsd32/netbsd32.h> 54 #include <compat/netbsd32/netbsd32_syscallargs.h> 55 #include <compat/netbsd32/netbsd32_conv.h> 56 #include <compat/sys/mount.h> 57 58 59 static int dofilereadv32(int, struct file *, struct netbsd32_iovec *, 60 int, off_t *, int, register_t *); 61 static int dofilewritev32(int, struct file *, struct netbsd32_iovec *, 62 int, off_t *, int, register_t *); 63 64 struct iovec * 65 netbsd32_get_iov(struct netbsd32_iovec *iov32, int iovlen, struct iovec *aiov, 66 int aiov_len) 67 { 68 #define N_IOV32 8 69 struct netbsd32_iovec aiov32[N_IOV32]; 70 struct iovec *iov = aiov; 71 struct iovec *iovp; 72 int i, n, j; 73 int error; 74 75 if (iovlen < 0 || iovlen > IOV_MAX) 76 return NULL; 77 78 if (iovlen > aiov_len) 79 iov = malloc(iovlen * sizeof (*iov), M_TEMP, M_WAITOK); 80 81 iovp = iov; 82 for (i = 0; i < iovlen; iov32 += N_IOV32, i += N_IOV32) { 83 n = iovlen - i; 84 if (n > N_IOV32) 85 n = N_IOV32; 86 error = copyin(iov32, aiov32, n * sizeof (*iov32)); 87 if (error != 0) { 88 if (iov != aiov) 89 free(iov, M_TEMP); 90 return NULL; 91 } 92 for (j = 0; j < n; iovp++, j++) { 93 iovp->iov_base = NETBSD32PTR64(aiov32[j].iov_base); 94 iovp->iov_len = aiov32[j].iov_len; 95 } 96 } 97 return iov; 98 #undef N_IOV32 99 } 100 101 int 102 netbsd32_readv(struct lwp *l, const struct netbsd32_readv_args *uap, register_t *retval) 103 { 104 /* { 105 syscallarg(int) fd; 106 syscallarg(const netbsd32_iovecp_t) iovp; 107 syscallarg(int) iovcnt; 108 } */ 109 int fd = SCARG(uap, fd); 110 file_t *fp; 111 112 if ((fp = fd_getfile(fd)) == NULL) 113 return (EBADF); 114 115 if ((fp->f_flag & FREAD) == 0) { 116 fd_putfile(fd); 117 return (EBADF); 118 } 119 120 return (dofilereadv32(fd, fp, 121 (struct netbsd32_iovec *)SCARG_P32(uap, iovp), 122 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval)); 123 } 124 125 /* Damn thing copies in the iovec! */ 126 int 127 dofilereadv32(int fd, struct file *fp, struct netbsd32_iovec *iovp, int iovcnt, off_t *offset, int flags, register_t *retval) 128 { 129 struct uio auio; 130 struct iovec *iov; 131 struct iovec *needfree; 132 struct iovec aiov[UIO_SMALLIOV]; 133 long i, cnt, error = 0; 134 u_int iovlen; 135 struct iovec *ktriov = NULL; 136 137 /* note: can't use iovlen until iovcnt is validated */ 138 iovlen = iovcnt * sizeof(struct iovec); 139 if ((u_int)iovcnt > UIO_SMALLIOV) { 140 if ((u_int)iovcnt > IOV_MAX) { 141 error = EINVAL; 142 goto out; 143 } 144 iov = malloc(iovlen, M_IOV, M_WAITOK); 145 needfree = iov; 146 } else if ((u_int)iovcnt > 0) { 147 iov = aiov; 148 needfree = NULL; 149 } else { 150 error = EINVAL; 151 goto out; 152 } 153 154 auio.uio_iov = iov; 155 auio.uio_iovcnt = iovcnt; 156 auio.uio_rw = UIO_READ; 157 auio.uio_vmspace = curproc->p_vmspace; 158 error = netbsd32_to_iovecin(iovp, iov, iovcnt); 159 if (error) 160 goto done; 161 auio.uio_resid = 0; 162 for (i = 0; i < iovcnt; i++) { 163 auio.uio_resid += iov->iov_len; 164 /* 165 * Reads return ssize_t because -1 is returned on error. 166 * Therefore we must restrict the length to SSIZE_MAX to 167 * avoid garbage return values. 168 */ 169 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { 170 error = EINVAL; 171 goto done; 172 } 173 iov++; 174 } 175 176 /* 177 * if tracing, save a copy of iovec 178 */ 179 if (ktrpoint(KTR_GENIO)) { 180 ktriov = malloc(iovlen, M_TEMP, M_WAITOK); 181 memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen); 182 } 183 184 cnt = auio.uio_resid; 185 error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred, flags); 186 if (error) 187 if (auio.uio_resid != cnt && (error == ERESTART || 188 error == EINTR || error == EWOULDBLOCK)) 189 error = 0; 190 cnt -= auio.uio_resid; 191 192 if (ktriov != NULL) { 193 ktrgeniov(fd, UIO_READ, ktriov, cnt, error); 194 free(ktriov, M_TEMP); 195 } 196 197 *retval = cnt; 198 done: 199 if (needfree) 200 free(needfree, M_IOV); 201 out: 202 fd_putfile(fd); 203 return (error); 204 } 205 206 int 207 netbsd32_writev(struct lwp *l, const struct netbsd32_writev_args *uap, register_t *retval) 208 { 209 /* { 210 syscallarg(int) fd; 211 syscallarg(const netbsd32_iovecp_t) iovp; 212 syscallarg(int) iovcnt; 213 } */ 214 int fd = SCARG(uap, fd); 215 file_t *fp; 216 217 if ((fp = fd_getfile(fd)) == NULL) 218 return (EBADF); 219 220 if ((fp->f_flag & FWRITE) == 0) { 221 fd_putfile(fd); 222 return (EBADF); 223 } 224 225 return (dofilewritev32(fd, fp, 226 (struct netbsd32_iovec *)SCARG_P32(uap, iovp), 227 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval)); 228 } 229 230 int 231 dofilewritev32(int fd, struct file *fp, struct netbsd32_iovec *iovp, int iovcnt, off_t *offset, int flags, register_t *retval) 232 { 233 struct uio auio; 234 struct iovec *iov; 235 struct iovec *needfree; 236 struct iovec aiov[UIO_SMALLIOV]; 237 long i, cnt, error = 0; 238 u_int iovlen; 239 struct iovec *ktriov = NULL; 240 241 /* note: can't use iovlen until iovcnt is validated */ 242 iovlen = iovcnt * sizeof(struct iovec); 243 if ((u_int)iovcnt > UIO_SMALLIOV) { 244 if ((u_int)iovcnt > IOV_MAX) { 245 error = EINVAL; 246 goto out; 247 } 248 iov = malloc(iovlen, M_IOV, M_WAITOK); 249 needfree = iov; 250 } else if ((u_int)iovcnt > 0) { 251 iov = aiov; 252 needfree = NULL; 253 } else { 254 error = EINVAL; 255 goto out; 256 } 257 258 auio.uio_iov = iov; 259 auio.uio_iovcnt = iovcnt; 260 auio.uio_rw = UIO_WRITE; 261 auio.uio_vmspace = curproc->p_vmspace; 262 error = netbsd32_to_iovecin(iovp, iov, iovcnt); 263 if (error) 264 goto done; 265 auio.uio_resid = 0; 266 for (i = 0; i < iovcnt; i++) { 267 auio.uio_resid += iov->iov_len; 268 /* 269 * Writes return ssize_t because -1 is returned on error. 270 * Therefore we must restrict the length to SSIZE_MAX to 271 * avoid garbage return values. 272 */ 273 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { 274 error = EINVAL; 275 goto done; 276 } 277 iov++; 278 } 279 280 /* 281 * if tracing, save a copy of iovec 282 */ 283 if (ktrpoint(KTR_GENIO)) { 284 ktriov = malloc(iovlen, M_TEMP, M_WAITOK); 285 memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen); 286 } 287 288 cnt = auio.uio_resid; 289 error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred, flags); 290 if (error) { 291 if (auio.uio_resid != cnt && (error == ERESTART || 292 error == EINTR || error == EWOULDBLOCK)) 293 error = 0; 294 if (error == EPIPE) { 295 mutex_enter(proc_lock); 296 psignal(curproc, SIGPIPE); 297 mutex_exit(proc_lock); 298 } 299 } 300 cnt -= auio.uio_resid; 301 if (ktriov != NULL) { 302 ktrgenio(fd, UIO_WRITE, ktriov, cnt, error); 303 free(ktriov, M_TEMP); 304 } 305 *retval = cnt; 306 done: 307 if (needfree) 308 free(needfree, M_IOV); 309 out: 310 fd_putfile(fd); 311 return (error); 312 } 313 314 /* 315 * Common routine to set access and modification times given a vnode. 316 */ 317 static int 318 get_utimes32(const netbsd32_timevalp_t *tptr, struct timeval *tv, 319 struct timeval **tvp) 320 { 321 int error; 322 struct netbsd32_timeval tv32[2]; 323 324 if (tptr == NULL) { 325 *tvp = NULL; 326 return 0; 327 } 328 329 error = copyin(tptr, tv32, sizeof(tv32)); 330 if (error) 331 return error; 332 netbsd32_to_timeval(&tv32[0], &tv[0]); 333 netbsd32_to_timeval(&tv32[1], &tv[1]); 334 335 *tvp = tv; 336 return 0; 337 } 338 339 int 340 netbsd32_utimes(struct lwp *l, const struct netbsd32_utimes_args *uap, register_t *retval) 341 { 342 /* { 343 syscallarg(const netbsd32_charp) path; 344 syscallarg(const netbsd32_timevalp_t) tptr; 345 } */ 346 int error; 347 struct timeval tv[2], *tvp; 348 349 error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp); 350 if (error != 0) 351 return error; 352 353 return do_sys_utimes(l, NULL, SCARG_P32(uap, path), FOLLOW, 354 tvp, UIO_SYSSPACE); 355 } 356 357 static int 358 netbds32_copyout_statvfs(const void *kp, void *up, size_t len) 359 { 360 struct netbsd32_statvfs *sbuf_32; 361 int error; 362 363 sbuf_32 = malloc(sizeof *sbuf_32, M_TEMP, M_WAITOK); 364 netbsd32_from_statvfs(kp, sbuf_32); 365 error = copyout(sbuf_32, up, sizeof(*sbuf_32)); 366 free(sbuf_32, M_TEMP); 367 368 return error; 369 } 370 371 int 372 netbsd32_statvfs1(struct lwp *l, const struct netbsd32_statvfs1_args *uap, register_t *retval) 373 { 374 /* { 375 syscallarg(const netbsd32_charp) path; 376 syscallarg(netbsd32_statvfsp_t) buf; 377 syscallarg(int) flags; 378 } */ 379 struct statvfs *sb; 380 int error; 381 382 sb = STATVFSBUF_GET(); 383 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), SCARG(uap, flags), sb); 384 if (error == 0) 385 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0); 386 STATVFSBUF_PUT(sb); 387 return error; 388 } 389 390 int 391 netbsd32_fstatvfs1(struct lwp *l, const struct netbsd32_fstatvfs1_args *uap, register_t *retval) 392 { 393 /* { 394 syscallarg(int) fd; 395 syscallarg(netbsd32_statvfsp_t) buf; 396 syscallarg(int) flags; 397 } */ 398 struct statvfs *sb; 399 int error; 400 401 sb = STATVFSBUF_GET(); 402 error = do_sys_fstatvfs(l, SCARG(uap, fd), SCARG(uap, flags), sb); 403 if (error == 0) 404 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0); 405 STATVFSBUF_PUT(sb); 406 return error; 407 } 408 409 int 410 netbsd32_getvfsstat(struct lwp *l, const struct netbsd32_getvfsstat_args *uap, register_t *retval) 411 { 412 /* { 413 syscallarg(netbsd32_statvfsp_t) buf; 414 syscallarg(netbsd32_size_t) bufsize; 415 syscallarg(int) flags; 416 } */ 417 418 return do_sys_getvfsstat(l, SCARG_P32(uap, buf), SCARG(uap, bufsize), 419 SCARG(uap, flags), netbds32_copyout_statvfs, 420 sizeof (struct netbsd32_statvfs), retval); 421 } 422 423 int 424 netbsd32___fhstatvfs140(struct lwp *l, const struct netbsd32___fhstatvfs140_args *uap, register_t *retval) 425 { 426 /* { 427 syscallarg(const netbsd32_pointer_t) fhp; 428 syscallarg(netbsd32_size_t) fh_size; 429 syscallarg(netbsd32_statvfsp_t) buf; 430 syscallarg(int) flags; 431 } */ 432 struct statvfs *sb; 433 int error; 434 435 sb = STATVFSBUF_GET(); 436 error = do_fhstatvfs(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), sb, 437 SCARG(uap, flags)); 438 439 if (error == 0) 440 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0); 441 STATVFSBUF_PUT(sb); 442 443 return error; 444 } 445 446 int 447 netbsd32_futimes(struct lwp *l, const struct netbsd32_futimes_args *uap, register_t *retval) 448 { 449 /* { 450 syscallarg(int) fd; 451 syscallarg(const netbsd32_timevalp_t) tptr; 452 } */ 453 int error; 454 file_t *fp; 455 struct timeval tv[2], *tvp; 456 457 error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp); 458 if (error != 0) 459 return error; 460 461 /* fd_getvnode() will use the descriptor for us */ 462 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 463 return (error); 464 465 error = do_sys_utimes(l, fp->f_data, NULL, 0, tvp, UIO_SYSSPACE); 466 467 fd_putfile(SCARG(uap, fd)); 468 return (error); 469 } 470 471 int 472 netbsd32_sys___getdents30(struct lwp *l, const struct netbsd32_sys___getdents30_args *uap, register_t *retval) 473 { 474 /* { 475 syscallarg(int) fd; 476 syscallarg(netbsd32_charp) buf; 477 syscallarg(netbsd32_size_t) count; 478 } */ 479 file_t *fp; 480 int error, done; 481 482 /* fd_getvnode() will use the descriptor for us */ 483 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 484 return (error); 485 if ((fp->f_flag & FREAD) == 0) { 486 error = EBADF; 487 goto out; 488 } 489 error = vn_readdir(fp, SCARG_P32(uap, buf), 490 UIO_USERSPACE, SCARG(uap, count), &done, l, 0, 0); 491 *retval = done; 492 out: 493 fd_putfile(SCARG(uap, fd)); 494 return (error); 495 } 496 497 int 498 netbsd32_lutimes(struct lwp *l, const struct netbsd32_lutimes_args *uap, register_t *retval) 499 { 500 /* { 501 syscallarg(const netbsd32_charp) path; 502 syscallarg(const netbsd32_timevalp_t) tptr; 503 } */ 504 int error; 505 struct timeval tv[2], *tvp; 506 507 error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp); 508 if (error != 0) 509 return error; 510 511 return do_sys_utimes(l, NULL, SCARG_P32(uap, path), NOFOLLOW, 512 tvp, UIO_SYSSPACE); 513 } 514 515 int 516 netbsd32_sys___stat30(struct lwp *l, const struct netbsd32_sys___stat30_args *uap, register_t *retval) 517 { 518 /* { 519 syscallarg(const netbsd32_charp) path; 520 syscallarg(netbsd32_statp_t) ub; 521 } */ 522 struct netbsd32_stat sb32; 523 struct stat sb; 524 int error; 525 const char *path; 526 527 path = SCARG_P32(uap, path); 528 529 error = do_sys_stat(path, FOLLOW, &sb); 530 if (error) 531 return (error); 532 netbsd32_from___stat30(&sb, &sb32); 533 error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32)); 534 return (error); 535 } 536 537 int 538 netbsd32_sys___fstat30(struct lwp *l, const struct netbsd32_sys___fstat30_args *uap, register_t *retval) 539 { 540 /* { 541 syscallarg(int) fd; 542 syscallarg(netbsd32_statp_t) sb; 543 } */ 544 int fd = SCARG(uap, fd); 545 file_t *fp; 546 struct netbsd32_stat sb32; 547 struct stat ub; 548 int error = 0; 549 550 if ((fp = fd_getfile(fd)) == NULL) 551 return (EBADF); 552 error = (*fp->f_ops->fo_stat)(fp, &ub); 553 fd_putfile(fd); 554 if (error == 0) { 555 netbsd32_from___stat30(&ub, &sb32); 556 error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb32)); 557 } 558 return (error); 559 } 560 561 int 562 netbsd32_sys___lstat30(struct lwp *l, const struct netbsd32_sys___lstat30_args *uap, register_t *retval) 563 { 564 /* { 565 syscallarg(const netbsd32_charp) path; 566 syscallarg(netbsd32_statp_t) ub; 567 } */ 568 struct netbsd32_stat sb32; 569 struct stat sb; 570 int error; 571 const char *path; 572 573 path = SCARG_P32(uap, path); 574 575 error = do_sys_stat(path, NOFOLLOW, &sb); 576 if (error) 577 return (error); 578 netbsd32_from___stat30(&sb, &sb32); 579 error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32)); 580 return (error); 581 } 582 583 int 584 netbsd32___fhstat40(struct lwp *l, const struct netbsd32___fhstat40_args *uap, register_t *retval) 585 { 586 /* { 587 syscallarg(const netbsd32_pointer_t) fhp; 588 syscallarg(netbsd32_size_t) fh_size; 589 syscallarg(netbsd32_statp_t) sb; 590 } */ 591 struct stat sb; 592 struct netbsd32_stat sb32; 593 int error; 594 595 error = do_fhstat(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), &sb); 596 if (error != 0) { 597 netbsd32_from___stat30(&sb, &sb32); 598 error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb)); 599 } 600 return error; 601 } 602 603 int 604 netbsd32_preadv(struct lwp *l, const struct netbsd32_preadv_args *uap, register_t *retval) 605 { 606 /* { 607 syscallarg(int) fd; 608 syscallarg(const netbsd32_iovecp_t) iovp; 609 syscallarg(int) iovcnt; 610 syscallarg(int) pad; 611 syscallarg(off_t) offset; 612 } */ 613 file_t *fp; 614 struct vnode *vp; 615 off_t offset; 616 int error, fd = SCARG(uap, fd); 617 618 if ((fp = fd_getfile(fd)) == NULL) 619 return (EBADF); 620 621 if ((fp->f_flag & FREAD) == 0) { 622 fd_putfile(fd); 623 return (EBADF); 624 } 625 626 vp = fp->f_data; 627 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 628 error = ESPIPE; 629 goto out; 630 } 631 632 offset = SCARG(uap, offset); 633 634 /* 635 * XXX This works because no file systems actually 636 * XXX take any action on the seek operation. 637 */ 638 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0) 639 goto out; 640 641 return (dofilereadv32(fd, fp, SCARG_P32(uap, iovp), 642 SCARG(uap, iovcnt), &offset, 0, retval)); 643 644 out: 645 fd_putfile(fd); 646 return (error); 647 } 648 649 int 650 netbsd32_pwritev(struct lwp *l, const struct netbsd32_pwritev_args *uap, register_t *retval) 651 { 652 /* { 653 syscallarg(int) fd; 654 syscallarg(const netbsd32_iovecp_t) iovp; 655 syscallarg(int) iovcnt; 656 syscallarg(int) pad; 657 syscallarg(off_t) offset; 658 } */ 659 file_t *fp; 660 struct vnode *vp; 661 off_t offset; 662 int error, fd = SCARG(uap, fd); 663 664 if ((fp = fd_getfile(fd)) == NULL) 665 return (EBADF); 666 667 if ((fp->f_flag & FWRITE) == 0) { 668 fd_putfile(fd); 669 return (EBADF); 670 } 671 672 vp = fp->f_data; 673 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 674 error = ESPIPE; 675 goto out; 676 } 677 678 offset = SCARG(uap, offset); 679 680 /* 681 * XXX This works because no file systems actually 682 * XXX take any action on the seek operation. 683 */ 684 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0) 685 goto out; 686 687 return (dofilewritev32(fd, fp, SCARG_P32(uap, iovp), 688 SCARG(uap, iovcnt), &offset, 0, retval)); 689 690 out: 691 fd_putfile(fd); 692 return (error); 693 } 694 695 /* 696 * Find pathname of process's current directory. 697 * 698 * Use vfs vnode-to-name reverse cache; if that fails, fall back 699 * to reading directory contents. 700 */ 701 /* XXX NH Why does this exist */ 702 int 703 getcwd_common(struct vnode *, struct vnode *, 704 char **, char *, int, int, struct lwp *); 705 706 int 707 netbsd32___getcwd(struct lwp *l, const struct netbsd32___getcwd_args *uap, register_t *retval) 708 { 709 /* { 710 syscallarg(char *) bufp; 711 syscallarg(size_t) length; 712 } */ 713 struct proc *p = l->l_proc; 714 int error; 715 char *path; 716 char *bp, *bend; 717 int len = (int)SCARG(uap, length); 718 int lenused; 719 struct cwdinfo *cwdi; 720 721 if (len > MAXPATHLEN*4) 722 len = MAXPATHLEN*4; 723 else if (len < 2) 724 return ERANGE; 725 726 path = (char *)malloc(len, M_TEMP, M_WAITOK); 727 if (!path) 728 return ENOMEM; 729 730 bp = &path[len]; 731 bend = bp; 732 *(--bp) = '\0'; 733 734 /* 735 * 5th argument here is "max number of vnodes to traverse". 736 * Since each entry takes up at least 2 bytes in the output buffer, 737 * limit it to N/2 vnodes for an N byte buffer. 738 */ 739 #define GETCWD_CHECK_ACCESS 0x0001 740 cwdi = p->p_cwdi; 741 rw_enter(&cwdi->cwdi_lock, RW_READER); 742 error = getcwd_common (cwdi->cwdi_cdir, NULL, &bp, path, len/2, 743 GETCWD_CHECK_ACCESS, l); 744 rw_exit(&cwdi->cwdi_lock); 745 746 if (error) 747 goto out; 748 lenused = bend - bp; 749 *retval = lenused; 750 /* put the result into user buffer */ 751 error = copyout(bp, SCARG_P32(uap, bufp), lenused); 752 753 out: 754 free(path, M_TEMP); 755 return error; 756 } 757