1/* $NetBSD: vfs_syscalls.c,v 1.57 1995/10/07 06:28:51 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 62static 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 */ 72sys_mount(p, v, retval) 73 struct proc *p; 74 void *v; 75 register_t *retval; 76{ 77 register struct sys_mount_args /* { 78 syscallarg(char *) type; 79 syscallarg(char *) path; 80 syscallarg(int) flags; 81 syscallarg(caddr_t) data; 82 } */ *uap = v; 83 register struct vnode *vp; 84 register struct mount *mp; 85 int error, flag; 86 u_long fsindex; 87 char fstypename[MFSNAMELEN]; 88 struct vattr va; 89 struct nameidata nd; 90 91 /* 92 * Get vnode to be covered 93 */ 94 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 95 SCARG(uap, path), p); 96 if (error = namei(&nd)) 97 return (error); 98 vp = nd.ni_vp; 99 if (SCARG(uap, flags) & MNT_UPDATE) { 100 if ((vp->v_flag & VROOT) == 0) { 101 vput(vp); 102 return (EINVAL); 103 } 104 mp = vp->v_mount; 105 flag = mp->mnt_flag; 106 /* 107 * We only allow the filesystem to be reloaded if it 108 * is currently mounted read-only. 109 */ 110 if ((SCARG(uap, flags) & MNT_RELOAD) && 111 ((mp->mnt_flag & MNT_RDONLY) == 0)) { 112 vput(vp); 113 return (EOPNOTSUPP); /* Needs translation */ 114 } 115 mp->mnt_flag |= 116 SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 117 /* 118 * Only root, or the user that did the original mount is 119 * permitted to update it. 120 */ 121 if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && 122 (error = suser(p->p_ucred, &p->p_acflag))) { 123 vput(vp); 124 return (error); 125 } 126 /* 127 * Do not allow NFS export by non-root users. Silently 128 * enforce MNT_NOSUID and MNT_NODEV for non-root users. 129 */ 130 if (p->p_ucred->cr_uid != 0) { 131 if (SCARG(uap, flags) & MNT_EXPORTED) { 132 vput(vp); 133 return (EPERM); 134 } 135 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 136 } 137 VOP_UNLOCK(vp); 138 goto update; 139 } 140 /* 141 * If the user is not root, ensure that they own the directory 142 * onto which we are attempting to mount. 143 */ 144 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || 145 (va.va_uid != p->p_ucred->cr_uid && 146 (error = suser(p->p_ucred, &p->p_acflag)))) { 147 vput(vp); 148 return (error); 149 } 150 /* 151 * Do not allow NFS export by non-root users. Silently 152 * enforce MNT_NOSUID and MNT_NODEV for non-root users. 153 */ 154 if (p->p_ucred->cr_uid != 0) { 155 if (SCARG(uap, flags) & MNT_EXPORTED) { 156 vput(vp); 157 return (EPERM); 158 } 159 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 160 } 161 if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) 162 return (error); 163 if (vp->v_type != VDIR) { 164 vput(vp); 165 return (ENOTDIR); 166 } 167 if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, 168 (size_t *)0)) { 169#if defined(COMPAT_09) || defined(COMPAT_43) 170 /* 171 * Historically filesystem types were identified by number. 172 * If we get an integer for the filesystem type instead of a 173 * string, we check to see if it matches one of the historic 174 * filesystem types. 175 */ 176 fsindex = (u_long)SCARG(uap, type); 177 if (fsindex >= nvfssw || vfssw[fsindex] == NULL) { 178 vput(vp); 179 return (ENODEV); 180 } 181 strncpy(fstypename, vfssw[fsindex]->vfs_name, MFSNAMELEN); 182#else 183 vput(vp); 184 return (error); 185#endif 186 } 187 for (fsindex = 0; fsindex < nvfssw; fsindex++) 188 if (vfssw[fsindex] != NULL && 189 !strncmp(vfssw[fsindex]->vfs_name, fstypename, MFSNAMELEN)) 190 break; 191 if (fsindex >= nvfssw) { 192 vput(vp); 193 return (ENODEV); 194 } 195 if (vp->v_mountedhere != NULL) { 196 vput(vp); 197 return (EBUSY); 198 } 199 200 /* 201 * Allocate and initialize the file system. 202 */ 203 mp = (struct mount *)malloc((u_long)sizeof(struct mount), 204 M_MOUNT, M_WAITOK); 205 bzero((char *)mp, (u_long)sizeof(struct mount)); 206 mp->mnt_op = vfssw[fsindex]; 207 if (error = vfs_lock(mp)) { 208 free((caddr_t)mp, M_MOUNT); 209 vput(vp); 210 return (error); 211 } 212 /* Do this early in case we block later. */ 213 vfssw[fsindex]->vfs_refcount++; 214 vp->v_mountedhere = mp; 215 mp->mnt_vnodecovered = vp; 216 mp->mnt_stat.f_owner = p->p_ucred->cr_uid; 217update: 218 /* 219 * Set the mount level flags. 220 */ 221 if (SCARG(uap, flags) & MNT_RDONLY) 222 mp->mnt_flag |= MNT_RDONLY; 223 else if (mp->mnt_flag & MNT_RDONLY) 224 mp->mnt_flag |= MNT_WANTRDWR; 225 mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 226 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 227 mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC | 228 MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 229 /* 230 * Mount the filesystem. 231 */ 232 error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p); 233 if (mp->mnt_flag & MNT_UPDATE) { 234 vrele(vp); 235 if (mp->mnt_flag & MNT_WANTRDWR) 236 mp->mnt_flag &= ~MNT_RDONLY; 237 mp->mnt_flag &=~ 238 (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 239 if (error) 240 mp->mnt_flag = flag; 241 return (error); 242 } 243 /* 244 * Put the new filesystem on the mount list after root. 245 */ 246 cache_purge(vp); 247 if (!error) { 248 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 249 checkdirs(vp); 250 VOP_UNLOCK(vp); 251 vfs_unlock(mp); 252 (void) VFS_STATFS(mp, &mp->mnt_stat, p); 253 error = VFS_START(mp, 0, p); 254 } else { 255 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 256 vfssw[fsindex]->vfs_refcount--; 257 vfs_unlock(mp); 258 free((caddr_t)mp, M_MOUNT); 259 vput(vp); 260 } 261 return (error); 262} 263 264/* 265 * Scan all active processes to see if any of them have a current 266 * or root directory onto which the new filesystem has just been 267 * mounted. If so, replace them with the new mount point. 268 */ 269checkdirs(olddp) 270 struct vnode *olddp; 271{ 272 struct filedesc *fdp; 273 struct vnode *newdp; 274 struct proc *p; 275 276 if (olddp->v_usecount == 1) 277 return; 278 if (VFS_ROOT(olddp->v_mountedhere, &newdp)) 279 panic("mount: lost mount"); 280 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 281 fdp = p->p_fd; 282 if (fdp->fd_cdir == olddp) { 283 vrele(fdp->fd_cdir); 284 VREF(newdp); 285 fdp->fd_cdir = newdp; 286 } 287 if (fdp->fd_rdir == olddp) { 288 vrele(fdp->fd_rdir); 289 VREF(newdp); 290 fdp->fd_rdir = newdp; 291 } 292 } 293 if (rootvnode == olddp) { 294 vrele(rootvnode); 295 VREF(newdp); 296 rootvnode = newdp; 297 } 298 vput(newdp); 299} 300 301/* 302 * Unmount a file system. 303 * 304 * Note: unmount takes a path to the vnode mounted on as argument, 305 * not special file (as before). 306 */ 307/* ARGSUSED */ 308sys_unmount(p, v, retval) 309 struct proc *p; 310 void *v; 311 register_t *retval; 312{ 313 register struct sys_unmount_args /* { 314 syscallarg(char *) path; 315 syscallarg(int) flags; 316 } */ *uap = v; 317 register struct vnode *vp; 318 struct mount *mp; 319 int error; 320 struct nameidata nd; 321 322 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 323 SCARG(uap, path), p); 324 if (error = namei(&nd)) 325 return (error); 326 vp = nd.ni_vp; 327 mp = vp->v_mount; 328 329 /* 330 * Only root, or the user that did the original mount is 331 * permitted to unmount this filesystem. 332 */ 333 if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && 334 (error = suser(p->p_ucred, &p->p_acflag))) { 335 vput(vp); 336 return (error); 337 } 338 339 /* 340 * Don't allow unmounting the root file system. 341 */ 342 if (mp->mnt_flag & MNT_ROOTFS) { 343 vput(vp); 344 return (EINVAL); 345 } 346 347 /* 348 * Must be the root of the filesystem 349 */ 350 if ((vp->v_flag & VROOT) == 0) { 351 vput(vp); 352 return (EINVAL); 353 } 354 vput(vp); 355 return (dounmount(mp, SCARG(uap, flags), p)); 356} 357 358/* 359 * Do the actual file system unmount. 360 */ 361dounmount(mp, flags, p) 362 register struct mount *mp; 363 int flags; 364 struct proc *p; 365{ 366 struct vnode *coveredvp; 367 int error; 368 369 coveredvp = mp->mnt_vnodecovered; 370 if (vfs_busy(mp)) 371 return (EBUSY); 372 mp->mnt_flag |= MNT_UNMOUNT; 373 if (error = vfs_lock(mp)) 374 return (error); 375 376 mp->mnt_flag &=~ MNT_ASYNC; 377 vnode_pager_umount(mp); /* release cached vnodes */ 378 cache_purgevfs(mp); /* remove cache entries for this file sys */ 379 if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 380 (flags & MNT_FORCE)) 381 error = VFS_UNMOUNT(mp, flags, p); 382 mp->mnt_flag &= ~MNT_UNMOUNT; 383 vfs_unbusy(mp); 384 if (error) { 385 vfs_unlock(mp); 386 } else { 387 TAILQ_REMOVE(&mountlist, mp, mnt_list); 388 if (coveredvp != NULLVP) { 389 vrele(coveredvp); 390 coveredvp->v_mountedhere = (struct mount *)0; 391 } 392 mp->mnt_op->vfs_refcount--; 393 vfs_unlock(mp); 394 if (mp->mnt_vnodelist.lh_first != NULL) 395 panic("unmount: dangling vnode"); 396 free((caddr_t)mp, M_MOUNT); 397 } 398 return (error); 399} 400 401/* 402 * Sync each mounted filesystem. 403 */ 404#ifdef DEBUG 405int syncprt = 0; 406struct ctldebug debug0 = { "syncprt", &syncprt }; 407#endif 408 409/* ARGSUSED */ 410sys_sync(p, v, retval) 411 struct proc *p; 412 void *v; 413 register_t *retval; 414{ 415 register struct mount *mp, *nmp; 416 int asyncflag; 417 418 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 419 /* 420 * Get the next pointer in case we hang on vfs_busy 421 * while we are being unmounted. 422 */ 423 nmp = mp->mnt_list.cqe_next; 424 /* 425 * The lock check below is to avoid races with mount 426 * and unmount. 427 */ 428 if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 429 !vfs_busy(mp)) { 430 asyncflag = mp->mnt_flag & MNT_ASYNC; 431 mp->mnt_flag &= ~MNT_ASYNC; 432 VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 433 if (asyncflag) 434 mp->mnt_flag |= MNT_ASYNC; 435 /* 436 * Get the next pointer again, as the next filesystem 437 * might have been unmounted while we were sync'ing. 438 */ 439 nmp = mp->mnt_list.cqe_next; 440 vfs_unbusy(mp); 441 } 442 } 443#ifdef DEBUG 444 if (syncprt) 445 vfs_bufstats(); 446#endif /* DEBUG */ 447 return (0); 448} 449 450/* 451 * Change filesystem quotas. 452 */ 453/* ARGSUSED */ 454sys_quotactl(p, v, retval) 455 struct proc *p; 456 void *v; 457 register_t *retval; 458{ 459 register struct sys_quotactl_args /* { 460 syscallarg(char *) path; 461 syscallarg(int) cmd; 462 syscallarg(int) uid; 463 syscallarg(caddr_t) arg; 464 } */ *uap = v; 465 register struct mount *mp; 466 int error; 467 struct nameidata nd; 468 469 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 470 if (error = namei(&nd)) 471 return (error); 472 mp = nd.ni_vp->v_mount; 473 vrele(nd.ni_vp); 474 return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), 475 SCARG(uap, arg), p)); 476} 477 478/* 479 * Get filesystem statistics. 480 */ 481/* ARGSUSED */ 482sys_statfs(p, v, retval) 483 struct proc *p; 484 void *v; 485 register_t *retval; 486{ 487 register struct sys_statfs_args /* { 488 syscallarg(char *) path; 489 syscallarg(struct statfs *) buf; 490 } */ *uap = v; 491 register struct mount *mp; 492 register struct statfs *sp; 493 int error; 494 struct nameidata nd; 495 496 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 497 if (error = namei(&nd)) 498 return (error); 499 mp = nd.ni_vp->v_mount; 500 sp = &mp->mnt_stat; 501 vrele(nd.ni_vp); 502 if (error = VFS_STATFS(mp, sp, p)) 503 return (error); 504 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 505 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 506} 507 508/* 509 * Get filesystem statistics. 510 */ 511/* ARGSUSED */ 512sys_fstatfs(p, v, retval) 513 struct proc *p; 514 void *v; 515 register_t *retval; 516{ 517 register struct sys_fstatfs_args /* { 518 syscallarg(int) fd; 519 syscallarg(struct statfs *) buf; 520 } */ *uap = v; 521 struct file *fp; 522 struct mount *mp; 523 register struct statfs *sp; 524 int error; 525 526 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 527 return (error); 528 mp = ((struct vnode *)fp->f_data)->v_mount; 529 sp = &mp->mnt_stat; 530 if (error = VFS_STATFS(mp, sp, p)) 531 return (error); 532 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 533 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 534} 535 536/* 537 * Get statistics on all filesystems. 538 */ 539sys_getfsstat(p, v, retval) 540 struct proc *p; 541 void *v; 542 register_t *retval; 543{ 544 register struct sys_getfsstat_args /* { 545 syscallarg(struct statfs *) buf; 546 syscallarg(long) bufsize; 547 syscallarg(int) flags; 548 } */ *uap = v; 549 register struct mount *mp, *nmp; 550 register struct statfs *sp; 551 caddr_t sfsp; 552 long count, maxcount, error; 553 554 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); 555 sfsp = (caddr_t)SCARG(uap, buf); 556 for (count = 0, 557 mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 558 nmp = mp->mnt_list.cqe_next; 559 if (sfsp && count < maxcount && 560 ((mp->mnt_flag & MNT_MLOCK) == 0)) { 561 sp = &mp->mnt_stat; 562 /* 563 * If MNT_NOWAIT is specified, do not refresh the 564 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 565 */ 566 if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 || 567 (SCARG(uap, flags) & MNT_WAIT)) && 568 (error = VFS_STATFS(mp, sp, p))) 569 continue; 570 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 571 if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 572 return (error); 573 sfsp += sizeof(*sp); 574 } 575 count++; 576 } 577 if (sfsp && count > maxcount) 578 *retval = maxcount; 579 else 580 *retval = count; 581 return (0); 582} 583 584/* 585 * Change current working directory to a given file descriptor. 586 */ 587/* ARGSUSED */ 588sys_fchdir(p, v, retval) 589 struct proc *p; 590 void *v; 591 register_t *retval; 592{ 593 struct sys_fchdir_args /* { 594 syscallarg(int) fd; 595 } */ *uap = v; 596 register struct filedesc *fdp = p->p_fd; 597 struct vnode *vp, *tdp; 598 struct mount *mp; 599 struct file *fp; 600 int error; 601 602 if (error = getvnode(fdp, SCARG(uap, fd), &fp)) 603 return (error); 604 vp = (struct vnode *)fp->f_data; 605 VREF(vp); 606 VOP_LOCK(vp); 607 if (vp->v_type != VDIR) 608 error = ENOTDIR; 609 else 610 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 611 while (!error && (mp = vp->v_mountedhere) != NULL) { 612 if (mp->mnt_flag & MNT_MLOCK) { 613 mp->mnt_flag |= MNT_MWAIT; 614 sleep((caddr_t)mp, PVFS); 615 continue; 616 } 617 if (error = VFS_ROOT(mp, &tdp)) 618 break; 619 vput(vp); 620 vp = tdp; 621 } 622 VOP_UNLOCK(vp); 623 if (error) { 624 vrele(vp); 625 return (error); 626 } 627 vrele(fdp->fd_cdir); 628 fdp->fd_cdir = vp; 629 return (0); 630} 631 632/* 633 * Change current working directory (``.''). 634 */ 635/* ARGSUSED */ 636sys_chdir(p, v, retval) 637 struct proc *p; 638 void *v; 639 register_t *retval; 640{ 641 struct sys_chdir_args /* { 642 syscallarg(char *) path; 643 } */ *uap = v; 644 register struct filedesc *fdp = p->p_fd; 645 int error; 646 struct nameidata nd; 647 648 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 649 SCARG(uap, path), p); 650 if (error = change_dir(&nd, p)) 651 return (error); 652 vrele(fdp->fd_cdir); 653 fdp->fd_cdir = nd.ni_vp; 654 return (0); 655} 656 657/* 658 * Change notion of root (``/'') directory. 659 */ 660/* ARGSUSED */ 661sys_chroot(p, v, retval) 662 struct proc *p; 663 void *v; 664 register_t *retval; 665{ 666 struct sys_chroot_args /* { 667 syscallarg(char *) path; 668 } */ *uap = v; 669 register struct filedesc *fdp = p->p_fd; 670 int error; 671 struct nameidata nd; 672 673 if (error = suser(p->p_ucred, &p->p_acflag)) 674 return (error); 675 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 676 SCARG(uap, path), p); 677 if (error = change_dir(&nd, p)) 678 return (error); 679 if (fdp->fd_rdir != NULL) 680 vrele(fdp->fd_rdir); 681 fdp->fd_rdir = nd.ni_vp; 682 return (0); 683} 684 685/* 686 * Common routine for chroot and chdir. 687 */ 688static int 689change_dir(ndp, p) 690 register struct nameidata *ndp; 691 struct proc *p; 692{ 693 struct vnode *vp; 694 int error; 695 696 if (error = namei(ndp)) 697 return (error); 698 vp = ndp->ni_vp; 699 if (vp->v_type != VDIR) 700 error = ENOTDIR; 701 else 702 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 703 VOP_UNLOCK(vp); 704 if (error) 705 vrele(vp); 706 return (error); 707} 708 709/* 710 * Check permissions, allocate an open file structure, 711 * and call the device open routine if any. 712 */ 713sys_open(p, v, retval) 714 struct proc *p; 715 void *v; 716 register_t *retval; 717{ 718 register struct sys_open_args /* { 719 syscallarg(char *) path; 720 syscallarg(int) flags; 721 syscallarg(int) mode; 722 } */ *uap = v; 723 register struct filedesc *fdp = p->p_fd; 724 register struct file *fp; 725 register struct vnode *vp; 726 int flags, cmode; 727 struct file *nfp; 728 int type, indx, error; 729 struct flock lf; 730 struct nameidata nd; 731 extern struct fileops vnops; 732 733 if (error = falloc(p, &nfp, &indx)) 734 return (error); 735 fp = nfp; 736 flags = FFLAGS(SCARG(uap, flags)); 737 cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 738 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 739 p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 740 if (error = vn_open(&nd, flags, cmode)) { 741 ffree(fp); 742 if ((error == ENODEV || error == ENXIO) && 743 p->p_dupfd >= 0 && /* XXX from fdopen */ 744 (error = 745 dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 746 *retval = indx; 747 return (0); 748 } 749 if (error == ERESTART) 750 error = EINTR; 751 fdp->fd_ofiles[indx] = NULL; 752 return (error); 753 } 754 p->p_dupfd = 0; 755 vp = nd.ni_vp; 756 fp->f_flag = flags & FMASK; 757 fp->f_type = DTYPE_VNODE; 758 fp->f_ops = &vnops; 759 fp->f_data = (caddr_t)vp; 760 if (flags & (O_EXLOCK | O_SHLOCK)) { 761 lf.l_whence = SEEK_SET; 762 lf.l_start = 0; 763 lf.l_len = 0; 764 if (flags & O_EXLOCK) 765 lf.l_type = F_WRLCK; 766 else 767 lf.l_type = F_RDLCK; 768 type = F_FLOCK; 769 if ((flags & FNONBLOCK) == 0) 770 type |= F_WAIT; 771 VOP_UNLOCK(vp); 772 if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 773 (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 774 ffree(fp); 775 fdp->fd_ofiles[indx] = NULL; 776 return (error); 777 } 778 VOP_LOCK(vp); 779 fp->f_flag |= FHASLOCK; 780 } 781 VOP_UNLOCK(vp); 782 *retval = indx; 783 return (0); 784} 785 786/* 787 * Create a special file. 788 */ 789/* ARGSUSED */ 790sys_mknod(p, v, retval) 791 struct proc *p; 792 void *v; 793 register_t *retval; 794{ 795 register struct sys_mknod_args /* { 796 syscallarg(char *) path; 797 syscallarg(int) mode; 798 syscallarg(int) dev; 799 } */ *uap = v; 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 */ 865sys_mkfifo(p, v, retval) 866 struct proc *p; 867 void *v; 868 register_t *retval; 869{ 870 register struct sys_mkfifo_args /* { 871 syscallarg(char *) path; 872 syscallarg(int) mode; 873 } */ *uap = v; 874 struct vattr vattr; 875 int error; 876 struct nameidata nd; 877 878#ifndef FIFO 879 return (EOPNOTSUPP); 880#else 881 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 882 if (error = namei(&nd)) 883 return (error); 884 if (nd.ni_vp != NULL) { 885 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 886 if (nd.ni_dvp == nd.ni_vp) 887 vrele(nd.ni_dvp); 888 else 889 vput(nd.ni_dvp); 890 vrele(nd.ni_vp); 891 return (EEXIST); 892 } 893 VATTR_NULL(&vattr); 894 vattr.va_type = VFIFO; 895 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 896 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 897 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 898#endif /* FIFO */ 899} 900 901/* 902 * Make a hard file link. 903 */ 904/* ARGSUSED */ 905sys_link(p, v, retval) 906 struct proc *p; 907 void *v; 908 register_t *retval; 909{ 910 register struct sys_link_args /* { 911 syscallarg(char *) path; 912 syscallarg(char *) link; 913 } */ *uap = v; 914 register struct vnode *vp; 915 struct nameidata nd; 916 int error; 917 918 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 919 if (error = namei(&nd)) 920 return (error); 921 vp = nd.ni_vp; 922 if (vp->v_type != VDIR || 923 (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 924 nd.ni_cnd.cn_nameiop = CREATE; 925 nd.ni_cnd.cn_flags = LOCKPARENT; 926 nd.ni_dirp = SCARG(uap, link); 927 if ((error = namei(&nd)) == 0) { 928 if (nd.ni_vp != NULL) 929 error = EEXIST; 930 if (!error) { 931 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, 932 LEASE_WRITE); 933 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 934 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 935 } else { 936 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 937 if (nd.ni_dvp == nd.ni_vp) 938 vrele(nd.ni_dvp); 939 else 940 vput(nd.ni_dvp); 941 if (nd.ni_vp) 942 vrele(nd.ni_vp); 943 } 944 } 945 } 946 vrele(vp); 947 return (error); 948} 949 950/* 951 * Make a symbolic link. 952 */ 953/* ARGSUSED */ 954sys_symlink(p, v, retval) 955 struct proc *p; 956 void *v; 957 register_t *retval; 958{ 959 register struct sys_symlink_args /* { 960 syscallarg(char *) path; 961 syscallarg(char *) link; 962 } */ *uap = v; 963 struct vattr vattr; 964 char *path; 965 int error; 966 struct nameidata nd; 967 968 MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 969 if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, (size_t *)0)) 970 goto out; 971 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); 972 if (error = namei(&nd)) 973 goto out; 974 if (nd.ni_vp) { 975 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 976 if (nd.ni_dvp == nd.ni_vp) 977 vrele(nd.ni_dvp); 978 else 979 vput(nd.ni_dvp); 980 vrele(nd.ni_vp); 981 error = EEXIST; 982 goto out; 983 } 984 VATTR_NULL(&vattr); 985 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 986 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 987 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 988out: 989 FREE(path, M_NAMEI); 990 return (error); 991} 992 993/* 994 * Delete a whiteout from the filesystem. 995 */ 996/* ARGSUSED */ 997sys_undelete(p, v, retval) 998 struct proc *p; 999 void *v; 1000 register_t *retval; 1001{ 1002 register struct sys_undelete_args /* { 1003 syscallarg(char *) path; 1004 } */ *uap = v; 1005 int error; 1006 struct nameidata nd; 1007 1008 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, 1009 SCARG(uap, path), p); 1010 error = namei(&nd); 1011 if (error) 1012 return (error); 1013 1014 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 1015 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1016 if (nd.ni_dvp == nd.ni_vp) 1017 vrele(nd.ni_dvp); 1018 else 1019 vput(nd.ni_dvp); 1020 if (nd.ni_vp) 1021 vrele(nd.ni_vp); 1022 return (EEXIST); 1023 } 1024 1025 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1026 if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) 1027 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1028 vput(nd.ni_dvp); 1029 return (error); 1030} 1031 1032/* 1033 * Delete a name from the filesystem. 1034 */ 1035/* ARGSUSED */ 1036sys_unlink(p, v, retval) 1037 struct proc *p; 1038 void *v; 1039 register_t *retval; 1040{ 1041 struct sys_unlink_args /* { 1042 syscallarg(char *) path; 1043 } */ *uap = v; 1044 register struct vnode *vp; 1045 int error; 1046 struct nameidata nd; 1047 1048 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1049 if (error = namei(&nd)) 1050 return (error); 1051 vp = nd.ni_vp; 1052 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1053 VOP_LOCK(vp); 1054 1055 if (vp->v_type != VDIR || 1056 (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 1057 /* 1058 * The root of a mounted filesystem cannot be deleted. 1059 */ 1060 if (vp->v_flag & VROOT) 1061 error = EBUSY; 1062 else 1063 (void)vnode_pager_uncache(vp); 1064 } 1065 1066 if (!error) { 1067 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1068 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1069 } else { 1070 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1071 if (nd.ni_dvp == vp) 1072 vrele(nd.ni_dvp); 1073 else 1074 vput(nd.ni_dvp); 1075 if (vp != NULLVP) 1076 vput(vp); 1077 } 1078 return (error); 1079} 1080 1081/* 1082 * Reposition read/write file offset. 1083 */ 1084sys_lseek(p, v, retval) 1085 struct proc *p; 1086 void *v; 1087 register_t *retval; 1088{ 1089 register struct sys_lseek_args /* { 1090 syscallarg(int) fd; 1091 syscallarg(int) pad; 1092 syscallarg(off_t) offset; 1093 syscallarg(int) whence; 1094 } */ *uap = v; 1095 struct ucred *cred = p->p_ucred; 1096 register struct filedesc *fdp = p->p_fd; 1097 register struct file *fp; 1098 struct vattr vattr; 1099 int error; 1100 1101 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 1102 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) 1103 return (EBADF); 1104 if (fp->f_type != DTYPE_VNODE) 1105 return (ESPIPE); 1106 switch (SCARG(uap, whence)) { 1107 case L_INCR: 1108 fp->f_offset += SCARG(uap, offset); 1109 break; 1110 case L_XTND: 1111 if (error = 1112 VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) 1113 return (error); 1114 fp->f_offset = SCARG(uap, offset) + vattr.va_size; 1115 break; 1116 case L_SET: 1117 fp->f_offset = SCARG(uap, offset); 1118 break; 1119 default: 1120 return (EINVAL); 1121 } 1122 *(off_t *)retval = fp->f_offset; 1123 return (0); 1124} 1125 1126/* 1127 * Check access permissions. 1128 */ 1129sys_access(p, v, retval) 1130 struct proc *p; 1131 void *v; 1132 register_t *retval; 1133{ 1134 register struct sys_access_args /* { 1135 syscallarg(char *) path; 1136 syscallarg(int) flags; 1137 } */ *uap = v; 1138 register struct ucred *cred = p->p_ucred; 1139 register struct vnode *vp; 1140 int error, flags, t_gid, t_uid; 1141 struct nameidata nd; 1142 1143 t_uid = cred->cr_uid; 1144 t_gid = cred->cr_gid; 1145 cred->cr_uid = p->p_cred->p_ruid; 1146 cred->cr_gid = p->p_cred->p_rgid; 1147 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1148 SCARG(uap, path), p); 1149 if (error = namei(&nd)) 1150 goto out1; 1151 vp = nd.ni_vp; 1152 1153 /* Flags == 0 means only check for existence. */ 1154 if (SCARG(uap, flags)) { 1155 flags = 0; 1156 if (SCARG(uap, flags) & R_OK) 1157 flags |= VREAD; 1158 if (SCARG(uap, flags) & W_OK) 1159 flags |= VWRITE; 1160 if (SCARG(uap, flags) & X_OK) 1161 flags |= VEXEC; 1162 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 1163 error = VOP_ACCESS(vp, flags, cred, p); 1164 } 1165 vput(vp); 1166out1: 1167 cred->cr_uid = t_uid; 1168 cred->cr_gid = t_gid; 1169 return (error); 1170} 1171 1172/* 1173 * Get file status; this version follows links. 1174 */ 1175/* ARGSUSED */ 1176sys_stat(p, v, retval) 1177 struct proc *p; 1178 void *v; 1179 register_t *retval; 1180{ 1181 register struct sys_stat_args /* { 1182 syscallarg(char *) path; 1183 syscallarg(struct stat *) ub; 1184 } */ *uap = v; 1185 struct stat sb; 1186 int error; 1187 struct nameidata nd; 1188 1189 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1190 SCARG(uap, path), p); 1191 if (error = namei(&nd)) 1192 return (error); 1193 error = vn_stat(nd.ni_vp, &sb, p); 1194 vput(nd.ni_vp); 1195 if (error) 1196 return (error); 1197 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1198 return (error); 1199} 1200 1201/* 1202 * Get file status; this version does not follow links. 1203 */ 1204/* ARGSUSED */ 1205sys_lstat(p, v, retval) 1206 struct proc *p; 1207 void *v; 1208 register_t *retval; 1209{ 1210 register struct sys_lstat_args /* { 1211 syscallarg(char *) path; 1212 syscallarg(struct stat *) ub; 1213 } */ *uap = v; 1214 int error; 1215 struct vnode *vp, *dvp; 1216 struct stat sb, sb1; 1217 struct nameidata nd; 1218 1219 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 1220 SCARG(uap, path), p); 1221 if (error = namei(&nd)) 1222 return (error); 1223 /* 1224 * For symbolic links, always return the attributes of its 1225 * containing directory, except for mode, size, and links. 1226 */ 1227 vp = nd.ni_vp; 1228 dvp = nd.ni_dvp; 1229 if (vp->v_type != VLNK) { 1230 if (dvp == vp) 1231 vrele(dvp); 1232 else 1233 vput(dvp); 1234 error = vn_stat(vp, &sb, p); 1235 vput(vp); 1236 if (error) 1237 return (error); 1238 } else { 1239 error = vn_stat(dvp, &sb, p); 1240 vput(dvp); 1241 if (error) { 1242 vput(vp); 1243 return (error); 1244 } 1245 error = vn_stat(vp, &sb1, p); 1246 vput(vp); 1247 if (error) 1248 return (error); 1249 sb.st_mode &= ~S_IFDIR; 1250 sb.st_mode |= S_IFLNK; 1251 sb.st_nlink = sb1.st_nlink; 1252 sb.st_size = sb1.st_size; 1253 sb.st_blocks = sb1.st_blocks; 1254 } 1255 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1256 return (error); 1257} 1258 1259/* 1260 * Get configurable pathname variables. 1261 */ 1262/* ARGSUSED */ 1263sys_pathconf(p, v, retval) 1264 struct proc *p; 1265 void *v; 1266 register_t *retval; 1267{ 1268 register struct sys_pathconf_args /* { 1269 syscallarg(char *) path; 1270 syscallarg(int) name; 1271 } */ *uap = v; 1272 int error; 1273 struct nameidata nd; 1274 1275 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1276 SCARG(uap, path), p); 1277 if (error = namei(&nd)) 1278 return (error); 1279 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval); 1280 vput(nd.ni_vp); 1281 return (error); 1282} 1283 1284/* 1285 * Return target name of a symbolic link. 1286 */ 1287/* ARGSUSED */ 1288sys_readlink(p, v, retval) 1289 struct proc *p; 1290 void *v; 1291 register_t *retval; 1292{ 1293 register struct sys_readlink_args /* { 1294 syscallarg(char *) path; 1295 syscallarg(char *) buf; 1296 syscallarg(int) count; 1297 } */ *uap = v; 1298 register struct vnode *vp; 1299 struct iovec aiov; 1300 struct uio auio; 1301 int error; 1302 struct nameidata nd; 1303 1304 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 1305 SCARG(uap, path), p); 1306 if (error = namei(&nd)) 1307 return (error); 1308 vp = nd.ni_vp; 1309 if (vp->v_type != VLNK) 1310 error = EINVAL; 1311 else { 1312 aiov.iov_base = SCARG(uap, buf); 1313 aiov.iov_len = SCARG(uap, count); 1314 auio.uio_iov = &aiov; 1315 auio.uio_iovcnt = 1; 1316 auio.uio_offset = 0; 1317 auio.uio_rw = UIO_READ; 1318 auio.uio_segflg = UIO_USERSPACE; 1319 auio.uio_procp = p; 1320 auio.uio_resid = SCARG(uap, count); 1321 error = VOP_READLINK(vp, &auio, p->p_ucred); 1322 } 1323 vput(vp); 1324 *retval = SCARG(uap, count) - auio.uio_resid; 1325 return (error); 1326} 1327 1328/* 1329 * Change flags of a file given a path name. 1330 */ 1331/* ARGSUSED */ 1332sys_chflags(p, v, retval) 1333 struct proc *p; 1334 void *v; 1335 register_t *retval; 1336{ 1337 register struct sys_chflags_args /* { 1338 syscallarg(char *) path; 1339 syscallarg(int) flags; 1340 } */ *uap = v; 1341 register struct vnode *vp; 1342 struct vattr vattr; 1343 int error; 1344 struct nameidata nd; 1345 1346 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1347 if (error = namei(&nd)) 1348 return (error); 1349 vp = nd.ni_vp; 1350 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1351 VOP_LOCK(vp); 1352 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1353 error = EROFS; 1354 else { 1355 VATTR_NULL(&vattr); 1356 vattr.va_flags = SCARG(uap, flags); 1357 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1358 } 1359 vput(vp); 1360 return (error); 1361} 1362 1363/* 1364 * Change flags of a file given a file descriptor. 1365 */ 1366/* ARGSUSED */ 1367sys_fchflags(p, v, retval) 1368 struct proc *p; 1369 void *v; 1370 register_t *retval; 1371{ 1372 register struct sys_fchflags_args /* { 1373 syscallarg(int) fd; 1374 syscallarg(int) flags; 1375 } */ *uap = v; 1376 struct vattr vattr; 1377 struct vnode *vp; 1378 struct file *fp; 1379 int error; 1380 1381 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1382 return (error); 1383 vp = (struct vnode *)fp->f_data; 1384 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1385 VOP_LOCK(vp); 1386 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1387 error = EROFS; 1388 else { 1389 VATTR_NULL(&vattr); 1390 vattr.va_flags = SCARG(uap, flags); 1391 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1392 } 1393 VOP_UNLOCK(vp); 1394 return (error); 1395} 1396 1397/* 1398 * Change mode of a file given path name. 1399 */ 1400/* ARGSUSED */ 1401sys_chmod(p, v, retval) 1402 struct proc *p; 1403 void *v; 1404 register_t *retval; 1405{ 1406 register struct sys_chmod_args /* { 1407 syscallarg(char *) path; 1408 syscallarg(int) mode; 1409 } */ *uap = v; 1410 register struct vnode *vp; 1411 struct vattr vattr; 1412 int error; 1413 struct nameidata nd; 1414 1415 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1416 if (error = namei(&nd)) 1417 return (error); 1418 vp = nd.ni_vp; 1419 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1420 VOP_LOCK(vp); 1421 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1422 error = EROFS; 1423 else { 1424 VATTR_NULL(&vattr); 1425 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1426 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1427 } 1428 vput(vp); 1429 return (error); 1430} 1431 1432/* 1433 * Change mode of a file given a file descriptor. 1434 */ 1435/* ARGSUSED */ 1436sys_fchmod(p, v, retval) 1437 struct proc *p; 1438 void *v; 1439 register_t *retval; 1440{ 1441 register struct sys_fchmod_args /* { 1442 syscallarg(int) fd; 1443 syscallarg(int) mode; 1444 } */ *uap = v; 1445 struct vattr vattr; 1446 struct vnode *vp; 1447 struct file *fp; 1448 int error; 1449 1450 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1451 return (error); 1452 vp = (struct vnode *)fp->f_data; 1453 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1454 VOP_LOCK(vp); 1455 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1456 error = EROFS; 1457 else { 1458 VATTR_NULL(&vattr); 1459 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1460 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1461 } 1462 VOP_UNLOCK(vp); 1463 return (error); 1464} 1465 1466/* 1467 * Set ownership given a path name. 1468 */ 1469/* ARGSUSED */ 1470sys_chown(p, v, retval) 1471 struct proc *p; 1472 void *v; 1473 register_t *retval; 1474{ 1475 register struct sys_chown_args /* { 1476 syscallarg(char *) path; 1477 syscallarg(int) uid; 1478 syscallarg(int) gid; 1479 } */ *uap = v; 1480 register struct vnode *vp; 1481 struct vattr vattr; 1482 int error; 1483 struct nameidata nd; 1484 1485 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1486 if (error = namei(&nd)) 1487 return (error); 1488 vp = nd.ni_vp; 1489 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1490 VOP_LOCK(vp); 1491 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1492 error = EROFS; 1493 else { 1494 VATTR_NULL(&vattr); 1495 vattr.va_uid = SCARG(uap, uid); 1496 vattr.va_gid = SCARG(uap, gid); 1497 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1498 } 1499 vput(vp); 1500 return (error); 1501} 1502 1503/* 1504 * Set ownership given a file descriptor. 1505 */ 1506/* ARGSUSED */ 1507sys_fchown(p, v, retval) 1508 struct proc *p; 1509 void *v; 1510 register_t *retval; 1511{ 1512 register struct sys_fchown_args /* { 1513 syscallarg(int) fd; 1514 syscallarg(int) uid; 1515 syscallarg(int) gid; 1516 } */ *uap = v; 1517 struct vattr vattr; 1518 struct vnode *vp; 1519 struct file *fp; 1520 int error; 1521 1522 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1523 return (error); 1524 vp = (struct vnode *)fp->f_data; 1525 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1526 VOP_LOCK(vp); 1527 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1528 error = EROFS; 1529 else { 1530 VATTR_NULL(&vattr); 1531 vattr.va_uid = SCARG(uap, uid); 1532 vattr.va_gid = SCARG(uap, gid); 1533 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1534 } 1535 VOP_UNLOCK(vp); 1536 return (error); 1537} 1538 1539/* 1540 * Set the access and modification times of a file. 1541 */ 1542/* ARGSUSED */ 1543sys_utimes(p, v, retval) 1544 struct proc *p; 1545 void *v; 1546 register_t *retval; 1547{ 1548 register struct sys_utimes_args /* { 1549 syscallarg(char *) path; 1550 syscallarg(struct timeval *) tptr; 1551 } */ *uap = v; 1552 register struct vnode *vp; 1553 struct timeval tv[2]; 1554 struct vattr vattr; 1555 int error; 1556 struct nameidata nd; 1557 1558 VATTR_NULL(&vattr); 1559 if (SCARG(uap, tptr) == NULL) { 1560 microtime(&tv[0]); 1561 tv[1] = tv[0]; 1562 vattr.va_vaflags |= VA_UTIMES_NULL; 1563 } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 1564 sizeof (tv))) 1565 return (error); 1566 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1567 if (error = namei(&nd)) 1568 return (error); 1569 vp = nd.ni_vp; 1570 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1571 VOP_LOCK(vp); 1572 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1573 error = EROFS; 1574 else { 1575 vattr.va_atime.ts_sec = tv[0].tv_sec; 1576 vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 1577 vattr.va_mtime.ts_sec = tv[1].tv_sec; 1578 vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 1579 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1580 } 1581 vput(vp); 1582 return (error); 1583} 1584 1585/* 1586 * Truncate a file given its path name. 1587 */ 1588/* ARGSUSED */ 1589sys_truncate(p, v, retval) 1590 struct proc *p; 1591 void *v; 1592 register_t *retval; 1593{ 1594 register struct sys_truncate_args /* { 1595 syscallarg(char *) path; 1596 syscallarg(int) pad; 1597 syscallarg(off_t) length; 1598 } */ *uap = v; 1599 register struct vnode *vp; 1600 struct vattr vattr; 1601 int error; 1602 struct nameidata nd; 1603 1604 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1605 if (error = namei(&nd)) 1606 return (error); 1607 vp = nd.ni_vp; 1608 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1609 VOP_LOCK(vp); 1610 if (vp->v_type == VDIR) 1611 error = EISDIR; 1612 else if ((error = vn_writechk(vp)) == 0 && 1613 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 1614 VATTR_NULL(&vattr); 1615 vattr.va_size = SCARG(uap, length); 1616 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1617 } 1618 vput(vp); 1619 return (error); 1620} 1621 1622/* 1623 * Truncate a file given a file descriptor. 1624 */ 1625/* ARGSUSED */ 1626sys_ftruncate(p, v, retval) 1627 struct proc *p; 1628 void *v; 1629 register_t *retval; 1630{ 1631 register struct sys_ftruncate_args /* { 1632 syscallarg(int) fd; 1633 syscallarg(int) pad; 1634 syscallarg(off_t) length; 1635 } */ *uap = v; 1636 struct vattr vattr; 1637 struct vnode *vp; 1638 struct file *fp; 1639 int error; 1640 1641 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1642 return (error); 1643 if ((fp->f_flag & FWRITE) == 0) 1644 return (EINVAL); 1645 vp = (struct vnode *)fp->f_data; 1646 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1647 VOP_LOCK(vp); 1648 if (vp->v_type == VDIR) 1649 error = EISDIR; 1650 else if ((error = vn_writechk(vp)) == 0) { 1651 VATTR_NULL(&vattr); 1652 vattr.va_size = SCARG(uap, length); 1653 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 1654 } 1655 VOP_UNLOCK(vp); 1656 return (error); 1657} 1658 1659/* 1660 * Sync an open file. 1661 */ 1662/* ARGSUSED */ 1663sys_fsync(p, v, retval) 1664 struct proc *p; 1665 void *v; 1666 register_t *retval; 1667{ 1668 struct sys_fsync_args /* { 1669 syscallarg(int) fd; 1670 } */ *uap = v; 1671 register struct vnode *vp; 1672 struct file *fp; 1673 int error; 1674 1675 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1676 return (error); 1677 vp = (struct vnode *)fp->f_data; 1678 VOP_LOCK(vp); 1679 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 1680 VOP_UNLOCK(vp); 1681 return (error); 1682} 1683 1684/* 1685 * Rename files. Source and destination must either both be directories, 1686 * or both not be directories. If target is a directory, it must be empty. 1687 */ 1688/* ARGSUSED */ 1689sys_rename(p, v, retval) 1690 struct proc *p; 1691 void *v; 1692 register_t *retval; 1693{ 1694 register struct sys_rename_args /* { 1695 syscallarg(char *) from; 1696 syscallarg(char *) to; 1697 } */ *uap = v; 1698 register struct vnode *tvp, *fvp, *tdvp; 1699 struct nameidata fromnd, tond; 1700 int error; 1701 1702 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 1703 SCARG(uap, from), p); 1704 if (error = namei(&fromnd)) 1705 return (error); 1706 fvp = fromnd.ni_vp; 1707 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 1708 UIO_USERSPACE, SCARG(uap, to), p); 1709 if (error = namei(&tond)) { 1710 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1711 vrele(fromnd.ni_dvp); 1712 vrele(fvp); 1713 goto out1; 1714 } 1715 tdvp = tond.ni_dvp; 1716 tvp = tond.ni_vp; 1717 if (tvp != NULL) { 1718 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 1719 error = ENOTDIR; 1720 goto out; 1721 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 1722 error = EISDIR; 1723 goto out; 1724 } 1725 } 1726 if (fvp == tdvp) 1727 error = EINVAL; 1728 /* 1729 * If source is the same as the destination (that is the 1730 * same inode number with the same name in the same directory), 1731 * then there is nothing to do. 1732 */ 1733 if (fvp == tvp && fromnd.ni_dvp == tdvp && 1734 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 1735 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 1736 fromnd.ni_cnd.cn_namelen)) 1737 error = -1; 1738out: 1739 if (!error) { 1740 VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); 1741 if (fromnd.ni_dvp != tdvp) 1742 VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1743 if (tvp) 1744 VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); 1745 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 1746 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 1747 } else { 1748 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 1749 if (tdvp == tvp) 1750 vrele(tdvp); 1751 else 1752 vput(tdvp); 1753 if (tvp) 1754 vput(tvp); 1755 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1756 vrele(fromnd.ni_dvp); 1757 vrele(fvp); 1758 } 1759 vrele(tond.ni_startdir); 1760 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 1761out1: 1762 if (fromnd.ni_startdir) 1763 vrele(fromnd.ni_startdir); 1764 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 1765 if (error == -1) 1766 return (0); 1767 return (error); 1768} 1769 1770/* 1771 * Make a directory file. 1772 */ 1773/* ARGSUSED */ 1774sys_mkdir(p, v, retval) 1775 struct proc *p; 1776 void *v; 1777 register_t *retval; 1778{ 1779 register struct sys_mkdir_args /* { 1780 syscallarg(char *) path; 1781 syscallarg(int) mode; 1782 } */ *uap = v; 1783 register struct vnode *vp; 1784 struct vattr vattr; 1785 int error; 1786 struct nameidata nd; 1787 1788 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1789 if (error = namei(&nd)) 1790 return (error); 1791 vp = nd.ni_vp; 1792 if (vp != NULL) { 1793 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1794 if (nd.ni_dvp == vp) 1795 vrele(nd.ni_dvp); 1796 else 1797 vput(nd.ni_dvp); 1798 vrele(vp); 1799 return (EEXIST); 1800 } 1801 VATTR_NULL(&vattr); 1802 vattr.va_type = VDIR; 1803 vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; 1804 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1805 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 1806 if (!error) 1807 vput(nd.ni_vp); 1808 return (error); 1809} 1810 1811/* 1812 * Remove a directory file. 1813 */ 1814/* ARGSUSED */ 1815sys_rmdir(p, v, retval) 1816 struct proc *p; 1817 void *v; 1818 register_t *retval; 1819{ 1820 struct sys_rmdir_args /* { 1821 syscallarg(char *) path; 1822 } */ *uap = v; 1823 register struct vnode *vp; 1824 int error; 1825 struct nameidata nd; 1826 1827 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 1828 SCARG(uap, path), p); 1829 if (error = namei(&nd)) 1830 return (error); 1831 vp = nd.ni_vp; 1832 if (vp->v_type != VDIR) { 1833 error = ENOTDIR; 1834 goto out; 1835 } 1836 /* 1837 * No rmdir "." please. 1838 */ 1839 if (nd.ni_dvp == vp) { 1840 error = EINVAL; 1841 goto out; 1842 } 1843 /* 1844 * The root of a mounted filesystem cannot be deleted. 1845 */ 1846 if (vp->v_flag & VROOT) 1847 error = EBUSY; 1848out: 1849 if (!error) { 1850 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1851 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1852 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1853 } else { 1854 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1855 if (nd.ni_dvp == vp) 1856 vrele(nd.ni_dvp); 1857 else 1858 vput(nd.ni_dvp); 1859 vput(vp); 1860 } 1861 return (error); 1862} 1863 1864/* 1865 * Read a block of directory entries in a file system independent format. 1866 */ 1867sys_getdirentries(p, v, retval) 1868 struct proc *p; 1869 void *v; 1870 register_t *retval; 1871{ 1872 register struct sys_getdirentries_args /* { 1873 syscallarg(int) fd; 1874 syscallarg(char *) buf; 1875 syscallarg(u_int) count; 1876 syscallarg(long *) basep; 1877 } */ *uap = v; 1878 register struct vnode *vp; 1879 struct file *fp; 1880 struct uio auio; 1881 struct iovec aiov; 1882 long loff; 1883 int error, eofflag; 1884 1885 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1886 return (error); 1887 if ((fp->f_flag & FREAD) == 0) 1888 return (EBADF); 1889 vp = (struct vnode *)fp->f_data; 1890unionread: 1891 if (vp->v_type != VDIR) 1892 return (EINVAL); 1893 aiov.iov_base = SCARG(uap, buf); 1894 aiov.iov_len = SCARG(uap, count); 1895 auio.uio_iov = &aiov; 1896 auio.uio_iovcnt = 1; 1897 auio.uio_rw = UIO_READ; 1898 auio.uio_segflg = UIO_USERSPACE; 1899 auio.uio_procp = p; 1900 auio.uio_resid = SCARG(uap, count); 1901 VOP_LOCK(vp); 1902 loff = auio.uio_offset = fp->f_offset; 1903 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0); 1904 fp->f_offset = auio.uio_offset; 1905 VOP_UNLOCK(vp); 1906 if (error) 1907 return (error); 1908 1909#ifdef UNION 1910{ 1911 extern int (**union_vnodeop_p)(); 1912 extern struct vnode *union_dircache __P((struct vnode *)); 1913 1914 if ((SCARG(uap, count) == auio.uio_resid) && 1915 (vp->v_op == union_vnodeop_p)) { 1916 struct vnode *lvp; 1917 1918 lvp = union_dircache(vp); 1919 if (lvp != NULLVP) { 1920 struct vattr va; 1921 1922 /* 1923 * If the directory is opaque, 1924 * then don't show lower entries 1925 */ 1926 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 1927 if (va.va_flags & OPAQUE) { 1928 vput(lvp); 1929 lvp = NULL; 1930 } 1931 } 1932 1933 if (lvp != NULLVP) { 1934 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 1935 VOP_UNLOCK(lvp); 1936 1937 if (error) { 1938 vrele(lvp); 1939 return (error); 1940 } 1941 fp->f_data = (caddr_t) lvp; 1942 fp->f_offset = 0; 1943 error = vn_close(vp, FREAD, fp->f_cred, p); 1944 if (error) 1945 return (error); 1946 vp = lvp; 1947 goto unionread; 1948 } 1949 } 1950} 1951#endif /* UNION */ 1952 1953 if ((SCARG(uap, count) == auio.uio_resid) && 1954 (vp->v_flag & VROOT) && 1955 (vp->v_mount->mnt_flag & MNT_UNION)) { 1956 struct vnode *tvp = vp; 1957 vp = vp->v_mount->mnt_vnodecovered; 1958 VREF(vp); 1959 fp->f_data = (caddr_t) vp; 1960 fp->f_offset = 0; 1961 vrele(tvp); 1962 goto unionread; 1963 } 1964 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 1965 sizeof(long)); 1966 *retval = SCARG(uap, count) - auio.uio_resid; 1967 return (error); 1968} 1969 1970/* 1971 * Set the mode mask for creation of filesystem nodes. 1972 */ 1973int 1974sys_umask(p, v, retval) 1975 struct proc *p; 1976 void *v; 1977 register_t *retval; 1978{ 1979 struct sys_umask_args /* { 1980 syscallarg(int) newmask; 1981 } */ *uap = v; 1982 register struct filedesc *fdp; 1983 1984 fdp = p->p_fd; 1985 *retval = fdp->fd_cmask; 1986 fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS; 1987 return (0); 1988} 1989 1990/* 1991 * Void all references to file by ripping underlying filesystem 1992 * away from vnode. 1993 */ 1994/* ARGSUSED */ 1995sys_revoke(p, v, retval) 1996 struct proc *p; 1997 void *v; 1998 register_t *retval; 1999{ 2000 register struct sys_revoke_args /* { 2001 syscallarg(char *) path; 2002 } */ *uap = v; 2003 register struct vnode *vp; 2004 struct vattr vattr; 2005 int error; 2006 struct nameidata nd; 2007 2008 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2009 if (error = namei(&nd)) 2010 return (error); 2011 vp = nd.ni_vp; 2012 if (vp->v_type != VCHR && vp->v_type != VBLK) { 2013 error = EINVAL; 2014 goto out; 2015 } 2016 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 2017 goto out; 2018 if (p->p_ucred->cr_uid != vattr.va_uid && 2019 (error = suser(p->p_ucred, &p->p_acflag))) 2020 goto out; 2021 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 2022 vgoneall(vp); 2023out: 2024 vrele(vp); 2025 return (error); 2026} 2027 2028/* 2029 * Convert a user file descriptor to a kernel file entry. 2030 */ 2031getvnode(fdp, fd, fpp) 2032 struct filedesc *fdp; 2033 struct file **fpp; 2034 int fd; 2035{ 2036 struct file *fp; 2037 2038 if ((u_int)fd >= fdp->fd_nfiles || 2039 (fp = fdp->fd_ofiles[fd]) == NULL) 2040 return (EBADF); 2041 if (fp->f_type != DTYPE_VNODE) 2042 return (EINVAL); 2043 *fpp = fp; 2044 return (0); 2045} 2046