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