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