1/* $OpenBSD: t9.2,v 1.2 2013/12/01 16:40:56 krw Exp $ */ 2/* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */ 3 4/* 5 * Copyright (c) 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * (c) UNIX System Laboratories, Inc. 8 * All or some portions of this file are derived from material licensed 9 * to the University of California by American Telephone and Telegraph 10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11 * the permission of UNIX System Laboratories, Inc. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)vfs_syscalls.c 8.28 (Berkeley) 12/10/94 38 */ 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/namei.h> 43#include <sys/filedesc.h> 44#include <sys/kernel.h> 45#include <sys/file.h> 46#include <sys/stat.h> 47#include <sys/vnode.h> 48#include <sys/mount.h> 49#include <sys/proc.h> 50#include <sys/uio.h> 51#include <sys/malloc.h> 52#include <sys/dirent.h> 53#include <sys/extattr.h> 54 55#include <sys/syscallargs.h> 56 57#include <uvm/uvm_extern.h> 58#include <sys/sysctl.h> 59 60extern int suid_clear; 61int usermount = 0; /* sysctl: by default, users may not mount */ 62 63static int change_dir(struct nameidata *, struct proc *); 64 65void checkdirs(struct vnode *); 66 67/* 68 * Redirection info so we don't have to include the union fs routines in 69 * the kernel directly. This way, we can build unionfs as an LKM. The 70 * pointer gets filled in later, when we modload the LKM, or when the 71 * compiled-in unionfs code gets initialized. For now, we just set 72 * it to a stub routine. 73 */ 74 75int (*union_check_p)(struct proc *, struct vnode **, 76 struct file *, struct uio, int *) = NULL; 77 78/* 79 * Virtual File System System Calls 80 */ 81 82/* 83 * Mount a file system. 84 */ 85/* ARGSUSED */ 86int 87sys_mount(p, v, retval) 88 struct proc *p; 89 void *v; 90 register_t *retval; 91{ 92 register struct sys_mount_args /* { 93 syscallarg(char *) type; 94 syscallarg(char *) path; 95 syscallarg(int) flags; 96 syscallarg(void *) data; 97 } */ *uap = v; 98 register struct vnode *vp; 99 register struct mount *mp; 100 int error, flag = 0; 101#ifdef COMPAT_43 102 u_long fstypenum = 0; 103#endif 104 char fstypename[MFSNAMELEN]; 105 char fspath[MNAMELEN]; 106 struct vattr va; 107 struct nameidata nd; 108 struct vfsconf *vfsp; 109 struct timeval tv; 110 111 if (usermount == 0 && (error = suser(p->p_ucred, &p->p_acflag))) 112 return (error); 113 114 /* 115 * Mount points must fit in MNAMELEN, not MAXPATHLEN. 116 */ 117 error = copyinstr(SCARG(uap, path), fspath, MNAMELEN, NULL); 118 if (error) 119 return(error); 120 121 /* 122 * Get vnode to be covered 123 */ 124 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, p); 125 if ((error = namei(&nd)) != 0) 126 return (error); 127 vp = nd.ni_vp; 128 if (SCARG(uap, flags) & MNT_UPDATE) { 129 if ((vp->v_flag & VROOT) == 0) { 130 vput(vp); 131 return (EINVAL); 132 } 133 mp = vp->v_mount; 134 flag = mp->mnt_flag; 135 /* 136 * We only allow the filesystem to be reloaded if it 137 * is currently mounted read-only. 138 */ 139 if ((SCARG(uap, flags) & MNT_RELOAD) && 140 ((mp->mnt_flag & MNT_RDONLY) == 0)) { 141 vput(vp); 142 return (EOPNOTSUPP); /* Needs translation */ 143 } 144 mp->mnt_flag |= 145 SCARG(uap, flags) & (MNT_RELOAD | MNT_UPDATE); 146 /* 147 * Only root, or the user that did the original mount is 148 * permitted to update it. 149 */ 150 if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && 151 (error = suser(p->p_ucred, &p->p_acflag))) { 152 vput(vp); 153 return (error); 154 } 155 /* 156 * Do not allow NFS export by non-root users. Silently 157 * enforce MNT_NOSUID and MNT_NODEV for non-root users. 158 */ 159 if (p->p_ucred->cr_uid != 0) { 160 if (SCARG(uap, flags) & MNT_EXPORTED) { 161 vput(vp); 162 return (EPERM); 163 } 164 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 165 } 166 if ((error = vfs_busy(mp, LK_NOWAIT, 0, p)) != 0) { 167 vput(vp); 168 return (error); 169 } 170 VOP_UNLOCK(vp, 0, p); 171 goto update; 172 } 173 /* 174 * If the user is not root, ensure that they own the directory 175 * onto which we are attempting to mount. 176 */ 177 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || 178 (va.va_uid != p->p_ucred->cr_uid && 179 (error = suser(p->p_ucred, &p->p_acflag)))) { 180 vput(vp); 181 return (error); 182 } 183 /* 184 * Do not allow NFS export by non-root users. Silently 185 * enforce MNT_NOSUID and MNT_NODEV for non-root users. 186 */ 187 if (p->p_ucred->cr_uid != 0) { 188 if (SCARG(uap, flags) & MNT_EXPORTED) { 189 vput(vp); 190 return (EPERM); 191 } 192 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 193 } 194 if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0) 195 return (error); 196 if (vp->v_type != VDIR) { 197 vput(vp); 198 return (ENOTDIR); 199 } 200 error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL); 201 if (error) { 202#ifdef COMPAT_43 203 /* 204 * Historically filesystem types were identified by number. 205 * If we get an integer for the filesystem type instead of a 206 * string, we check to see if it matches one of the historic 207 * filesystem types. 208 */ 209 fstypenum = (u_long)SCARG(uap, type); 210 211 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 212 if (vfsp->vfc_typenum == fstypenum) 213 break; 214 if (vfsp == NULL) { 215 vput(vp); 216 return (ENODEV); 217 } 218 strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN); 219 220#else 221 vput(vp); 222 return (error); 223#endif 224 } 225 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) { 226 if (!strcmp(vfsp->vfc_name, fstypename)) 227 break; 228 } 229 230 if (vfsp == NULL) { 231 vput(vp); 232 return (EOPNOTSUPP); 233 } 234 235 if (vp->v_mountedhere != NULL) { 236 vput(vp); 237 return (EBUSY); 238 } 239 240 /* 241 * Allocate and initialize the file system. 242 */ 243 mp = (struct mount *)malloc((u_long)sizeof(struct mount), 244 M_MOUNT, M_WAITOK); 245 bzero((char *)mp, (u_long)sizeof(struct mount)); 246 lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0); 247 /* This error never happens, but it makes auditing easier */ 248 if ((error = vfs_busy(mp, LK_NOWAIT, 0, p))) 249 return (error); 250 mp->mnt_op = vfsp->vfc_vfsops; 251 mp->mnt_vfc = vfsp; 252 mp->mnt_flag |= (vfsp->vfc_flags & MNT_VISFLAGMASK); 253 strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); 254 mp->mnt_vnodecovered = vp; 255 mp->mnt_stat.f_owner = p->p_ucred->cr_uid; 256update: 257 /* 258 * Set the mount level flags. 259 */ 260 if (SCARG(uap, flags) & MNT_RDONLY) 261 mp->mnt_flag |= MNT_RDONLY; 262 else if (mp->mnt_flag & MNT_RDONLY) 263 mp->mnt_flag |= MNT_WANTRDWR; 264 mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 265 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_SOFTDEP | 266 MNT_NOATIME | MNT_FORCE); 267 mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC | 268 MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | 269 MNT_SOFTDEP | MNT_NOATIME | MNT_FORCE); 270 /* 271 * Mount the filesystem. 272 */ 273 error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p); 274 if (!error) { 275 microtime(&tv); 276 mp->mnt_stat.f_ctime = tv.tv_sec; 277 } 278 if (mp->mnt_flag & MNT_UPDATE) { 279 vrele(vp); 280 if (mp->mnt_flag & MNT_WANTRDWR) 281 mp->mnt_flag &= ~MNT_RDONLY; 282 mp->mnt_flag &=~ 283 (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 284 if (error) 285 mp->mnt_flag = flag; 286 287 if ((mp->mnt_flag & MNT_RDONLY) == 0) { 288 if (mp->mnt_syncer == NULL) 289 error = vfs_allocate_syncvnode(mp); 290 } else { 291 if (mp->mnt_syncer != NULL) 292 vgone(mp->mnt_syncer); 293 mp->mnt_syncer = NULL; 294 } 295 296 vfs_unbusy(mp, p); 297 return (error); 298 } 299 300 vp->v_mountedhere = mp; 301 302 /* 303 * Put the new filesystem on the mount list after root. 304 */ 305 cache_purge(vp); 306 if (!error) { 307 vfsp->vfc_refcount++; 308 simple_lock(&mountlist_slock); 309 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 310 simple_unlock(&mountlist_slock); 311 checkdirs(vp); 312 VOP_UNLOCK(vp, 0, p); 313 if ((mp->mnt_flag & MNT_RDONLY) == 0) 314 error = vfs_allocate_syncvnode(mp); 315 vfs_unbusy(mp, p); 316 (void) VFS_STATFS(mp, &mp->mnt_stat, p); 317 if ((error = VFS_START(mp, 0, p)) != 0) 318 vrele(vp); 319 } else { 320 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 321 vfs_unbusy(mp, p); 322 free((caddr_t)mp, M_MOUNT); 323 vput(vp); 324 } 325 return (error); 326} 327 328/* 329 * Scan all active processes to see if any of them have a current 330 * or root directory onto which the new filesystem has just been 331 * mounted. If so, replace them with the new mount point. 332 */ 333void 334checkdirs(olddp) 335 struct vnode *olddp; 336{ 337 struct filedesc *fdp; 338 struct vnode *newdp; 339 struct proc *p; 340 341 if (olddp->v_usecount == 1) 342 return; 343 if (VFS_ROOT(olddp->v_mountedhere, &newdp)) 344 panic("mount: lost mount"); 345 for (p = LIST_FIRST(&allproc); p != 0; p = LIST_NEXT(p, p_list)) { 346 fdp = p->p_fd; 347 if (fdp->fd_cdir == olddp) { 348 vrele(fdp->fd_cdir); 349 VREF(newdp); 350 fdp->fd_cdir = newdp; 351 } 352 if (fdp->fd_rdir == olddp) { 353 vrele(fdp->fd_rdir); 354 VREF(newdp); 355 fdp->fd_rdir = newdp; 356 } 357 } 358 if (rootvnode == olddp) { 359 vrele(rootvnode); 360 VREF(newdp); 361 rootvnode = newdp; 362 } 363 vput(newdp); 364} 365 366/* 367 * Unmount a file system. 368 * 369 * Note: unmount takes a path to the vnode mounted on as argument, 370 * not special file (as before). 371 */ 372/* ARGSUSED */ 373int 374sys_unmount(p, v, retval) 375 struct proc *p; 376 void *v; 377 register_t *retval; 378{ 379 register struct sys_unmount_args /* { 380 syscallarg(char *) path; 381 syscallarg(int) flags; 382 } */ *uap = v; 383 register struct vnode *vp; 384 struct mount *mp; 385 int error; 386 struct nameidata nd; 387 388 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 389 SCARG(uap, path), p); 390 if ((error = namei(&nd)) != 0) 391 return (error); 392 vp = nd.ni_vp; 393 mp = vp->v_mount; 394 395 /* 396 * Only root, or the user that did the original mount is 397 * permitted to unmount this filesystem. 398 */ 399 if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && 400 (error = suser(p->p_ucred, &p->p_acflag))) { 401 vput(vp); 402 return (error); 403 } 404 405 /* 406 * Don't allow unmounting the root file system. 407 */ 408 if (mp->mnt_flag & MNT_ROOTFS) { 409 vput(vp); 410 return (EINVAL); 411 } 412 413 /* 414 * Must be the root of the filesystem 415 */ 416 if ((vp->v_flag & VROOT) == 0) { 417 vput(vp); 418 return (EINVAL); 419 } 420 vput(vp); 421 422 if (vfs_busy(mp, LK_EXCLUSIVE, NULL, p)) 423 return (EBUSY); 424 425 return (dounmount(mp, SCARG(uap, flags), p, vp)); 426} 427 428/* 429 * Do the actual file system unmount. 430 */ 431int 432dounmount(struct mount *mp, int flags, struct proc *p, struct vnode *olddp) 433{ 434 struct vnode *coveredvp; 435 struct proc *p2; 436 int error; 437 int hadsyncer = 0; 438 439 mp->mnt_flag &=~ MNT_ASYNC; 440 cache_purgevfs(mp); /* remove cache entries for this file sys */ 441 if (mp->mnt_syncer != NULL) { 442 hadsyncer = 1; 443 vgone(mp->mnt_syncer); 444 mp->mnt_syncer = NULL; 445 } 446 if (((mp->mnt_flag & MNT_RDONLY) || 447 (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) || 448 (flags & MNT_FORCE)) 449 error = VFS_UNMOUNT(mp, flags, p); 450 simple_lock(&mountlist_slock); 451 if (error) { 452 if ((mp->mnt_flag & MNT_RDONLY) == 0 && hadsyncer) 453 (void) vfs_allocate_syncvnode(mp); 454 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, 455 &mountlist_slock, p); 456 return (error); 457 } 458 TAILQ_REMOVE(&mountlist, mp, mnt_list); 459 if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) { 460 if (olddp) { 461 /* 462 * Try to put processes back in a real directory 463 * after a forced unmount. 464 * XXX We're not holding a ref on olddp, which may 465 * change, so compare id numbers. 466 */ 467 LIST_FOREACH(p2, &allproc, p_list) { 468 struct filedesc *fdp = p2->p_fd; 469 if (fdp->fd_cdir && 470 fdp->fd_cdir->v_id == olddp->v_id) { 471 vrele(fdp->fd_cdir); 472 vref(coveredvp); 473 fdp->fd_cdir = coveredvp; 474 } 475 if (fdp->fd_rdir && 476 fdp->fd_rdir->v_id == olddp->v_id) { 477 vrele(fdp->fd_rdir); 478 vref(coveredvp); 479 fdp->fd_rdir = coveredvp; 480 } 481 } 482 } 483 coveredvp->v_mountedhere = NULL; 484 vrele(coveredvp); 485 } 486 mp->mnt_vfc->vfc_refcount--; 487 if (mp->mnt_vnodelist.lh_first != NULL) 488 panic("unmount: dangling vnode"); 489 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p); 490 free((caddr_t)mp, M_MOUNT); 491 return (0); 492} 493 494/* 495 * Sync each mounted filesystem. 496 */ 497#ifdef DEBUG 498int syncprt = 0; 499struct ctldebug debug0 = { "syncprt", &syncprt }; 500#endif 501 502/* ARGSUSED */ 503int 504sys_sync(p, v, retval) 505 struct proc *p; 506 void *v; 507 register_t *retval; 508{ 509 register struct mount *mp, *nmp; 510 int asyncflag; 511 512 simple_lock(&mountlist_slock); 513 TAILQ_FOREACH_REVERSE_SAFE(mp, &mountlist, mnt_list, nmp) { 514 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) 515 continue; 516 if ((mp->mnt_flag & MNT_RDONLY) == 0) { 517 asyncflag = mp->mnt_flag & MNT_ASYNC; 518 mp->mnt_flag &= ~MNT_ASYNC; 519 uvm_vnp_sync(mp); 520 VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 521 if (asyncflag) 522 mp->mnt_flag |= MNT_ASYNC; 523 } 524 simple_lock(&mountlist_slock); 525 vfs_unbusy(mp, p); 526 } 527 simple_unlock(&mountlist_slock); 528 529#ifdef DEBUG 530 if (syncprt) 531 vfs_bufstats(); 532#endif /* DEBUG */ 533 return (0); 534} 535 536/* 537 * Change filesystem quotas. 538 */ 539/* ARGSUSED */ 540int 541sys_quotactl(p, v, retval) 542 struct proc *p; 543 void *v; 544 register_t *retval; 545{ 546 register struct sys_quotactl_args /* { 547 syscallarg(char *) path; 548 syscallarg(int) cmd; 549 syscallarg(int) uid; 550 syscallarg(caddr_t) arg; 551 } */ *uap = v; 552 register struct mount *mp; 553 int error; 554 struct nameidata nd; 555 556 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 557 if ((error = namei(&nd)) != 0) 558 return (error); 559 mp = nd.ni_vp->v_mount; 560 vrele(nd.ni_vp); 561 return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), 562 SCARG(uap, arg), p)); 563} 564 565/* 566 * Get filesystem statistics. 567 */ 568/* ARGSUSED */ 569int 570sys_statfs(p, v, retval) 571 struct proc *p; 572 void *v; 573 register_t *retval; 574{ 575 register struct sys_statfs_args /* { 576 syscallarg(char *) path; 577 syscallarg(struct statfs *) buf; 578 } */ *uap = v; 579 register struct mount *mp; 580 register struct statfs *sp; 581 int error; 582 struct nameidata nd; 583 struct statfs sb; 584 585 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 586 if ((error = namei(&nd)) != 0) 587 return (error); 588 mp = nd.ni_vp->v_mount; 589 sp = &mp->mnt_stat; 590 vrele(nd.ni_vp); 591 if ((error = VFS_STATFS(mp, sp, p)) != 0) 592 return (error); 593 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 594#if notyet 595 if (mp->mnt_flag & MNT_SOFTDEP) 596 sp->f_eflags = STATFS_SOFTUPD; 597#endif 598 /* Don't let non-root see filesystem id (for NFS security) */ 599 if (suser(p->p_ucred, &p->p_acflag)) { 600 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 601 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 602 sp = &sb; 603 } 604 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 605} 606 607/* 608 * Get filesystem statistics. 609 */ 610/* ARGSUSED */ 611int 612sys_fstatfs(p, v, retval) 613 struct proc *p; 614 void *v; 615 register_t *retval; 616{ 617 struct sys_fstatfs_args /* { 618 syscallarg(int) fd; 619 syscallarg(struct statfs *) buf; 620 } */ *uap = v; 621 struct file *fp; 622 struct mount *mp; 623 struct statfs *sp; 624 int error; 625 struct statfs sb; 626 627 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 628 return (error); 629 mp = ((struct vnode *)fp->f_data)->v_mount; 630 sp = &mp->mnt_stat; 631 error = VFS_STATFS(mp, sp, p); 632 FRELE(fp); 633 if (error) 634 return (error); 635 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 636#if notyet 637 if (mp->mnt_flag & MNT_SOFTDEP) 638 sp->f_eflags = STATFS_SOFTUPD; 639#endif 640 /* Don't let non-root see filesystem id (for NFS security) */ 641 if (suser(p->p_ucred, &p->p_acflag)) { 642 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 643 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 644 sp = &sb; 645 } 646 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 647} 648 649/* 650 * Get statistics on all filesystems. 651 */ 652int 653sys_getfsstat(p, v, retval) 654 struct proc *p; 655 void *v; 656 register_t *retval; 657{ 658 register struct sys_getfsstat_args /* { 659 syscallarg(struct statfs *) buf; 660 syscallarg(size_t) bufsize; 661 syscallarg(int) flags; 662 } */ *uap = v; 663 register struct mount *mp *nmp; 664 register struct statfs *sp; 665 struct statfs sb; 666 caddr_t sfsp; 667 size_t count, maxcount; 668 int error, flags = SCARG(uap, flags); 669 670 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); 671 sfsp = (caddr_t)SCARG(uap, buf); 672 count = 0; 673 simple_lock(&mountlist_slock); 674 TAILQ_FOREACH_REVERSE_SAFE(mp, &mountlist, mnt_list, nmp) { 675 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) 676 continue; 677 if (sfsp && count < maxcount) { 678 sp = &mp->mnt_stat; 679 680 /* Refresh stats unless MNT_NOWAIT is specified */ 681 if (flags != MNT_NOWAIT && 682 flags != MNT_LAZY && 683 (flags == MNT_WAIT || 684 flags == 0) && 685 (error = VFS_STATFS(mp, sp, p))) { 686 simple_lock(&mountlist_slock); 687 vfs_unbusy(mp, p); 688 continue; 689 } 690 691 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 692#if notyet 693 if (mp->mnt_flag & MNT_SOFTDEP) 694 sp->f_eflags = STATFS_SOFTUPD; 695#endif 696 if (suser(p->p_ucred, &p->p_acflag)) { 697 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 698 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 699 sp = &sb; 700 } 701 error = copyout((caddr_t)sp, sfsp, sizeof(*sp)); 702 if (error) { 703 vfs_unbusy(mp, p); 704 return (error); 705 } 706 sfsp += sizeof(*sp); 707 } 708 count++; 709 simple_lock(&mountlist_slock); 710 vfs_unbusy(mp, p); 711 } 712 simple_unlock(&mountlist_slock); 713 if (sfsp && count > maxcount) 714 *retval = maxcount; 715 else 716 *retval = count; 717 return (0); 718} 719 720/* 721 * Change current working directory to a given file descriptor. 722 */ 723/* ARGSUSED */ 724int 725sys_fchdir(p, v, retval) 726 struct proc *p; 727 void *v; 728 register_t *retval; 729{ 730 struct sys_fchdir_args /* { 731 syscallarg(int) fd; 732 } */ *uap = v; 733 struct filedesc *fdp = p->p_fd; 734 struct vnode *vp, *tdp; 735 struct mount *mp; 736 struct file *fp; 737 int error; 738 739 if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0) 740 return (error); 741 vp = (struct vnode *)fp->f_data; 742 VREF(vp); 743 FRELE(fp); 744 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 745 if (vp->v_type != VDIR) 746 error = ENOTDIR; 747 else 748 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 749 750 while (!error && (mp = vp->v_mountedhere) != NULL) { 751 if (vfs_busy(mp, 0, 0, p)) 752 continue; 753 error = VFS_ROOT(mp, &tdp); 754 vfs_unbusy(mp, p); 755 if (error) 756 break; 757 vput(vp); 758 vp = tdp; 759 } 760 if (error) { 761 vput(vp); 762 return (error); 763 } 764 VOP_UNLOCK(vp, 0, p); 765 vrele(fdp->fd_cdir); 766 fdp->fd_cdir = vp; 767 return (0); 768} 769 770/* 771 * Change current working directory (``.''). 772 */ 773/* ARGSUSED */ 774int 775sys_chdir(p, v, retval) 776 struct proc *p; 777 void *v; 778 register_t *retval; 779{ 780 struct sys_chdir_args /* { 781 syscallarg(char *) path; 782 } */ *uap = v; 783 register struct filedesc *fdp = p->p_fd; 784 int error; 785 struct nameidata nd; 786 787 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 788 SCARG(uap, path), p); 789 if ((error = change_dir(&nd, p)) != 0) 790 return (error); 791 vrele(fdp->fd_cdir); 792 fdp->fd_cdir = nd.ni_vp; 793 return (0); 794} 795 796/* 797 * Change notion of root (``/'') directory. 798 */ 799/* ARGSUSED */ 800int 801sys_chroot(p, v, retval) 802 struct proc *p; 803 void *v; 804 register_t *retval; 805{ 806 struct sys_chroot_args /* { 807 syscallarg(char *) path; 808 } */ *uap = v; 809 register struct filedesc *fdp = p->p_fd; 810 int error; 811 struct nameidata nd; 812 813 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 814 return (error); 815 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 816 SCARG(uap, path), p); 817 if ((error = change_dir(&nd, p)) != 0) 818 return (error); 819 if (fdp->fd_rdir != NULL) { 820 /* 821 * A chroot() done inside a changed root environment does 822 * an automatic chdir to avoid the out-of-tree experience. 823 */ 824 vrele(fdp->fd_rdir); 825 vrele(fdp->fd_cdir); 826 VREF(nd.ni_vp); 827 fdp->fd_cdir = nd.ni_vp; 828 } 829 fdp->fd_rdir = nd.ni_vp; 830 return (0); 831} 832 833/* 834 * Common routine for chroot and chdir. 835 */ 836static int 837change_dir(ndp, p) 838 register struct nameidata *ndp; 839 struct proc *p; 840{ 841 struct vnode *vp; 842 int error; 843 844 if ((error = namei(ndp)) != 0) 845 return (error); 846 vp = ndp->ni_vp; 847 if (vp->v_type != VDIR) 848 error = ENOTDIR; 849 else 850 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 851 if (error) 852 vput(vp); 853 else 854 VOP_UNLOCK(vp, 0, p); 855 return (error); 856} 857 858/* 859 * Check permissions, allocate an open file structure, 860 * and call the device open routine if any. 861 */ 862int 863sys_open(p, v, retval) 864 struct proc *p; 865 void *v; 866 register_t *retval; 867{ 868 struct sys_open_args /* { 869 syscallarg(char *) path; 870 syscallarg(int) flags; 871 syscallarg(int) mode; 872 } */ *uap = v; 873 struct filedesc *fdp = p->p_fd; 874 struct file *fp; 875 struct vnode *vp; 876 struct vattr vattr; 877 int flags, cmode; 878 int type, indx, error, localtrunc = 0; 879 struct flock lf; 880 struct nameidata nd; 881 882 if ((error = falloc(p, &fp, &indx)) != 0) 883 return (error); 884 885 flags = FFLAGS(SCARG(uap, flags)); 886 cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 887 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 888 p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 889 if ((flags & O_TRUNC) && (flags & (O_EXLOCK | O_SHLOCK))) { 890 localtrunc = 1; 891 flags &= ~O_TRUNC; /* Must do truncate ourselves */ 892 } 893 if ((error = vn_open(&nd, flags, cmode)) != 0) { 894 if ((error == ENODEV || error == ENXIO) && 895 p->p_dupfd >= 0 && /* XXX from fdopen */ 896 (error = 897 dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 898 closef(fp, p); 899 *retval = indx; 900 return (0); 901 } 902 if (error == ERESTART) 903 error = EINTR; 904 fdremove(fdp, indx); 905 closef(fp, p); 906 return (error); 907 } 908 p->p_dupfd = 0; 909 vp = nd.ni_vp; 910 fp->f_flag = flags & FMASK; 911 fp->f_type = DTYPE_VNODE; 912 fp->f_ops = &vnops; 913 fp->f_data = (caddr_t)vp; 914 if (flags & (O_EXLOCK | O_SHLOCK)) { 915 lf.l_whence = SEEK_SET; 916 lf.l_start = 0; 917 lf.l_len = 0; 918 if (flags & O_EXLOCK) 919 lf.l_type = F_WRLCK; 920 else 921 lf.l_type = F_RDLCK; 922 type = F_FLOCK; 923 if ((flags & FNONBLOCK) == 0) 924 type |= F_WAIT; 925 VOP_UNLOCK(vp, 0, p); 926 error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type); 927 if (error) { 928 /* closef will vn_close the file for us. */ 929 fdremove(fdp, indx); 930 closef(fp, p); 931 return (error); 932 } 933 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 934 fp->f_flag |= FHASLOCK; 935 } 936 if (localtrunc) { 937 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 938 if ((fp->f_flag & FWRITE) == 0) 939 error = EACCES; 940 else if (vp->v_mount->mnt_flag & MNT_RDONLY) 941 error = EROFS; 942 else if (vp->v_type == VDIR) 943 error = EISDIR; 944 else if ((error = vn_writechk(vp)) == 0) { 945 VATTR_NULL(&vattr); 946 vattr.va_size = 0; 947 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 948 } 949 if (error) { 950 VOP_UNLOCK(vp, 0, p); 951 /* closef will close the file for us. */ 952 fdremove(fdp, indx); 953 closef(fp, p); 954 return (error); 955 } 956 } 957 VOP_UNLOCK(vp, 0, p); 958 *retval = indx; 959 FILE_SET_MATURE(fp); 960 return (0); 961} 962 963/* 964 * Get file handle system call 965 */ 966int 967sys_getfh(p, v, retval) 968 struct proc *p; 969 register void *v; 970 register_t *retval; 971{ 972 register struct sys_getfh_args /* { 973 syscallarg(char *) fname; 974 syscallarg(fhandle_t *) fhp; 975 } */ *uap = v; 976 register struct vnode *vp; 977 fhandle_t fh; 978 int error; 979 struct nameidata nd; 980 981 /* 982 * Must be super user 983 */ 984 error = suser(p->p_ucred, &p->p_acflag); 985 if (error) 986 return (error); 987 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 988 SCARG(uap, fname), p); 989 error = namei(&nd); 990 if (error) 991 return (error); 992 vp = nd.ni_vp; 993 bzero((caddr_t)&fh, sizeof(fh)); 994 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 995 error = VFS_VPTOFH(vp, &fh.fh_fid); 996 vput(vp); 997 if (error) 998 return (error); 999 error = copyout((caddr_t)&fh, (caddr_t)SCARG(uap, fhp), sizeof (fh)); 1000 return (error); 1001} 1002 1003/* 1004 * Open a file given a file handle. 1005 * 1006 * Check permissions, allocate an open file structure, 1007 * and call the device open routine if any. 1008 */ 1009int 1010sys_fhopen(p, v, retval) 1011 struct proc *p; 1012 void *v; 1013 register_t *retval; 1014{ 1015 register struct sys_fhopen_args /* { 1016 syscallarg(const fhandle_t *) fhp; 1017 syscallarg(int) flags; 1018 } */ *uap = v; 1019 struct filedesc *fdp = p->p_fd; 1020 struct file *fp; 1021 struct vnode *vp = NULL; 1022 struct mount *mp; 1023 struct ucred *cred = p->p_ucred; 1024 int flags; 1025 int type, indx, error=0; 1026 struct flock lf; 1027 struct vattr va; 1028 fhandle_t fh; 1029 1030 /* 1031 * Must be super user 1032 */ 1033 if ((error = suser(p->p_ucred, &p->p_acflag))) 1034 return (error); 1035 1036 flags = FFLAGS(SCARG(uap, flags)); 1037 if ((flags & (FREAD | FWRITE)) == 0) 1038 return (EINVAL); 1039 if ((flags & O_CREAT)) 1040 return (EINVAL); 1041 1042 if ((error = falloc(p, &fp, &indx)) != 0) 1043 return (error); 1044 1045 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0) 1046 goto bad; 1047 1048 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) { 1049 error = ESTALE; 1050 goto bad; 1051 } 1052 1053 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)) != 0) { 1054 vp = NULL; /* most likely unnecessary sanity for bad: */ 1055 goto bad; 1056 } 1057 1058 /* Now do an effective vn_open */ 1059 1060 if (vp->v_type == VSOCK) { 1061 error = EOPNOTSUPP; 1062 goto bad; 1063 } 1064 if (flags & FREAD) { 1065 if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0) 1066 goto bad; 1067 } 1068 if (flags & (FWRITE | O_TRUNC)) { 1069 if (vp->v_type == VDIR) { 1070 error = EISDIR; 1071 goto bad; 1072 } 1073 if ((error = vn_writechk(vp)) != 0 || 1074 (error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0) 1075 goto bad; 1076 } 1077 if (flags & O_TRUNC) { 1078 VOP_UNLOCK(vp, 0, p); /* XXX */ 1079 VOP_LEASE(vp, p, cred, LEASE_WRITE); 1080 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */ 1081 VATTR_NULL(&va); 1082 va.va_size = 0; 1083 if ((error = VOP_SETATTR(vp, &va, cred, p)) != 0) 1084 goto bad; 1085 } 1086 if ((error = VOP_OPEN(vp, flags, cred, p)) != 0) 1087 goto bad; 1088 if (flags & FWRITE) 1089 vp->v_writecount++; 1090 1091 /* done with modified vn_open, now finish what sys_open does. */ 1092 1093 fp->f_flag = flags & FMASK; 1094 fp->f_type = DTYPE_VNODE; 1095 fp->f_ops = &vnops; 1096 fp->f_data = (caddr_t)vp; 1097 if (flags & (O_EXLOCK | O_SHLOCK)) { 1098 lf.l_whence = SEEK_SET; 1099 lf.l_start = 0; 1100 lf.l_len = 0; 1101 if (flags & O_EXLOCK) 1102 lf.l_type = F_WRLCK; 1103 else 1104 lf.l_type = F_RDLCK; 1105 type = F_FLOCK; 1106 if ((flags & FNONBLOCK) == 0) 1107 type |= F_WAIT; 1108 VOP_UNLOCK(vp, 0, p); 1109 error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type); 1110 if (error) { 1111 /* closef will vn_close the file for us. */ 1112 fdremove(fdp, indx); 1113 closef(fp, p); 1114 return (error); 1115 } 1116 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1117 fp->f_flag |= FHASLOCK; 1118 } 1119 VOP_UNLOCK(vp, 0, p); 1120 *retval = indx; 1121 FILE_SET_MATURE(fp); 1122 return (0); 1123 1124bad: 1125 fdremove(fdp, indx); 1126 closef(fp, p); 1127 if (vp != NULL) 1128 vput(vp); 1129 return (error); 1130} 1131 1132/* ARGSUSED */ 1133int 1134sys_fhstat(p, v, retval) 1135 struct proc *p; 1136 void *v; 1137 register_t *retval; 1138{ 1139 register struct sys_fhstat_args /* { 1140 syscallarg(const fhandle_t *) fhp; 1141 syscallarg(struct stat *) sb; 1142 } */ *uap = v; 1143 struct stat sb; 1144 int error; 1145 fhandle_t fh; 1146 struct mount *mp; 1147 struct vnode *vp; 1148 1149 /* 1150 * Must be super user 1151 */ 1152 if ((error = suser(p->p_ucred, &p->p_acflag))) 1153 return (error); 1154 1155 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0) 1156 return (error); 1157 1158 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) 1159 return (ESTALE); 1160 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) 1161 return (error); 1162 error = vn_stat(vp, &sb, p); 1163 vput(vp); 1164 if (error) 1165 return (error); 1166 error = copyout(&sb, SCARG(uap, sb), sizeof(sb)); 1167 return (error); 1168} 1169 1170/* ARGSUSED */ 1171int 1172sys_fhstatfs(p, v, retval) 1173 struct proc *p; 1174 void *v; 1175 register_t *retval; 1176{ 1177 register struct sys_fhstatfs_args /* 1178 syscallarg(const fhandle_t *) fhp; 1179 syscallarg(struct statfs *) buf; 1180 } */ *uap = v; 1181 struct statfs sp; 1182 fhandle_t fh; 1183 struct mount *mp; 1184 struct vnode *vp; 1185 int error; 1186 1187 /* 1188 * Must be super user 1189 */ 1190 if ((error = suser(p->p_ucred, &p->p_acflag))) 1191 return (error); 1192 1193 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0) 1194 return (error); 1195 1196 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) 1197 return (ESTALE); 1198 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) 1199 return (error); 1200 mp = vp->v_mount; 1201 vput(vp); 1202 if ((error = VFS_STATFS(mp, &sp, p)) != 0) 1203 return (error); 1204 sp.f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 1205 return (copyout(&sp, SCARG(uap, buf), sizeof(sp))); 1206} 1207 1208/* 1209 * Create a special file. 1210 */ 1211/* ARGSUSED */ 1212int 1213sys_mknod(p, v, retval) 1214 struct proc *p; 1215 void *v; 1216 register_t *retval; 1217{ 1218 register struct sys_mknod_args /* { 1219 syscallarg(char *) path; 1220 syscallarg(int) mode; 1221 syscallarg(int) dev; 1222 } */ *uap = v; 1223 register struct vnode *vp; 1224 struct vattr vattr; 1225 int error; 1226 int whiteout = 0; 1227 struct nameidata nd; 1228 1229 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 1230 return (error); 1231 if (p->p_fd->fd_rdir) 1232 return (EINVAL); 1233 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1234 if ((error = namei(&nd)) != 0) 1235 return (error); 1236 vp = nd.ni_vp; 1237 if (vp != NULL) 1238 error = EEXIST; 1239 else { 1240 VATTR_NULL(&vattr); 1241 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 1242 vattr.va_rdev = SCARG(uap, dev); 1243 whiteout = 0; 1244 1245 switch (SCARG(uap, mode) & S_IFMT) { 1246 case S_IFMT: /* used by badsect to flag bad sectors */ 1247 vattr.va_type = VBAD; 1248 break; 1249 case S_IFCHR: 1250 vattr.va_type = VCHR; 1251 break; 1252 case S_IFBLK: 1253 vattr.va_type = VBLK; 1254 break; 1255 case S_IFWHT: 1256 whiteout = 1; 1257 break; 1258 default: 1259 error = EINVAL; 1260 break; 1261 } 1262 } 1263 if (!error) { 1264 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1265 if (whiteout) { 1266 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 1267 if (error) 1268 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1269 vput(nd.ni_dvp); 1270 } else { 1271 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, 1272 &nd.ni_cnd, &vattr); 1273 } 1274 } else { 1275 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1276 if (nd.ni_dvp == vp) 1277 vrele(nd.ni_dvp); 1278 else 1279 vput(nd.ni_dvp); 1280 if (vp) 1281 vrele(vp); 1282 } 1283 return (error); 1284} 1285 1286/* 1287 * Create a named pipe. 1288 */ 1289/* ARGSUSED */ 1290int 1291sys_mkfifo(p, v, retval) 1292 struct proc *p; 1293 void *v; 1294 register_t *retval; 1295{ 1296#ifndef FIFO 1297 return (EOPNOTSUPP); 1298#else 1299 register struct sys_mkfifo_args /* { 1300 syscallarg(char *) path; 1301 syscallarg(int) mode; 1302 } */ *uap = v; 1303 struct vattr vattr; 1304 int error; 1305 struct nameidata nd; 1306 1307 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1308 if ((error = namei(&nd)) != 0) 1309 return (error); 1310 if (nd.ni_vp != NULL) { 1311 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1312 if (nd.ni_dvp == nd.ni_vp) 1313 vrele(nd.ni_dvp); 1314 else 1315 vput(nd.ni_dvp); 1316 vrele(nd.ni_vp); 1317 return (EEXIST); 1318 } 1319 VATTR_NULL(&vattr); 1320 vattr.va_type = VFIFO; 1321 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 1322 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1323 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 1324#endif /* FIFO */ 1325} 1326 1327/* 1328 * Make a hard file link. 1329 */ 1330/* ARGSUSED */ 1331int 1332sys_link(p, v, retval) 1333 struct proc *p; 1334 void *v; 1335 register_t *retval; 1336{ 1337 register struct sys_link_args /* { 1338 syscallarg(char *) path; 1339 syscallarg(char *) link; 1340 } */ *uap = v; 1341 register struct vnode *vp; 1342 struct nameidata nd; 1343 int error; 1344 int flags; 1345 1346 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1347 if ((error = namei(&nd)) != 0) 1348 return (error); 1349 vp = nd.ni_vp; 1350 1351 flags = LOCKPARENT; 1352 if (vp->v_type == VDIR) { 1353 flags |= STRIPSLASHES; 1354 } 1355 1356 NDINIT(&nd, CREATE, flags, UIO_USERSPACE, SCARG(uap, link), p); 1357 if ((error = namei(&nd)) != 0) 1358 goto out; 1359 if (nd.ni_vp) { 1360 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1361 if (nd.ni_dvp == nd.ni_vp) 1362 vrele(nd.ni_dvp); 1363 else 1364 vput(nd.ni_dvp); 1365 vrele(nd.ni_vp); 1366 error = EEXIST; 1367 goto out; 1368 } 1369 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1370 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1371 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 1372out: 1373 vrele(vp); 1374 return (error); 1375} 1376 1377/* 1378 * Make a symbolic link. 1379 */ 1380/* ARGSUSED */ 1381int 1382sys_symlink(p, v, retval) 1383 struct proc *p; 1384 void *v; 1385 register_t *retval; 1386{ 1387 register struct sys_symlink_args /* { 1388 syscallarg(char *) path; 1389 syscallarg(char *) link; 1390 } */ *uap = v; 1391 struct vattr vattr; 1392 char *path; 1393 int error; 1394 struct nameidata nd; 1395 1396 MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 1397 error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL); 1398 if (error) 1399 goto out; 1400 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); 1401 if ((error = namei(&nd)) != 0) 1402 goto out; 1403 if (nd.ni_vp) { 1404 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1405 if (nd.ni_dvp == nd.ni_vp) 1406 vrele(nd.ni_dvp); 1407 else 1408 vput(nd.ni_dvp); 1409 vrele(nd.ni_vp); 1410 error = EEXIST; 1411 goto out; 1412 } 1413 VATTR_NULL(&vattr); 1414 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 1415 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1416 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 1417out: 1418 FREE(path, M_NAMEI); 1419 return (error); 1420} 1421 1422/* 1423 * Delete a whiteout from the filesystem. 1424 */ 1425/* ARGSUSED */ 1426int 1427sys_undelete(p, v, retval) 1428 struct proc *p; 1429 void *v; 1430 register_t *retval; 1431{ 1432 register struct sys_undelete_args /* { 1433 syscallarg(char *) path; 1434 } */ *uap = v; 1435 int error; 1436 struct nameidata nd; 1437 1438 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, 1439 SCARG(uap, path), p); 1440 error = namei(&nd); 1441 if (error) 1442 return (error); 1443 1444 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 1445 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1446 if (nd.ni_dvp == nd.ni_vp) 1447 vrele(nd.ni_dvp); 1448 else 1449 vput(nd.ni_dvp); 1450 if (nd.ni_vp) 1451 vrele(nd.ni_vp); 1452 return (EEXIST); 1453 } 1454 1455 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1456 if ((error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) != 0) 1457 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1458 vput(nd.ni_dvp); 1459 return (error); 1460} 1461 1462/* 1463 * Delete a name from the filesystem. 1464 */ 1465/* ARGSUSED */ 1466int 1467sys_unlink(p, v, retval) 1468 struct proc *p; 1469 void *v; 1470 register_t *retval; 1471{ 1472 struct sys_unlink_args /* { 1473 syscallarg(char *) path; 1474 } */ *uap = v; 1475 register struct vnode *vp; 1476 int error; 1477 struct nameidata nd; 1478 1479 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 1480 SCARG(uap, path), p); 1481 if ((error = namei(&nd)) != 0) 1482 return (error); 1483 vp = nd.ni_vp; 1484 1485 /* 1486 * The root of a mounted filesystem cannot be deleted. 1487 */ 1488 if (vp->v_flag & VROOT) { 1489 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1490 if (nd.ni_dvp == vp) 1491 vrele(nd.ni_dvp); 1492 else 1493 vput(nd.ni_dvp); 1494 vput(vp); 1495 error = EBUSY; 1496 goto out; 1497 } 1498 1499 (void)uvm_vnp_uncache(vp); 1500 1501 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1502 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1503 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1504out: 1505 return (error); 1506} 1507 1508/* 1509 * Reposition read/write file offset. 1510 */ 1511int 1512sys_lseek(p, v, retval) 1513 struct proc *p; 1514 void *v; 1515 register_t *retval; 1516{ 1517 register struct sys_lseek_args /* { 1518 syscallarg(int) fd; 1519 syscallarg(int) pad; 1520 syscallarg(off_t) offset; 1521 syscallarg(int) whence; 1522 } */ *uap = v; 1523 struct ucred *cred = p->p_ucred; 1524 register struct filedesc *fdp = p->p_fd; 1525 register struct file *fp; 1526 struct vattr vattr; 1527 struct vnode *vp; 1528 int error, special; 1529 1530 if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) 1531 return (EBADF); 1532 if (fp->f_type != DTYPE_VNODE) 1533 return (ESPIPE); 1534 vp = (struct vnode *)fp->f_data; 1535 if (vp->v_type == VFIFO) 1536 return (ESPIPE); 1537 if (vp->v_type == VCHR) 1538 special = 1; 1539 else 1540 special = 0; 1541 switch (SCARG(uap, whence)) { 1542 case SEEK_CUR: 1543 if (!special && fp->f_offset + SCARG(uap, offset) < 0) 1544 return (EINVAL); 1545 fp->f_offset += SCARG(uap, offset); 1546 break; 1547 case SEEK_END: 1548 error = VOP_GETATTR((struct vnode *)fp->f_data, &vattr, 1549 cred, p); 1550 if (error) 1551 return (error); 1552 if (!special && (off_t)vattr.va_size + SCARG(uap, offset) < 0) 1553 return (EINVAL); 1554 fp->f_offset = SCARG(uap, offset) + vattr.va_size; 1555 break; 1556 case SEEK_SET: 1557 if (!special && SCARG(uap, offset) < 0) 1558 return (EINVAL); 1559 fp->f_offset = SCARG(uap, offset); 1560 break; 1561 default: 1562 return (EINVAL); 1563 } 1564 *(off_t *)retval = fp->f_offset; 1565 return (0); 1566} 1567 1568/* 1569 * Check access permissions. 1570 */ 1571int 1572sys_access(p, v, retval) 1573 struct proc *p; 1574 void *v; 1575 register_t *retval; 1576{ 1577 register struct sys_access_args /* { 1578 syscallarg(char *) path; 1579 syscallarg(int) flags; 1580 } */ *uap = v; 1581 register struct ucred *cred = p->p_ucred; 1582 register struct vnode *vp; 1583 int error, flags, t_gid, t_uid; 1584 struct nameidata nd; 1585 1586 if (SCARG(uap, flags) & ~(R_OK | W_OK | X_OK)) 1587 return (EINVAL); 1588 t_uid = cred->cr_uid; 1589 t_gid = cred->cr_gid; 1590 cred->cr_uid = p->p_cred->p_ruid; 1591 cred->cr_gid = p->p_cred->p_rgid; 1592 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1593 SCARG(uap, path), p); 1594 if ((error = namei(&nd)) != 0) 1595 goto out1; 1596 vp = nd.ni_vp; 1597 1598 /* Flags == 0 means only check for existence. */ 1599 if (SCARG(uap, flags)) { 1600 flags = 0; 1601 if (SCARG(uap, flags) & R_OK) 1602 flags |= VREAD; 1603 if (SCARG(uap, flags) & W_OK) 1604 flags |= VWRITE; 1605 if (SCARG(uap, flags) & X_OK) 1606 flags |= VEXEC; 1607 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 1608 error = VOP_ACCESS(vp, flags, cred, p); 1609 } 1610 vput(vp); 1611out1: 1612 cred->cr_uid = t_uid; 1613 cred->cr_gid = t_gid; 1614 return (error); 1615} 1616 1617/* 1618 * Get file status; this version follows links. 1619 */ 1620/* ARGSUSED */ 1621int 1622sys_stat(p, v, retval) 1623 struct proc *p; 1624 void *v; 1625 register_t *retval; 1626{ 1627 register struct sys_stat_args /* { 1628 syscallarg(char *) path; 1629 syscallarg(struct stat *) ub; 1630 } */ *uap = v; 1631 struct stat sb; 1632 int error; 1633 struct nameidata nd; 1634 1635 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1636 SCARG(uap, path), p); 1637 if ((error = namei(&nd)) != 0) 1638 return (error); 1639 error = vn_stat(nd.ni_vp, &sb, p); 1640 vput(nd.ni_vp); 1641 if (error) 1642 return (error); 1643 /* Don't let non-root see generation numbers (for NFS security) */ 1644 if (suser(p->p_ucred, &p->p_acflag)) 1645 sb.st_gen = 0; 1646 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1647 return (error); 1648} 1649 1650/* 1651 * Get file status; this version does not follow links. 1652 */ 1653/* ARGSUSED */ 1654int 1655sys_lstat(p, v, retval) 1656 struct proc *p; 1657 void *v; 1658 register_t *retval; 1659{ 1660 register struct sys_lstat_args /* { 1661 syscallarg(char *) path; 1662 syscallarg(struct stat *) ub; 1663 } */ *uap = v; 1664 struct stat sb; 1665 int error; 1666 struct nameidata nd; 1667 1668 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 1669 SCARG(uap, path), p); 1670 if ((error = namei(&nd)) != 0) 1671 return (error); 1672 error = vn_stat(nd.ni_vp, &sb, p); 1673 vput(nd.ni_vp); 1674 if (error) 1675 return (error); 1676 /* Don't let non-root see generation numbers (for NFS security) */ 1677 if (suser(p->p_ucred, &p->p_acflag)) 1678 sb.st_gen = 0; 1679 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1680 return (error); 1681} 1682 1683/* 1684 * Get configurable pathname variables. 1685 */ 1686/* ARGSUSED */ 1687int 1688sys_pathconf(p, v, retval) 1689 struct proc *p; 1690 void *v; 1691 register_t *retval; 1692{ 1693 register struct sys_pathconf_args /* { 1694 syscallarg(char *) path; 1695 syscallarg(int) name; 1696 } */ *uap = v; 1697 int error; 1698 struct nameidata nd; 1699 1700 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1701 SCARG(uap, path), p); 1702 if ((error = namei(&nd)) != 0) 1703 return (error); 1704 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval); 1705 vput(nd.ni_vp); 1706 return (error); 1707} 1708 1709/* 1710 * Return target name of a symbolic link. 1711 */ 1712/* ARGSUSED */ 1713int 1714sys_readlink(p, v, retval) 1715 struct proc *p; 1716 void *v; 1717 register_t *retval; 1718{ 1719 register struct sys_readlink_args /* { 1720 syscallarg(char *) path; 1721 syscallarg(char *) buf; 1722 syscallarg(size_t) count; 1723 } */ *uap = v; 1724 register struct vnode *vp; 1725 struct iovec aiov; 1726 struct uio auio; 1727 int error; 1728 struct nameidata nd; 1729 1730 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 1731 SCARG(uap, path), p); 1732 if ((error = namei(&nd)) != 0) 1733 return (error); 1734 vp = nd.ni_vp; 1735 if (vp->v_type != VLNK) 1736 error = EINVAL; 1737 else { 1738 aiov.iov_base = SCARG(uap, buf); 1739 aiov.iov_len = SCARG(uap, count); 1740 auio.uio_iov = &aiov; 1741 auio.uio_iovcnt = 1; 1742 auio.uio_offset = 0; 1743 auio.uio_rw = UIO_READ; 1744 auio.uio_segflg = UIO_USERSPACE; 1745 auio.uio_procp = p; 1746 auio.uio_resid = SCARG(uap, count); 1747 error = VOP_READLINK(vp, &auio, p->p_ucred); 1748 } 1749 vput(vp); 1750 *retval = SCARG(uap, count) - auio.uio_resid; 1751 return (error); 1752} 1753 1754/* 1755 * Change flags of a file given a path name. 1756 */ 1757/* ARGSUSED */ 1758int 1759sys_chflags(p, v, retval) 1760 struct proc *p; 1761 void *v; 1762 register_t *retval; 1763{ 1764 register struct sys_chflags_args /* { 1765 syscallarg(char *) path; 1766 syscallarg(unsigned int) flags; 1767 } */ *uap = v; 1768 register struct vnode *vp; 1769 struct vattr vattr; 1770 int error; 1771 struct nameidata nd; 1772 1773 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1774 if ((error = namei(&nd)) != 0) 1775 return (error); 1776 vp = nd.ni_vp; 1777 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1778 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1779 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1780 error = EROFS; 1781 else if (SCARG(uap, flags) == VNOVAL) 1782 error = EINVAL; 1783 else { 1784 if (suser(p->p_ucred, &p->p_acflag)) { 1785 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0) 1786 goto out; 1787 if (vattr.va_type == VCHR || vattr.va_type == VBLK) { 1788 error = EINVAL; 1789 goto out; 1790 } 1791 } 1792 VATTR_NULL(&vattr); 1793 vattr.va_flags = SCARG(uap, flags); 1794 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1795 } 1796out: 1797 vput(vp); 1798 return (error); 1799} 1800 1801/* 1802 * Change flags of a file given a file descriptor. 1803 */ 1804/* ARGSUSED */ 1805int 1806sys_fchflags(p, v, retval) 1807 struct proc *p; 1808 void *v; 1809 register_t *retval; 1810{ 1811 struct sys_fchflags_args /* { 1812 syscallarg(int) fd; 1813 syscallarg(unsigned int) flags; 1814 } */ *uap = v; 1815 struct vattr vattr; 1816 struct vnode *vp; 1817 struct file *fp; 1818 int error; 1819 1820 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 1821 return (error); 1822 vp = (struct vnode *)fp->f_data; 1823 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1824 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1825 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1826 error = EROFS; 1827 else if (SCARG(uap, flags) == VNOVAL) 1828 error = EINVAL; 1829 else { 1830 if (suser(p->p_ucred, &p->p_acflag)) { 1831 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 1832 != 0) 1833 goto out; 1834 if (vattr.va_type == VCHR || vattr.va_type == VBLK) { 1835 error = EINVAL; 1836 goto out; 1837 } 1838 } 1839 VATTR_NULL(&vattr); 1840 vattr.va_flags = SCARG(uap, flags); 1841 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1842 } 1843out: 1844 VOP_UNLOCK(vp, 0, p); 1845 FRELE(fp); 1846 return (error); 1847} 1848 1849/* 1850 * Change mode of a file given path name. 1851 */ 1852/* ARGSUSED */ 1853int 1854sys_chmod(p, v, retval) 1855 struct proc *p; 1856 void *v; 1857 register_t *retval; 1858{ 1859 register struct sys_chmod_args /* { 1860 syscallarg(char *) path; 1861 syscallarg(int) mode; 1862 } */ *uap = v; 1863 register struct vnode *vp; 1864 struct vattr vattr; 1865 int error; 1866 struct nameidata nd; 1867 1868 if (SCARG(uap, mode) & ~(S_IFMT | ALLPERMS)) 1869 return (EINVAL); 1870 1871 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1872 if ((error = namei(&nd)) != 0) 1873 return (error); 1874 vp = nd.ni_vp; 1875 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1876 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1877 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1878 error = EROFS; 1879 else { 1880 VATTR_NULL(&vattr); 1881 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1882 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1883 } 1884 vput(vp); 1885 return (error); 1886} 1887 1888/* 1889 * Change mode of a file given a file descriptor. 1890 */ 1891/* ARGSUSED */ 1892int 1893sys_fchmod(p, v, retval) 1894 struct proc *p; 1895 void *v; 1896 register_t *retval; 1897{ 1898 struct sys_fchmod_args /* { 1899 syscallarg(int) fd; 1900 syscallarg(int) mode; 1901 } */ *uap = v; 1902 struct vattr vattr; 1903 struct vnode *vp; 1904 struct file *fp; 1905 int error; 1906 1907 if (SCARG(uap, mode) & ~(S_IFMT | ALLPERMS)) 1908 return (EINVAL); 1909 1910 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 1911 return (error); 1912 vp = (struct vnode *)fp->f_data; 1913 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1914 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1915 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1916 error = EROFS; 1917 else { 1918 VATTR_NULL(&vattr); 1919 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1920 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1921 } 1922 VOP_UNLOCK(vp, 0, p); 1923 FRELE(fp); 1924 return (error); 1925} 1926 1927/* 1928 * Set ownership given a path name. 1929 */ 1930/* ARGSUSED */ 1931int 1932sys_chown(p, v, retval) 1933 struct proc *p; 1934 void *v; 1935 register_t *retval; 1936{ 1937 register struct sys_chown_args /* { 1938 syscallarg(char *) path; 1939 syscallarg(int) uid; 1940 syscallarg(int) gid; 1941 } */ *uap = v; 1942 register struct vnode *vp; 1943 struct vattr vattr; 1944 int error; 1945 struct nameidata nd; 1946 u_short mode; 1947 1948 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1949 if ((error = namei(&nd)) != 0) 1950 return (error); 1951 vp = nd.ni_vp; 1952 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1953 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1954 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1955 error = EROFS; 1956 else { 1957 if ((SCARG(uap, uid) != -1 || SCARG(uap, gid) != -1) && 1958 (suser(p->p_ucred, &p->p_acflag) || suid_clear)) { 1959 error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); 1960 if (error) 1961 goto out; 1962 mode = vattr.va_mode & ~(VSUID | VSGID); 1963 if (mode == vattr.va_mode) 1964 mode = VNOVAL; 1965 } 1966 else 1967 mode = VNOVAL; 1968 VATTR_NULL(&vattr); 1969 vattr.va_uid = SCARG(uap, uid); 1970 vattr.va_gid = SCARG(uap, gid); 1971 vattr.va_mode = mode; 1972 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1973 } 1974out: 1975 vput(vp); 1976 return (error); 1977} 1978 1979/* 1980 * Set ownership given a path name, without following links. 1981 */ 1982/* ARGSUSED */ 1983int 1984sys_lchown(p, v, retval) 1985 struct proc *p; 1986 void *v; 1987 register_t *retval; 1988{ 1989 register struct sys_lchown_args /* { 1990 syscallarg(char *) path; 1991 syscallarg(int) uid; 1992 syscallarg(int) gid; 1993 } */ *uap = v; 1994 register struct vnode *vp; 1995 struct vattr vattr; 1996 int error; 1997 struct nameidata nd; 1998 u_short mode; 1999 2000 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2001 if ((error = namei(&nd)) != 0) 2002 return (error); 2003 vp = nd.ni_vp; 2004 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2005 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2006 if (vp->v_mount->mnt_flag & MNT_RDONLY) 2007 error = EROFS; 2008 else { 2009 if ((SCARG(uap, uid) != -1 || SCARG(uap, gid) != -1) && 2010 (suser(p->p_ucred, &p->p_acflag) || suid_clear)) { 2011 error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); 2012 if (error) 2013 goto out; 2014 mode = vattr.va_mode & ~(VSUID | VSGID); 2015 if (mode == vattr.va_mode) 2016 mode = VNOVAL; 2017 } 2018 else 2019 mode = VNOVAL; 2020 VATTR_NULL(&vattr); 2021 vattr.va_uid = SCARG(uap, uid); 2022 vattr.va_gid = SCARG(uap, gid); 2023 vattr.va_mode = mode; 2024 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2025 } 2026out: 2027 vput(vp); 2028 return (error); 2029} 2030 2031/* 2032 * Set ownership given a file descriptor. 2033 */ 2034/* ARGSUSED */ 2035int 2036sys_fchown(p, v, retval) 2037 struct proc *p; 2038 void *v; 2039 register_t *retval; 2040{ 2041 struct sys_fchown_args /* { 2042 syscallarg(int) fd; 2043 syscallarg(int) uid; 2044 syscallarg(int) gid; 2045 } */ *uap = v; 2046 struct vnode *vp; 2047 struct vattr vattr; 2048 int error; 2049 struct file *fp; 2050 u_short mode; 2051 2052 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2053 return (error); 2054 vp = (struct vnode *)fp->f_data; 2055 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2056 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2057 if (vp->v_mount->mnt_flag & MNT_RDONLY) 2058 error = EROFS; 2059 else { 2060 if ((SCARG(uap, uid) != -1 || SCARG(uap, gid) != -1) && 2061 (suser(p->p_ucred, &p->p_acflag) || suid_clear)) { 2062 error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); 2063 if (error) 2064 goto out; 2065 mode = vattr.va_mode & ~(VSUID | VSGID); 2066 if (mode == vattr.va_mode) 2067 mode = VNOVAL; 2068 } else 2069 mode = VNOVAL; 2070 VATTR_NULL(&vattr); 2071 vattr.va_uid = SCARG(uap, uid); 2072 vattr.va_gid = SCARG(uap, gid); 2073 vattr.va_mode = mode; 2074 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2075 } 2076out: 2077 VOP_UNLOCK(vp, 0, p); 2078 FRELE(fp); 2079 return (error); 2080} 2081 2082/* 2083 * Set the access and modification times given a path name. 2084 */ 2085/* ARGSUSED */ 2086int 2087sys_utimes(p, v, retval) 2088 struct proc *p; 2089 void *v; 2090 register_t *retval; 2091{ 2092 register struct sys_utimes_args /* { 2093 syscallarg(char *) path; 2094 syscallarg(struct timeval *) tptr; 2095 } */ *uap = v; 2096 register struct vnode *vp; 2097 struct timeval tv[2]; 2098 struct vattr vattr; 2099 int error; 2100 struct nameidata nd; 2101 2102 VATTR_NULL(&vattr); 2103 if (SCARG(uap, tptr) == NULL) { 2104 microtime(&tv[0]); 2105 tv[1] = tv[0]; 2106 vattr.va_vaflags |= VA_UTIMES_NULL; 2107 } else { 2108 error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 2109 sizeof (tv)); 2110 if (error) 2111 return (error); 2112 /* XXX workaround timeval matching the VFS constant VNOVAL */ 2113 if (tv[0].tv_sec == VNOVAL) 2114 tv[0].tv_sec = VNOVAL - 1; 2115 if (tv[1].tv_sec == VNOVAL) 2116 tv[1].tv_sec = VNOVAL - 1; 2117 } 2118 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2119 if ((error = namei(&nd)) != 0) 2120 return (error); 2121 vp = nd.ni_vp; 2122 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2123 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2124 if (vp->v_mount->mnt_flag & MNT_RDONLY) 2125 error = EROFS; 2126 else { 2127 vattr.va_atime.tv_sec = tv[0].tv_sec; 2128 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; 2129 vattr.va_mtime.tv_sec = tv[1].tv_sec; 2130 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; 2131 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2132 } 2133 vput(vp); 2134 return (error); 2135} 2136 2137 2138/* 2139 * Set the access and modification times given a file descriptor. 2140 */ 2141/* ARGSUSED */ 2142int 2143sys_futimes(p, v, retval) 2144 struct proc *p; 2145 void *v; 2146 register_t *retval; 2147{ 2148 register struct sys_futimes_args /* { 2149 syscallarg(int) fd; 2150 syscallarg(struct timeval *) tptr; 2151 } */ *uap = v; 2152 struct vnode *vp; 2153 struct timeval tv[2]; 2154 struct vattr vattr; 2155 int error; 2156 struct file *fp; 2157 2158 VATTR_NULL(&vattr); 2159 if (SCARG(uap, tptr) == NULL) { 2160 microtime(&tv[0]); 2161 tv[1] = tv[0]; 2162 vattr.va_vaflags |= VA_UTIMES_NULL; 2163 } else { 2164 error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 2165 sizeof (tv)); 2166 if (error) 2167 return (error); 2168 /* XXX workaround timeval matching the VFS constant VNOVAL */ 2169 if (tv[0].tv_sec == VNOVAL) 2170 tv[0].tv_sec = VNOVAL - 1; 2171 if (tv[1].tv_sec == VNOVAL) 2172 tv[1].tv_sec = VNOVAL - 1; 2173 } 2174 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2175 return (error); 2176 vp = (struct vnode *)fp->f_data; 2177 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2178 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2179 if (vp->v_mount->mnt_flag & MNT_RDONLY) 2180 error = EROFS; 2181 else { 2182 vattr.va_atime.tv_sec = tv[0].tv_sec; 2183 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; 2184 vattr.va_mtime.tv_sec = tv[1].tv_sec; 2185 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; 2186 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2187 } 2188 VOP_UNLOCK(vp, 0, p); 2189 FRELE(fp); 2190 return (error); 2191} 2192 2193/* 2194 * Truncate a file given its path name. 2195 */ 2196/* ARGSUSED */ 2197int 2198sys_truncate(p, v, retval) 2199 struct proc *p; 2200 void *v; 2201 register_t *retval; 2202{ 2203 register struct sys_truncate_args /* { 2204 syscallarg(char *) path; 2205 syscallarg(int) pad; 2206 syscallarg(off_t) length; 2207 } */ *uap = v; 2208 register struct vnode *vp; 2209 struct vattr vattr; 2210 int error; 2211 struct nameidata nd; 2212 2213 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2214 if ((error = namei(&nd)) != 0) 2215 return (error); 2216 vp = nd.ni_vp; 2217 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2218 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2219 if (vp->v_type == VDIR) 2220 error = EISDIR; 2221 else if ((error = vn_writechk(vp)) == 0 && 2222 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 2223 VATTR_NULL(&vattr); 2224 vattr.va_size = SCARG(uap, length); 2225 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2226 } 2227 vput(vp); 2228 return (error); 2229} 2230 2231/* 2232 * Truncate a file given a file descriptor. 2233 */ 2234/* ARGSUSED */ 2235int 2236sys_ftruncate(p, v, retval) 2237 struct proc *p; 2238 void *v; 2239 register_t *retval; 2240{ 2241 struct sys_ftruncate_args /* { 2242 syscallarg(int) fd; 2243 syscallarg(int) pad; 2244 syscallarg(off_t) length; 2245 } */ *uap = v; 2246 struct vattr vattr; 2247 struct vnode *vp; 2248 struct file *fp; 2249 int error; 2250 2251 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2252 return (error); 2253 if ((fp->f_flag & FWRITE) == 0) { 2254 error = EINVAL; 2255 goto bad; 2256 } 2257 vp = (struct vnode *)fp->f_data; 2258 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2259 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2260 if (vp->v_type == VDIR) 2261 error = EISDIR; 2262 else if ((error = vn_writechk(vp)) == 0) { 2263 VATTR_NULL(&vattr); 2264 vattr.va_size = SCARG(uap, length); 2265 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 2266 } 2267 VOP_UNLOCK(vp, 0, p); 2268bad: 2269 FRELE(fp); 2270 return (error); 2271} 2272 2273/* 2274 * Sync an open file. 2275 */ 2276/* ARGSUSED */ 2277int 2278sys_fsync(p, v, retval) 2279 struct proc *p; 2280 void *v; 2281 register_t *retval; 2282{ 2283 struct sys_fsync_args /* { 2284 syscallarg(int) fd; 2285 } */ *uap = v; 2286 struct vnode *vp; 2287 struct file *fp; 2288 int error; 2289 2290 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2291 return (error); 2292 vp = (struct vnode *)fp->f_data; 2293 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2294 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 2295#ifdef FFS_SOFTUPDATES 2296 if (error == 0 && vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP)) 2297 error = softdep_fsync(vp); 2298#endif 2299 2300 VOP_UNLOCK(vp, 0, p); 2301 FRELE(fp); 2302 return (error); 2303} 2304 2305/* 2306 * Rename files. Source and destination must either both be directories, 2307 * or both not be directories. If target is a directory, it must be empty. 2308 */ 2309/* ARGSUSED */ 2310int 2311sys_rename(p, v, retval) 2312 struct proc *p; 2313 void *v; 2314 register_t *retval; 2315{ 2316 register struct sys_rename_args /* { 2317 syscallarg(char *) from; 2318 syscallarg(char *) to; 2319 } */ *uap = v; 2320 register struct vnode *tvp, *fvp, *tdvp; 2321 struct nameidata fromnd, tond; 2322 int error; 2323 int flags; 2324 2325 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 2326 SCARG(uap, from), p); 2327 if ((error = namei(&fromnd)) != 0) 2328 return (error); 2329 fvp = fromnd.ni_vp; 2330 2331 flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 2332 /* 2333 * rename("foo/", "bar/"); is OK 2334 */ 2335 if (fvp->v_type == VDIR) 2336 flags |= STRIPSLASHES; 2337 2338 NDINIT(&tond, RENAME, flags, 2339 UIO_USERSPACE, SCARG(uap, to), p); 2340 if ((error = namei(&tond)) != 0) { 2341 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2342 vrele(fromnd.ni_dvp); 2343 vrele(fvp); 2344 goto out1; 2345 } 2346 tdvp = tond.ni_dvp; 2347 tvp = tond.ni_vp; 2348 if (tvp != NULL) { 2349 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 2350 error = ENOTDIR; 2351 goto out; 2352 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 2353 error = EISDIR; 2354 goto out; 2355 } 2356 } 2357 if (fvp == tdvp) 2358 error = EINVAL; 2359 /* 2360 * If source is the same as the destination (that is the 2361 * same inode number) 2362 */ 2363 if (fvp == tvp) 2364 error = -1; 2365out: 2366 if (!error) { 2367 VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); 2368 if (fromnd.ni_dvp != tdvp) 2369 VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2370 if (tvp) { 2371 (void)uvm_vnp_uncache(tvp); 2372 VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); 2373 } 2374 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 2375 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 2376 } else { 2377 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 2378 if (tdvp == tvp) 2379 vrele(tdvp); 2380 else 2381 vput(tdvp); 2382 if (tvp) 2383 vput(tvp); 2384 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2385 vrele(fromnd.ni_dvp); 2386 vrele(fvp); 2387 } 2388 vrele(tond.ni_startdir); 2389 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 2390out1: 2391 if (fromnd.ni_startdir) 2392 vrele(fromnd.ni_startdir); 2393 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 2394 if (error == -1) 2395 return (0); 2396 return (error); 2397} 2398 2399/* 2400 * Make a directory file. 2401 */ 2402/* ARGSUSED */ 2403int 2404sys_mkdir(p, v, retval) 2405 struct proc *p; 2406 void *v; 2407 register_t *retval; 2408{ 2409 register struct sys_mkdir_args /* { 2410 syscallarg(char *) path; 2411 syscallarg(int) mode; 2412 } */ *uap = v; 2413 register struct vnode *vp; 2414 struct vattr vattr; 2415 int error; 2416 struct nameidata nd; 2417 2418 NDINIT(&nd, CREATE, LOCKPARENT | STRIPSLASHES, 2419 UIO_USERSPACE, SCARG(uap, path), p); 2420 if ((error = namei(&nd)) != 0) 2421 return (error); 2422 vp = nd.ni_vp; 2423 if (vp != NULL) { 2424 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2425 if (nd.ni_dvp == vp) 2426 vrele(nd.ni_dvp); 2427 else 2428 vput(nd.ni_dvp); 2429 vrele(vp); 2430 return (EEXIST); 2431 } 2432 VATTR_NULL(&vattr); 2433 vattr.va_type = VDIR; 2434 vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; 2435 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2436 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 2437 if (!error) 2438 vput(nd.ni_vp); 2439 return (error); 2440} 2441 2442/* 2443 * Remove a directory file. 2444 */ 2445/* ARGSUSED */ 2446int 2447sys_rmdir(p, v, retval) 2448 struct proc *p; 2449 void *v; 2450 register_t *retval; 2451{ 2452 struct sys_rmdir_args /* { 2453 syscallarg(char *) path; 2454 } */ *uap = v; 2455 register struct vnode *vp; 2456 int error; 2457 struct nameidata nd; 2458 2459 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 2460 SCARG(uap, path), p); 2461 if ((error = namei(&nd)) != 0) 2462 return (error); 2463 vp = nd.ni_vp; 2464 if (vp->v_type != VDIR) { 2465 error = ENOTDIR; 2466 goto out; 2467 } 2468 /* 2469 * No rmdir "." please. 2470 */ 2471 if (nd.ni_dvp == vp) { 2472 error = EBUSY; 2473 goto out; 2474 } 2475 /* 2476 * The root of a mounted filesystem cannot be deleted. 2477 */ 2478 if (vp->v_flag & VROOT) 2479 error = EBUSY; 2480out: 2481 if (!error) { 2482 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2483 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2484 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 2485 } else { 2486 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2487 if (nd.ni_dvp == vp) 2488 vrele(nd.ni_dvp); 2489 else 2490 vput(nd.ni_dvp); 2491 vput(vp); 2492 } 2493 return (error); 2494} 2495 2496/* 2497 * Read a block of directory entries in a file system independent format. 2498 */ 2499int 2500sys_getdirentries(p, v, retval) 2501 struct proc *p; 2502 void *v; 2503 register_t *retval; 2504{ 2505 struct sys_getdirentries_args /* { 2506 syscallarg(int) fd; 2507 syscallarg(char *) buf; 2508 syscallarg(int) count; 2509 syscallarg(long *) basep; 2510 } */ *uap = v; 2511 struct vnode *vp; 2512 struct file *fp; 2513 struct uio auio; 2514 struct iovec aiov; 2515 long loff; 2516 int error, eofflag; 2517 2518 if (SCARG(uap, count) < 0) 2519 return EINVAL; 2520 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2521 return (error); 2522 if ((fp->f_flag & FREAD) == 0) { 2523 error = EBADF; 2524 goto bad; 2525 } 2526 vp = (struct vnode *)fp->f_data; 2527unionread: 2528 if (vp->v_type != VDIR) { 2529 error = EINVAL; 2530 goto bad; 2531 } 2532 aiov.iov_base = SCARG(uap, buf); 2533 aiov.iov_len = SCARG(uap, count); 2534 auio.uio_iov = &aiov; 2535 auio.uio_iovcnt = 1; 2536 auio.uio_rw = UIO_READ; 2537 auio.uio_segflg = UIO_USERSPACE; 2538 auio.uio_procp = p; 2539 auio.uio_resid = SCARG(uap, count); 2540 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2541 loff = auio.uio_offset = fp->f_offset; 2542 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 0, 0); 2543 fp->f_offset = auio.uio_offset; 2544 VOP_UNLOCK(vp, 0, p); 2545 if (error) 2546 goto bad; 2547 if ((SCARG(uap, count) == auio.uio_resid) && 2548 union_check_p && 2549 (union_check_p(p, &vp, fp, auio, &error) != 0)) 2550 goto unionread; 2551 if (error) 2552 goto bad; 2553 2554 if ((SCARG(uap, count) == auio.uio_resid) && 2555 (vp->v_flag & VROOT) && 2556 (vp->v_mount->mnt_flag & MNT_UNION)) { 2557 struct vnode *tvp = vp; 2558 vp = vp->v_mount->mnt_vnodecovered; 2559 VREF(vp); 2560 fp->f_data = (caddr_t) vp; 2561 fp->f_offset = 0; 2562 vrele(tvp); 2563 goto unionread; 2564 } 2565 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 2566 sizeof(long)); 2567 *retval = SCARG(uap, count) - auio.uio_resid; 2568bad: 2569 FRELE(fp); 2570 return (error); 2571} 2572 2573/* 2574 * Set the mode mask for creation of filesystem nodes. 2575 */ 2576int 2577sys_umask(p, v, retval) 2578 struct proc *p; 2579 void *v; 2580 register_t *retval; 2581{ 2582 struct sys_umask_args /* { 2583 syscallarg(int) newmask; 2584 } */ *uap = v; 2585 register struct filedesc *fdp; 2586 2587 fdp = p->p_fd; 2588 *retval = fdp->fd_cmask; 2589 fdp->fd_cmask = SCARG(uap, newmask) & ACCESSPERMS; 2590 return (0); 2591} 2592 2593/* 2594 * Void all references to file by ripping underlying filesystem 2595 * away from vnode. 2596 */ 2597/* ARGSUSED */ 2598int 2599sys_revoke(p, v, retval) 2600 struct proc *p; 2601 void *v; 2602 register_t *retval; 2603{ 2604 register struct sys_revoke_args /* { 2605 syscallarg(char *) path; 2606 } */ *uap = v; 2607 register struct vnode *vp; 2608 struct vattr vattr; 2609 int error; 2610 struct nameidata nd; 2611 2612 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2613 if ((error = namei(&nd)) != 0) 2614 return (error); 2615 vp = nd.ni_vp; 2616 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0) 2617 goto out; 2618 if (p->p_ucred->cr_uid != vattr.va_uid && 2619 (error = suser(p->p_ucred, &p->p_acflag))) 2620 goto out; 2621 if (vp->v_usecount > 1 || (vp->v_flag & (VALIASED | VLAYER))) 2622 VOP_REVOKE(vp, REVOKEALL); 2623out: 2624 vrele(vp); 2625 return (error); 2626} 2627 2628/* 2629 * Convert a user file descriptor to a kernel file entry. 2630 * 2631 * On return *fpp is FREF:ed. 2632 */ 2633int 2634getvnode(fdp, fd, fpp) 2635 struct filedesc *fdp; 2636 struct file **fpp; 2637 int fd; 2638{ 2639 struct file *fp; 2640 2641 if ((fp = fd_getfile(fdp, fd)) == NULL) 2642 return (EBADF); 2643 if (fp->f_type != DTYPE_VNODE) 2644 return (EINVAL); 2645 FREF(fp); 2646 *fpp = fp; 2647 2648 return (0); 2649} 2650 2651/* 2652 * Positional read system call. 2653 */ 2654int 2655sys_pread(p, v, retval) 2656 struct proc *p; 2657 void *v; 2658 register_t *retval; 2659{ 2660 struct sys_pread_args /* { 2661 syscallarg(int) fd; 2662 syscallarg(void *) buf; 2663 syscallarg(size_t) nbyte; 2664 syscallarg(int) pad; 2665 syscallarg(off_t) offset; 2666 } */ *uap = v; 2667 struct filedesc *fdp = p->p_fd; 2668 struct file *fp; 2669 struct vnode *vp; 2670 off_t offset; 2671 int fd = SCARG(uap, fd); 2672 2673 if ((fp = fd_getfile(fdp, fd)) == NULL) 2674 return (EBADF); 2675 if ((fp->f_flag & FREAD) == 0) 2676 return (EBADF); 2677 2678 vp = (struct vnode *)fp->f_data; 2679 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 2680 return (ESPIPE); 2681 } 2682 2683 offset = SCARG(uap, offset); 2684 2685 FREF(fp); 2686 2687 /* dofileread() will FRELE the descriptor for us */ 2688 return (dofileread(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte), 2689 &offset, retval)); 2690} 2691 2692/* 2693 * Positional scatter read system call. 2694 */ 2695int 2696sys_preadv(p, v, retval) 2697 struct proc *p; 2698 void *v; 2699 register_t *retval; 2700{ 2701 struct sys_preadv_args /* { 2702 syscallarg(int) fd; 2703 syscallarg(const struct iovec *) iovp; 2704 syscallarg(int) iovcnt; 2705 syscallarg(int) pad; 2706 syscallarg(off_t) offset; 2707 } */ *uap = v; 2708 struct filedesc *fdp = p->p_fd; 2709 struct file *fp; 2710 struct vnode *vp; 2711 off_t offset; 2712 int fd = SCARG(uap, fd); 2713 2714 if ((fp = fd_getfile(fdp, fd)) == NULL) 2715 return (EBADF); 2716 if ((fp->f_flag & FREAD) == 0) 2717 return (EBADF); 2718 2719 vp = (struct vnode *)fp->f_data; 2720 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 2721 return (ESPIPE); 2722 } 2723 2724 FREF(fp); 2725 2726 offset = SCARG(uap, offset); 2727 2728 /* dofilereadv() will FRELE the descriptor for us */ 2729 return (dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 2730 &offset, retval)); 2731} 2732 2733/* 2734 * Positional write system call. 2735 */ 2736int 2737sys_pwrite(p, v, retval) 2738 struct proc *p; 2739 void *v; 2740 register_t *retval; 2741{ 2742 struct sys_pwrite_args /* { 2743 syscallarg(int) fd; 2744 syscallarg(const void *) buf; 2745 syscallarg(size_t) nbyte; 2746 syscallarg(int) pad; 2747 syscallarg(off_t) offset; 2748 } */ *uap = v; 2749 struct filedesc *fdp = p->p_fd; 2750 struct file *fp; 2751 struct vnode *vp; 2752 off_t offset; 2753 int fd = SCARG(uap, fd); 2754 2755 if ((fp = fd_getfile(fdp, fd)) == NULL) 2756 return (EBADF); 2757 if ((fp->f_flag & FWRITE) == 0) 2758 return (EBADF); 2759 2760 vp = (struct vnode *)fp->f_data; 2761 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 2762 return (ESPIPE); 2763 } 2764 2765 FREF(fp); 2766 2767 offset = SCARG(uap, offset); 2768 2769 /* dofilewrite() will FRELE the descriptor for us */ 2770 return (dofilewrite(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte), 2771 &offset, retval)); 2772} 2773 2774 2775/* 2776 * Positional gather write system call. 2777 */ 2778int 2779sys_pwritev(p, v, retval) 2780 struct proc *p; 2781 void *v; 2782 register_t *retval; 2783{ 2784 struct sys_pwritev_args /* { 2785 syscallarg(int) fd; 2786 syscallarg(const struct iovec *) iovp; 2787 syscallarg(int) iovcnt; 2788 syscallarg(int) pad; 2789 syscallarg(off_t) offset; 2790 } */ *uap = v; 2791 struct filedesc *fdp = p->p_fd; 2792 struct file *fp; 2793 struct vnode *vp; 2794 off_t offset; 2795 int fd = SCARG(uap, fd); 2796 2797 if ((fp = fd_getfile(fdp, fd)) == NULL) 2798 return (EBADF); 2799 if ((fp->f_flag & FWRITE) == 0) 2800 return (EBADF); 2801 2802 vp = (struct vnode *)fp->f_data; 2803 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 2804 return (ESPIPE); 2805 } 2806 2807 FREF(fp); 2808 2809 offset = SCARG(uap, offset); 2810 2811 /* dofilewritev() will FRELE the descriptor for us */ 2812 return (dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 2813 &offset, retval)); 2814} 2815 2816#ifdef UFS_EXTATTR 2817/* 2818 * Syscall to push extended attribute configuration information into the 2819 * VFS. Accepts a path, which it converts to a mountpoint, as well as 2820 * a command (int cmd), and attribute name and misc data. For now, the 2821 * attribute name is left in userspace for consumption by the VFS_op. 2822 * It will probably be changed to be copied into sysspace by the 2823 * syscall in the future, once issues with various consumers of the 2824 * attribute code have raised their hands. 2825 * 2826 * Currently this is used only by UFS Extended Attributes. 2827 */ 2828int 2829sys_extattrctl(struct proc *p, void *v, register_t *reval) 2830{ 2831 struct sys_extattrctl_args /* { 2832 syscallarg(const char *) path; 2833 syscallarg(int) cmd; 2834 syscallarg(const char *) filename; 2835 syscallarg(int) attrnamespace; 2836 syscallarg(const char *) attrname; 2837 } */ *uap = v; 2838 struct vnode *filename_vp; 2839 struct nameidata nd; 2840 struct mount *mp; 2841 char attrname[EXTATTR_MAXNAMELEN]; 2842 int error; 2843 2844 /* 2845 * SCARG(uap, attrname) not always defined. We check again later 2846 * when we invoke the VFS call so as to pass in NULL there if needed. 2847 */ 2848 if (SCARG(uap, attrname) != NULL) { 2849 error = copyinstr(SCARG(uap, attrname), attrname, 2850 EXTATTR_MAXNAMELEN, NULL); 2851 if (error) 2852 return (error); 2853 } 2854 2855 /* 2856 * SCARG(uap, filename) not always defined. If it is, grab 2857 * a vnode lock, which VFS_EXTATTRCTL() will later release. 2858 */ 2859 filename_vp = NULL; 2860 if (SCARG(uap, filename) != NULL) { 2861 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 2862 SCARG(uap, filename), p); 2863 if ((error = namei(&nd)) != 0) 2864 return (error); 2865 filename_vp = nd.ni_vp; 2866 } 2867 2868 /* SCARG(uap, path) always defined. */ 2869 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2870 if ((error = namei(&nd)) != 0) { 2871 if (filename_vp != NULL) 2872 vput(filename_vp); 2873 return (error); 2874 } 2875 2876 mp = nd.ni_vp->v_mount; 2877 if (error) { 2878 if (filename_vp != NULL) 2879 vput(filename_vp); 2880 return (error); 2881 } 2882 2883 if (SCARG(uap, attrname) != NULL) { 2884 error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp, 2885 SCARG(uap, attrnamespace), attrname, p); 2886 } else { 2887 error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp, 2888 SCARG(uap, attrnamespace), NULL, p); 2889 } 2890 2891 /* 2892 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, 2893 * filename_vp, so vrele it if it is defined. 2894 */ 2895 if (filename_vp != NULL) 2896 vrele(filename_vp); 2897 2898 return (error); 2899} 2900 2901/*- 2902 * Set a named extended attribute on a file or directory 2903 * 2904 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 2905 * kernelspace string pointer "attrname", userspace buffer 2906 * pointer "data", buffer length "nbytes", thread "td". 2907 * Returns: 0 on success, an error number otherwise 2908 * Locks: none 2909 * References: vp must be a valid reference for the duration of the call 2910 */ 2911static int 2912extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname, 2913 void *data, size_t nbytes, struct proc *p, register_t *retval) 2914{ 2915 struct uio auio; 2916 struct iovec aiov; 2917 ssize_t cnt; 2918 int error; 2919 2920 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2921 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2922 2923 aiov.iov_base = data; 2924 aiov.iov_len = nbytes; 2925 auio.uio_iov = &aiov; 2926 auio.uio_iovcnt = 1; 2927 auio.uio_offset = 0; 2928 if (nbytes > INT_MAX) { 2929 error = EINVAL; 2930 goto done; 2931 } 2932 auio.uio_resid = nbytes; 2933 auio.uio_rw = UIO_WRITE; 2934 auio.uio_segflg = UIO_USERSPACE; 2935 auio.uio_procp = p; 2936 cnt = nbytes; 2937 2938 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, 2939 p->p_ucred, p); 2940 cnt -= auio.uio_resid; 2941 retval[0] = cnt; 2942 2943done: 2944 VOP_UNLOCK(vp, 0, p); 2945 return (error); 2946} 2947 2948int 2949sys_extattr_set_file(struct proc *p, void *v, register_t *retval) 2950{ 2951 struct sys_extattr_set_file_args /* { 2952 syscallarg(const char *) path; 2953 syscallarg(int) attrnamespace; 2954 syscallarg(const char *) attrname; 2955 syscallarg(void *) data; 2956 syscallarg(size_t) nbytes; 2957 } */ *uap = v; 2958 struct nameidata nd; 2959 char attrname[EXTATTR_MAXNAMELEN]; 2960 int error; 2961 2962 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 2963 NULL); 2964 if (error) 2965 return (error); 2966 2967 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2968 if ((error = namei(&nd)) != 0) 2969 return (error); 2970 2971 error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname, 2972 SCARG(uap, data), SCARG(uap, nbytes), p, retval); 2973 2974 vrele(nd.ni_vp); 2975 return (error); 2976} 2977 2978int 2979sys_extattr_set_fd(struct proc *p, void *v, register_t *retval) 2980{ 2981 struct sys_extattr_set_fd_args /* { 2982 syscallarg(int) fd; 2983 syscallarg(int) attrnamespace; 2984 syscallarg(const char *) attrname; 2985 syscallarg(struct iovec *) iovp; 2986 syscallarg(int) iovcnt; 2987 } */ *uap = v; 2988 struct file *fp; 2989 char attrname[EXTATTR_MAXNAMELEN]; 2990 int error; 2991 2992 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 2993 NULL); 2994 if (error) 2995 return (error); 2996 2997 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2998 return (error); 2999 3000 error = extattr_set_vp((struct vnode *)fp->f_data, 3001 SCARG(uap, attrnamespace), attrname, SCARG(uap, data), 3002 SCARG(uap, nbytes), p, retval); 3003 FRELE(fp); 3004 3005 return (error); 3006} 3007 3008/*- 3009 * Get a named extended attribute on a file or directory 3010 * 3011 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 3012 * kernelspace string pointer "attrname", userspace buffer 3013 * pointer "data", buffer length "nbytes", thread "td". 3014 * Returns: 0 on success, an error number otherwise 3015 * Locks: none 3016 * References: vp must be a valid reference for the duration of the call 3017 */ 3018static int 3019extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, 3020 void *data, size_t nbytes, struct proc *p, register_t *retval) 3021{ 3022 struct uio auio; 3023 struct iovec aiov; 3024 ssize_t cnt; 3025 size_t size; 3026 int error; 3027 3028 VOP_LEASE(vp, p, p->p_ucred, LEASE_READ); 3029 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 3030 3031 /* 3032 * Slightly unusual semantics: if the user provides a NULL data 3033 * pointer, they don't want to receive the data, just the 3034 * maximum read length. 3035 */ 3036 if (data != NULL) { 3037 aiov.iov_base = data; 3038 aiov.iov_len = nbytes; 3039 auio.uio_iov = &aiov; 3040 auio.uio_offset = 0; 3041 if (nbytes > INT_MAX) { 3042 error = EINVAL; 3043 goto done; 3044 } 3045 auio.uio_resid = nbytes; 3046 auio.uio_rw = UIO_READ; 3047 auio.uio_segflg = UIO_USERSPACE; 3048 auio.uio_procp = p; 3049 cnt = nbytes; 3050 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio, 3051 NULL, p->p_ucred, p); 3052 cnt -= auio.uio_resid; 3053 retval[0] = cnt; 3054 } else { 3055 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL, 3056 &size, p->p_ucred, p); 3057 retval[0] = size; 3058 } 3059done: 3060 VOP_UNLOCK(vp, 0, p); 3061 return (error); 3062} 3063 3064int 3065sys_extattr_get_file(p, v, retval) 3066 struct proc *p; 3067 void *v; 3068 register_t *retval; 3069{ 3070 struct sys_extattr_get_file_args /* { 3071 syscallarg(const char *) path; 3072 syscallarg(int) attrnamespace; 3073 syscallarg(const char *) attrname; 3074 syscallarg(void *) data; 3075 syscallarg(size_t) nbytes; 3076 } */ *uap = v; 3077 struct nameidata nd; 3078 char attrname[EXTATTR_MAXNAMELEN]; 3079 int error; 3080 3081 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 3082 NULL); 3083 if (error) 3084 return (error); 3085 3086 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 3087 if ((error = namei(&nd)) != 0) 3088 return (error); 3089 3090 error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname, 3091 SCARG(uap, data), SCARG(uap, nbytes), p, retval); 3092 3093 vrele(nd.ni_vp); 3094 return (error); 3095} 3096 3097int 3098sys_extattr_get_fd(p, v, retval) 3099 struct proc *p; 3100 void *v; 3101 register_t *retval; 3102{ 3103 struct sys_extattr_get_fd_args /* { 3104 syscallarg(int) fd; 3105 syscallarg(int) attrnamespace; 3106 syscallarg(const char *) attrname; 3107 syscallarg(void *) data; 3108 syscallarg(size_t) nbytes; 3109 } */ *uap = v; 3110 struct file *fp; 3111 char attrname[EXTATTR_MAXNAMELEN]; 3112 int error; 3113 3114 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 3115 NULL); 3116 if (error) 3117 return (error); 3118 3119 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 3120 return (error); 3121 3122 error = extattr_get_vp((struct vnode *)fp->f_data, 3123 SCARG(uap, attrnamespace), attrname, SCARG(uap, data), 3124 SCARG(uap, nbytes), p, retval); 3125 FRELE(fp); 3126 3127 return (error); 3128} 3129 3130/* 3131 * extattr_delete_vp(): Delete a named extended attribute on a file or 3132 * directory 3133 * 3134 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 3135 * kernelspace string pointer "attrname", proc "p" 3136 * Returns: 0 on success, an error number otherwise 3137 * Locks: none 3138 * References: vp must be a valid reference for the duration of the call 3139 */ 3140static int 3141extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname, 3142 struct proc *p) 3143{ 3144 int error; 3145 3146 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 3147 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 3148 3149 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, 3150 p->p_ucred, p); 3151 3152 VOP_UNLOCK(vp, 0, p); 3153 return (error); 3154} 3155 3156int 3157sys_extattr_delete_file(p, v, retval) 3158 struct proc *p; 3159 void *v; 3160 register_t *retval; 3161{ 3162 struct sys_extattr_delete_file_args /* { 3163 syscallarg(int) fd; 3164 syscallarg(int) attrnamespace; 3165 syscallarg(const char *) attrname; 3166 } */ *uap = v; 3167 struct nameidata nd; 3168 char attrname[EXTATTR_MAXNAMELEN]; 3169 int error; 3170 3171 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 3172 NULL); 3173 if (error) 3174 return(error); 3175 3176 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 3177 if ((error = namei(&nd)) != 0) 3178 return(error); 3179 3180 error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace), 3181 attrname, p); 3182 3183 vrele(nd.ni_vp); 3184 return(error); 3185} 3186 3187int 3188sys_extattr_delete_fd(p, v, retval) 3189 struct proc *p; 3190 void *v; 3191 register_t *retval; 3192{ 3193 struct sys_extattr_delete_fd_args /* { 3194 syscallarg(int) fd; 3195 syscallarg(int) attrnamespace; 3196 syscallarg(const char *) attrname; 3197 } */ *uap = v; 3198 struct file *fp; 3199 char attrname[EXTATTR_MAXNAMELEN]; 3200 int error; 3201 3202 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 3203 NULL); 3204 if (error) 3205 return (error); 3206 3207 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 3208 return (error); 3209 3210 error = extattr_delete_vp((struct vnode *)fp->f_data, 3211 SCARG(uap, attrnamespace), attrname, p); 3212 FRELE(fp); 3213 3214 return (error); 3215} 3216#endif 3217