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