1 /* $NetBSD: netbsd32_fs.c,v 1.17 2004/04/22 14:32:09 hannken 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.17 2004/04/22 14:32:09 hannken Exp $"); 33 34 #if defined(_KERNEL_OPT) 35 #include "opt_ktrace.h" 36 #endif 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/malloc.h> 41 #include <sys/mount.h> 42 #include <sys/socket.h> 43 #include <sys/socketvar.h> 44 #include <sys/stat.h> 45 #include <sys/time.h> 46 #include <sys/ktrace.h> 47 #include <sys/resourcevar.h> 48 #include <sys/vnode.h> 49 #include <sys/file.h> 50 #include <sys/filedesc.h> 51 #include <sys/namei.h> 52 #include <sys/sa.h> 53 #include <sys/syscallargs.h> 54 #include <sys/proc.h> 55 56 #include <compat/netbsd32/netbsd32.h> 57 #include <compat/netbsd32/netbsd32_syscallargs.h> 58 #include <compat/netbsd32/netbsd32_conv.h> 59 60 61 static int dofilereadv32 __P((struct proc *, int, struct file *, struct netbsd32_iovec *, 62 int, off_t *, int, register_t *)); 63 static int dofilewritev32 __P((struct proc *, int, struct file *, struct netbsd32_iovec *, 64 int, off_t *, int, register_t *)); 65 static int change_utimes32 __P((struct vnode *, netbsd32_timevalp_t, struct proc *)); 66 67 int 68 netbsd32_getfsstat(l, v, retval) 69 struct lwp *l; 70 void *v; 71 register_t *retval; 72 { 73 struct netbsd32_getfsstat_args /* { 74 syscallarg(netbsd32_statfsp_t) buf; 75 syscallarg(netbsd32_long) bufsize; 76 syscallarg(int) flags; 77 } */ *uap = v; 78 struct mount *mp, *nmp; 79 struct statvfs *sp; 80 struct netbsd32_statfs sb32; 81 caddr_t sfsp; 82 long count, maxcount, error; 83 struct proc *p = l->l_proc; 84 85 maxcount = SCARG(uap, bufsize) / sizeof(struct netbsd32_statfs); 86 sfsp = (caddr_t)NETBSD32PTR64(SCARG(uap, buf)); 87 simple_lock(&mountlist_slock); 88 count = 0; 89 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 90 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) { 91 nmp = mp->mnt_list.cqe_next; 92 continue; 93 } 94 if (sfsp && count < maxcount) { 95 sp = &mp->mnt_stat; 96 /* 97 * If MNT_NOWAIT or MNT_LAZY is specified, do not 98 * refresh the fsstat cache. MNT_WAIT or MNT_LAXY 99 * overrides MNT_NOWAIT. 100 */ 101 if (SCARG(uap, flags) != MNT_NOWAIT && 102 SCARG(uap, flags) != MNT_LAZY && 103 (SCARG(uap, flags) == MNT_WAIT || 104 SCARG(uap, flags) == 0) && 105 (error = VFS_STATVFS(mp, sp, p)) != 0) { 106 simple_lock(&mountlist_slock); 107 nmp = mp->mnt_list.cqe_next; 108 vfs_unbusy(mp); 109 continue; 110 } 111 sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK; 112 netbsd32_from_statvfs(sp, &sb32); 113 error = copyout(&sb32, sfsp, sizeof(sb32)); 114 if (error) { 115 vfs_unbusy(mp); 116 return (error); 117 } 118 sfsp += sizeof(sb32); 119 } 120 count++; 121 simple_lock(&mountlist_slock); 122 nmp = mp->mnt_list.cqe_next; 123 vfs_unbusy(mp); 124 } 125 simple_unlock(&mountlist_slock); 126 if (sfsp && count > maxcount) 127 *retval = maxcount; 128 else 129 *retval = count; 130 return (0); 131 } 132 133 int 134 netbsd32_readv(l, v, retval) 135 struct lwp *l; 136 void *v; 137 register_t *retval; 138 { 139 struct netbsd32_readv_args /* { 140 syscallarg(int) fd; 141 syscallarg(const netbsd32_iovecp_t) iovp; 142 syscallarg(int) iovcnt; 143 } */ *uap = v; 144 int fd = SCARG(uap, fd); 145 struct proc *p = l->l_proc; 146 struct file *fp; 147 struct filedesc *fdp = p->p_fd; 148 149 if ((fp = fd_getfile(fdp, fd)) == NULL) 150 return (EBADF); 151 152 if ((fp->f_flag & FREAD) == 0) 153 return (EBADF); 154 155 FILE_USE(fp); 156 157 return (dofilereadv32(p, fd, fp, 158 (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)), 159 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval)); 160 } 161 162 /* Damn thing copies in the iovec! */ 163 int 164 dofilereadv32(p, fd, fp, iovp, iovcnt, offset, flags, retval) 165 struct proc *p; 166 int fd; 167 struct file *fp; 168 struct netbsd32_iovec *iovp; 169 int iovcnt; 170 off_t *offset; 171 int flags; 172 register_t *retval; 173 { 174 struct uio auio; 175 struct iovec *iov; 176 struct iovec *needfree; 177 struct iovec aiov[UIO_SMALLIOV]; 178 long i, cnt, error = 0; 179 u_int iovlen; 180 #ifdef KTRACE 181 struct iovec *ktriov = NULL; 182 #endif 183 184 /* note: can't use iovlen until iovcnt is validated */ 185 iovlen = iovcnt * sizeof(struct iovec); 186 if ((u_int)iovcnt > UIO_SMALLIOV) { 187 if ((u_int)iovcnt > IOV_MAX) { 188 error = EINVAL; 189 goto out; 190 } 191 iov = malloc(iovlen, M_IOV, M_WAITOK); 192 needfree = iov; 193 } else if ((u_int)iovcnt > 0) { 194 iov = aiov; 195 needfree = NULL; 196 } else { 197 error = EINVAL; 198 goto out; 199 } 200 201 auio.uio_iov = iov; 202 auio.uio_iovcnt = iovcnt; 203 auio.uio_rw = UIO_READ; 204 auio.uio_segflg = UIO_USERSPACE; 205 auio.uio_procp = p; 206 error = netbsd32_to_iovecin(iovp, iov, iovcnt); 207 if (error) 208 goto done; 209 auio.uio_resid = 0; 210 for (i = 0; i < iovcnt; i++) { 211 auio.uio_resid += iov->iov_len; 212 /* 213 * Reads return ssize_t because -1 is returned on error. 214 * Therefore we must restrict the length to SSIZE_MAX to 215 * avoid garbage return values. 216 */ 217 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { 218 error = EINVAL; 219 goto done; 220 } 221 iov++; 222 } 223 #ifdef KTRACE 224 /* 225 * if tracing, save a copy of iovec 226 */ 227 if (KTRPOINT(p, KTR_GENIO)) { 228 ktriov = malloc(iovlen, M_TEMP, M_WAITOK); 229 memcpy((caddr_t)ktriov, (caddr_t)auio.uio_iov, iovlen); 230 } 231 #endif 232 cnt = auio.uio_resid; 233 error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred, flags); 234 if (error) 235 if (auio.uio_resid != cnt && (error == ERESTART || 236 error == EINTR || error == EWOULDBLOCK)) 237 error = 0; 238 cnt -= auio.uio_resid; 239 #ifdef KTRACE 240 if (KTRPOINT(p, KTR_GENIO)) 241 if (error == 0) { 242 ktrgenio(p, fd, UIO_READ, ktriov, cnt, 243 error); 244 free(ktriov, M_TEMP); 245 } 246 #endif 247 *retval = cnt; 248 done: 249 if (needfree) 250 free(needfree, M_IOV); 251 out: 252 FILE_UNUSE(fp, p); 253 return (error); 254 } 255 256 int 257 netbsd32_writev(l, v, retval) 258 struct lwp *l; 259 void *v; 260 register_t *retval; 261 { 262 struct netbsd32_writev_args /* { 263 syscallarg(int) fd; 264 syscallarg(const netbsd32_iovecp_t) iovp; 265 syscallarg(int) iovcnt; 266 } */ *uap = v; 267 int fd = SCARG(uap, fd); 268 struct file *fp; 269 struct proc *p = l->l_proc; 270 struct filedesc *fdp = p->p_fd; 271 272 if ((fp = fd_getfile(fdp, fd)) == NULL) 273 return (EBADF); 274 275 if ((fp->f_flag & FWRITE) == 0) 276 return (EBADF); 277 278 FILE_USE(fp); 279 280 return (dofilewritev32(p, fd, fp, 281 (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)), 282 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval)); 283 } 284 285 int 286 dofilewritev32(p, fd, fp, iovp, iovcnt, offset, flags, retval) 287 struct proc *p; 288 int fd; 289 struct file *fp; 290 struct netbsd32_iovec *iovp; 291 int iovcnt; 292 off_t *offset; 293 int flags; 294 register_t *retval; 295 { 296 struct uio auio; 297 struct iovec *iov; 298 struct iovec *needfree; 299 struct iovec aiov[UIO_SMALLIOV]; 300 long i, cnt, error = 0; 301 u_int iovlen; 302 #ifdef KTRACE 303 struct iovec *ktriov = NULL; 304 #endif 305 306 /* note: can't use iovlen until iovcnt is validated */ 307 iovlen = iovcnt * sizeof(struct iovec); 308 if ((u_int)iovcnt > UIO_SMALLIOV) { 309 if ((u_int)iovcnt > IOV_MAX) { 310 error = EINVAL; 311 goto out; 312 } 313 iov = malloc(iovlen, M_IOV, M_WAITOK); 314 needfree = iov; 315 } else if ((u_int)iovcnt > 0) { 316 iov = aiov; 317 needfree = NULL; 318 } else { 319 error = EINVAL; 320 goto out; 321 } 322 323 auio.uio_iov = iov; 324 auio.uio_iovcnt = iovcnt; 325 auio.uio_rw = UIO_WRITE; 326 auio.uio_segflg = UIO_USERSPACE; 327 auio.uio_procp = p; 328 error = netbsd32_to_iovecin(iovp, iov, iovcnt); 329 if (error) 330 goto done; 331 auio.uio_resid = 0; 332 for (i = 0; i < iovcnt; i++) { 333 auio.uio_resid += iov->iov_len; 334 /* 335 * Writes return ssize_t because -1 is returned on error. 336 * Therefore we must restrict the length to SSIZE_MAX to 337 * avoid garbage return values. 338 */ 339 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { 340 error = EINVAL; 341 goto done; 342 } 343 iov++; 344 } 345 #ifdef KTRACE 346 /* 347 * if tracing, save a copy of iovec 348 */ 349 if (KTRPOINT(p, KTR_GENIO)) { 350 ktriov = malloc(iovlen, M_TEMP, M_WAITOK); 351 memcpy((caddr_t)ktriov, (caddr_t)auio.uio_iov, iovlen); 352 } 353 #endif 354 cnt = auio.uio_resid; 355 error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred, flags); 356 if (error) { 357 if (auio.uio_resid != cnt && (error == ERESTART || 358 error == EINTR || error == EWOULDBLOCK)) 359 error = 0; 360 if (error == EPIPE) 361 psignal(p, SIGPIPE); 362 } 363 cnt -= auio.uio_resid; 364 #ifdef KTRACE 365 if (KTRPOINT(p, KTR_GENIO)) 366 if (error == 0) { 367 ktrgenio(p, fd, UIO_WRITE, ktriov, cnt, 368 error); 369 free(ktriov, M_TEMP); 370 } 371 #endif 372 *retval = cnt; 373 done: 374 if (needfree) 375 free(needfree, M_IOV); 376 out: 377 FILE_UNUSE(fp, p); 378 return (error); 379 } 380 381 int 382 netbsd32_utimes(l, v, retval) 383 struct lwp *l; 384 void *v; 385 register_t *retval; 386 { 387 struct netbsd32_utimes_args /* { 388 syscallarg(const netbsd32_charp) path; 389 syscallarg(const netbsd32_timevalp_t) tptr; 390 } */ *uap = v; 391 int error; 392 struct nameidata nd; 393 struct proc *p = l->l_proc; 394 395 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, 396 (char *)NETBSD32PTR64(SCARG(uap, path)), p); 397 if ((error = namei(&nd)) != 0) 398 return (error); 399 400 error = change_utimes32(nd.ni_vp, SCARG(uap, tptr), p); 401 402 vrele(nd.ni_vp); 403 return (error); 404 } 405 406 /* 407 * Common routine to set access and modification times given a vnode. 408 */ 409 static int 410 change_utimes32(vp, tptr, p) 411 struct vnode *vp; 412 netbsd32_timevalp_t tptr; 413 struct proc *p; 414 { 415 struct netbsd32_timeval tv32[2]; 416 struct timeval tv[2]; 417 struct vattr vattr; 418 int error; 419 420 VATTR_NULL(&vattr); 421 if (tptr == 0) { 422 microtime(&tv[0]); 423 tv[1] = tv[0]; 424 vattr.va_vaflags |= VA_UTIMES_NULL; 425 } else { 426 error = copyin((caddr_t)NETBSD32PTR64(tptr), tv32, 427 sizeof(tv32)); 428 if (error) 429 return (error); 430 netbsd32_to_timeval(&tv32[0], &tv[0]); 431 netbsd32_to_timeval(&tv32[1], &tv[1]); 432 } 433 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 434 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 435 vattr.va_atime.tv_sec = tv[0].tv_sec; 436 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; 437 vattr.va_mtime.tv_sec = tv[1].tv_sec; 438 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; 439 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 440 VOP_UNLOCK(vp, 0); 441 return (error); 442 } 443 444 int 445 netbsd32_statfs(l, v, retval) 446 struct lwp *l; 447 void *v; 448 register_t *retval; 449 { 450 struct netbsd32_statfs_args /* { 451 syscallarg(const netbsd32_charp) path; 452 syscallarg(netbsd32_statfsp_t) buf; 453 } */ *uap = v; 454 struct mount *mp; 455 struct statvfs *sp; 456 struct netbsd32_statfs s32; 457 int error; 458 struct nameidata nd; 459 struct proc *p = l->l_proc; 460 461 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, 462 (char *)NETBSD32PTR64(SCARG(uap, path)), p); 463 if ((error = namei(&nd)) != 0) 464 return (error); 465 mp = nd.ni_vp->v_mount; 466 sp = &mp->mnt_stat; 467 vrele(nd.ni_vp); 468 if ((error = VFS_STATVFS(mp, sp, p)) != 0) 469 return (error); 470 sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK; 471 netbsd32_from_statvfs(sp, &s32); 472 return (copyout(&s32, (caddr_t)NETBSD32PTR64(SCARG(uap, buf)), 473 sizeof(s32))); 474 } 475 476 int 477 netbsd32_fstatfs(l, v, retval) 478 struct lwp *l; 479 void *v; 480 register_t *retval; 481 { 482 struct netbsd32_fstatfs_args /* { 483 syscallarg(int) fd; 484 syscallarg(netbsd32_statfsp_t) buf; 485 } */ *uap = v; 486 struct file *fp; 487 struct mount *mp; 488 struct statvfs *sp; 489 struct netbsd32_statfs s32; 490 int error; 491 struct proc *p = l->l_proc; 492 493 /* getvnode() will use the descriptor for us */ 494 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 495 return (error); 496 mp = ((struct vnode *)fp->f_data)->v_mount; 497 sp = &mp->mnt_stat; 498 if ((error = VFS_STATVFS(mp, sp, p)) != 0) 499 goto out; 500 sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK; 501 netbsd32_from_statvfs(sp, &s32); 502 error = copyout(&s32, (caddr_t)NETBSD32PTR64(SCARG(uap, buf)), 503 sizeof(s32)); 504 out: 505 FILE_UNUSE(fp, p); 506 return (error); 507 } 508 509 int 510 netbsd32_futimes(l, v, retval) 511 struct lwp *l; 512 void *v; 513 register_t *retval; 514 { 515 struct netbsd32_futimes_args /* { 516 syscallarg(int) fd; 517 syscallarg(const netbsd32_timevalp_t) tptr; 518 } */ *uap = v; 519 int error; 520 struct file *fp; 521 struct proc *p = l->l_proc; 522 523 /* getvnode() will use the descriptor for us */ 524 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 525 return (error); 526 527 error = change_utimes32((struct vnode *)fp->f_data, 528 SCARG(uap, tptr), p); 529 FILE_UNUSE(fp, p); 530 return (error); 531 } 532 533 int 534 netbsd32_getdents(l, v, retval) 535 struct lwp *l; 536 void *v; 537 register_t *retval; 538 { 539 struct netbsd32_getdents_args /* { 540 syscallarg(int) fd; 541 syscallarg(netbsd32_charp) buf; 542 syscallarg(netbsd32_size_t) count; 543 } */ *uap = v; 544 struct file *fp; 545 int error, done; 546 struct proc *p = l->l_proc; 547 548 /* getvnode() will use the descriptor for us */ 549 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 550 return (error); 551 if ((fp->f_flag & FREAD) == 0) { 552 error = EBADF; 553 goto out; 554 } 555 error = vn_readdir(fp, (caddr_t)NETBSD32PTR64(SCARG(uap, buf)), 556 UIO_USERSPACE, SCARG(uap, count), &done, p, 0, 0); 557 *retval = done; 558 out: 559 FILE_UNUSE(fp, p); 560 return (error); 561 } 562 563 int 564 netbsd32_lutimes(l, v, retval) 565 struct lwp *l; 566 void *v; 567 register_t *retval; 568 { 569 struct netbsd32_lutimes_args /* { 570 syscallarg(const netbsd32_charp) path; 571 syscallarg(const netbsd32_timevalp_t) tptr; 572 } */ *uap = v; 573 int error; 574 struct nameidata nd; 575 struct proc *p = l->l_proc; 576 577 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, 578 (caddr_t)NETBSD32PTR64(SCARG(uap, path)), p); 579 if ((error = namei(&nd)) != 0) 580 return (error); 581 582 error = change_utimes32(nd.ni_vp, SCARG(uap, tptr), p); 583 584 vrele(nd.ni_vp); 585 return (error); 586 } 587 588 int 589 netbsd32___stat13(l, v, retval) 590 struct lwp *l; 591 void *v; 592 register_t *retval; 593 { 594 struct netbsd32___stat13_args /* { 595 syscallarg(const netbsd32_charp) path; 596 syscallarg(netbsd32_statp_t) ub; 597 } */ *uap = v; 598 struct netbsd32_stat sb32; 599 struct stat sb; 600 int error; 601 struct nameidata nd; 602 caddr_t sg; 603 const char *path; 604 struct proc *p = l->l_proc; 605 606 path = (char *)NETBSD32PTR64(SCARG(uap, path)); 607 sg = stackgap_init(p, 0); 608 CHECK_ALT_EXIST(p, &sg, path); 609 610 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, path, p); 611 if ((error = namei(&nd)) != 0) 612 return (error); 613 error = vn_stat(nd.ni_vp, &sb, p); 614 vput(nd.ni_vp); 615 if (error) 616 return (error); 617 netbsd32_from___stat13(&sb, &sb32); 618 error = copyout(&sb32, (caddr_t)NETBSD32PTR64(SCARG(uap, ub)), 619 sizeof(sb32)); 620 return (error); 621 } 622 623 int 624 netbsd32___fstat13(l, v, retval) 625 struct lwp *l; 626 void *v; 627 register_t *retval; 628 { 629 struct netbsd32___fstat13_args /* { 630 syscallarg(int) fd; 631 syscallarg(netbsd32_statp_t) sb; 632 } */ *uap = v; 633 int fd = SCARG(uap, fd); 634 struct proc *p = l->l_proc; 635 struct filedesc *fdp = p->p_fd; 636 struct file *fp; 637 struct netbsd32_stat sb32; 638 struct stat ub; 639 int error = 0; 640 641 if ((fp = fd_getfile(fdp, fd)) == NULL) 642 return (EBADF); 643 644 FILE_USE(fp); 645 error = (*fp->f_ops->fo_stat)(fp, &ub, p); 646 FILE_UNUSE(fp, p); 647 648 if (error == 0) { 649 netbsd32_from___stat13(&ub, &sb32); 650 error = copyout(&sb32, (caddr_t)NETBSD32PTR64(SCARG(uap, sb)), 651 sizeof(sb32)); 652 } 653 return (error); 654 } 655 656 int 657 netbsd32___lstat13(l, v, retval) 658 struct lwp *l; 659 void *v; 660 register_t *retval; 661 { 662 struct netbsd32___lstat13_args /* { 663 syscallarg(const netbsd32_charp) path; 664 syscallarg(netbsd32_statp_t) ub; 665 } */ *uap = v; 666 struct netbsd32_stat sb32; 667 struct stat sb; 668 int error; 669 struct nameidata nd; 670 caddr_t sg; 671 const char *path; 672 struct proc *p = l->l_proc; 673 674 path = (char *)NETBSD32PTR64(SCARG(uap, path)); 675 sg = stackgap_init(p, 0); 676 CHECK_ALT_EXIST(p, &sg, path); 677 678 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, path, p); 679 if ((error = namei(&nd)) != 0) 680 return (error); 681 error = vn_stat(nd.ni_vp, &sb, p); 682 vput(nd.ni_vp); 683 if (error) 684 return (error); 685 netbsd32_from___stat13(&sb, &sb32); 686 error = copyout(&sb32, (caddr_t)NETBSD32PTR64(SCARG(uap, ub)), 687 sizeof(sb32)); 688 return (error); 689 } 690 691 int 692 netbsd32_preadv(l, v, retval) 693 struct lwp *l; 694 void *v; 695 register_t *retval; 696 { 697 struct netbsd32_preadv_args /* { 698 syscallarg(int) fd; 699 syscallarg(const netbsd32_iovecp_t) iovp; 700 syscallarg(int) iovcnt; 701 syscallarg(int) pad; 702 syscallarg(off_t) offset; 703 } */ *uap = v; 704 struct proc *p = l->l_proc; 705 struct filedesc *fdp = p->p_fd; 706 struct file *fp; 707 struct vnode *vp; 708 off_t offset; 709 int error, fd = SCARG(uap, fd); 710 711 if ((fp = fd_getfile(fdp, fd)) == NULL) 712 return (EBADF); 713 714 if ((fp->f_flag & FREAD) == 0) 715 return (EBADF); 716 717 FILE_USE(fp); 718 719 vp = (struct vnode *)fp->f_data; 720 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 721 error = ESPIPE; 722 goto out; 723 } 724 725 offset = SCARG(uap, offset); 726 727 /* 728 * XXX This works because no file systems actually 729 * XXX take any action on the seek operation. 730 */ 731 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0) 732 goto out; 733 734 return (dofilereadv32(p, fd, fp, 735 (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)), 736 SCARG(uap, iovcnt), &offset, 0, retval)); 737 738 out: 739 FILE_UNUSE(fp, p); 740 return (error); 741 } 742 743 int 744 netbsd32_pwritev(l, v, retval) 745 struct lwp *l; 746 void *v; 747 register_t *retval; 748 { 749 struct netbsd32_pwritev_args /* { 750 syscallarg(int) fd; 751 syscallarg(const netbsd32_iovecp_t) iovp; 752 syscallarg(int) iovcnt; 753 syscallarg(int) pad; 754 syscallarg(off_t) offset; 755 } */ *uap = v; 756 struct proc *p = l->l_proc; 757 struct filedesc *fdp = p->p_fd; 758 struct file *fp; 759 struct vnode *vp; 760 off_t offset; 761 int error, fd = SCARG(uap, fd); 762 763 if ((fp = fd_getfile(fdp, fd)) == NULL) 764 return (EBADF); 765 766 if ((fp->f_flag & FWRITE) == 0) 767 return (EBADF); 768 769 FILE_USE(fp); 770 771 vp = (struct vnode *)fp->f_data; 772 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 773 error = ESPIPE; 774 goto out; 775 } 776 777 offset = SCARG(uap, offset); 778 779 /* 780 * XXX This works because no file systems actually 781 * XXX take any action on the seek operation. 782 */ 783 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0) 784 goto out; 785 786 return (dofilewritev32(p, fd, fp, 787 (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)), 788 SCARG(uap, iovcnt), &offset, 0, retval)); 789 790 out: 791 FILE_UNUSE(fp, p); 792 return (error); 793 } 794 795 /* 796 * Find pathname of process's current directory. 797 * 798 * Use vfs vnode-to-name reverse cache; if that fails, fall back 799 * to reading directory contents. 800 */ 801 int 802 getcwd_common __P((struct vnode *, struct vnode *, 803 char **, char *, int, int, struct proc *)); 804 805 int netbsd32___getcwd(l, v, retval) 806 struct lwp *l; 807 void *v; 808 register_t *retval; 809 { 810 struct netbsd32___getcwd_args /* { 811 syscallarg(char *) bufp; 812 syscallarg(size_t) length; 813 } */ *uap = v; 814 struct proc *p = l->l_proc; 815 int error; 816 char *path; 817 char *bp, *bend; 818 int len = (int)SCARG(uap, length); 819 int lenused; 820 821 if (len > MAXPATHLEN*4) 822 len = MAXPATHLEN*4; 823 else if (len < 2) 824 return ERANGE; 825 826 path = (char *)malloc(len, M_TEMP, M_WAITOK); 827 if (!path) 828 return ENOMEM; 829 830 bp = &path[len]; 831 bend = bp; 832 *(--bp) = '\0'; 833 834 /* 835 * 5th argument here is "max number of vnodes to traverse". 836 * Since each entry takes up at least 2 bytes in the output buffer, 837 * limit it to N/2 vnodes for an N byte buffer. 838 */ 839 #define GETCWD_CHECK_ACCESS 0x0001 840 error = getcwd_common (p->p_cwdi->cwdi_cdir, NULL, &bp, path, len/2, 841 GETCWD_CHECK_ACCESS, p); 842 843 if (error) 844 goto out; 845 lenused = bend - bp; 846 *retval = lenused; 847 /* put the result into user buffer */ 848 error = copyout(bp, (caddr_t)NETBSD32PTR64(SCARG(uap, bufp)), lenused); 849 850 out: 851 free(path, M_TEMP); 852 return error; 853 } 854