1 /* $NetBSD: vfs_syscalls.c,v 1.45 1994/12/14 19:36:15 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * (c) UNIX System Laboratories, Inc. 7 * All or some portions of this file are derived from material licensed 8 * to the University of California by American Telephone and Telegraph 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 * the permission of UNIX System Laboratories, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)vfs_syscalls.c 8.28 (Berkeley) 12/10/94 41 */ 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/namei.h> 46 #include <sys/filedesc.h> 47 #include <sys/kernel.h> 48 #include <sys/file.h> 49 #include <sys/stat.h> 50 #include <sys/vnode.h> 51 #include <sys/mount.h> 52 #include <sys/proc.h> 53 #include <sys/uio.h> 54 #include <sys/malloc.h> 55 #include <sys/dirent.h> 56 57 #include <sys/syscallargs.h> 58 59 #include <vm/vm.h> 60 #include <sys/sysctl.h> 61 62 static int change_dir __P((struct nameidata *ndp, struct proc *p)); 63 64 /* 65 * Virtual File System System Calls 66 */ 67 68 /* 69 * Mount a file system. 70 */ 71 /* ARGSUSED */ 72 mount(p, uap, retval) 73 struct proc *p; 74 register struct mount_args /* { 75 syscallarg(char *) type; 76 syscallarg(char *) path; 77 syscallarg(int) flags; 78 syscallarg(caddr_t) data; 79 } */ *uap; 80 register_t *retval; 81 { 82 register struct vnode *vp; 83 register struct mount *mp; 84 int error, flag; 85 u_long fsindex; 86 char fstypename[MFSNAMELEN]; 87 struct vattr va; 88 struct nameidata nd; 89 90 /* 91 * Get vnode to be covered 92 */ 93 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 94 SCARG(uap, path), p); 95 if (error = namei(&nd)) 96 return (error); 97 vp = nd.ni_vp; 98 if (SCARG(uap, flags) & MNT_UPDATE) { 99 if ((vp->v_flag & VROOT) == 0) { 100 vput(vp); 101 return (EINVAL); 102 } 103 mp = vp->v_mount; 104 flag = mp->mnt_flag; 105 /* 106 * We only allow the filesystem to be reloaded if it 107 * is currently mounted read-only. 108 */ 109 if ((SCARG(uap, flags) & MNT_RELOAD) && 110 ((mp->mnt_flag & MNT_RDONLY) == 0)) { 111 vput(vp); 112 return (EOPNOTSUPP); /* Needs translation */ 113 } 114 mp->mnt_flag |= 115 SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 116 /* 117 * Only root, or the user that did the original mount is 118 * permitted to update it. 119 */ 120 if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && 121 (error = suser(p->p_ucred, &p->p_acflag))) { 122 vput(vp); 123 return (error); 124 } 125 /* 126 * Do not allow NFS export by non-root users. Silently 127 * enforce MNT_NOSUID and MNT_NODEV for non-root users. 128 */ 129 if (p->p_ucred->cr_uid != 0) { 130 if (SCARG(uap, flags) & MNT_EXPORTED) { 131 vput(vp); 132 return (EPERM); 133 } 134 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 135 } 136 VOP_UNLOCK(vp); 137 goto update; 138 } 139 /* 140 * If the user is not root, ensure that they own the directory 141 * onto which we are attempting to mount. 142 */ 143 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || 144 (va.va_uid != p->p_ucred->cr_uid && 145 (error = suser(p->p_ucred, &p->p_acflag)))) { 146 vput(vp); 147 return (error); 148 } 149 /* 150 * Do not allow NFS export by non-root users. Silently 151 * enforce MNT_NOSUID and MNT_NODEV for non-root users. 152 */ 153 if (p->p_ucred->cr_uid != 0) { 154 if (SCARG(uap, flags) & MNT_EXPORTED) { 155 vput(vp); 156 return (EPERM); 157 } 158 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 159 } 160 if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) 161 return (error); 162 if (vp->v_type != VDIR) { 163 vput(vp); 164 return (ENOTDIR); 165 } 166 if (error = copyin(SCARG(uap, type), fstypename, MFSNAMELEN)) { 167 #ifdef COMPAT_09 168 goto check_num; 169 #else 170 vput(vp); 171 return (error); 172 #endif 173 } 174 fstypename[MFSNAMELEN] = '\0'; 175 for (fsindex = 0; fsindex < nvfssw; fsindex++) 176 if (vfssw[fsindex] != NULL && 177 !strncmp(vfssw[fsindex]->vfs_name, fstypename, MFSNAMELEN)) 178 break; 179 if (fsindex >= nvfssw) { 180 #ifdef COMPAT_09 181 check_num: 182 fsindex = (u_long)SCARG(uap, type); 183 if (fsindex >= nvfssw || vfssw[fsindex] == NULL) { 184 vput(vp); 185 return (ENODEV); 186 } 187 #else 188 vput(vp); 189 return (ENODEV); 190 #endif 191 } 192 if (vp->v_mountedhere != NULL) { 193 vput(vp); 194 return (EBUSY); 195 } 196 197 /* 198 * Allocate and initialize the file system. 199 */ 200 mp = (struct mount *)malloc((u_long)sizeof(struct mount), 201 M_MOUNT, M_WAITOK); 202 bzero((char *)mp, (u_long)sizeof(struct mount)); 203 mp->mnt_op = vfssw[fsindex]; 204 if (error = vfs_lock(mp)) { 205 free((caddr_t)mp, M_MOUNT); 206 vput(vp); 207 return (error); 208 } 209 /* Do this early in case we block later. */ 210 vfssw[fsindex]->vfs_refcount++; 211 vp->v_mountedhere = mp; 212 mp->mnt_vnodecovered = vp; 213 mp->mnt_stat.f_owner = p->p_ucred->cr_uid; 214 update: 215 /* 216 * Set the mount level flags. 217 */ 218 if (SCARG(uap, flags) & MNT_RDONLY) 219 mp->mnt_flag |= MNT_RDONLY; 220 else if (mp->mnt_flag & MNT_RDONLY) 221 mp->mnt_flag |= MNT_WANTRDWR; 222 mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 223 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 224 mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC | 225 MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 226 /* 227 * Mount the filesystem. 228 */ 229 error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p); 230 if (mp->mnt_flag & MNT_UPDATE) { 231 vrele(vp); 232 if (mp->mnt_flag & MNT_WANTRDWR) 233 mp->mnt_flag &= ~MNT_RDONLY; 234 mp->mnt_flag &=~ 235 (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 236 if (error) 237 mp->mnt_flag = flag; 238 return (error); 239 } 240 /* 241 * Put the new filesystem on the mount list after root. 242 */ 243 cache_purge(vp); 244 if (!error) { 245 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 246 checkdirs(vp); 247 VOP_UNLOCK(vp); 248 vfs_unlock(mp); 249 error = VFS_START(mp, 0, p); 250 } else { 251 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 252 vfssw[fsindex]->vfs_refcount--; 253 vfs_unlock(mp); 254 free((caddr_t)mp, M_MOUNT); 255 vput(vp); 256 } 257 return (error); 258 } 259 260 /* 261 * Scan all active processes to see if any of them have a current 262 * or root directory onto which the new filesystem has just been 263 * mounted. If so, replace them with the new mount point. 264 */ 265 checkdirs(olddp) 266 struct vnode *olddp; 267 { 268 struct filedesc *fdp; 269 struct vnode *newdp; 270 struct proc *p; 271 272 if (olddp->v_usecount == 1) 273 return; 274 if (VFS_ROOT(olddp->v_mountedhere, &newdp)) 275 panic("mount: lost mount"); 276 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 277 fdp = p->p_fd; 278 if (fdp->fd_cdir == olddp) { 279 vrele(fdp->fd_cdir); 280 VREF(newdp); 281 fdp->fd_cdir = newdp; 282 } 283 if (fdp->fd_rdir == olddp) { 284 vrele(fdp->fd_rdir); 285 VREF(newdp); 286 fdp->fd_rdir = newdp; 287 } 288 } 289 if (rootvnode == olddp) { 290 vrele(rootvnode); 291 VREF(newdp); 292 rootvnode = newdp; 293 } 294 vput(newdp); 295 } 296 297 /* 298 * Unmount a file system. 299 * 300 * Note: unmount takes a path to the vnode mounted on as argument, 301 * not special file (as before). 302 */ 303 /* ARGSUSED */ 304 unmount(p, uap, retval) 305 struct proc *p; 306 register struct unmount_args /* { 307 syscallarg(char *) path; 308 syscallarg(int) flags; 309 } */ *uap; 310 register_t *retval; 311 { 312 register struct vnode *vp; 313 struct mount *mp; 314 int error; 315 struct nameidata nd; 316 317 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 318 SCARG(uap, path), p); 319 if (error = namei(&nd)) 320 return (error); 321 vp = nd.ni_vp; 322 mp = vp->v_mount; 323 324 /* 325 * Only root, or the user that did the original mount is 326 * permitted to unmount this filesystem. 327 */ 328 if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && 329 (error = suser(p->p_ucred, &p->p_acflag))) { 330 vput(vp); 331 return (error); 332 } 333 334 /* 335 * Must be the root of the filesystem 336 */ 337 if ((vp->v_flag & VROOT) == 0) { 338 vput(vp); 339 return (EINVAL); 340 } 341 vput(vp); 342 return (dounmount(mp, SCARG(uap, flags), p)); 343 } 344 345 /* 346 * Do the actual file system unmount. 347 */ 348 dounmount(mp, flags, p) 349 register struct mount *mp; 350 int flags; 351 struct proc *p; 352 { 353 struct vnode *coveredvp; 354 int error; 355 356 coveredvp = mp->mnt_vnodecovered; 357 if (vfs_busy(mp)) 358 return (EBUSY); 359 mp->mnt_flag |= MNT_UNMOUNT; 360 if (error = vfs_lock(mp)) 361 return (error); 362 363 mp->mnt_flag &=~ MNT_ASYNC; 364 vnode_pager_umount(mp); /* release cached vnodes */ 365 cache_purgevfs(mp); /* remove cache entries for this file sys */ 366 if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 367 (flags & MNT_FORCE)) 368 error = VFS_UNMOUNT(mp, flags, p); 369 mp->mnt_flag &= ~MNT_UNMOUNT; 370 vfs_unbusy(mp); 371 if (error) { 372 vfs_unlock(mp); 373 } else { 374 vrele(coveredvp); 375 TAILQ_REMOVE(&mountlist, mp, mnt_list); 376 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 377 mp->mnt_op->vfs_refcount--; 378 vfs_unlock(mp); 379 if (mp->mnt_vnodelist.lh_first != NULL) 380 panic("unmount: dangling vnode"); 381 free((caddr_t)mp, M_MOUNT); 382 } 383 return (error); 384 } 385 386 /* 387 * Sync each mounted filesystem. 388 */ 389 #ifdef DEBUG 390 int syncprt = 0; 391 struct ctldebug debug0 = { "syncprt", &syncprt }; 392 #endif 393 394 /* ARGSUSED */ 395 sync(p, uap, retval) 396 struct proc *p; 397 void *uap; 398 register_t *retval; 399 { 400 register struct mount *mp, *nmp; 401 int asyncflag; 402 403 for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 404 /* 405 * Get the next pointer in case we hang on vfs_busy 406 * while we are being unmounted. 407 */ 408 nmp = mp->mnt_list.tqe_next; 409 /* 410 * The lock check below is to avoid races with mount 411 * and unmount. 412 */ 413 if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 414 !vfs_busy(mp)) { 415 asyncflag = mp->mnt_flag & MNT_ASYNC; 416 mp->mnt_flag &= ~MNT_ASYNC; 417 VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 418 if (asyncflag) 419 mp->mnt_flag |= MNT_ASYNC; 420 /* 421 * Get the next pointer again, as the next filesystem 422 * might have been unmounted while we were sync'ing. 423 */ 424 nmp = mp->mnt_list.tqe_next; 425 vfs_unbusy(mp); 426 } 427 } 428 #ifdef DEBUG 429 if (syncprt) 430 vfs_bufstats(); 431 #endif /* DEBUG */ 432 return (0); 433 } 434 435 /* 436 * Change filesystem quotas. 437 */ 438 /* ARGSUSED */ 439 quotactl(p, uap, retval) 440 struct proc *p; 441 register struct quotactl_args /* { 442 syscallarg(char *) path; 443 syscallarg(int) cmd; 444 syscallarg(int) uid; 445 syscallarg(caddr_t) arg; 446 } */ *uap; 447 register_t *retval; 448 { 449 register struct mount *mp; 450 int error; 451 struct nameidata nd; 452 453 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 454 if (error = namei(&nd)) 455 return (error); 456 mp = nd.ni_vp->v_mount; 457 vrele(nd.ni_vp); 458 return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), 459 SCARG(uap, arg), p)); 460 } 461 462 /* 463 * Get filesystem statistics. 464 */ 465 /* ARGSUSED */ 466 statfs(p, uap, retval) 467 struct proc *p; 468 register struct statfs_args /* { 469 syscallarg(char *) path; 470 syscallarg(struct statfs *) buf; 471 } */ *uap; 472 register_t *retval; 473 { 474 register struct mount *mp; 475 register struct statfs *sp; 476 int error; 477 struct nameidata nd; 478 479 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 480 if (error = namei(&nd)) 481 return (error); 482 mp = nd.ni_vp->v_mount; 483 sp = &mp->mnt_stat; 484 vrele(nd.ni_vp); 485 if (error = VFS_STATFS(mp, sp, p)) 486 return (error); 487 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 488 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 489 } 490 491 /* 492 * Get filesystem statistics. 493 */ 494 /* ARGSUSED */ 495 fstatfs(p, uap, retval) 496 struct proc *p; 497 register struct fstatfs_args /* { 498 syscallarg(int) fd; 499 syscallarg(struct statfs *) buf; 500 } */ *uap; 501 register_t *retval; 502 { 503 struct file *fp; 504 struct mount *mp; 505 register struct statfs *sp; 506 int error; 507 508 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 509 return (error); 510 mp = ((struct vnode *)fp->f_data)->v_mount; 511 sp = &mp->mnt_stat; 512 if (error = VFS_STATFS(mp, sp, p)) 513 return (error); 514 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 515 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 516 } 517 518 /* 519 * Get statistics on all filesystems. 520 */ 521 getfsstat(p, uap, retval) 522 struct proc *p; 523 register struct getfsstat_args /* { 524 syscallarg(struct statfs *) buf; 525 syscallarg(long) bufsize; 526 syscallarg(int) flags; 527 } */ *uap; 528 register_t *retval; 529 { 530 register struct mount *mp, *nmp; 531 register struct statfs *sp; 532 caddr_t sfsp; 533 long count, maxcount, error; 534 535 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); 536 sfsp = (caddr_t)SCARG(uap, buf); 537 for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 538 nmp = mp->mnt_list.tqe_next; 539 if (sfsp && count < maxcount && 540 ((mp->mnt_flag & MNT_MLOCK) == 0)) { 541 sp = &mp->mnt_stat; 542 /* 543 * If MNT_NOWAIT is specified, do not refresh the 544 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 545 */ 546 if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 || 547 (SCARG(uap, flags) & MNT_WAIT)) && 548 (error = VFS_STATFS(mp, sp, p))) 549 continue; 550 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 551 if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 552 return (error); 553 sfsp += sizeof(*sp); 554 } 555 count++; 556 } 557 if (sfsp && count > maxcount) 558 *retval = maxcount; 559 else 560 *retval = count; 561 return (0); 562 } 563 564 /* 565 * Change current working directory to a given file descriptor. 566 */ 567 /* ARGSUSED */ 568 fchdir(p, uap, retval) 569 struct proc *p; 570 struct fchdir_args /* { 571 syscallarg(int) fd; 572 } */ *uap; 573 register_t *retval; 574 { 575 register struct filedesc *fdp = p->p_fd; 576 struct vnode *vp, *tdp; 577 struct mount *mp; 578 struct file *fp; 579 int error; 580 581 if (error = getvnode(fdp, SCARG(uap, fd), &fp)) 582 return (error); 583 vp = (struct vnode *)fp->f_data; 584 VREF(vp); 585 VOP_LOCK(vp); 586 if (vp->v_type != VDIR) 587 error = ENOTDIR; 588 else 589 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 590 while (!error && (mp = vp->v_mountedhere) != NULL) { 591 if (mp->mnt_flag & MNT_MLOCK) { 592 mp->mnt_flag |= MNT_MWAIT; 593 sleep((caddr_t)mp, PVFS); 594 continue; 595 } 596 if (error = VFS_ROOT(mp, &tdp)) 597 break; 598 vput(vp); 599 vp = tdp; 600 } 601 VOP_UNLOCK(vp); 602 if (error) { 603 vrele(vp); 604 return (error); 605 } 606 vrele(fdp->fd_cdir); 607 fdp->fd_cdir = vp; 608 return (0); 609 } 610 611 /* 612 * Change current working directory (``.''). 613 */ 614 /* ARGSUSED */ 615 chdir(p, uap, retval) 616 struct proc *p; 617 struct chdir_args /* { 618 syscallarg(char *) path; 619 } */ *uap; 620 register_t *retval; 621 { 622 register struct filedesc *fdp = p->p_fd; 623 int error; 624 struct nameidata nd; 625 626 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 627 SCARG(uap, path), p); 628 if (error = change_dir(&nd, p)) 629 return (error); 630 vrele(fdp->fd_cdir); 631 fdp->fd_cdir = nd.ni_vp; 632 return (0); 633 } 634 635 /* 636 * Change notion of root (``/'') directory. 637 */ 638 /* ARGSUSED */ 639 chroot(p, uap, retval) 640 struct proc *p; 641 struct chroot_args /* { 642 syscallarg(char *) path; 643 } */ *uap; 644 register_t *retval; 645 { 646 register struct filedesc *fdp = p->p_fd; 647 int error; 648 struct nameidata nd; 649 650 if (error = suser(p->p_ucred, &p->p_acflag)) 651 return (error); 652 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 653 SCARG(uap, path), p); 654 if (error = change_dir(&nd, p)) 655 return (error); 656 if (fdp->fd_rdir != NULL) 657 vrele(fdp->fd_rdir); 658 fdp->fd_rdir = nd.ni_vp; 659 return (0); 660 } 661 662 /* 663 * Common routine for chroot and chdir. 664 */ 665 static int 666 change_dir(ndp, p) 667 register struct nameidata *ndp; 668 struct proc *p; 669 { 670 struct vnode *vp; 671 int error; 672 673 if (error = namei(ndp)) 674 return (error); 675 vp = ndp->ni_vp; 676 if (vp->v_type != VDIR) 677 error = ENOTDIR; 678 else 679 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 680 VOP_UNLOCK(vp); 681 if (error) 682 vrele(vp); 683 return (error); 684 } 685 686 /* 687 * Check permissions, allocate an open file structure, 688 * and call the device open routine if any. 689 */ 690 open(p, uap, retval) 691 struct proc *p; 692 register struct open_args /* { 693 syscallarg(char *) path; 694 syscallarg(int) flags; 695 syscallarg(int) mode; 696 } */ *uap; 697 register_t *retval; 698 { 699 register struct filedesc *fdp = p->p_fd; 700 register struct file *fp; 701 register struct vnode *vp; 702 int flags, cmode; 703 struct file *nfp; 704 int type, indx, error; 705 struct flock lf; 706 struct nameidata nd; 707 extern struct fileops vnops; 708 709 if (error = falloc(p, &nfp, &indx)) 710 return (error); 711 fp = nfp; 712 flags = FFLAGS(SCARG(uap, flags)); 713 cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 714 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 715 p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 716 if (error = vn_open(&nd, flags, cmode)) { 717 ffree(fp); 718 if ((error == ENODEV || error == ENXIO) && 719 p->p_dupfd >= 0 && /* XXX from fdopen */ 720 (error = 721 dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 722 *retval = indx; 723 return (0); 724 } 725 if (error == ERESTART) 726 error = EINTR; 727 fdp->fd_ofiles[indx] = NULL; 728 return (error); 729 } 730 p->p_dupfd = 0; 731 vp = nd.ni_vp; 732 fp->f_flag = flags & FMASK; 733 fp->f_type = DTYPE_VNODE; 734 fp->f_ops = &vnops; 735 fp->f_data = (caddr_t)vp; 736 if (flags & (O_EXLOCK | O_SHLOCK)) { 737 lf.l_whence = SEEK_SET; 738 lf.l_start = 0; 739 lf.l_len = 0; 740 if (flags & O_EXLOCK) 741 lf.l_type = F_WRLCK; 742 else 743 lf.l_type = F_RDLCK; 744 type = F_FLOCK; 745 if ((flags & FNONBLOCK) == 0) 746 type |= F_WAIT; 747 VOP_UNLOCK(vp); 748 if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 749 (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 750 ffree(fp); 751 fdp->fd_ofiles[indx] = NULL; 752 return (error); 753 } 754 VOP_LOCK(vp); 755 fp->f_flag |= FHASLOCK; 756 } 757 VOP_UNLOCK(vp); 758 *retval = indx; 759 return (0); 760 } 761 762 #ifdef COMPAT_43 763 /* 764 * Create a file. 765 */ 766 compat_43_creat(p, uap, retval) 767 struct proc *p; 768 register struct compat_43_creat_args /* { 769 syscallarg(char *) path; 770 syscallarg(int) mode; 771 } */ *uap; 772 register_t *retval; 773 { 774 struct open_args /* { 775 syscallarg(char *) path; 776 syscallarg(int) flags; 777 syscallarg(int) mode; 778 } */ nuap; 779 780 SCARG(&nuap, path) = SCARG(uap, path); 781 SCARG(&nuap, mode) = SCARG(uap, mode); 782 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; 783 return (open(p, &nuap, retval)); 784 } 785 #endif /* COMPAT_43 */ 786 787 /* 788 * Create a special file. 789 */ 790 /* ARGSUSED */ 791 mknod(p, uap, retval) 792 struct proc *p; 793 register struct mknod_args /* { 794 syscallarg(char *) path; 795 syscallarg(int) mode; 796 syscallarg(int) dev; 797 } */ *uap; 798 register_t *retval; 799 { 800 register struct vnode *vp; 801 struct vattr vattr; 802 int error; 803 int whiteout; 804 struct nameidata nd; 805 806 if (error = suser(p->p_ucred, &p->p_acflag)) 807 return (error); 808 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 809 if (error = namei(&nd)) 810 return (error); 811 vp = nd.ni_vp; 812 if (vp != NULL) 813 error = EEXIST; 814 else { 815 VATTR_NULL(&vattr); 816 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 817 vattr.va_rdev = SCARG(uap, dev); 818 whiteout = 0; 819 820 switch (SCARG(uap, mode) & S_IFMT) { 821 case S_IFMT: /* used by badsect to flag bad sectors */ 822 vattr.va_type = VBAD; 823 break; 824 case S_IFCHR: 825 vattr.va_type = VCHR; 826 break; 827 case S_IFBLK: 828 vattr.va_type = VBLK; 829 break; 830 case S_IFWHT: 831 whiteout = 1; 832 break; 833 default: 834 error = EINVAL; 835 break; 836 } 837 } 838 if (!error) { 839 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 840 if (whiteout) { 841 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 842 if (error) 843 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 844 vput(nd.ni_dvp); 845 } else { 846 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, 847 &nd.ni_cnd, &vattr); 848 } 849 } else { 850 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 851 if (nd.ni_dvp == vp) 852 vrele(nd.ni_dvp); 853 else 854 vput(nd.ni_dvp); 855 if (vp) 856 vrele(vp); 857 } 858 return (error); 859 } 860 861 /* 862 * Create a named pipe. 863 */ 864 /* ARGSUSED */ 865 mkfifo(p, uap, retval) 866 struct proc *p; 867 register struct mkfifo_args /* { 868 syscallarg(char *) path; 869 syscallarg(int) mode; 870 } */ *uap; 871 register_t *retval; 872 { 873 struct vattr vattr; 874 int error; 875 struct nameidata nd; 876 877 #ifndef FIFO 878 return (EOPNOTSUPP); 879 #else 880 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 881 if (error = namei(&nd)) 882 return (error); 883 if (nd.ni_vp != NULL) { 884 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 885 if (nd.ni_dvp == nd.ni_vp) 886 vrele(nd.ni_dvp); 887 else 888 vput(nd.ni_dvp); 889 vrele(nd.ni_vp); 890 return (EEXIST); 891 } 892 VATTR_NULL(&vattr); 893 vattr.va_type = VFIFO; 894 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 895 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 896 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 897 #endif /* FIFO */ 898 } 899 900 /* 901 * Make a hard file link. 902 */ 903 /* ARGSUSED */ 904 link(p, uap, retval) 905 struct proc *p; 906 register struct link_args /* { 907 syscallarg(char *) path; 908 syscallarg(char *) link; 909 } */ *uap; 910 register_t *retval; 911 { 912 register struct vnode *vp; 913 struct nameidata nd; 914 int error; 915 916 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 917 if (error = namei(&nd)) 918 return (error); 919 vp = nd.ni_vp; 920 if (vp->v_type != VDIR || 921 (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 922 nd.ni_cnd.cn_nameiop = CREATE; 923 nd.ni_cnd.cn_flags = LOCKPARENT; 924 nd.ni_dirp = SCARG(uap, link); 925 if ((error = namei(&nd)) == 0) { 926 if (nd.ni_vp != NULL) 927 error = EEXIST; 928 if (!error) { 929 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, 930 LEASE_WRITE); 931 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 932 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 933 } else { 934 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 935 if (nd.ni_dvp == nd.ni_vp) 936 vrele(nd.ni_dvp); 937 else 938 vput(nd.ni_dvp); 939 if (nd.ni_vp) 940 vrele(nd.ni_vp); 941 } 942 } 943 } 944 vrele(vp); 945 return (error); 946 } 947 948 /* 949 * Make a symbolic link. 950 */ 951 /* ARGSUSED */ 952 symlink(p, uap, retval) 953 struct proc *p; 954 register struct symlink_args /* { 955 syscallarg(char *) path; 956 syscallarg(char *) link; 957 } */ *uap; 958 register_t *retval; 959 { 960 struct vattr vattr; 961 char *path; 962 int error; 963 struct nameidata nd; 964 965 MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 966 if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, (u_int*)0)) 967 goto out; 968 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); 969 if (error = namei(&nd)) 970 goto out; 971 if (nd.ni_vp) { 972 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 973 if (nd.ni_dvp == nd.ni_vp) 974 vrele(nd.ni_dvp); 975 else 976 vput(nd.ni_dvp); 977 vrele(nd.ni_vp); 978 error = EEXIST; 979 goto out; 980 } 981 VATTR_NULL(&vattr); 982 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 983 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 984 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 985 out: 986 FREE(path, M_NAMEI); 987 return (error); 988 } 989 990 /* 991 * Delete a whiteout from the filesystem. 992 */ 993 /* ARGSUSED */ 994 undelete(p, uap, retval) 995 struct proc *p; 996 register struct undelete_args /* { 997 syscallarg(char *) path; 998 } */ *uap; 999 register_t *retval; 1000 { 1001 int error; 1002 struct nameidata nd; 1003 1004 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, 1005 SCARG(uap, path), p); 1006 error = namei(&nd); 1007 if (error) 1008 return (error); 1009 1010 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 1011 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1012 if (nd.ni_dvp == nd.ni_vp) 1013 vrele(nd.ni_dvp); 1014 else 1015 vput(nd.ni_dvp); 1016 if (nd.ni_vp) 1017 vrele(nd.ni_vp); 1018 return (EEXIST); 1019 } 1020 1021 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1022 if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) 1023 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1024 vput(nd.ni_dvp); 1025 return (error); 1026 } 1027 1028 /* 1029 * Delete a name from the filesystem. 1030 */ 1031 /* ARGSUSED */ 1032 unlink(p, uap, retval) 1033 struct proc *p; 1034 struct unlink_args /* { 1035 syscallarg(char *) path; 1036 } */ *uap; 1037 register_t *retval; 1038 { 1039 register struct vnode *vp; 1040 int error; 1041 struct nameidata nd; 1042 1043 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1044 if (error = namei(&nd)) 1045 return (error); 1046 vp = nd.ni_vp; 1047 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1048 VOP_LOCK(vp); 1049 1050 if (vp->v_type != VDIR || 1051 (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 1052 /* 1053 * The root of a mounted filesystem cannot be deleted. 1054 */ 1055 if (vp->v_flag & VROOT) 1056 error = EBUSY; 1057 else 1058 (void)vnode_pager_uncache(vp); 1059 } 1060 1061 if (!error) { 1062 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1063 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1064 } else { 1065 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1066 if (nd.ni_dvp == vp) 1067 vrele(nd.ni_dvp); 1068 else 1069 vput(nd.ni_dvp); 1070 if (vp != NULLVP) 1071 vput(vp); 1072 } 1073 return (error); 1074 } 1075 1076 /* 1077 * Reposition read/write file offset. 1078 */ 1079 lseek(p, uap, retval) 1080 struct proc *p; 1081 register struct lseek_args /* { 1082 syscallarg(int) fd; 1083 syscallarg(int) pad; 1084 syscallarg(off_t) offset; 1085 syscallarg(int) whence; 1086 } */ *uap; 1087 register_t *retval; 1088 { 1089 struct ucred *cred = p->p_ucred; 1090 register struct filedesc *fdp = p->p_fd; 1091 register struct file *fp; 1092 struct vattr vattr; 1093 int error; 1094 1095 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 1096 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) 1097 return (EBADF); 1098 if (fp->f_type != DTYPE_VNODE) 1099 return (ESPIPE); 1100 switch (SCARG(uap, whence)) { 1101 case L_INCR: 1102 fp->f_offset += SCARG(uap, offset); 1103 break; 1104 case L_XTND: 1105 if (error = 1106 VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) 1107 return (error); 1108 fp->f_offset = SCARG(uap, offset) + vattr.va_size; 1109 break; 1110 case L_SET: 1111 fp->f_offset = SCARG(uap, offset); 1112 break; 1113 default: 1114 return (EINVAL); 1115 } 1116 *(off_t *)retval = fp->f_offset; 1117 return (0); 1118 } 1119 1120 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_SVR4) 1121 /* 1122 * Reposition read/write file offset. 1123 */ 1124 compat_43_lseek(p, uap, retval) 1125 struct proc *p; 1126 register struct compat_43_lseek_args /* { 1127 syscallarg(int) fd; 1128 syscallarg(long) offset; 1129 syscallarg(int) whence; 1130 } */ *uap; 1131 register_t *retval; 1132 { 1133 struct lseek_args /* { 1134 syscallarg(int) fd; 1135 syscallarg(int) pad; 1136 syscallarg(off_t) offset; 1137 syscallarg(int) whence; 1138 } */ nuap; 1139 off_t qret; 1140 int error; 1141 1142 SCARG(&nuap, fd) = SCARG(uap, fd); 1143 SCARG(&nuap, offset) = SCARG(uap, offset); 1144 SCARG(&nuap, whence) = SCARG(uap, whence); 1145 error = lseek(p, &nuap, &qret); 1146 *(long *)retval = qret; 1147 return (error); 1148 } 1149 #endif /* COMPAT_43 || COMPAT_SUNOS */ 1150 1151 /* 1152 * Check access permissions. 1153 */ 1154 access(p, uap, retval) 1155 struct proc *p; 1156 register struct access_args /* { 1157 syscallarg(char *) path; 1158 syscallarg(int) flags; 1159 } */ *uap; 1160 register_t *retval; 1161 { 1162 register struct ucred *cred = p->p_ucred; 1163 register struct vnode *vp; 1164 int error, flags, t_gid, t_uid; 1165 struct nameidata nd; 1166 1167 t_uid = cred->cr_uid; 1168 t_gid = cred->cr_groups[0]; 1169 cred->cr_uid = p->p_cred->p_ruid; 1170 cred->cr_groups[0] = p->p_cred->p_rgid; 1171 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1172 SCARG(uap, path), p); 1173 if (error = namei(&nd)) 1174 goto out1; 1175 vp = nd.ni_vp; 1176 1177 /* Flags == 0 means only check for existence. */ 1178 if (SCARG(uap, flags)) { 1179 flags = 0; 1180 if (SCARG(uap, flags) & R_OK) 1181 flags |= VREAD; 1182 if (SCARG(uap, flags) & W_OK) 1183 flags |= VWRITE; 1184 if (SCARG(uap, flags) & X_OK) 1185 flags |= VEXEC; 1186 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 1187 error = VOP_ACCESS(vp, flags, cred, p); 1188 } 1189 vput(vp); 1190 out1: 1191 cred->cr_uid = t_uid; 1192 cred->cr_groups[0] = t_gid; 1193 return (error); 1194 } 1195 1196 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) 1197 /* 1198 * Get file status; this version follows links. 1199 */ 1200 /* ARGSUSED */ 1201 compat_43_stat(p, uap, retval) 1202 struct proc *p; 1203 register struct compat_43_stat_args /* { 1204 syscallarg(char *) path; 1205 syscallarg(struct ostat *) ub; 1206 } */ *uap; 1207 register_t *retval; 1208 { 1209 struct stat sb; 1210 struct ostat osb; 1211 int error; 1212 struct nameidata nd; 1213 1214 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1215 SCARG(uap, path), p); 1216 if (error = namei(&nd)) 1217 return (error); 1218 error = vn_stat(nd.ni_vp, &sb, p); 1219 vput(nd.ni_vp); 1220 if (error) 1221 return (error); 1222 cvtstat(&sb, &osb); 1223 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 1224 return (error); 1225 } 1226 1227 /* 1228 * Get file status; this version does not follow links. 1229 */ 1230 /* ARGSUSED */ 1231 compat_43_lstat(p, uap, retval) 1232 struct proc *p; 1233 register struct compat_43_lstat_args /* { 1234 syscallarg(char *) path; 1235 syscallarg(struct ostat *) ub; 1236 } */ *uap; 1237 register_t *retval; 1238 { 1239 struct vnode *vp, *dvp; 1240 struct stat sb, sb1; 1241 struct ostat osb; 1242 int error; 1243 struct nameidata nd; 1244 1245 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 1246 SCARG(uap, path), p); 1247 if (error = namei(&nd)) 1248 return (error); 1249 /* 1250 * For symbolic links, always return the attributes of its 1251 * containing directory, except for mode, size, and links. 1252 */ 1253 vp = nd.ni_vp; 1254 dvp = nd.ni_dvp; 1255 if (vp->v_type != VLNK) { 1256 if (dvp == vp) 1257 vrele(dvp); 1258 else 1259 vput(dvp); 1260 error = vn_stat(vp, &sb, p); 1261 vput(vp); 1262 if (error) 1263 return (error); 1264 } else { 1265 error = vn_stat(dvp, &sb, p); 1266 vput(dvp); 1267 if (error) { 1268 vput(vp); 1269 return (error); 1270 } 1271 error = vn_stat(vp, &sb1, p); 1272 vput(vp); 1273 if (error) 1274 return (error); 1275 sb.st_mode &= ~S_IFDIR; 1276 sb.st_mode |= S_IFLNK; 1277 sb.st_nlink = sb1.st_nlink; 1278 sb.st_size = sb1.st_size; 1279 sb.st_blocks = sb1.st_blocks; 1280 } 1281 cvtstat(&sb, &osb); 1282 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 1283 return (error); 1284 } 1285 1286 /* 1287 * Convert from an old to a new stat structure. 1288 */ 1289 cvtstat(st, ost) 1290 struct stat *st; 1291 struct ostat *ost; 1292 { 1293 1294 ost->st_dev = st->st_dev; 1295 ost->st_ino = st->st_ino; 1296 ost->st_mode = st->st_mode; 1297 ost->st_nlink = st->st_nlink; 1298 ost->st_uid = st->st_uid; 1299 ost->st_gid = st->st_gid; 1300 ost->st_rdev = st->st_rdev; 1301 if (st->st_size < (quad_t)1 << 32) 1302 ost->st_size = st->st_size; 1303 else 1304 ost->st_size = -2; 1305 ost->st_atime = st->st_atime; 1306 ost->st_mtime = st->st_mtime; 1307 ost->st_ctime = st->st_ctime; 1308 ost->st_blksize = st->st_blksize; 1309 ost->st_blocks = st->st_blocks; 1310 ost->st_flags = st->st_flags; 1311 ost->st_gen = st->st_gen; 1312 } 1313 #endif /* COMPAT_43 || COMPAT_SUNOS || COMPAT_IBCS2 */ 1314 1315 /* 1316 * Get file status; this version follows links. 1317 */ 1318 /* ARGSUSED */ 1319 stat(p, uap, retval) 1320 struct proc *p; 1321 register struct stat_args /* { 1322 syscallarg(char *) path; 1323 syscallarg(struct stat *) ub; 1324 } */ *uap; 1325 register_t *retval; 1326 { 1327 struct stat sb; 1328 int error; 1329 struct nameidata nd; 1330 1331 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1332 SCARG(uap, path), p); 1333 if (error = namei(&nd)) 1334 return (error); 1335 error = vn_stat(nd.ni_vp, &sb, p); 1336 vput(nd.ni_vp); 1337 if (error) 1338 return (error); 1339 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1340 return (error); 1341 } 1342 1343 /* 1344 * Get file status; this version does not follow links. 1345 */ 1346 /* ARGSUSED */ 1347 lstat(p, uap, retval) 1348 struct proc *p; 1349 register struct lstat_args /* { 1350 syscallarg(char *) path; 1351 syscallarg(struct stat *) ub; 1352 } */ *uap; 1353 register_t *retval; 1354 { 1355 int error; 1356 struct vnode *vp, *dvp; 1357 struct stat sb, sb1; 1358 struct nameidata nd; 1359 1360 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 1361 SCARG(uap, path), p); 1362 if (error = namei(&nd)) 1363 return (error); 1364 /* 1365 * For symbolic links, always return the attributes of its 1366 * containing directory, except for mode, size, and links. 1367 */ 1368 vp = nd.ni_vp; 1369 dvp = nd.ni_dvp; 1370 if (vp->v_type != VLNK) { 1371 if (dvp == vp) 1372 vrele(dvp); 1373 else 1374 vput(dvp); 1375 error = vn_stat(vp, &sb, p); 1376 vput(vp); 1377 if (error) 1378 return (error); 1379 } else { 1380 error = vn_stat(dvp, &sb, p); 1381 vput(dvp); 1382 if (error) { 1383 vput(vp); 1384 return (error); 1385 } 1386 error = vn_stat(vp, &sb1, p); 1387 vput(vp); 1388 if (error) 1389 return (error); 1390 sb.st_mode &= ~S_IFDIR; 1391 sb.st_mode |= S_IFLNK; 1392 sb.st_nlink = sb1.st_nlink; 1393 sb.st_size = sb1.st_size; 1394 sb.st_blocks = sb1.st_blocks; 1395 } 1396 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1397 return (error); 1398 } 1399 1400 /* 1401 * Get configurable pathname variables. 1402 */ 1403 /* ARGSUSED */ 1404 pathconf(p, uap, retval) 1405 struct proc *p; 1406 register struct pathconf_args /* { 1407 syscallarg(char *) path; 1408 syscallarg(int) name; 1409 } */ *uap; 1410 register_t *retval; 1411 { 1412 int error; 1413 struct nameidata nd; 1414 1415 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1416 SCARG(uap, path), p); 1417 if (error = namei(&nd)) 1418 return (error); 1419 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval); 1420 vput(nd.ni_vp); 1421 return (error); 1422 } 1423 1424 /* 1425 * Return target name of a symbolic link. 1426 */ 1427 /* ARGSUSED */ 1428 readlink(p, uap, retval) 1429 struct proc *p; 1430 register struct readlink_args /* { 1431 syscallarg(char *) path; 1432 syscallarg(char *) buf; 1433 syscallarg(int) count; 1434 } */ *uap; 1435 register_t *retval; 1436 { 1437 register struct vnode *vp; 1438 struct iovec aiov; 1439 struct uio auio; 1440 int error; 1441 struct nameidata nd; 1442 1443 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 1444 SCARG(uap, path), p); 1445 if (error = namei(&nd)) 1446 return (error); 1447 vp = nd.ni_vp; 1448 if (vp->v_type != VLNK) 1449 error = EINVAL; 1450 else { 1451 aiov.iov_base = SCARG(uap, buf); 1452 aiov.iov_len = SCARG(uap, count); 1453 auio.uio_iov = &aiov; 1454 auio.uio_iovcnt = 1; 1455 auio.uio_offset = 0; 1456 auio.uio_rw = UIO_READ; 1457 auio.uio_segflg = UIO_USERSPACE; 1458 auio.uio_procp = p; 1459 auio.uio_resid = SCARG(uap, count); 1460 error = VOP_READLINK(vp, &auio, p->p_ucred); 1461 } 1462 vput(vp); 1463 *retval = SCARG(uap, count) - auio.uio_resid; 1464 return (error); 1465 } 1466 1467 /* 1468 * Change flags of a file given a path name. 1469 */ 1470 /* ARGSUSED */ 1471 chflags(p, uap, retval) 1472 struct proc *p; 1473 register struct chflags_args /* { 1474 syscallarg(char *) path; 1475 syscallarg(int) flags; 1476 } */ *uap; 1477 register_t *retval; 1478 { 1479 register struct vnode *vp; 1480 struct vattr vattr; 1481 int error; 1482 struct nameidata nd; 1483 1484 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1485 if (error = namei(&nd)) 1486 return (error); 1487 vp = nd.ni_vp; 1488 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1489 VOP_LOCK(vp); 1490 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1491 error = EROFS; 1492 else { 1493 VATTR_NULL(&vattr); 1494 vattr.va_flags = SCARG(uap, flags); 1495 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1496 } 1497 vput(vp); 1498 return (error); 1499 } 1500 1501 /* 1502 * Change flags of a file given a file descriptor. 1503 */ 1504 /* ARGSUSED */ 1505 fchflags(p, uap, retval) 1506 struct proc *p; 1507 register struct fchflags_args /* { 1508 syscallarg(int) fd; 1509 syscallarg(int) flags; 1510 } */ *uap; 1511 register_t *retval; 1512 { 1513 struct vattr vattr; 1514 struct vnode *vp; 1515 struct file *fp; 1516 int error; 1517 1518 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1519 return (error); 1520 vp = (struct vnode *)fp->f_data; 1521 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1522 VOP_LOCK(vp); 1523 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1524 error = EROFS; 1525 else { 1526 VATTR_NULL(&vattr); 1527 vattr.va_flags = SCARG(uap, flags); 1528 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1529 } 1530 VOP_UNLOCK(vp); 1531 return (error); 1532 } 1533 1534 /* 1535 * Change mode of a file given path name. 1536 */ 1537 /* ARGSUSED */ 1538 chmod(p, uap, retval) 1539 struct proc *p; 1540 register struct chmod_args /* { 1541 syscallarg(char *) path; 1542 syscallarg(int) mode; 1543 } */ *uap; 1544 register_t *retval; 1545 { 1546 register struct vnode *vp; 1547 struct vattr vattr; 1548 int error; 1549 struct nameidata nd; 1550 1551 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1552 if (error = namei(&nd)) 1553 return (error); 1554 vp = nd.ni_vp; 1555 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1556 VOP_LOCK(vp); 1557 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1558 error = EROFS; 1559 else { 1560 VATTR_NULL(&vattr); 1561 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1562 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1563 } 1564 vput(vp); 1565 return (error); 1566 } 1567 1568 /* 1569 * Change mode of a file given a file descriptor. 1570 */ 1571 /* ARGSUSED */ 1572 fchmod(p, uap, retval) 1573 struct proc *p; 1574 register struct fchmod_args /* { 1575 syscallarg(int) fd; 1576 syscallarg(int) mode; 1577 } */ *uap; 1578 register_t *retval; 1579 { 1580 struct vattr vattr; 1581 struct vnode *vp; 1582 struct file *fp; 1583 int error; 1584 1585 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1586 return (error); 1587 vp = (struct vnode *)fp->f_data; 1588 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1589 VOP_LOCK(vp); 1590 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1591 error = EROFS; 1592 else { 1593 VATTR_NULL(&vattr); 1594 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1595 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1596 } 1597 VOP_UNLOCK(vp); 1598 return (error); 1599 } 1600 1601 /* 1602 * Set ownership given a path name. 1603 */ 1604 /* ARGSUSED */ 1605 chown(p, uap, retval) 1606 struct proc *p; 1607 register struct chown_args /* { 1608 syscallarg(char *) path; 1609 syscallarg(int) uid; 1610 syscallarg(int) gid; 1611 } */ *uap; 1612 register_t *retval; 1613 { 1614 register struct vnode *vp; 1615 struct vattr vattr; 1616 int error; 1617 struct nameidata nd; 1618 1619 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1620 if (error = namei(&nd)) 1621 return (error); 1622 vp = nd.ni_vp; 1623 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1624 VOP_LOCK(vp); 1625 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1626 error = EROFS; 1627 else { 1628 VATTR_NULL(&vattr); 1629 vattr.va_uid = SCARG(uap, uid); 1630 vattr.va_gid = SCARG(uap, gid); 1631 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1632 } 1633 vput(vp); 1634 return (error); 1635 } 1636 1637 /* 1638 * Set ownership given a file descriptor. 1639 */ 1640 /* ARGSUSED */ 1641 fchown(p, uap, retval) 1642 struct proc *p; 1643 register struct fchown_args /* { 1644 syscallarg(int) fd; 1645 syscallarg(int) uid; 1646 syscallarg(int) gid; 1647 } */ *uap; 1648 register_t *retval; 1649 { 1650 struct vattr vattr; 1651 struct vnode *vp; 1652 struct file *fp; 1653 int error; 1654 1655 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1656 return (error); 1657 vp = (struct vnode *)fp->f_data; 1658 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1659 VOP_LOCK(vp); 1660 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1661 error = EROFS; 1662 else { 1663 VATTR_NULL(&vattr); 1664 vattr.va_uid = SCARG(uap, uid); 1665 vattr.va_gid = SCARG(uap, gid); 1666 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1667 } 1668 VOP_UNLOCK(vp); 1669 return (error); 1670 } 1671 1672 /* 1673 * Set the access and modification times of a file. 1674 */ 1675 /* ARGSUSED */ 1676 utimes(p, uap, retval) 1677 struct proc *p; 1678 register struct utimes_args /* { 1679 syscallarg(char *) path; 1680 syscallarg(struct timeval *) tptr; 1681 } */ *uap; 1682 register_t *retval; 1683 { 1684 register struct vnode *vp; 1685 struct timeval tv[2]; 1686 struct vattr vattr; 1687 int error; 1688 struct nameidata nd; 1689 1690 VATTR_NULL(&vattr); 1691 if (SCARG(uap, tptr) == NULL) { 1692 microtime(&tv[0]); 1693 tv[1] = tv[0]; 1694 vattr.va_vaflags |= VA_UTIMES_NULL; 1695 } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 1696 sizeof (tv))) 1697 return (error); 1698 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1699 if (error = namei(&nd)) 1700 return (error); 1701 vp = nd.ni_vp; 1702 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1703 VOP_LOCK(vp); 1704 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1705 error = EROFS; 1706 else { 1707 vattr.va_atime.ts_sec = tv[0].tv_sec; 1708 vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 1709 vattr.va_mtime.ts_sec = tv[1].tv_sec; 1710 vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 1711 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1712 } 1713 vput(vp); 1714 return (error); 1715 } 1716 1717 /* 1718 * Truncate a file given its path name. 1719 */ 1720 /* ARGSUSED */ 1721 truncate(p, uap, retval) 1722 struct proc *p; 1723 register struct truncate_args /* { 1724 syscallarg(char *) path; 1725 syscallarg(int) pad; 1726 syscallarg(off_t) length; 1727 } */ *uap; 1728 register_t *retval; 1729 { 1730 register struct vnode *vp; 1731 struct vattr vattr; 1732 int error; 1733 struct nameidata nd; 1734 1735 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1736 if (error = namei(&nd)) 1737 return (error); 1738 vp = nd.ni_vp; 1739 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1740 VOP_LOCK(vp); 1741 if (vp->v_type == VDIR) 1742 error = EISDIR; 1743 else if ((error = vn_writechk(vp)) == 0 && 1744 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 1745 VATTR_NULL(&vattr); 1746 vattr.va_size = SCARG(uap, length); 1747 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1748 } 1749 vput(vp); 1750 return (error); 1751 } 1752 1753 /* 1754 * Truncate a file given a file descriptor. 1755 */ 1756 /* ARGSUSED */ 1757 ftruncate(p, uap, retval) 1758 struct proc *p; 1759 register struct ftruncate_args /* { 1760 syscallarg(int) fd; 1761 syscallarg(int) pad; 1762 syscallarg(off_t) length; 1763 } */ *uap; 1764 register_t *retval; 1765 { 1766 struct vattr vattr; 1767 struct vnode *vp; 1768 struct file *fp; 1769 int error; 1770 1771 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1772 return (error); 1773 if ((fp->f_flag & FWRITE) == 0) 1774 return (EINVAL); 1775 vp = (struct vnode *)fp->f_data; 1776 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1777 VOP_LOCK(vp); 1778 if (vp->v_type == VDIR) 1779 error = EISDIR; 1780 else if ((error = vn_writechk(vp)) == 0) { 1781 VATTR_NULL(&vattr); 1782 vattr.va_size = SCARG(uap, length); 1783 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 1784 } 1785 VOP_UNLOCK(vp); 1786 return (error); 1787 } 1788 1789 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1790 /* 1791 * Truncate a file given its path name. 1792 */ 1793 /* ARGSUSED */ 1794 compat_43_truncate(p, uap, retval) 1795 struct proc *p; 1796 register struct compat_43_truncate_args /* { 1797 syscallarg(char *) path; 1798 syscallarg(long) length; 1799 } */ *uap; 1800 register_t *retval; 1801 { 1802 struct truncate_args /* { 1803 syscallarg(char *) path; 1804 syscallarg(int) pad; 1805 syscallarg(off_t) length; 1806 } */ nuap; 1807 1808 SCARG(&nuap, path) = SCARG(uap, path); 1809 SCARG(&nuap, length) = SCARG(uap, length); 1810 return (truncate(p, &nuap, retval)); 1811 } 1812 1813 /* 1814 * Truncate a file given a file descriptor. 1815 */ 1816 /* ARGSUSED */ 1817 compat_43_ftruncate(p, uap, retval) 1818 struct proc *p; 1819 register struct compat_43_ftruncate_args /* { 1820 syscallarg(int) fd; 1821 syscallarg(long) length; 1822 } */ *uap; 1823 register_t *retval; 1824 { 1825 struct ftruncate_args /* { 1826 syscallarg(int) fd; 1827 syscallarg(int) pad; 1828 syscallarg(off_t) length; 1829 } */ nuap; 1830 1831 SCARG(&nuap, fd) = SCARG(uap, fd); 1832 SCARG(&nuap, length) = SCARG(uap, length); 1833 return (ftruncate(p, &nuap, retval)); 1834 } 1835 #endif /* COMPAT_43 || COMPAT_SUNOS */ 1836 1837 /* 1838 * Sync an open file. 1839 */ 1840 /* ARGSUSED */ 1841 fsync(p, uap, retval) 1842 struct proc *p; 1843 struct fsync_args /* { 1844 syscallarg(int) fd; 1845 } */ *uap; 1846 register_t *retval; 1847 { 1848 register struct vnode *vp; 1849 struct file *fp; 1850 int error; 1851 1852 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1853 return (error); 1854 vp = (struct vnode *)fp->f_data; 1855 VOP_LOCK(vp); 1856 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 1857 VOP_UNLOCK(vp); 1858 return (error); 1859 } 1860 1861 /* 1862 * Rename files. Source and destination must either both be directories, 1863 * or both not be directories. If target is a directory, it must be empty. 1864 */ 1865 /* ARGSUSED */ 1866 rename(p, uap, retval) 1867 struct proc *p; 1868 register struct rename_args /* { 1869 syscallarg(char *) from; 1870 syscallarg(char *) to; 1871 } */ *uap; 1872 register_t *retval; 1873 { 1874 register struct vnode *tvp, *fvp, *tdvp; 1875 struct nameidata fromnd, tond; 1876 int error; 1877 1878 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 1879 SCARG(uap, from), p); 1880 if (error = namei(&fromnd)) 1881 return (error); 1882 fvp = fromnd.ni_vp; 1883 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 1884 UIO_USERSPACE, SCARG(uap, to), p); 1885 if (error = namei(&tond)) { 1886 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1887 vrele(fromnd.ni_dvp); 1888 vrele(fvp); 1889 goto out1; 1890 } 1891 tdvp = tond.ni_dvp; 1892 tvp = tond.ni_vp; 1893 if (tvp != NULL) { 1894 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 1895 error = ENOTDIR; 1896 goto out; 1897 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 1898 error = EISDIR; 1899 goto out; 1900 } 1901 } 1902 if (fvp == tdvp) 1903 error = EINVAL; 1904 /* 1905 * If source is the same as the destination (that is the 1906 * same inode number with the same name in the same directory), 1907 * then there is nothing to do. 1908 */ 1909 if (fvp == tvp && fromnd.ni_dvp == tdvp && 1910 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 1911 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 1912 fromnd.ni_cnd.cn_namelen)) 1913 error = -1; 1914 out: 1915 if (!error) { 1916 VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); 1917 if (fromnd.ni_dvp != tdvp) 1918 VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1919 if (tvp) 1920 VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); 1921 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 1922 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 1923 } else { 1924 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 1925 if (tdvp == tvp) 1926 vrele(tdvp); 1927 else 1928 vput(tdvp); 1929 if (tvp) 1930 vput(tvp); 1931 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1932 vrele(fromnd.ni_dvp); 1933 vrele(fvp); 1934 } 1935 vrele(tond.ni_startdir); 1936 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 1937 out1: 1938 if (fromnd.ni_startdir) 1939 vrele(fromnd.ni_startdir); 1940 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 1941 if (error == -1) 1942 return (0); 1943 return (error); 1944 } 1945 1946 /* 1947 * Make a directory file. 1948 */ 1949 /* ARGSUSED */ 1950 mkdir(p, uap, retval) 1951 struct proc *p; 1952 register struct mkdir_args /* { 1953 syscallarg(char *) path; 1954 syscallarg(int) mode; 1955 } */ *uap; 1956 register_t *retval; 1957 { 1958 register struct vnode *vp; 1959 struct vattr vattr; 1960 int error; 1961 struct nameidata nd; 1962 1963 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1964 if (error = namei(&nd)) 1965 return (error); 1966 vp = nd.ni_vp; 1967 if (vp != NULL) { 1968 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1969 if (nd.ni_dvp == vp) 1970 vrele(nd.ni_dvp); 1971 else 1972 vput(nd.ni_dvp); 1973 vrele(vp); 1974 return (EEXIST); 1975 } 1976 VATTR_NULL(&vattr); 1977 vattr.va_type = VDIR; 1978 vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; 1979 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1980 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 1981 if (!error) 1982 vput(nd.ni_vp); 1983 return (error); 1984 } 1985 1986 /* 1987 * Remove a directory file. 1988 */ 1989 /* ARGSUSED */ 1990 rmdir(p, uap, retval) 1991 struct proc *p; 1992 struct rmdir_args /* { 1993 syscallarg(char *) path; 1994 } */ *uap; 1995 register_t *retval; 1996 { 1997 register struct vnode *vp; 1998 int error; 1999 struct nameidata nd; 2000 2001 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 2002 SCARG(uap, path), p); 2003 if (error = namei(&nd)) 2004 return (error); 2005 vp = nd.ni_vp; 2006 if (vp->v_type != VDIR) { 2007 error = ENOTDIR; 2008 goto out; 2009 } 2010 /* 2011 * No rmdir "." please. 2012 */ 2013 if (nd.ni_dvp == vp) { 2014 error = EINVAL; 2015 goto out; 2016 } 2017 /* 2018 * The root of a mounted filesystem cannot be deleted. 2019 */ 2020 if (vp->v_flag & VROOT) 2021 error = EBUSY; 2022 out: 2023 if (!error) { 2024 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2025 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2026 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 2027 } else { 2028 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2029 if (nd.ni_dvp == vp) 2030 vrele(nd.ni_dvp); 2031 else 2032 vput(nd.ni_dvp); 2033 vput(vp); 2034 } 2035 return (error); 2036 } 2037 2038 #if defined(COMPAT_43) || defined(COMPAT_HPUX) 2039 /* 2040 * Read a block of directory entries in a file system independent format. 2041 */ 2042 compat_43_getdirentries(p, uap, retval) 2043 struct proc *p; 2044 register struct compat_43_getdirentries_args /* { 2045 syscallarg(int) fd; 2046 syscallarg(char *) buf; 2047 syscallarg(u_int) count; 2048 syscallarg(long *) basep; 2049 } */ *uap; 2050 register_t *retval; 2051 { 2052 register struct vnode *vp; 2053 struct file *fp; 2054 struct uio auio, kuio; 2055 struct iovec aiov, kiov; 2056 struct dirent *dp, *edp; 2057 caddr_t dirbuf; 2058 int error, eofflag, readcnt; 2059 long loff; 2060 2061 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2062 return (error); 2063 if ((fp->f_flag & FREAD) == 0) 2064 return (EBADF); 2065 vp = (struct vnode *)fp->f_data; 2066 unionread: 2067 if (vp->v_type != VDIR) 2068 return (EINVAL); 2069 aiov.iov_base = SCARG(uap, buf); 2070 aiov.iov_len = SCARG(uap, count); 2071 auio.uio_iov = &aiov; 2072 auio.uio_iovcnt = 1; 2073 auio.uio_rw = UIO_READ; 2074 auio.uio_segflg = UIO_USERSPACE; 2075 auio.uio_procp = p; 2076 auio.uio_resid = SCARG(uap, count); 2077 VOP_LOCK(vp); 2078 loff = auio.uio_offset = fp->f_offset; 2079 # if (BYTE_ORDER != LITTLE_ENDIAN) 2080 if (vp->v_mount->mnt_maxsymlinklen <= 0) { 2081 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 2082 (u_long *)0, 0); 2083 fp->f_offset = auio.uio_offset; 2084 } else 2085 # endif 2086 { 2087 kuio = auio; 2088 kuio.uio_iov = &kiov; 2089 kuio.uio_segflg = UIO_SYSSPACE; 2090 kiov.iov_len = SCARG(uap, count); 2091 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); 2092 kiov.iov_base = dirbuf; 2093 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 2094 (u_long *)0, 0); 2095 fp->f_offset = kuio.uio_offset; 2096 if (error == 0) { 2097 readcnt = SCARG(uap, count) - kuio.uio_resid; 2098 edp = (struct dirent *)&dirbuf[readcnt]; 2099 for (dp = (struct dirent *)dirbuf; dp < edp; ) { 2100 # if (BYTE_ORDER == LITTLE_ENDIAN) 2101 /* 2102 * The expected low byte of 2103 * dp->d_namlen is our dp->d_type. 2104 * The high MBZ byte of dp->d_namlen 2105 * is our dp->d_namlen. 2106 */ 2107 dp->d_type = dp->d_namlen; 2108 dp->d_namlen = 0; 2109 # else 2110 /* 2111 * The dp->d_type is the high byte 2112 * of the expected dp->d_namlen, 2113 * so must be zero'ed. 2114 */ 2115 dp->d_type = 0; 2116 # endif 2117 if (dp->d_reclen > 0) { 2118 dp = (struct dirent *) 2119 ((char *)dp + dp->d_reclen); 2120 } else { 2121 error = EIO; 2122 break; 2123 } 2124 } 2125 if (dp >= edp) 2126 error = uiomove(dirbuf, readcnt, &auio); 2127 } 2128 FREE(dirbuf, M_TEMP); 2129 } 2130 VOP_UNLOCK(vp); 2131 if (error) 2132 return (error); 2133 2134 #ifdef UNION 2135 { 2136 extern int (**union_vnodeop_p)(); 2137 extern struct vnode *union_dircache __P((struct vnode *)); 2138 2139 if ((SCARG(uap, count) == auio.uio_resid) && 2140 (vp->v_op == union_vnodeop_p)) { 2141 struct vnode *lvp; 2142 2143 lvp = union_dircache(vp); 2144 if (lvp != NULLVP) { 2145 struct vattr va; 2146 2147 /* 2148 * If the directory is opaque, 2149 * then don't show lower entries 2150 */ 2151 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 2152 if (va.va_flags & OPAQUE) { 2153 vput(lvp); 2154 lvp = NULL; 2155 } 2156 } 2157 2158 if (lvp != NULLVP) { 2159 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 2160 VOP_UNLOCK(lvp); 2161 2162 if (error) { 2163 vrele(lvp); 2164 return (error); 2165 } 2166 fp->f_data = (caddr_t) lvp; 2167 fp->f_offset = 0; 2168 error = vn_close(vp, FREAD, fp->f_cred, p); 2169 if (error) 2170 return (error); 2171 vp = lvp; 2172 goto unionread; 2173 } 2174 } 2175 } 2176 #endif /* UNION */ 2177 2178 if ((SCARG(uap, count) == auio.uio_resid) && 2179 (vp->v_flag & VROOT) && 2180 (vp->v_mount->mnt_flag & MNT_UNION)) { 2181 struct vnode *tvp = vp; 2182 vp = vp->v_mount->mnt_vnodecovered; 2183 VREF(vp); 2184 fp->f_data = (caddr_t) vp; 2185 fp->f_offset = 0; 2186 vrele(tvp); 2187 goto unionread; 2188 } 2189 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 2190 sizeof(long)); 2191 *retval = SCARG(uap, count) - auio.uio_resid; 2192 return (error); 2193 } 2194 #endif /* COMPAT_43 */ 2195 2196 /* 2197 * Read a block of directory entries in a file system independent format. 2198 */ 2199 getdirentries(p, uap, retval) 2200 struct proc *p; 2201 register struct getdirentries_args /* { 2202 syscallarg(int) fd; 2203 syscallarg(char *) buf; 2204 syscallarg(u_int) count; 2205 syscallarg(long *) basep; 2206 } */ *uap; 2207 register_t *retval; 2208 { 2209 register struct vnode *vp; 2210 struct file *fp; 2211 struct uio auio; 2212 struct iovec aiov; 2213 long loff; 2214 int error, eofflag; 2215 2216 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2217 return (error); 2218 if ((fp->f_flag & FREAD) == 0) 2219 return (EBADF); 2220 vp = (struct vnode *)fp->f_data; 2221 unionread: 2222 if (vp->v_type != VDIR) 2223 return (EINVAL); 2224 aiov.iov_base = SCARG(uap, buf); 2225 aiov.iov_len = SCARG(uap, count); 2226 auio.uio_iov = &aiov; 2227 auio.uio_iovcnt = 1; 2228 auio.uio_rw = UIO_READ; 2229 auio.uio_segflg = UIO_USERSPACE; 2230 auio.uio_procp = p; 2231 auio.uio_resid = SCARG(uap, count); 2232 VOP_LOCK(vp); 2233 loff = auio.uio_offset = fp->f_offset; 2234 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0); 2235 fp->f_offset = auio.uio_offset; 2236 VOP_UNLOCK(vp); 2237 if (error) 2238 return (error); 2239 2240 #ifdef UNION 2241 { 2242 extern int (**union_vnodeop_p)(); 2243 extern struct vnode *union_dircache __P((struct vnode *)); 2244 2245 if ((SCARG(uap, count) == auio.uio_resid) && 2246 (vp->v_op == union_vnodeop_p)) { 2247 struct vnode *lvp; 2248 2249 lvp = union_dircache(vp); 2250 if (lvp != NULLVP) { 2251 struct vattr va; 2252 2253 /* 2254 * If the directory is opaque, 2255 * then don't show lower entries 2256 */ 2257 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 2258 if (va.va_flags & OPAQUE) { 2259 vput(lvp); 2260 lvp = NULL; 2261 } 2262 } 2263 2264 if (lvp != NULLVP) { 2265 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 2266 VOP_UNLOCK(lvp); 2267 2268 if (error) { 2269 vrele(lvp); 2270 return (error); 2271 } 2272 fp->f_data = (caddr_t) lvp; 2273 fp->f_offset = 0; 2274 error = vn_close(vp, FREAD, fp->f_cred, p); 2275 if (error) 2276 return (error); 2277 vp = lvp; 2278 goto unionread; 2279 } 2280 } 2281 } 2282 #endif /* UNION */ 2283 2284 if ((SCARG(uap, count) == auio.uio_resid) && 2285 (vp->v_flag & VROOT) && 2286 (vp->v_mount->mnt_flag & MNT_UNION)) { 2287 struct vnode *tvp = vp; 2288 vp = vp->v_mount->mnt_vnodecovered; 2289 VREF(vp); 2290 fp->f_data = (caddr_t) vp; 2291 fp->f_offset = 0; 2292 vrele(tvp); 2293 goto unionread; 2294 } 2295 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 2296 sizeof(long)); 2297 *retval = SCARG(uap, count) - auio.uio_resid; 2298 return (error); 2299 } 2300 2301 /* 2302 * Set the mode mask for creation of filesystem nodes. 2303 */ 2304 mode_t /* XXX */ 2305 umask(p, uap, retval) 2306 struct proc *p; 2307 struct umask_args /* { 2308 syscallarg(int) newmask; 2309 } */ *uap; 2310 register_t *retval; 2311 { 2312 register struct filedesc *fdp; 2313 2314 fdp = p->p_fd; 2315 *retval = fdp->fd_cmask; 2316 fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS; 2317 return (0); 2318 } 2319 2320 /* 2321 * Void all references to file by ripping underlying filesystem 2322 * away from vnode. 2323 */ 2324 /* ARGSUSED */ 2325 revoke(p, uap, retval) 2326 struct proc *p; 2327 register struct revoke_args /* { 2328 syscallarg(char *) path; 2329 } */ *uap; 2330 register_t *retval; 2331 { 2332 register struct vnode *vp; 2333 struct vattr vattr; 2334 int error; 2335 struct nameidata nd; 2336 2337 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2338 if (error = namei(&nd)) 2339 return (error); 2340 vp = nd.ni_vp; 2341 if (vp->v_type != VCHR && vp->v_type != VBLK) { 2342 error = EINVAL; 2343 goto out; 2344 } 2345 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 2346 goto out; 2347 if (p->p_ucred->cr_uid != vattr.va_uid && 2348 (error = suser(p->p_ucred, &p->p_acflag))) 2349 goto out; 2350 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 2351 vgoneall(vp); 2352 out: 2353 vrele(vp); 2354 return (error); 2355 } 2356 2357 /* 2358 * Convert a user file descriptor to a kernel file entry. 2359 */ 2360 getvnode(fdp, fd, fpp) 2361 struct filedesc *fdp; 2362 struct file **fpp; 2363 int fd; 2364 { 2365 struct file *fp; 2366 2367 if ((u_int)fd >= fdp->fd_nfiles || 2368 (fp = fdp->fd_ofiles[fd]) == NULL) 2369 return (EBADF); 2370 if (fp->f_type != DTYPE_VNODE) 2371 return (EINVAL); 2372 *fpp = fp; 2373 return (0); 2374 } 2375