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