1 /* $NetBSD: netbsd32_fs.c,v 1.33 2006/08/04 16:29:51 yamt 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.33 2006/08/04 16:29:51 yamt 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 #include <sys/kauth.h> 58 59 #include <compat/netbsd32/netbsd32.h> 60 #include <compat/netbsd32/netbsd32_syscallargs.h> 61 #include <compat/netbsd32/netbsd32_conv.h> 62 #include <compat/sys/mount.h> 63 64 65 static int dofilereadv32 __P((struct lwp *, int, struct file *, struct netbsd32_iovec *, 66 int, off_t *, int, register_t *)); 67 static int dofilewritev32 __P((struct lwp *, int, struct file *, struct netbsd32_iovec *, 68 int, off_t *, int, register_t *)); 69 static int change_utimes32 __P((struct vnode *, netbsd32_timevalp_t, struct lwp *)); 70 71 int 72 netbsd32_readv(l, v, retval) 73 struct lwp *l; 74 void *v; 75 register_t *retval; 76 { 77 struct netbsd32_readv_args /* { 78 syscallarg(int) fd; 79 syscallarg(const netbsd32_iovecp_t) iovp; 80 syscallarg(int) iovcnt; 81 } */ *uap = v; 82 int fd = SCARG(uap, fd); 83 struct proc *p = l->l_proc; 84 struct file *fp; 85 struct filedesc *fdp = p->p_fd; 86 87 if ((fp = fd_getfile(fdp, fd)) == NULL) 88 return (EBADF); 89 90 if ((fp->f_flag & FREAD) == 0) 91 return (EBADF); 92 93 FILE_USE(fp); 94 95 return (dofilereadv32(l, fd, fp, 96 (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)), 97 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval)); 98 } 99 100 /* Damn thing copies in the iovec! */ 101 int 102 dofilereadv32(l, fd, fp, iovp, iovcnt, offset, flags, retval) 103 struct lwp *l; 104 int fd; 105 struct file *fp; 106 struct netbsd32_iovec *iovp; 107 int iovcnt; 108 off_t *offset; 109 int flags; 110 register_t *retval; 111 { 112 struct uio auio; 113 struct iovec *iov; 114 struct iovec *needfree; 115 struct iovec aiov[UIO_SMALLIOV]; 116 long i, cnt, error = 0; 117 u_int iovlen; 118 #ifdef KTRACE 119 struct iovec *ktriov = NULL; 120 #endif 121 122 /* note: can't use iovlen until iovcnt is validated */ 123 iovlen = iovcnt * sizeof(struct iovec); 124 if ((u_int)iovcnt > UIO_SMALLIOV) { 125 if ((u_int)iovcnt > IOV_MAX) { 126 error = EINVAL; 127 goto out; 128 } 129 iov = malloc(iovlen, M_IOV, M_WAITOK); 130 needfree = iov; 131 } else if ((u_int)iovcnt > 0) { 132 iov = aiov; 133 needfree = NULL; 134 } else { 135 error = EINVAL; 136 goto out; 137 } 138 139 auio.uio_iov = iov; 140 auio.uio_iovcnt = iovcnt; 141 auio.uio_rw = UIO_READ; 142 auio.uio_vmspace = l->l_proc->p_vmspace; 143 error = netbsd32_to_iovecin(iovp, iov, iovcnt); 144 if (error) 145 goto done; 146 auio.uio_resid = 0; 147 for (i = 0; i < iovcnt; i++) { 148 auio.uio_resid += iov->iov_len; 149 /* 150 * Reads return ssize_t because -1 is returned on error. 151 * Therefore we must restrict the length to SSIZE_MAX to 152 * avoid garbage return values. 153 */ 154 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { 155 error = EINVAL; 156 goto done; 157 } 158 iov++; 159 } 160 #ifdef KTRACE 161 /* 162 * if tracing, save a copy of iovec 163 */ 164 if (KTRPOINT(l->l_proc, KTR_GENIO)) { 165 ktriov = malloc(iovlen, M_TEMP, M_WAITOK); 166 memcpy((caddr_t)ktriov, (caddr_t)auio.uio_iov, iovlen); 167 } 168 #endif 169 cnt = auio.uio_resid; 170 error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred, flags); 171 if (error) 172 if (auio.uio_resid != cnt && (error == ERESTART || 173 error == EINTR || error == EWOULDBLOCK)) 174 error = 0; 175 cnt -= auio.uio_resid; 176 #ifdef KTRACE 177 if (KTRPOINT(l->l_proc, KTR_GENIO)) 178 if (error == 0) { 179 ktrgenio(l, fd, UIO_READ, ktriov, cnt, 180 error); 181 free(ktriov, M_TEMP); 182 } 183 #endif 184 *retval = cnt; 185 done: 186 if (needfree) 187 free(needfree, M_IOV); 188 out: 189 FILE_UNUSE(fp, l); 190 return (error); 191 } 192 193 int 194 netbsd32_writev(l, v, retval) 195 struct lwp *l; 196 void *v; 197 register_t *retval; 198 { 199 struct netbsd32_writev_args /* { 200 syscallarg(int) fd; 201 syscallarg(const netbsd32_iovecp_t) iovp; 202 syscallarg(int) iovcnt; 203 } */ *uap = v; 204 int fd = SCARG(uap, fd); 205 struct file *fp; 206 struct proc *p = l->l_proc; 207 struct filedesc *fdp = p->p_fd; 208 209 if ((fp = fd_getfile(fdp, fd)) == NULL) 210 return (EBADF); 211 212 if ((fp->f_flag & FWRITE) == 0) 213 return (EBADF); 214 215 FILE_USE(fp); 216 217 return (dofilewritev32(l, fd, fp, 218 (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)), 219 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval)); 220 } 221 222 int 223 dofilewritev32(l, fd, fp, iovp, iovcnt, offset, flags, retval) 224 struct lwp *l; 225 int fd; 226 struct file *fp; 227 struct netbsd32_iovec *iovp; 228 int iovcnt; 229 off_t *offset; 230 int flags; 231 register_t *retval; 232 { 233 struct uio auio; 234 struct iovec *iov; 235 struct iovec *needfree; 236 struct iovec aiov[UIO_SMALLIOV]; 237 struct proc *p = l->l_proc; 238 long i, cnt, error = 0; 239 u_int iovlen; 240 #ifdef KTRACE 241 struct iovec *ktriov = NULL; 242 #endif 243 244 /* note: can't use iovlen until iovcnt is validated */ 245 iovlen = iovcnt * sizeof(struct iovec); 246 if ((u_int)iovcnt > UIO_SMALLIOV) { 247 if ((u_int)iovcnt > IOV_MAX) { 248 error = EINVAL; 249 goto out; 250 } 251 iov = malloc(iovlen, M_IOV, M_WAITOK); 252 needfree = iov; 253 } else if ((u_int)iovcnt > 0) { 254 iov = aiov; 255 needfree = NULL; 256 } else { 257 error = EINVAL; 258 goto out; 259 } 260 261 auio.uio_iov = iov; 262 auio.uio_iovcnt = iovcnt; 263 auio.uio_rw = UIO_WRITE; 264 auio.uio_vmspace = l->l_proc->p_vmspace; 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 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, l, l->l_cred, 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, l->l_cred, l); 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 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)), l); 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, l, 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, l, 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, l); 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 sbuf = (struct statvfs *)malloc(sizeof(struct statvfs), M_TEMP, 480 M_WAITOK); 481 s32 = (struct netbsd32_statvfs *) 482 malloc(sizeof(struct netbsd32_statvfs), M_TEMP, M_WAITOK); 483 simple_lock(&mountlist_slock); 484 count = 0; 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, l, 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, l, 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___fhstatvfs140(l, v, retval) 540 struct lwp *l; 541 void *v; 542 register_t *retval; 543 { 544 struct netbsd32___fhstatvfs140_args /* { 545 syscallarg(const netbsd32_pointer_t) fhp; 546 syscallarg(netbsd32_size_t) fh_size; 547 syscallarg(netbsd32_statvfsp_t) buf; 548 syscallarg(int) flags; 549 } */ *uap = v; 550 struct statvfs *sbuf; 551 struct netbsd32_statvfs *s32; 552 fhandle_t *fh; 553 struct vnode *vp; 554 int error; 555 556 /* 557 * Must be super user 558 */ 559 if ((error = kauth_authorize_generic(l->l_cred, 560 KAUTH_GENERIC_ISSUSER, &l->l_acflag)) != 0) 561 return error; 562 563 if ((error = vfs_copyinfh_alloc(NETBSD32PTR64(SCARG(uap, fhp)), 564 SCARG(uap, fh_size), &fh)) != 0) 565 goto bad; 566 if ((error = vfs_fhtovp(fh, &vp)) != 0) 567 goto bad; 568 569 sbuf = (struct statvfs *)malloc(sizeof(struct statvfs), M_TEMP, 570 M_WAITOK); 571 error = dostatvfs(vp->v_mount, sbuf, l, SCARG(uap, flags), 1); 572 vput(vp); 573 if (error != 0) 574 goto out; 575 576 s32 = (struct netbsd32_statvfs *) 577 malloc(sizeof(struct netbsd32_statvfs), M_TEMP, M_WAITOK); 578 netbsd32_from_statvfs(sbuf, s32); 579 error = copyout(s32, (caddr_t)NETBSD32PTR64(SCARG(uap, buf)), 580 sizeof(struct netbsd32_statvfs)); 581 free(s32, M_TEMP); 582 583 out: 584 free(sbuf, M_TEMP); 585 bad: 586 vfs_copyinfh_free(fh); 587 return (error); 588 } 589 590 int 591 netbsd32_futimes(l, v, retval) 592 struct lwp *l; 593 void *v; 594 register_t *retval; 595 { 596 struct netbsd32_futimes_args /* { 597 syscallarg(int) fd; 598 syscallarg(const netbsd32_timevalp_t) tptr; 599 } */ *uap = v; 600 int error; 601 struct file *fp; 602 struct proc *p = l->l_proc; 603 604 /* getvnode() will use the descriptor for us */ 605 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 606 return (error); 607 608 error = change_utimes32((struct vnode *)fp->f_data, 609 SCARG(uap, tptr), l); 610 FILE_UNUSE(fp, l); 611 return (error); 612 } 613 614 int 615 netbsd32_sys___getdents30(l, v, retval) 616 struct lwp *l; 617 void *v; 618 register_t *retval; 619 { 620 struct netbsd32_sys___getdents30_args /* { 621 syscallarg(int) fd; 622 syscallarg(netbsd32_charp) buf; 623 syscallarg(netbsd32_size_t) count; 624 } */ *uap = v; 625 struct file *fp; 626 int error, done; 627 struct proc *p = l->l_proc; 628 629 /* getvnode() will use the descriptor for us */ 630 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 631 return (error); 632 if ((fp->f_flag & FREAD) == 0) { 633 error = EBADF; 634 goto out; 635 } 636 error = vn_readdir(fp, (caddr_t)NETBSD32PTR64(SCARG(uap, buf)), 637 UIO_USERSPACE, SCARG(uap, count), &done, l, 0, 0); 638 *retval = done; 639 out: 640 FILE_UNUSE(fp, l); 641 return (error); 642 } 643 644 int 645 netbsd32_lutimes(l, v, retval) 646 struct lwp *l; 647 void *v; 648 register_t *retval; 649 { 650 struct netbsd32_lutimes_args /* { 651 syscallarg(const netbsd32_charp) path; 652 syscallarg(const netbsd32_timevalp_t) tptr; 653 } */ *uap = v; 654 int error; 655 struct nameidata nd; 656 657 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, 658 (caddr_t)NETBSD32PTR64(SCARG(uap, path)), l); 659 if ((error = namei(&nd)) != 0) 660 return (error); 661 662 error = change_utimes32(nd.ni_vp, SCARG(uap, tptr), l); 663 664 vrele(nd.ni_vp); 665 return (error); 666 } 667 668 int 669 netbsd32_sys___stat30(l, v, retval) 670 struct lwp *l; 671 void *v; 672 register_t *retval; 673 { 674 struct netbsd32_sys___stat30_args /* { 675 syscallarg(const netbsd32_charp) path; 676 syscallarg(netbsd32_statp_t) ub; 677 } */ *uap = v; 678 struct netbsd32_stat sb32; 679 struct stat sb; 680 int error; 681 struct nameidata nd; 682 caddr_t sg; 683 const char *path; 684 struct proc *p = l->l_proc; 685 686 path = (char *)NETBSD32PTR64(SCARG(uap, path)); 687 sg = stackgap_init(p, 0); 688 CHECK_ALT_EXIST(l, &sg, path); 689 690 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, path, l); 691 if ((error = namei(&nd)) != 0) 692 return (error); 693 error = vn_stat(nd.ni_vp, &sb, l); 694 vput(nd.ni_vp); 695 if (error) 696 return (error); 697 netbsd32_from___stat30(&sb, &sb32); 698 error = copyout(&sb32, (caddr_t)NETBSD32PTR64(SCARG(uap, ub)), 699 sizeof(sb32)); 700 return (error); 701 } 702 703 int 704 netbsd32_sys___fstat30(l, v, retval) 705 struct lwp *l; 706 void *v; 707 register_t *retval; 708 { 709 struct netbsd32_sys___fstat30_args /* { 710 syscallarg(int) fd; 711 syscallarg(netbsd32_statp_t) sb; 712 } */ *uap = v; 713 int fd = SCARG(uap, fd); 714 struct proc *p = l->l_proc; 715 struct filedesc *fdp = p->p_fd; 716 struct file *fp; 717 struct netbsd32_stat sb32; 718 struct stat ub; 719 int error = 0; 720 721 if ((fp = fd_getfile(fdp, fd)) == NULL) 722 return (EBADF); 723 724 FILE_USE(fp); 725 error = (*fp->f_ops->fo_stat)(fp, &ub, l); 726 FILE_UNUSE(fp, l); 727 728 if (error == 0) { 729 netbsd32_from___stat30(&ub, &sb32); 730 error = copyout(&sb32, (caddr_t)NETBSD32PTR64(SCARG(uap, sb)), 731 sizeof(sb32)); 732 } 733 return (error); 734 } 735 736 int 737 netbsd32_sys___lstat30(l, v, retval) 738 struct lwp *l; 739 void *v; 740 register_t *retval; 741 { 742 struct netbsd32_sys___lstat30_args /* { 743 syscallarg(const netbsd32_charp) path; 744 syscallarg(netbsd32_statp_t) ub; 745 } */ *uap = v; 746 struct netbsd32_stat sb32; 747 struct stat sb; 748 int error; 749 struct nameidata nd; 750 caddr_t sg; 751 const char *path; 752 struct proc *p = l->l_proc; 753 754 path = (char *)NETBSD32PTR64(SCARG(uap, path)); 755 sg = stackgap_init(p, 0); 756 CHECK_ALT_EXIST(l, &sg, path); 757 758 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, path, l); 759 if ((error = namei(&nd)) != 0) 760 return (error); 761 error = vn_stat(nd.ni_vp, &sb, l); 762 vput(nd.ni_vp); 763 if (error) 764 return (error); 765 netbsd32_from___stat30(&sb, &sb32); 766 error = copyout(&sb32, (caddr_t)NETBSD32PTR64(SCARG(uap, ub)), 767 sizeof(sb32)); 768 return (error); 769 } 770 771 int netbsd32___fhstat40(l, v, retval) 772 struct lwp *l; 773 void *v; 774 register_t *retval; 775 { 776 struct netbsd32___fhstat40_args /* { 777 syscallarg(const netbsd32_pointer_t) fhp; 778 syscallarg(netbsd32_size_t) fh_size; 779 syscallarg(netbsd32_statp_t) sb; 780 } */ *uap = v; 781 struct stat sb; 782 struct netbsd32_stat sb32; 783 int error; 784 fhandle_t *fh; 785 struct vnode *vp; 786 787 /* 788 * Must be super user 789 */ 790 if ((error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, 791 &l->l_acflag))) 792 return error; 793 794 if ((error = vfs_copyinfh_alloc(NETBSD32PTR64(SCARG(uap, fhp)), 795 SCARG(uap, fh_size), &fh)) != 0) 796 goto bad; 797 798 if ((error = vfs_fhtovp(fh, &vp)) != 0) 799 goto bad; 800 801 error = vn_stat(vp, &sb, l); 802 vput(vp); 803 if (error) 804 goto bad; 805 netbsd32_from___stat30(&sb, &sb32); 806 error = copyout(&sb32, NETBSD32PTR64(SCARG(uap, sb)), sizeof(sb)); 807 bad: 808 vfs_copyinfh_free(fh); 809 return error; 810 } 811 812 int 813 netbsd32_preadv(l, v, retval) 814 struct lwp *l; 815 void *v; 816 register_t *retval; 817 { 818 struct netbsd32_preadv_args /* { 819 syscallarg(int) fd; 820 syscallarg(const netbsd32_iovecp_t) iovp; 821 syscallarg(int) iovcnt; 822 syscallarg(int) pad; 823 syscallarg(off_t) offset; 824 } */ *uap = v; 825 struct proc *p = l->l_proc; 826 struct filedesc *fdp = p->p_fd; 827 struct file *fp; 828 struct vnode *vp; 829 off_t offset; 830 int error, fd = SCARG(uap, fd); 831 832 if ((fp = fd_getfile(fdp, fd)) == NULL) 833 return (EBADF); 834 835 if ((fp->f_flag & FREAD) == 0) 836 return (EBADF); 837 838 FILE_USE(fp); 839 840 vp = (struct vnode *)fp->f_data; 841 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 842 error = ESPIPE; 843 goto out; 844 } 845 846 offset = SCARG(uap, offset); 847 848 /* 849 * XXX This works because no file systems actually 850 * XXX take any action on the seek operation. 851 */ 852 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0) 853 goto out; 854 855 return (dofilereadv32(l, fd, fp, 856 (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)), 857 SCARG(uap, iovcnt), &offset, 0, retval)); 858 859 out: 860 FILE_UNUSE(fp, l); 861 return (error); 862 } 863 864 int 865 netbsd32_pwritev(l, v, retval) 866 struct lwp *l; 867 void *v; 868 register_t *retval; 869 { 870 struct netbsd32_pwritev_args /* { 871 syscallarg(int) fd; 872 syscallarg(const netbsd32_iovecp_t) iovp; 873 syscallarg(int) iovcnt; 874 syscallarg(int) pad; 875 syscallarg(off_t) offset; 876 } */ *uap = v; 877 struct proc *p = l->l_proc; 878 struct filedesc *fdp = p->p_fd; 879 struct file *fp; 880 struct vnode *vp; 881 off_t offset; 882 int error, fd = SCARG(uap, fd); 883 884 if ((fp = fd_getfile(fdp, fd)) == NULL) 885 return (EBADF); 886 887 if ((fp->f_flag & FWRITE) == 0) 888 return (EBADF); 889 890 FILE_USE(fp); 891 892 vp = (struct vnode *)fp->f_data; 893 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 894 error = ESPIPE; 895 goto out; 896 } 897 898 offset = SCARG(uap, offset); 899 900 /* 901 * XXX This works because no file systems actually 902 * XXX take any action on the seek operation. 903 */ 904 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0) 905 goto out; 906 907 return (dofilewritev32(l, fd, fp, 908 (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)), 909 SCARG(uap, iovcnt), &offset, 0, retval)); 910 911 out: 912 FILE_UNUSE(fp, l); 913 return (error); 914 } 915 916 /* 917 * Find pathname of process's current directory. 918 * 919 * Use vfs vnode-to-name reverse cache; if that fails, fall back 920 * to reading directory contents. 921 */ 922 /* XXX NH Why does this exist */ 923 int 924 getcwd_common __P((struct vnode *, struct vnode *, 925 char **, char *, int, int, struct lwp *)); 926 927 int netbsd32___getcwd(l, v, retval) 928 struct lwp *l; 929 void *v; 930 register_t *retval; 931 { 932 struct netbsd32___getcwd_args /* { 933 syscallarg(char *) bufp; 934 syscallarg(size_t) length; 935 } */ *uap = v; 936 struct proc *p = l->l_proc; 937 int error; 938 char *path; 939 char *bp, *bend; 940 int len = (int)SCARG(uap, length); 941 int lenused; 942 943 if (len > MAXPATHLEN*4) 944 len = MAXPATHLEN*4; 945 else if (len < 2) 946 return ERANGE; 947 948 path = (char *)malloc(len, M_TEMP, M_WAITOK); 949 if (!path) 950 return ENOMEM; 951 952 bp = &path[len]; 953 bend = bp; 954 *(--bp) = '\0'; 955 956 /* 957 * 5th argument here is "max number of vnodes to traverse". 958 * Since each entry takes up at least 2 bytes in the output buffer, 959 * limit it to N/2 vnodes for an N byte buffer. 960 */ 961 #define GETCWD_CHECK_ACCESS 0x0001 962 error = getcwd_common (p->p_cwdi->cwdi_cdir, NULL, &bp, path, len/2, 963 GETCWD_CHECK_ACCESS, l); 964 965 if (error) 966 goto out; 967 lenused = bend - bp; 968 *retval = lenused; 969 /* put the result into user buffer */ 970 error = copyout(bp, (caddr_t)NETBSD32PTR64(SCARG(uap, bufp)), lenused); 971 972 out: 973 free(path, M_TEMP); 974 return error; 975 } 976