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