1 /* $NetBSD: netbsd32_fs.c,v 1.23 2005/12/11 12:20:22 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.23 2005/12/11 12:20:22 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 lwp *, int, struct file *, struct netbsd32_iovec *, 64 int, off_t *, int, register_t *)); 65 static int dofilewritev32 __P((struct lwp *, 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 lwp *)); 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(l, 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(l, fd, fp, iovp, iovcnt, offset, flags, retval) 101 struct lwp *l; 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_lwp = l; 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(l->l_proc, 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(l->l_proc, KTR_GENIO)) 177 if (error == 0) { 178 ktrgenio(l, 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, l); 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(l, 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(l, fd, fp, iovp, iovcnt, offset, flags, retval) 223 struct lwp *l; 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 struct proc *p = l->l_proc; 237 long i, cnt, error = 0; 238 u_int iovlen; 239 #ifdef KTRACE 240 struct iovec *ktriov = NULL; 241 #endif 242 243 /* note: can't use iovlen until iovcnt is validated */ 244 iovlen = iovcnt * sizeof(struct iovec); 245 if ((u_int)iovcnt > UIO_SMALLIOV) { 246 if ((u_int)iovcnt > IOV_MAX) { 247 error = EINVAL; 248 goto out; 249 } 250 iov = malloc(iovlen, M_IOV, M_WAITOK); 251 needfree = iov; 252 } else if ((u_int)iovcnt > 0) { 253 iov = aiov; 254 needfree = NULL; 255 } else { 256 error = EINVAL; 257 goto out; 258 } 259 260 auio.uio_iov = iov; 261 auio.uio_iovcnt = iovcnt; 262 auio.uio_rw = UIO_WRITE; 263 auio.uio_segflg = UIO_USERSPACE; 264 auio.uio_lwp = l; 265 error = netbsd32_to_iovecin(iovp, iov, iovcnt); 266 if (error) 267 goto done; 268 auio.uio_resid = 0; 269 for (i = 0; i < iovcnt; i++) { 270 auio.uio_resid += iov->iov_len; 271 /* 272 * Writes return ssize_t because -1 is returned on error. 273 * Therefore we must restrict the length to SSIZE_MAX to 274 * avoid garbage return values. 275 */ 276 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { 277 error = EINVAL; 278 goto done; 279 } 280 iov++; 281 } 282 #ifdef KTRACE 283 /* 284 * if tracing, save a copy of iovec 285 */ 286 if (KTRPOINT(p, KTR_GENIO)) { 287 ktriov = malloc(iovlen, M_TEMP, M_WAITOK); 288 memcpy((caddr_t)ktriov, (caddr_t)auio.uio_iov, iovlen); 289 } 290 #endif 291 cnt = auio.uio_resid; 292 error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred, flags); 293 if (error) { 294 if (auio.uio_resid != cnt && (error == ERESTART || 295 error == EINTR || error == EWOULDBLOCK)) 296 error = 0; 297 if (error == EPIPE) 298 psignal(p, SIGPIPE); 299 } 300 cnt -= auio.uio_resid; 301 #ifdef KTRACE 302 if (KTRPOINT(p, KTR_GENIO)) 303 if (error == 0) { 304 ktrgenio(l, fd, UIO_WRITE, ktriov, cnt, 305 error); 306 free(ktriov, M_TEMP); 307 } 308 #endif 309 *retval = cnt; 310 done: 311 if (needfree) 312 free(needfree, M_IOV); 313 out: 314 FILE_UNUSE(fp, l); 315 return (error); 316 } 317 318 int 319 netbsd32_utimes(l, v, retval) 320 struct lwp *l; 321 void *v; 322 register_t *retval; 323 { 324 struct netbsd32_utimes_args /* { 325 syscallarg(const netbsd32_charp) path; 326 syscallarg(const netbsd32_timevalp_t) tptr; 327 } */ *uap = v; 328 int error; 329 struct nameidata nd; 330 331 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, 332 (char *)NETBSD32PTR64(SCARG(uap, path)), l); 333 if ((error = namei(&nd)) != 0) 334 return (error); 335 336 error = change_utimes32(nd.ni_vp, SCARG(uap, tptr), l); 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, l) 347 struct vnode *vp; 348 netbsd32_timevalp_t tptr; 349 struct lwp *l; 350 { 351 struct netbsd32_timeval tv32[2]; 352 struct timeval tv[2]; 353 struct proc *p = l->l_proc; 354 struct vattr vattr; 355 int error; 356 357 VATTR_NULL(&vattr); 358 if (tptr == 0) { 359 microtime(&tv[0]); 360 tv[1] = tv[0]; 361 vattr.va_vaflags |= VA_UTIMES_NULL; 362 } else { 363 error = copyin((caddr_t)NETBSD32PTR64(tptr), tv32, 364 sizeof(tv32)); 365 if (error) 366 return (error); 367 netbsd32_to_timeval(&tv32[0], &tv[0]); 368 netbsd32_to_timeval(&tv32[1], &tv[1]); 369 } 370 VOP_LEASE(vp, l, p->p_ucred, LEASE_WRITE); 371 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 372 vattr.va_atime.tv_sec = tv[0].tv_sec; 373 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; 374 vattr.va_mtime.tv_sec = tv[1].tv_sec; 375 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; 376 error = VOP_SETATTR(vp, &vattr, p->p_ucred, l); 377 VOP_UNLOCK(vp, 0); 378 return (error); 379 } 380 381 int 382 netbsd32_statvfs1(l, v, retval) 383 struct lwp *l; 384 void *v; 385 register_t *retval; 386 { 387 struct netbsd32_statvfs1_args /* { 388 syscallarg(const netbsd32_charp) path; 389 syscallarg(netbsd32_statvfsp_t) buf; 390 syscallarg(int) flags; 391 } */ *uap = v; 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)), l); 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, l, 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, l, 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, l); 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, l, 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, l, 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, l, 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), l); 614 FILE_UNUSE(fp, l); 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, l, 0, 0); 642 *retval = done; 643 out: 644 FILE_UNUSE(fp, l); 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 661 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, 662 (caddr_t)NETBSD32PTR64(SCARG(uap, path)), l); 663 if ((error = namei(&nd)) != 0) 664 return (error); 665 666 error = change_utimes32(nd.ni_vp, SCARG(uap, tptr), l); 667 668 vrele(nd.ni_vp); 669 return (error); 670 } 671 672 int 673 netbsd32_sys___stat30(l, v, retval) 674 struct lwp *l; 675 void *v; 676 register_t *retval; 677 { 678 struct netbsd32_sys___stat30_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(l, &sg, path); 693 694 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, path, l); 695 if ((error = namei(&nd)) != 0) 696 return (error); 697 error = vn_stat(nd.ni_vp, &sb, l); 698 vput(nd.ni_vp); 699 if (error) 700 return (error); 701 netbsd32_from___stat30(&sb, &sb32); 702 error = copyout(&sb32, (caddr_t)NETBSD32PTR64(SCARG(uap, ub)), 703 sizeof(sb32)); 704 return (error); 705 } 706 707 int 708 netbsd32_sys___fstat30(l, v, retval) 709 struct lwp *l; 710 void *v; 711 register_t *retval; 712 { 713 struct netbsd32_sys___fstat30_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, l); 730 FILE_UNUSE(fp, l); 731 732 if (error == 0) { 733 netbsd32_from___stat30(&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_sys___lstat30(l, v, retval) 742 struct lwp *l; 743 void *v; 744 register_t *retval; 745 { 746 struct netbsd32_sys___lstat30_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(l, &sg, path); 761 762 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, path, l); 763 if ((error = namei(&nd)) != 0) 764 return (error); 765 error = vn_stat(nd.ni_vp, &sb, l); 766 vput(nd.ni_vp); 767 if (error) 768 return (error); 769 netbsd32_from___stat30(&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(l, fd, fp, 819 (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)), 820 SCARG(uap, iovcnt), &offset, 0, retval)); 821 822 out: 823 FILE_UNUSE(fp, l); 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(l, fd, fp, 871 (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)), 872 SCARG(uap, iovcnt), &offset, 0, retval)); 873 874 out: 875 FILE_UNUSE(fp, l); 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 /* XXX NH Why does this exist */ 886 int 887 getcwd_common __P((struct vnode *, struct vnode *, 888 char **, char *, int, int, struct lwp *)); 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, l); 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