1 /* $NetBSD: netbsd32_fs.c,v 1.58 2009/12/14 00:47:11 matt 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: netbsd32_fs.c,v 1.58 2009/12/14 00:47:11 matt Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/malloc.h> 35 #include <sys/mount.h> 36 #include <sys/socket.h> 37 #include <sys/socketvar.h> 38 #include <sys/stat.h> 39 #include <sys/time.h> 40 #include <sys/ktrace.h> 41 #include <sys/resourcevar.h> 42 #include <sys/vnode.h> 43 #include <sys/file.h> 44 #include <sys/filedesc.h> 45 #include <sys/namei.h> 46 #include <sys/statvfs.h> 47 #include <sys/syscallargs.h> 48 #include <sys/proc.h> 49 #include <sys/dirent.h> 50 #include <sys/kauth.h> 51 #include <sys/vfs_syscalls.h> 52 53 #include <fs/cd9660/cd9660_mount.h> 54 #include <ufs/ufs/ufsmount.h> 55 56 #include <compat/netbsd32/netbsd32.h> 57 #include <compat/netbsd32/netbsd32_syscallargs.h> 58 #include <compat/netbsd32/netbsd32_conv.h> 59 #include <compat/sys/mount.h> 60 61 62 static int dofilereadv32(int, struct file *, struct netbsd32_iovec *, 63 int, off_t *, int, register_t *); 64 static int dofilewritev32(int, struct file *, struct netbsd32_iovec *, 65 int, off_t *, int, register_t *); 66 67 struct iovec * 68 netbsd32_get_iov(struct netbsd32_iovec *iov32, int iovlen, struct iovec *aiov, 69 int aiov_len) 70 { 71 #define N_IOV32 8 72 struct netbsd32_iovec aiov32[N_IOV32]; 73 struct iovec *iov = aiov; 74 struct iovec *iovp; 75 int i, n, j; 76 int error; 77 78 if (iovlen < 0 || iovlen > IOV_MAX) 79 return NULL; 80 81 if (iovlen > aiov_len) 82 iov = malloc(iovlen * sizeof (*iov), M_TEMP, M_WAITOK); 83 84 iovp = iov; 85 for (i = 0; i < iovlen; iov32 += N_IOV32, i += N_IOV32) { 86 n = iovlen - i; 87 if (n > N_IOV32) 88 n = N_IOV32; 89 error = copyin(iov32, aiov32, n * sizeof (*iov32)); 90 if (error != 0) { 91 if (iov != aiov) 92 free(iov, M_TEMP); 93 return NULL; 94 } 95 for (j = 0; j < n; iovp++, j++) { 96 iovp->iov_base = NETBSD32PTR64(aiov32[j].iov_base); 97 iovp->iov_len = aiov32[j].iov_len; 98 } 99 } 100 return iov; 101 #undef N_IOV32 102 } 103 104 int 105 netbsd32_readv(struct lwp *l, const struct netbsd32_readv_args *uap, register_t *retval) 106 { 107 /* { 108 syscallarg(int) fd; 109 syscallarg(const netbsd32_iovecp_t) iovp; 110 syscallarg(int) iovcnt; 111 } */ 112 int fd = SCARG(uap, fd); 113 file_t *fp; 114 115 if ((fp = fd_getfile(fd)) == NULL) 116 return (EBADF); 117 118 if ((fp->f_flag & FREAD) == 0) { 119 fd_putfile(fd); 120 return (EBADF); 121 } 122 123 return (dofilereadv32(fd, fp, 124 (struct netbsd32_iovec *)SCARG_P32(uap, iovp), 125 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval)); 126 } 127 128 /* Damn thing copies in the iovec! */ 129 int 130 dofilereadv32(int fd, struct file *fp, struct netbsd32_iovec *iovp, int iovcnt, off_t *offset, int flags, register_t *retval) 131 { 132 struct uio auio; 133 struct iovec *iov; 134 struct iovec *needfree; 135 struct iovec aiov[UIO_SMALLIOV]; 136 long i, cnt, error = 0; 137 u_int iovlen; 138 struct iovec *ktriov = NULL; 139 140 /* note: can't use iovlen until iovcnt is validated */ 141 iovlen = iovcnt * sizeof(struct iovec); 142 if ((u_int)iovcnt > UIO_SMALLIOV) { 143 if ((u_int)iovcnt > IOV_MAX) { 144 error = EINVAL; 145 goto out; 146 } 147 iov = malloc(iovlen, M_IOV, M_WAITOK); 148 needfree = iov; 149 } else if ((u_int)iovcnt > 0) { 150 iov = aiov; 151 needfree = NULL; 152 } else { 153 error = EINVAL; 154 goto out; 155 } 156 157 auio.uio_iov = iov; 158 auio.uio_iovcnt = iovcnt; 159 auio.uio_rw = UIO_READ; 160 auio.uio_vmspace = curproc->p_vmspace; 161 error = netbsd32_to_iovecin(iovp, iov, iovcnt); 162 if (error) 163 goto done; 164 auio.uio_resid = 0; 165 for (i = 0; i < iovcnt; i++) { 166 auio.uio_resid += iov->iov_len; 167 /* 168 * Reads return ssize_t because -1 is returned on error. 169 * Therefore we must restrict the length to SSIZE_MAX to 170 * avoid garbage return values. 171 */ 172 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { 173 error = EINVAL; 174 goto done; 175 } 176 iov++; 177 } 178 179 /* 180 * if tracing, save a copy of iovec 181 */ 182 if (ktrpoint(KTR_GENIO)) { 183 ktriov = malloc(iovlen, M_TEMP, M_WAITOK); 184 memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen); 185 } 186 187 cnt = auio.uio_resid; 188 error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred, flags); 189 if (error) 190 if (auio.uio_resid != cnt && (error == ERESTART || 191 error == EINTR || error == EWOULDBLOCK)) 192 error = 0; 193 cnt -= auio.uio_resid; 194 195 if (ktriov != NULL) { 196 ktrgeniov(fd, UIO_READ, ktriov, cnt, error); 197 free(ktriov, M_TEMP); 198 } 199 200 *retval = cnt; 201 done: 202 if (needfree) 203 free(needfree, M_IOV); 204 out: 205 fd_putfile(fd); 206 return (error); 207 } 208 209 int 210 netbsd32_writev(struct lwp *l, const struct netbsd32_writev_args *uap, register_t *retval) 211 { 212 /* { 213 syscallarg(int) fd; 214 syscallarg(const netbsd32_iovecp_t) iovp; 215 syscallarg(int) iovcnt; 216 } */ 217 int fd = SCARG(uap, fd); 218 file_t *fp; 219 220 if ((fp = fd_getfile(fd)) == NULL) 221 return (EBADF); 222 223 if ((fp->f_flag & FWRITE) == 0) { 224 fd_putfile(fd); 225 return (EBADF); 226 } 227 228 return (dofilewritev32(fd, fp, 229 (struct netbsd32_iovec *)SCARG_P32(uap, iovp), 230 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval)); 231 } 232 233 int 234 dofilewritev32(int fd, struct file *fp, struct netbsd32_iovec *iovp, int iovcnt, off_t *offset, int flags, register_t *retval) 235 { 236 struct uio auio; 237 struct iovec *iov; 238 struct iovec *needfree; 239 struct iovec aiov[UIO_SMALLIOV]; 240 long i, cnt, error = 0; 241 u_int iovlen; 242 struct iovec *ktriov = NULL; 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 = curproc->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 283 /* 284 * if tracing, save a copy of iovec 285 */ 286 if (ktrpoint(KTR_GENIO)) { 287 ktriov = malloc(iovlen, M_TEMP, M_WAITOK); 288 memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen); 289 } 290 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 mutex_enter(proc_lock); 299 psignal(curproc, SIGPIPE); 300 mutex_exit(proc_lock); 301 } 302 } 303 cnt -= auio.uio_resid; 304 if (ktriov != NULL) { 305 ktrgenio(fd, UIO_WRITE, ktriov, cnt, error); 306 free(ktriov, M_TEMP); 307 } 308 *retval = cnt; 309 done: 310 if (needfree) 311 free(needfree, M_IOV); 312 out: 313 fd_putfile(fd); 314 return (error); 315 } 316 317 /* 318 * Common routine to set access and modification times given a vnode. 319 */ 320 static int 321 get_utimes32(const netbsd32_timevalp_t *tptr, struct timeval *tv, 322 struct timeval **tvp) 323 { 324 int error; 325 struct netbsd32_timeval tv32[2]; 326 327 if (tptr == NULL) { 328 *tvp = NULL; 329 return 0; 330 } 331 332 error = copyin(tptr, tv32, sizeof(tv32)); 333 if (error) 334 return error; 335 netbsd32_to_timeval(&tv32[0], &tv[0]); 336 netbsd32_to_timeval(&tv32[1], &tv[1]); 337 338 *tvp = tv; 339 return 0; 340 } 341 342 int 343 netbsd32___utimes50(struct lwp *l, const struct netbsd32___utimes50_args *uap, register_t *retval) 344 { 345 /* { 346 syscallarg(const netbsd32_charp) path; 347 syscallarg(const netbsd32_timevalp_t) tptr; 348 } */ 349 int error; 350 struct timeval tv[2], *tvp; 351 352 error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp); 353 if (error != 0) 354 return error; 355 356 return do_sys_utimes(l, NULL, SCARG_P32(uap, path), FOLLOW, 357 tvp, UIO_SYSSPACE); 358 } 359 360 static int 361 netbds32_copyout_statvfs(const void *kp, void *up, size_t len) 362 { 363 struct netbsd32_statvfs *sbuf_32; 364 int error; 365 366 sbuf_32 = malloc(sizeof *sbuf_32, M_TEMP, M_WAITOK); 367 netbsd32_from_statvfs(kp, sbuf_32); 368 error = copyout(sbuf_32, up, sizeof(*sbuf_32)); 369 free(sbuf_32, M_TEMP); 370 371 return error; 372 } 373 374 int 375 netbsd32_statvfs1(struct lwp *l, const struct netbsd32_statvfs1_args *uap, register_t *retval) 376 { 377 /* { 378 syscallarg(const netbsd32_charp) path; 379 syscallarg(netbsd32_statvfsp_t) buf; 380 syscallarg(int) flags; 381 } */ 382 struct statvfs *sb; 383 int error; 384 385 sb = STATVFSBUF_GET(); 386 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), SCARG(uap, flags), sb); 387 if (error == 0) 388 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0); 389 STATVFSBUF_PUT(sb); 390 return error; 391 } 392 393 int 394 netbsd32_fstatvfs1(struct lwp *l, const struct netbsd32_fstatvfs1_args *uap, register_t *retval) 395 { 396 /* { 397 syscallarg(int) fd; 398 syscallarg(netbsd32_statvfsp_t) buf; 399 syscallarg(int) flags; 400 } */ 401 struct statvfs *sb; 402 int error; 403 404 sb = STATVFSBUF_GET(); 405 error = do_sys_fstatvfs(l, SCARG(uap, fd), SCARG(uap, flags), sb); 406 if (error == 0) 407 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0); 408 STATVFSBUF_PUT(sb); 409 return error; 410 } 411 412 int 413 netbsd32_getvfsstat(struct lwp *l, const struct netbsd32_getvfsstat_args *uap, register_t *retval) 414 { 415 /* { 416 syscallarg(netbsd32_statvfsp_t) buf; 417 syscallarg(netbsd32_size_t) bufsize; 418 syscallarg(int) flags; 419 } */ 420 421 return do_sys_getvfsstat(l, SCARG_P32(uap, buf), SCARG(uap, bufsize), 422 SCARG(uap, flags), netbds32_copyout_statvfs, 423 sizeof (struct netbsd32_statvfs), retval); 424 } 425 426 int 427 netbsd32___fhstatvfs140(struct lwp *l, const struct netbsd32___fhstatvfs140_args *uap, register_t *retval) 428 { 429 /* { 430 syscallarg(const netbsd32_pointer_t) fhp; 431 syscallarg(netbsd32_size_t) fh_size; 432 syscallarg(netbsd32_statvfsp_t) buf; 433 syscallarg(int) flags; 434 } */ 435 struct statvfs *sb; 436 int error; 437 438 sb = STATVFSBUF_GET(); 439 error = do_fhstatvfs(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), sb, 440 SCARG(uap, flags)); 441 442 if (error == 0) 443 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0); 444 STATVFSBUF_PUT(sb); 445 446 return error; 447 } 448 449 int 450 netbsd32___futimes50(struct lwp *l, const struct netbsd32___futimes50_args *uap, register_t *retval) 451 { 452 /* { 453 syscallarg(int) fd; 454 syscallarg(const netbsd32_timevalp_t) tptr; 455 } */ 456 int error; 457 file_t *fp; 458 struct timeval tv[2], *tvp; 459 460 error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp); 461 if (error != 0) 462 return error; 463 464 /* fd_getvnode() will use the descriptor for us */ 465 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 466 return (error); 467 468 error = do_sys_utimes(l, fp->f_data, NULL, 0, tvp, UIO_SYSSPACE); 469 470 fd_putfile(SCARG(uap, fd)); 471 return (error); 472 } 473 474 int 475 netbsd32___getdents30(struct lwp *l, 476 const struct netbsd32___getdents30_args *uap, register_t *retval) 477 { 478 /* { 479 syscallarg(int) fd; 480 syscallarg(netbsd32_charp) buf; 481 syscallarg(netbsd32_size_t) count; 482 } */ 483 file_t *fp; 484 int error, done; 485 486 /* fd_getvnode() will use the descriptor for us */ 487 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 488 return (error); 489 if ((fp->f_flag & FREAD) == 0) { 490 error = EBADF; 491 goto out; 492 } 493 error = vn_readdir(fp, SCARG_P32(uap, buf), 494 UIO_USERSPACE, SCARG(uap, count), &done, l, 0, 0); 495 *retval = done; 496 out: 497 fd_putfile(SCARG(uap, fd)); 498 return (error); 499 } 500 501 int 502 netbsd32___lutimes50(struct lwp *l, 503 const struct netbsd32___lutimes50_args *uap, register_t *retval) 504 { 505 /* { 506 syscallarg(const netbsd32_charp) path; 507 syscallarg(const netbsd32_timevalp_t) tptr; 508 } */ 509 int error; 510 struct timeval tv[2], *tvp; 511 512 error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp); 513 if (error != 0) 514 return error; 515 516 return do_sys_utimes(l, NULL, SCARG_P32(uap, path), NOFOLLOW, 517 tvp, UIO_SYSSPACE); 518 } 519 520 int 521 netbsd32___stat50(struct lwp *l, const struct netbsd32___stat50_args *uap, register_t *retval) 522 { 523 /* { 524 syscallarg(const netbsd32_charp) path; 525 syscallarg(netbsd32_statp_t) ub; 526 } */ 527 struct netbsd32_stat sb32; 528 struct stat sb; 529 int error; 530 const char *path; 531 532 path = SCARG_P32(uap, path); 533 534 error = do_sys_stat(path, FOLLOW, &sb); 535 if (error) 536 return (error); 537 netbsd32_from_stat(&sb, &sb32); 538 error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32)); 539 return (error); 540 } 541 542 int 543 netbsd32___fstat50(struct lwp *l, const struct netbsd32___fstat50_args *uap, register_t *retval) 544 { 545 /* { 546 syscallarg(int) fd; 547 syscallarg(netbsd32_statp_t) sb; 548 } */ 549 struct netbsd32_stat sb32; 550 struct stat ub; 551 int error; 552 553 error = do_sys_fstat(SCARG(uap, fd), &ub); 554 if (error == 0) { 555 netbsd32_from_stat(&ub, &sb32); 556 error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb32)); 557 } 558 return (error); 559 } 560 561 int 562 netbsd32___lstat50(struct lwp *l, const struct netbsd32___lstat50_args *uap, register_t *retval) 563 { 564 /* { 565 syscallarg(const netbsd32_charp) path; 566 syscallarg(netbsd32_statp_t) ub; 567 } */ 568 struct netbsd32_stat sb32; 569 struct stat sb; 570 int error; 571 const char *path; 572 573 path = SCARG_P32(uap, path); 574 575 error = do_sys_stat(path, NOFOLLOW, &sb); 576 if (error) 577 return (error); 578 netbsd32_from_stat(&sb, &sb32); 579 error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32)); 580 return (error); 581 } 582 583 int 584 netbsd32___fhstat50(struct lwp *l, const struct netbsd32___fhstat50_args *uap, register_t *retval) 585 { 586 /* { 587 syscallarg(const netbsd32_pointer_t) fhp; 588 syscallarg(netbsd32_size_t) fh_size; 589 syscallarg(netbsd32_statp_t) sb; 590 } */ 591 struct stat sb; 592 struct netbsd32_stat sb32; 593 int error; 594 595 error = do_fhstat(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), &sb); 596 if (error != 0) { 597 netbsd32_from_stat(&sb, &sb32); 598 error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb)); 599 } 600 return error; 601 } 602 603 int 604 netbsd32_preadv(struct lwp *l, const struct netbsd32_preadv_args *uap, register_t *retval) 605 { 606 /* { 607 syscallarg(int) fd; 608 syscallarg(const netbsd32_iovecp_t) iovp; 609 syscallarg(int) iovcnt; 610 syscallarg(int) pad; 611 syscallarg(off_t) offset; 612 } */ 613 file_t *fp; 614 struct vnode *vp; 615 off_t offset; 616 int error, fd = SCARG(uap, fd); 617 618 if ((fp = fd_getfile(fd)) == NULL) 619 return (EBADF); 620 621 if ((fp->f_flag & FREAD) == 0) { 622 fd_putfile(fd); 623 return (EBADF); 624 } 625 626 vp = fp->f_data; 627 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 628 error = ESPIPE; 629 goto out; 630 } 631 632 offset = SCARG(uap, offset); 633 634 /* 635 * XXX This works because no file systems actually 636 * XXX take any action on the seek operation. 637 */ 638 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0) 639 goto out; 640 641 return (dofilereadv32(fd, fp, SCARG_P32(uap, iovp), 642 SCARG(uap, iovcnt), &offset, 0, retval)); 643 644 out: 645 fd_putfile(fd); 646 return (error); 647 } 648 649 int 650 netbsd32_pwritev(struct lwp *l, const struct netbsd32_pwritev_args *uap, register_t *retval) 651 { 652 /* { 653 syscallarg(int) fd; 654 syscallarg(const netbsd32_iovecp_t) iovp; 655 syscallarg(int) iovcnt; 656 syscallarg(int) pad; 657 syscallarg(off_t) offset; 658 } */ 659 file_t *fp; 660 struct vnode *vp; 661 off_t offset; 662 int error, fd = SCARG(uap, fd); 663 664 if ((fp = fd_getfile(fd)) == NULL) 665 return (EBADF); 666 667 if ((fp->f_flag & FWRITE) == 0) { 668 fd_putfile(fd); 669 return (EBADF); 670 } 671 672 vp = fp->f_data; 673 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 674 error = ESPIPE; 675 goto out; 676 } 677 678 offset = SCARG(uap, offset); 679 680 /* 681 * XXX This works because no file systems actually 682 * XXX take any action on the seek operation. 683 */ 684 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0) 685 goto out; 686 687 return (dofilewritev32(fd, fp, SCARG_P32(uap, iovp), 688 SCARG(uap, iovcnt), &offset, 0, retval)); 689 690 out: 691 fd_putfile(fd); 692 return (error); 693 } 694 695 /* 696 * Find pathname of process's current directory. 697 * 698 * Use vfs vnode-to-name reverse cache; if that fails, fall back 699 * to reading directory contents. 700 */ 701 /* XXX NH Why does this exist */ 702 int 703 getcwd_common(struct vnode *, struct vnode *, 704 char **, char *, int, int, struct lwp *); 705 706 int 707 netbsd32___getcwd(struct lwp *l, const struct netbsd32___getcwd_args *uap, register_t *retval) 708 { 709 /* { 710 syscallarg(char *) bufp; 711 syscallarg(size_t) length; 712 } */ 713 struct proc *p = l->l_proc; 714 int error; 715 char *path; 716 char *bp, *bend; 717 int len = (int)SCARG(uap, length); 718 int lenused; 719 struct cwdinfo *cwdi; 720 721 if (len > MAXPATHLEN*4) 722 len = MAXPATHLEN*4; 723 else if (len < 2) 724 return ERANGE; 725 726 path = (char *)malloc(len, M_TEMP, M_WAITOK); 727 if (!path) 728 return ENOMEM; 729 730 bp = &path[len]; 731 bend = bp; 732 *(--bp) = '\0'; 733 734 /* 735 * 5th argument here is "max number of vnodes to traverse". 736 * Since each entry takes up at least 2 bytes in the output buffer, 737 * limit it to N/2 vnodes for an N byte buffer. 738 */ 739 #define GETCWD_CHECK_ACCESS 0x0001 740 cwdi = p->p_cwdi; 741 rw_enter(&cwdi->cwdi_lock, RW_READER); 742 error = getcwd_common (cwdi->cwdi_cdir, NULL, &bp, path, len/2, 743 GETCWD_CHECK_ACCESS, l); 744 rw_exit(&cwdi->cwdi_lock); 745 746 if (error) 747 goto out; 748 lenused = bend - bp; 749 *retval = lenused; 750 /* put the result into user buffer */ 751 error = copyout(bp, SCARG_P32(uap, bufp), lenused); 752 753 out: 754 free(path, M_TEMP); 755 return error; 756 } 757 758 int 759 netbsd32___mount50(struct lwp *l, const struct netbsd32___mount50_args *uap, 760 register_t *retval) 761 { 762 /* { 763 syscallarg(netbsd32_charp) type; 764 syscallarg(netbsd32_charp) path; 765 syscallarg(int) flags; 766 syscallarg(netbsd32_voidp) data; 767 syscallarg(netbsd32_size_t) data_len; 768 } */ 769 char mtype[MNAMELEN]; 770 union { 771 struct netbsd32_ufs_args ufs_args; 772 struct netbsd32_mfs_args mfs_args; 773 struct netbsd32_iso_args iso_args; 774 } fs_args32; 775 union { 776 struct ufs_args ufs_args; 777 struct mfs_args mfs_args; 778 struct iso_args iso_args; 779 } fs_args; 780 const char *type = SCARG_P32(uap, type); 781 const char *path = SCARG_P32(uap, path); 782 int flags = SCARG(uap, flags); 783 void *data = SCARG_P32(uap, data); 784 size_t data_len = SCARG(uap, data_len); 785 enum uio_seg data_seg; 786 size_t len; 787 int error; 788 789 error = copyinstr(type, mtype, sizeof(mtype), &len); 790 if (error) 791 return error; 792 if (strcmp(mtype, MOUNT_MFS) == 0) { 793 if (data_len != sizeof(fs_args32.mfs_args)) 794 return EINVAL; 795 if ((flags & MNT_GETARGS) == 0) { 796 error = copyin(data, &fs_args32.mfs_args, 797 sizeof(fs_args32.mfs_args)); 798 if (error) 799 return error; 800 fs_args.mfs_args.fspec = 801 NETBSD32PTR64(fs_args32.mfs_args.fspec); 802 memset(&fs_args.mfs_args._pad1, 0, 803 sizeof(fs_args.mfs_args._pad1)); 804 fs_args.mfs_args.base = 805 NETBSD32PTR64(fs_args32.mfs_args.base); 806 fs_args.mfs_args.size = fs_args32.mfs_args.size; 807 } 808 data_seg = UIO_SYSSPACE; 809 data = &fs_args.mfs_args; 810 data_len = sizeof(fs_args.mfs_args); 811 } else if (strcmp(mtype, MOUNT_UFS) == 0) { 812 if (data_len > sizeof(fs_args32.ufs_args)) 813 return EINVAL; 814 if ((flags & MNT_GETARGS) == 0) { 815 error = copyin(data, &fs_args32.ufs_args, 816 sizeof(fs_args32.ufs_args)); 817 if (error) 818 return error; 819 fs_args.ufs_args.fspec = 820 NETBSD32PTR64(fs_args32.ufs_args.fspec); 821 } 822 data_seg = UIO_SYSSPACE; 823 data = &fs_args.ufs_args; 824 data_len = sizeof(fs_args.ufs_args); 825 } else if (strcmp(mtype, MOUNT_CD9660) == 0) { 826 if (data_len != sizeof(fs_args32.iso_args)) 827 return EINVAL; 828 if ((flags & MNT_GETARGS) == 0) { 829 error = copyin(data, &fs_args32.iso_args, 830 sizeof(fs_args32.iso_args)); 831 if (error) 832 return error; 833 fs_args.iso_args.fspec = 834 NETBSD32PTR64(fs_args32.iso_args.fspec); 835 memset(&fs_args.iso_args._pad1, 0, 836 sizeof(fs_args.iso_args._pad1)); 837 fs_args.iso_args.flags = fs_args32.iso_args.flags; 838 } 839 data_seg = UIO_SYSSPACE; 840 data = &fs_args.iso_args; 841 data_len = sizeof(fs_args.iso_args); 842 } else { 843 data_seg = UIO_USERSPACE; 844 } 845 error = do_sys_mount(l, NULL, type, path, flags, data, data_seg, 846 data_len, retval); 847 if (error) 848 return error; 849 if (flags & MNT_GETARGS) { 850 data_len = *retval; 851 if (strcmp(mtype, MOUNT_MFS) == 0) { 852 if (data_len != sizeof(fs_args.mfs_args)) 853 return EINVAL; 854 NETBSD32PTR32(fs_args32.mfs_args.fspec, 855 fs_args.mfs_args.fspec); 856 memset(&fs_args32.mfs_args._pad1, 0, 857 sizeof(fs_args32.mfs_args._pad1)); 858 NETBSD32PTR32(fs_args32.mfs_args.base, 859 fs_args.mfs_args.base); 860 fs_args32.mfs_args.size = fs_args.mfs_args.size; 861 error = copyout(&fs_args32.mfs_args, data, 862 sizeof(fs_args32.mfs_args)); 863 } else if (strcmp(mtype, MOUNT_UFS) == 0) { 864 if (data_len != sizeof(fs_args.ufs_args)) 865 return EINVAL; 866 NETBSD32PTR32(fs_args32.ufs_args.fspec, 867 fs_args.ufs_args.fspec); 868 error = copyout(&fs_args32.ufs_args, data, 869 sizeof(fs_args32.ufs_args)); 870 } else if (strcmp(mtype, MOUNT_CD9660) == 0) { 871 if (data_len != sizeof(fs_args.iso_args)) 872 return EINVAL; 873 NETBSD32PTR32(fs_args32.iso_args.fspec, 874 fs_args.iso_args.fspec); 875 memset(&fs_args32.iso_args._pad1, 0, 876 sizeof(fs_args32.iso_args._pad1)); 877 fs_args32.iso_args.flags = fs_args.iso_args.flags; 878 error = copyout(&fs_args32.iso_args, data, 879 sizeof(fs_args32.iso_args)); 880 } 881 } 882 return error; 883 } 884