1/* $OpenBSD: t9.2,v 1.4 2024/07/10 09:24:03 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 /* Don't let non-root see filesystem id (for NFS security) */ 595 if (suser(p->p_ucred, &p->p_acflag)) { 596 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 597 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 598 sp = &sb; 599 } 600 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 601} 602 603/* 604 * Get filesystem statistics. 605 */ 606/* ARGSUSED */ 607int 608sys_fstatfs(p, v, retval) 609 struct proc *p; 610 void *v; 611 register_t *retval; 612{ 613 struct sys_fstatfs_args /* { 614 syscallarg(int) fd; 615 syscallarg(struct statfs *) buf; 616 } */ *uap = v; 617 struct file *fp; 618 struct mount *mp; 619 struct statfs *sp; 620 int error; 621 struct statfs sb; 622 623 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 624 return (error); 625 mp = ((struct vnode *)fp->f_data)->v_mount; 626 sp = &mp->mnt_stat; 627 error = VFS_STATFS(mp, sp, p); 628 FRELE(fp); 629 if (error) 630 return (error); 631 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 632 /* Don't let non-root see filesystem id (for NFS security) */ 633 if (suser(p->p_ucred, &p->p_acflag)) { 634 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 635 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 636 sp = &sb; 637 } 638 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 639} 640 641/* 642 * Get statistics on all filesystems. 643 */ 644int 645sys_getfsstat(p, v, retval) 646 struct proc *p; 647 void *v; 648 register_t *retval; 649{ 650 register struct sys_getfsstat_args /* { 651 syscallarg(struct statfs *) buf; 652 syscallarg(size_t) bufsize; 653 syscallarg(int) flags; 654 } */ *uap = v; 655 register struct mount *mp *nmp; 656 register struct statfs *sp; 657 struct statfs sb; 658 caddr_t sfsp; 659 size_t count, maxcount; 660 int error, flags = SCARG(uap, flags); 661 662 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); 663 sfsp = (caddr_t)SCARG(uap, buf); 664 count = 0; 665 simple_lock(&mountlist_slock); 666 TAILQ_FOREACH_REVERSE_SAFE(mp, &mountlist, mnt_list, nmp) { 667 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) 668 continue; 669 if (sfsp && count < maxcount) { 670 sp = &mp->mnt_stat; 671 672 /* Refresh stats unless MNT_NOWAIT is specified */ 673 if (flags != MNT_NOWAIT && 674 flags != MNT_LAZY && 675 (flags == MNT_WAIT || 676 flags == 0) && 677 (error = VFS_STATFS(mp, sp, p))) { 678 simple_lock(&mountlist_slock); 679 vfs_unbusy(mp, p); 680 continue; 681 } 682 683 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 684 if (suser(p->p_ucred, &p->p_acflag)) { 685 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 686 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 687 sp = &sb; 688 } 689 error = copyout((caddr_t)sp, sfsp, sizeof(*sp)); 690 if (error) { 691 vfs_unbusy(mp, p); 692 return (error); 693 } 694 sfsp += sizeof(*sp); 695 } 696 count++; 697 simple_lock(&mountlist_slock); 698 vfs_unbusy(mp, p); 699 } 700 simple_unlock(&mountlist_slock); 701 if (sfsp && count > maxcount) 702 *retval = maxcount; 703 else 704 *retval = count; 705 return (0); 706} 707 708/* 709 * Change current working directory to a given file descriptor. 710 */ 711/* ARGSUSED */ 712int 713sys_fchdir(p, v, retval) 714 struct proc *p; 715 void *v; 716 register_t *retval; 717{ 718 struct sys_fchdir_args /* { 719 syscallarg(int) fd; 720 } */ *uap = v; 721 struct filedesc *fdp = p->p_fd; 722 struct vnode *vp, *tdp; 723 struct mount *mp; 724 struct file *fp; 725 int error; 726 727 if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0) 728 return (error); 729 vp = (struct vnode *)fp->f_data; 730 VREF(vp); 731 FRELE(fp); 732 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 733 if (vp->v_type != VDIR) 734 error = ENOTDIR; 735 else 736 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 737 738 while (!error && (mp = vp->v_mountedhere) != NULL) { 739 if (vfs_busy(mp, 0, 0, p)) 740 continue; 741 error = VFS_ROOT(mp, &tdp); 742 vfs_unbusy(mp, p); 743 if (error) 744 break; 745 vput(vp); 746 vp = tdp; 747 } 748 if (error) { 749 vput(vp); 750 return (error); 751 } 752 VOP_UNLOCK(vp, 0, p); 753 vrele(fdp->fd_cdir); 754 fdp->fd_cdir = vp; 755 return (0); 756} 757 758/* 759 * Change current working directory (``.''). 760 */ 761/* ARGSUSED */ 762int 763sys_chdir(p, v, retval) 764 struct proc *p; 765 void *v; 766 register_t *retval; 767{ 768 struct sys_chdir_args /* { 769 syscallarg(char *) path; 770 } */ *uap = v; 771 register struct filedesc *fdp = p->p_fd; 772 int error; 773 struct nameidata nd; 774 775 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 776 SCARG(uap, path), p); 777 if ((error = change_dir(&nd, p)) != 0) 778 return (error); 779 vrele(fdp->fd_cdir); 780 fdp->fd_cdir = nd.ni_vp; 781 return (0); 782} 783 784/* 785 * Change notion of root (``/'') directory. 786 */ 787/* ARGSUSED */ 788int 789sys_chroot(p, v, retval) 790 struct proc *p; 791 void *v; 792 register_t *retval; 793{ 794 struct sys_chroot_args /* { 795 syscallarg(char *) path; 796 } */ *uap = v; 797 register struct filedesc *fdp = p->p_fd; 798 int error; 799 struct nameidata nd; 800 801 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 802 return (error); 803 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 804 SCARG(uap, path), p); 805 if ((error = change_dir(&nd, p)) != 0) 806 return (error); 807 if (fdp->fd_rdir != NULL) { 808 /* 809 * A chroot() done inside a changed root environment does 810 * an automatic chdir to avoid the out-of-tree experience. 811 */ 812 vrele(fdp->fd_rdir); 813 vrele(fdp->fd_cdir); 814 VREF(nd.ni_vp); 815 fdp->fd_cdir = nd.ni_vp; 816 } 817 fdp->fd_rdir = nd.ni_vp; 818 return (0); 819} 820 821/* 822 * Common routine for chroot and chdir. 823 */ 824static int 825change_dir(ndp, p) 826 register struct nameidata *ndp; 827 struct proc *p; 828{ 829 struct vnode *vp; 830 int error; 831 832 if ((error = namei(ndp)) != 0) 833 return (error); 834 vp = ndp->ni_vp; 835 if (vp->v_type != VDIR) 836 error = ENOTDIR; 837 else 838 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 839 if (error) 840 vput(vp); 841 else 842 VOP_UNLOCK(vp, 0, p); 843 return (error); 844} 845 846/* 847 * Check permissions, allocate an open file structure, 848 * and call the device open routine if any. 849 */ 850int 851sys_open(p, v, retval) 852 struct proc *p; 853 void *v; 854 register_t *retval; 855{ 856 struct sys_open_args /* { 857 syscallarg(char *) path; 858 syscallarg(int) flags; 859 syscallarg(int) mode; 860 } */ *uap = v; 861 struct filedesc *fdp = p->p_fd; 862 struct file *fp; 863 struct vnode *vp; 864 struct vattr vattr; 865 int flags, cmode; 866 int type, indx, error, localtrunc = 0; 867 struct flock lf; 868 struct nameidata nd; 869 870 if ((error = falloc(p, &fp, &indx)) != 0) 871 return (error); 872 873 flags = FFLAGS(SCARG(uap, flags)); 874 cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 875 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 876 p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 877 if ((flags & O_TRUNC) && (flags & (O_EXLOCK | O_SHLOCK))) { 878 localtrunc = 1; 879 flags &= ~O_TRUNC; /* Must do truncate ourselves */ 880 } 881 if ((error = vn_open(&nd, flags, cmode)) != 0) { 882 if ((error == ENODEV || error == ENXIO) && 883 p->p_dupfd >= 0 && /* XXX from fdopen */ 884 (error = 885 dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 886 closef(fp, p); 887 *retval = indx; 888 return (0); 889 } 890 if (error == ERESTART) 891 error = EINTR; 892 fdremove(fdp, indx); 893 closef(fp, p); 894 return (error); 895 } 896 p->p_dupfd = 0; 897 vp = nd.ni_vp; 898 fp->f_flag = flags & FMASK; 899 fp->f_type = DTYPE_VNODE; 900 fp->f_ops = &vnops; 901 fp->f_data = (caddr_t)vp; 902 if (flags & (O_EXLOCK | O_SHLOCK)) { 903 lf.l_whence = SEEK_SET; 904 lf.l_start = 0; 905 lf.l_len = 0; 906 if (flags & O_EXLOCK) 907 lf.l_type = F_WRLCK; 908 else 909 lf.l_type = F_RDLCK; 910 type = F_FLOCK; 911 if ((flags & FNONBLOCK) == 0) 912 type |= F_WAIT; 913 VOP_UNLOCK(vp, 0, p); 914 error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type); 915 if (error) { 916 /* closef will vn_close the file for us. */ 917 fdremove(fdp, indx); 918 closef(fp, p); 919 return (error); 920 } 921 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 922 fp->f_flag |= FHASLOCK; 923 } 924 if (localtrunc) { 925 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 926 if ((fp->f_flag & FWRITE) == 0) 927 error = EACCES; 928 else if (vp->v_mount->mnt_flag & MNT_RDONLY) 929 error = EROFS; 930 else if (vp->v_type == VDIR) 931 error = EISDIR; 932 else if ((error = vn_writechk(vp)) == 0) { 933 VATTR_NULL(&vattr); 934 vattr.va_size = 0; 935 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 936 } 937 if (error) { 938 VOP_UNLOCK(vp, 0, p); 939 /* closef will close the file for us. */ 940 fdremove(fdp, indx); 941 closef(fp, p); 942 return (error); 943 } 944 } 945 VOP_UNLOCK(vp, 0, p); 946 *retval = indx; 947 FILE_SET_MATURE(fp); 948 return (0); 949} 950 951/* 952 * Get file handle system call 953 */ 954int 955sys_getfh(p, v, retval) 956 struct proc *p; 957 register void *v; 958 register_t *retval; 959{ 960 register struct sys_getfh_args /* { 961 syscallarg(char *) fname; 962 syscallarg(fhandle_t *) fhp; 963 } */ *uap = v; 964 register struct vnode *vp; 965 fhandle_t fh; 966 int error; 967 struct nameidata nd; 968 969 /* 970 * Must be super user 971 */ 972 error = suser(p->p_ucred, &p->p_acflag); 973 if (error) 974 return (error); 975 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 976 SCARG(uap, fname), p); 977 error = namei(&nd); 978 if (error) 979 return (error); 980 vp = nd.ni_vp; 981 bzero((caddr_t)&fh, sizeof(fh)); 982 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 983 error = VFS_VPTOFH(vp, &fh.fh_fid); 984 vput(vp); 985 if (error) 986 return (error); 987 error = copyout((caddr_t)&fh, (caddr_t)SCARG(uap, fhp), sizeof (fh)); 988 return (error); 989} 990 991/* 992 * Open a file given a file handle. 993 * 994 * Check permissions, allocate an open file structure, 995 * and call the device open routine if any. 996 */ 997int 998sys_fhopen(p, v, retval) 999 struct proc *p; 1000 void *v; 1001 register_t *retval; 1002{ 1003 register struct sys_fhopen_args /* { 1004 syscallarg(const fhandle_t *) fhp; 1005 syscallarg(int) flags; 1006 } */ *uap = v; 1007 struct filedesc *fdp = p->p_fd; 1008 struct file *fp; 1009 struct vnode *vp = NULL; 1010 struct mount *mp; 1011 struct ucred *cred = p->p_ucred; 1012 int flags; 1013 int type, indx, error=0; 1014 struct flock lf; 1015 struct vattr va; 1016 fhandle_t fh; 1017 1018 /* 1019 * Must be super user 1020 */ 1021 if ((error = suser(p->p_ucred, &p->p_acflag))) 1022 return (error); 1023 1024 flags = FFLAGS(SCARG(uap, flags)); 1025 if ((flags & (FREAD | FWRITE)) == 0) 1026 return (EINVAL); 1027 if ((flags & O_CREAT)) 1028 return (EINVAL); 1029 1030 if ((error = falloc(p, &fp, &indx)) != 0) 1031 return (error); 1032 1033 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0) 1034 goto bad; 1035 1036 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) { 1037 error = ESTALE; 1038 goto bad; 1039 } 1040 1041 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)) != 0) { 1042 vp = NULL; /* most likely unnecessary sanity for bad: */ 1043 goto bad; 1044 } 1045 1046 /* Now do an effective vn_open */ 1047 1048 if (vp->v_type == VSOCK) { 1049 error = EOPNOTSUPP; 1050 goto bad; 1051 } 1052 if (flags & FREAD) { 1053 if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0) 1054 goto bad; 1055 } 1056 if (flags & (FWRITE | O_TRUNC)) { 1057 if (vp->v_type == VDIR) { 1058 error = EISDIR; 1059 goto bad; 1060 } 1061 if ((error = vn_writechk(vp)) != 0 || 1062 (error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0) 1063 goto bad; 1064 } 1065 if (flags & O_TRUNC) { 1066 VOP_UNLOCK(vp, 0, p); /* XXX */ 1067 VOP_LEASE(vp, p, cred, LEASE_WRITE); 1068 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */ 1069 VATTR_NULL(&va); 1070 va.va_size = 0; 1071 if ((error = VOP_SETATTR(vp, &va, cred, p)) != 0) 1072 goto bad; 1073 } 1074 if ((error = VOP_OPEN(vp, flags, cred, p)) != 0) 1075 goto bad; 1076 if (flags & FWRITE) 1077 vp->v_writecount++; 1078 1079 /* done with modified vn_open, now finish what sys_open does. */ 1080 1081 fp->f_flag = flags & FMASK; 1082 fp->f_type = DTYPE_VNODE; 1083 fp->f_ops = &vnops; 1084 fp->f_data = (caddr_t)vp; 1085 if (flags & (O_EXLOCK | O_SHLOCK)) { 1086 lf.l_whence = SEEK_SET; 1087 lf.l_start = 0; 1088 lf.l_len = 0; 1089 if (flags & O_EXLOCK) 1090 lf.l_type = F_WRLCK; 1091 else 1092 lf.l_type = F_RDLCK; 1093 type = F_FLOCK; 1094 if ((flags & FNONBLOCK) == 0) 1095 type |= F_WAIT; 1096 VOP_UNLOCK(vp, 0, p); 1097 error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type); 1098 if (error) { 1099 /* closef will vn_close the file for us. */ 1100 fdremove(fdp, indx); 1101 closef(fp, p); 1102 return (error); 1103 } 1104 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1105 fp->f_flag |= FHASLOCK; 1106 } 1107 VOP_UNLOCK(vp, 0, p); 1108 *retval = indx; 1109 FILE_SET_MATURE(fp); 1110 return (0); 1111 1112bad: 1113 fdremove(fdp, indx); 1114 closef(fp, p); 1115 if (vp != NULL) 1116 vput(vp); 1117 return (error); 1118} 1119 1120/* ARGSUSED */ 1121int 1122sys_fhstat(p, v, retval) 1123 struct proc *p; 1124 void *v; 1125 register_t *retval; 1126{ 1127 register struct sys_fhstat_args /* { 1128 syscallarg(const fhandle_t *) fhp; 1129 syscallarg(struct stat *) sb; 1130 } */ *uap = v; 1131 struct stat sb; 1132 int error; 1133 fhandle_t fh; 1134 struct mount *mp; 1135 struct vnode *vp; 1136 1137 /* 1138 * Must be super user 1139 */ 1140 if ((error = suser(p->p_ucred, &p->p_acflag))) 1141 return (error); 1142 1143 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0) 1144 return (error); 1145 1146 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) 1147 return (ESTALE); 1148 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) 1149 return (error); 1150 error = vn_stat(vp, &sb, p); 1151 vput(vp); 1152 if (error) 1153 return (error); 1154 error = copyout(&sb, SCARG(uap, sb), sizeof(sb)); 1155 return (error); 1156} 1157 1158/* ARGSUSED */ 1159int 1160sys_fhstatfs(p, v, retval) 1161 struct proc *p; 1162 void *v; 1163 register_t *retval; 1164{ 1165 register struct sys_fhstatfs_args /* 1166 syscallarg(const fhandle_t *) fhp; 1167 syscallarg(struct statfs *) buf; 1168 } */ *uap = v; 1169 struct statfs sp; 1170 fhandle_t fh; 1171 struct mount *mp; 1172 struct vnode *vp; 1173 int error; 1174 1175 /* 1176 * Must be super user 1177 */ 1178 if ((error = suser(p->p_ucred, &p->p_acflag))) 1179 return (error); 1180 1181 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0) 1182 return (error); 1183 1184 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) 1185 return (ESTALE); 1186 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) 1187 return (error); 1188 mp = vp->v_mount; 1189 vput(vp); 1190 if ((error = VFS_STATFS(mp, &sp, p)) != 0) 1191 return (error); 1192 sp.f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 1193 return (copyout(&sp, SCARG(uap, buf), sizeof(sp))); 1194} 1195 1196/* 1197 * Create a special file. 1198 */ 1199/* ARGSUSED */ 1200int 1201sys_mknod(p, v, retval) 1202 struct proc *p; 1203 void *v; 1204 register_t *retval; 1205{ 1206 register struct sys_mknod_args /* { 1207 syscallarg(char *) path; 1208 syscallarg(int) mode; 1209 syscallarg(int) dev; 1210 } */ *uap = v; 1211 register struct vnode *vp; 1212 struct vattr vattr; 1213 int error; 1214 int whiteout = 0; 1215 struct nameidata nd; 1216 1217 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 1218 return (error); 1219 if (p->p_fd->fd_rdir) 1220 return (EINVAL); 1221 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1222 if ((error = namei(&nd)) != 0) 1223 return (error); 1224 vp = nd.ni_vp; 1225 if (vp != NULL) 1226 error = EEXIST; 1227 else { 1228 VATTR_NULL(&vattr); 1229 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 1230 vattr.va_rdev = SCARG(uap, dev); 1231 whiteout = 0; 1232 1233 switch (SCARG(uap, mode) & S_IFMT) { 1234 case S_IFMT: /* used by badsect to flag bad sectors */ 1235 vattr.va_type = VBAD; 1236 break; 1237 case S_IFCHR: 1238 vattr.va_type = VCHR; 1239 break; 1240 case S_IFBLK: 1241 vattr.va_type = VBLK; 1242 break; 1243 case S_IFWHT: 1244 whiteout = 1; 1245 break; 1246 default: 1247 error = EINVAL; 1248 break; 1249 } 1250 } 1251 if (!error) { 1252 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1253 if (whiteout) { 1254 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 1255 if (error) 1256 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1257 vput(nd.ni_dvp); 1258 } else { 1259 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, 1260 &nd.ni_cnd, &vattr); 1261 } 1262 } else { 1263 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1264 if (nd.ni_dvp == vp) 1265 vrele(nd.ni_dvp); 1266 else 1267 vput(nd.ni_dvp); 1268 if (vp) 1269 vrele(vp); 1270 } 1271 return (error); 1272} 1273 1274/* 1275 * Create a named pipe. 1276 */ 1277/* ARGSUSED */ 1278int 1279sys_mkfifo(p, v, retval) 1280 struct proc *p; 1281 void *v; 1282 register_t *retval; 1283{ 1284#ifndef FIFO 1285 return (EOPNOTSUPP); 1286#else 1287 register struct sys_mkfifo_args /* { 1288 syscallarg(char *) path; 1289 syscallarg(int) mode; 1290 } */ *uap = v; 1291 struct vattr vattr; 1292 int error; 1293 struct nameidata nd; 1294 1295 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1296 if ((error = namei(&nd)) != 0) 1297 return (error); 1298 if (nd.ni_vp != NULL) { 1299 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1300 if (nd.ni_dvp == nd.ni_vp) 1301 vrele(nd.ni_dvp); 1302 else 1303 vput(nd.ni_dvp); 1304 vrele(nd.ni_vp); 1305 return (EEXIST); 1306 } 1307 VATTR_NULL(&vattr); 1308 vattr.va_type = VFIFO; 1309 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 1310 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1311 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 1312#endif /* FIFO */ 1313} 1314 1315/* 1316 * Make a hard file link. 1317 */ 1318/* ARGSUSED */ 1319int 1320sys_link(p, v, retval) 1321 struct proc *p; 1322 void *v; 1323 register_t *retval; 1324{ 1325 register struct sys_link_args /* { 1326 syscallarg(char *) path; 1327 syscallarg(char *) link; 1328 } */ *uap = v; 1329 register struct vnode *vp; 1330 struct nameidata nd; 1331 int error; 1332 int flags; 1333 1334 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1335 if ((error = namei(&nd)) != 0) 1336 return (error); 1337 vp = nd.ni_vp; 1338 1339 flags = LOCKPARENT; 1340 if (vp->v_type == VDIR) { 1341 flags |= STRIPSLASHES; 1342 } 1343 1344 NDINIT(&nd, CREATE, flags, UIO_USERSPACE, SCARG(uap, link), p); 1345 if ((error = namei(&nd)) != 0) 1346 goto out; 1347 if (nd.ni_vp) { 1348 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1349 if (nd.ni_dvp == nd.ni_vp) 1350 vrele(nd.ni_dvp); 1351 else 1352 vput(nd.ni_dvp); 1353 vrele(nd.ni_vp); 1354 error = EEXIST; 1355 goto out; 1356 } 1357 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1358 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1359 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 1360out: 1361 vrele(vp); 1362 return (error); 1363} 1364 1365/* 1366 * Make a symbolic link. 1367 */ 1368/* ARGSUSED */ 1369int 1370sys_symlink(p, v, retval) 1371 struct proc *p; 1372 void *v; 1373 register_t *retval; 1374{ 1375 register struct sys_symlink_args /* { 1376 syscallarg(char *) path; 1377 syscallarg(char *) link; 1378 } */ *uap = v; 1379 struct vattr vattr; 1380 char *path; 1381 int error; 1382 struct nameidata nd; 1383 1384 MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 1385 error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL); 1386 if (error) 1387 goto out; 1388 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); 1389 if ((error = namei(&nd)) != 0) 1390 goto out; 1391 if (nd.ni_vp) { 1392 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1393 if (nd.ni_dvp == nd.ni_vp) 1394 vrele(nd.ni_dvp); 1395 else 1396 vput(nd.ni_dvp); 1397 vrele(nd.ni_vp); 1398 error = EEXIST; 1399 goto out; 1400 } 1401 VATTR_NULL(&vattr); 1402 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 1403 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1404 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 1405out: 1406 FREE(path, M_NAMEI); 1407 return (error); 1408} 1409 1410/* 1411 * Delete a whiteout from the filesystem. 1412 */ 1413/* ARGSUSED */ 1414int 1415sys_undelete(p, v, retval) 1416 struct proc *p; 1417 void *v; 1418 register_t *retval; 1419{ 1420 register struct sys_undelete_args /* { 1421 syscallarg(char *) path; 1422 } */ *uap = v; 1423 int error; 1424 struct nameidata nd; 1425 1426 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, 1427 SCARG(uap, path), p); 1428 error = namei(&nd); 1429 if (error) 1430 return (error); 1431 1432 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 1433 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1434 if (nd.ni_dvp == nd.ni_vp) 1435 vrele(nd.ni_dvp); 1436 else 1437 vput(nd.ni_dvp); 1438 if (nd.ni_vp) 1439 vrele(nd.ni_vp); 1440 return (EEXIST); 1441 } 1442 1443 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1444 if ((error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) != 0) 1445 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1446 vput(nd.ni_dvp); 1447 return (error); 1448} 1449 1450/* 1451 * Delete a name from the filesystem. 1452 */ 1453/* ARGSUSED */ 1454int 1455sys_unlink(p, v, retval) 1456 struct proc *p; 1457 void *v; 1458 register_t *retval; 1459{ 1460 struct sys_unlink_args /* { 1461 syscallarg(char *) path; 1462 } */ *uap = v; 1463 register struct vnode *vp; 1464 int error; 1465 struct nameidata nd; 1466 1467 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 1468 SCARG(uap, path), p); 1469 if ((error = namei(&nd)) != 0) 1470 return (error); 1471 vp = nd.ni_vp; 1472 1473 /* 1474 * The root of a mounted filesystem cannot be deleted. 1475 */ 1476 if (vp->v_flag & VROOT) { 1477 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1478 if (nd.ni_dvp == vp) 1479 vrele(nd.ni_dvp); 1480 else 1481 vput(nd.ni_dvp); 1482 vput(vp); 1483 error = EBUSY; 1484 goto out; 1485 } 1486 1487 (void)uvm_vnp_uncache(vp); 1488 1489 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1490 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1491 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1492out: 1493 return (error); 1494} 1495 1496/* 1497 * Reposition read/write file offset. 1498 */ 1499int 1500sys_lseek(p, v, retval) 1501 struct proc *p; 1502 void *v; 1503 register_t *retval; 1504{ 1505 register struct sys_lseek_args /* { 1506 syscallarg(int) fd; 1507 syscallarg(int) pad; 1508 syscallarg(off_t) offset; 1509 syscallarg(int) whence; 1510 } */ *uap = v; 1511 struct ucred *cred = p->p_ucred; 1512 register struct filedesc *fdp = p->p_fd; 1513 register struct file *fp; 1514 struct vattr vattr; 1515 struct vnode *vp; 1516 int error, special; 1517 1518 if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) 1519 return (EBADF); 1520 if (fp->f_type != DTYPE_VNODE) 1521 return (ESPIPE); 1522 vp = (struct vnode *)fp->f_data; 1523 if (vp->v_type == VFIFO) 1524 return (ESPIPE); 1525 if (vp->v_type == VCHR) 1526 special = 1; 1527 else 1528 special = 0; 1529 switch (SCARG(uap, whence)) { 1530 case SEEK_CUR: 1531 if (!special && fp->f_offset + SCARG(uap, offset) < 0) 1532 return (EINVAL); 1533 fp->f_offset += SCARG(uap, offset); 1534 break; 1535 case SEEK_END: 1536 error = VOP_GETATTR((struct vnode *)fp->f_data, &vattr, 1537 cred, p); 1538 if (error) 1539 return (error); 1540 if (!special && (off_t)vattr.va_size + SCARG(uap, offset) < 0) 1541 return (EINVAL); 1542 fp->f_offset = SCARG(uap, offset) + vattr.va_size; 1543 break; 1544 case SEEK_SET: 1545 if (!special && SCARG(uap, offset) < 0) 1546 return (EINVAL); 1547 fp->f_offset = SCARG(uap, offset); 1548 break; 1549 default: 1550 return (EINVAL); 1551 } 1552 *(off_t *)retval = fp->f_offset; 1553 return (0); 1554} 1555 1556/* 1557 * Check access permissions. 1558 */ 1559int 1560sys_access(p, v, retval) 1561 struct proc *p; 1562 void *v; 1563 register_t *retval; 1564{ 1565 register struct sys_access_args /* { 1566 syscallarg(char *) path; 1567 syscallarg(int) flags; 1568 } */ *uap = v; 1569 register struct ucred *cred = p->p_ucred; 1570 register struct vnode *vp; 1571 int error, flags, t_gid, t_uid; 1572 struct nameidata nd; 1573 1574 if (SCARG(uap, flags) & ~(R_OK | W_OK | X_OK)) 1575 return (EINVAL); 1576 t_uid = cred->cr_uid; 1577 t_gid = cred->cr_gid; 1578 cred->cr_uid = p->p_cred->p_ruid; 1579 cred->cr_gid = p->p_cred->p_rgid; 1580 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1581 SCARG(uap, path), p); 1582 if ((error = namei(&nd)) != 0) 1583 goto out1; 1584 vp = nd.ni_vp; 1585 1586 /* Flags == 0 means only check for existence. */ 1587 if (SCARG(uap, flags)) { 1588 flags = 0; 1589 if (SCARG(uap, flags) & R_OK) 1590 flags |= VREAD; 1591 if (SCARG(uap, flags) & W_OK) 1592 flags |= VWRITE; 1593 if (SCARG(uap, flags) & X_OK) 1594 flags |= VEXEC; 1595 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 1596 error = VOP_ACCESS(vp, flags, cred, p); 1597 } 1598 vput(vp); 1599out1: 1600 cred->cr_uid = t_uid; 1601 cred->cr_gid = t_gid; 1602 return (error); 1603} 1604 1605/* 1606 * Get file status; this version follows links. 1607 */ 1608/* ARGSUSED */ 1609int 1610sys_stat(p, v, retval) 1611 struct proc *p; 1612 void *v; 1613 register_t *retval; 1614{ 1615 register struct sys_stat_args /* { 1616 syscallarg(char *) path; 1617 syscallarg(struct stat *) ub; 1618 } */ *uap = v; 1619 struct stat sb; 1620 int error; 1621 struct nameidata nd; 1622 1623 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1624 SCARG(uap, path), p); 1625 if ((error = namei(&nd)) != 0) 1626 return (error); 1627 error = vn_stat(nd.ni_vp, &sb, p); 1628 vput(nd.ni_vp); 1629 if (error) 1630 return (error); 1631 /* Don't let non-root see generation numbers (for NFS security) */ 1632 if (suser(p->p_ucred, &p->p_acflag)) 1633 sb.st_gen = 0; 1634 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1635 return (error); 1636} 1637 1638/* 1639 * Get file status; this version does not follow links. 1640 */ 1641/* ARGSUSED */ 1642int 1643sys_lstat(p, v, retval) 1644 struct proc *p; 1645 void *v; 1646 register_t *retval; 1647{ 1648 register struct sys_lstat_args /* { 1649 syscallarg(char *) path; 1650 syscallarg(struct stat *) ub; 1651 } */ *uap = v; 1652 struct stat sb; 1653 int error; 1654 struct nameidata nd; 1655 1656 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 1657 SCARG(uap, path), p); 1658 if ((error = namei(&nd)) != 0) 1659 return (error); 1660 error = vn_stat(nd.ni_vp, &sb, p); 1661 vput(nd.ni_vp); 1662 if (error) 1663 return (error); 1664 /* Don't let non-root see generation numbers (for NFS security) */ 1665 if (suser(p->p_ucred, &p->p_acflag)) 1666 sb.st_gen = 0; 1667 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1668 return (error); 1669} 1670 1671/* 1672 * Get configurable pathname variables. 1673 */ 1674/* ARGSUSED */ 1675int 1676sys_pathconf(p, v, retval) 1677 struct proc *p; 1678 void *v; 1679 register_t *retval; 1680{ 1681 register struct sys_pathconf_args /* { 1682 syscallarg(char *) path; 1683 syscallarg(int) name; 1684 } */ *uap = v; 1685 int error; 1686 struct nameidata nd; 1687 1688 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1689 SCARG(uap, path), p); 1690 if ((error = namei(&nd)) != 0) 1691 return (error); 1692 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval); 1693 vput(nd.ni_vp); 1694 return (error); 1695} 1696 1697/* 1698 * Return target name of a symbolic link. 1699 */ 1700/* ARGSUSED */ 1701int 1702sys_readlink(p, v, retval) 1703 struct proc *p; 1704 void *v; 1705 register_t *retval; 1706{ 1707 register struct sys_readlink_args /* { 1708 syscallarg(char *) path; 1709 syscallarg(char *) buf; 1710 syscallarg(size_t) count; 1711 } */ *uap = v; 1712 register struct vnode *vp; 1713 struct iovec aiov; 1714 struct uio auio; 1715 int error; 1716 struct nameidata nd; 1717 1718 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 1719 SCARG(uap, path), p); 1720 if ((error = namei(&nd)) != 0) 1721 return (error); 1722 vp = nd.ni_vp; 1723 if (vp->v_type != VLNK) 1724 error = EINVAL; 1725 else { 1726 aiov.iov_base = SCARG(uap, buf); 1727 aiov.iov_len = SCARG(uap, count); 1728 auio.uio_iov = &aiov; 1729 auio.uio_iovcnt = 1; 1730 auio.uio_offset = 0; 1731 auio.uio_rw = UIO_READ; 1732 auio.uio_segflg = UIO_USERSPACE; 1733 auio.uio_procp = p; 1734 auio.uio_resid = SCARG(uap, count); 1735 error = VOP_READLINK(vp, &auio, p->p_ucred); 1736 } 1737 vput(vp); 1738 *retval = SCARG(uap, count) - auio.uio_resid; 1739 return (error); 1740} 1741 1742/* 1743 * Change flags of a file given a path name. 1744 */ 1745/* ARGSUSED */ 1746int 1747sys_chflags(p, v, retval) 1748 struct proc *p; 1749 void *v; 1750 register_t *retval; 1751{ 1752 register struct sys_chflags_args /* { 1753 syscallarg(char *) path; 1754 syscallarg(unsigned int) flags; 1755 } */ *uap = v; 1756 register struct vnode *vp; 1757 struct vattr vattr; 1758 int error; 1759 struct nameidata nd; 1760 1761 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1762 if ((error = namei(&nd)) != 0) 1763 return (error); 1764 vp = nd.ni_vp; 1765 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1766 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1767 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1768 error = EROFS; 1769 else if (SCARG(uap, flags) == VNOVAL) 1770 error = EINVAL; 1771 else { 1772 if (suser(p->p_ucred, &p->p_acflag)) { 1773 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0) 1774 goto out; 1775 if (vattr.va_type == VCHR || vattr.va_type == VBLK) { 1776 error = EINVAL; 1777 goto out; 1778 } 1779 } 1780 VATTR_NULL(&vattr); 1781 vattr.va_flags = SCARG(uap, flags); 1782 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1783 } 1784out: 1785 vput(vp); 1786 return (error); 1787} 1788 1789/* 1790 * Change flags of a file given a file descriptor. 1791 */ 1792/* ARGSUSED */ 1793int 1794sys_fchflags(p, v, retval) 1795 struct proc *p; 1796 void *v; 1797 register_t *retval; 1798{ 1799 struct sys_fchflags_args /* { 1800 syscallarg(int) fd; 1801 syscallarg(unsigned int) flags; 1802 } */ *uap = v; 1803 struct vattr vattr; 1804 struct vnode *vp; 1805 struct file *fp; 1806 int error; 1807 1808 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 1809 return (error); 1810 vp = (struct vnode *)fp->f_data; 1811 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1812 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1813 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1814 error = EROFS; 1815 else if (SCARG(uap, flags) == VNOVAL) 1816 error = EINVAL; 1817 else { 1818 if (suser(p->p_ucred, &p->p_acflag)) { 1819 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 1820 != 0) 1821 goto out; 1822 if (vattr.va_type == VCHR || vattr.va_type == VBLK) { 1823 error = EINVAL; 1824 goto out; 1825 } 1826 } 1827 VATTR_NULL(&vattr); 1828 vattr.va_flags = SCARG(uap, flags); 1829 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1830 } 1831out: 1832 VOP_UNLOCK(vp, 0, p); 1833 FRELE(fp); 1834 return (error); 1835} 1836 1837/* 1838 * Change mode of a file given path name. 1839 */ 1840/* ARGSUSED */ 1841int 1842sys_chmod(p, v, retval) 1843 struct proc *p; 1844 void *v; 1845 register_t *retval; 1846{ 1847 register struct sys_chmod_args /* { 1848 syscallarg(char *) path; 1849 syscallarg(int) mode; 1850 } */ *uap = v; 1851 register struct vnode *vp; 1852 struct vattr vattr; 1853 int error; 1854 struct nameidata nd; 1855 1856 if (SCARG(uap, mode) & ~(S_IFMT | ALLPERMS)) 1857 return (EINVAL); 1858 1859 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1860 if ((error = namei(&nd)) != 0) 1861 return (error); 1862 vp = nd.ni_vp; 1863 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1864 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1865 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1866 error = EROFS; 1867 else { 1868 VATTR_NULL(&vattr); 1869 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1870 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1871 } 1872 vput(vp); 1873 return (error); 1874} 1875 1876/* 1877 * Change mode of a file given a file descriptor. 1878 */ 1879/* ARGSUSED */ 1880int 1881sys_fchmod(p, v, retval) 1882 struct proc *p; 1883 void *v; 1884 register_t *retval; 1885{ 1886 struct sys_fchmod_args /* { 1887 syscallarg(int) fd; 1888 syscallarg(int) mode; 1889 } */ *uap = v; 1890 struct vattr vattr; 1891 struct vnode *vp; 1892 struct file *fp; 1893 int error; 1894 1895 if (SCARG(uap, mode) & ~(S_IFMT | ALLPERMS)) 1896 return (EINVAL); 1897 1898 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 1899 return (error); 1900 vp = (struct vnode *)fp->f_data; 1901 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1902 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1903 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1904 error = EROFS; 1905 else { 1906 VATTR_NULL(&vattr); 1907 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1908 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1909 } 1910 VOP_UNLOCK(vp, 0, p); 1911 FRELE(fp); 1912 return (error); 1913} 1914 1915/* 1916 * Set ownership given a path name. 1917 */ 1918/* ARGSUSED */ 1919int 1920sys_chown(p, v, retval) 1921 struct proc *p; 1922 void *v; 1923 register_t *retval; 1924{ 1925 register struct sys_chown_args /* { 1926 syscallarg(char *) path; 1927 syscallarg(int) uid; 1928 syscallarg(int) gid; 1929 } */ *uap = v; 1930 register struct vnode *vp; 1931 struct vattr vattr; 1932 int error; 1933 struct nameidata nd; 1934 u_short mode; 1935 1936 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1937 if ((error = namei(&nd)) != 0) 1938 return (error); 1939 vp = nd.ni_vp; 1940 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1941 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1942 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1943 error = EROFS; 1944 else { 1945 if ((SCARG(uap, uid) != -1 || SCARG(uap, gid) != -1) && 1946 (suser(p->p_ucred, &p->p_acflag) || suid_clear)) { 1947 error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); 1948 if (error) 1949 goto out; 1950 mode = vattr.va_mode & ~(VSUID | VSGID); 1951 if (mode == vattr.va_mode) 1952 mode = VNOVAL; 1953 } 1954 else 1955 mode = VNOVAL; 1956 VATTR_NULL(&vattr); 1957 vattr.va_uid = SCARG(uap, uid); 1958 vattr.va_gid = SCARG(uap, gid); 1959 vattr.va_mode = mode; 1960 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1961 } 1962out: 1963 vput(vp); 1964 return (error); 1965} 1966 1967/* 1968 * Set ownership given a path name, without following links. 1969 */ 1970/* ARGSUSED */ 1971int 1972sys_lchown(p, v, retval) 1973 struct proc *p; 1974 void *v; 1975 register_t *retval; 1976{ 1977 register struct sys_lchown_args /* { 1978 syscallarg(char *) path; 1979 syscallarg(int) uid; 1980 syscallarg(int) gid; 1981 } */ *uap = v; 1982 register struct vnode *vp; 1983 struct vattr vattr; 1984 int error; 1985 struct nameidata nd; 1986 u_short mode; 1987 1988 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1989 if ((error = namei(&nd)) != 0) 1990 return (error); 1991 vp = nd.ni_vp; 1992 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1993 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1994 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1995 error = EROFS; 1996 else { 1997 if ((SCARG(uap, uid) != -1 || SCARG(uap, gid) != -1) && 1998 (suser(p->p_ucred, &p->p_acflag) || suid_clear)) { 1999 error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); 2000 if (error) 2001 goto out; 2002 mode = vattr.va_mode & ~(VSUID | VSGID); 2003 if (mode == vattr.va_mode) 2004 mode = VNOVAL; 2005 } 2006 else 2007 mode = VNOVAL; 2008 VATTR_NULL(&vattr); 2009 vattr.va_uid = SCARG(uap, uid); 2010 vattr.va_gid = SCARG(uap, gid); 2011 vattr.va_mode = mode; 2012 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2013 } 2014out: 2015 vput(vp); 2016 return (error); 2017} 2018 2019/* 2020 * Set ownership given a file descriptor. 2021 */ 2022/* ARGSUSED */ 2023int 2024sys_fchown(p, v, retval) 2025 struct proc *p; 2026 void *v; 2027 register_t *retval; 2028{ 2029 struct sys_fchown_args /* { 2030 syscallarg(int) fd; 2031 syscallarg(int) uid; 2032 syscallarg(int) gid; 2033 } */ *uap = v; 2034 struct vnode *vp; 2035 struct vattr vattr; 2036 int error; 2037 struct file *fp; 2038 u_short mode; 2039 2040 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2041 return (error); 2042 vp = (struct vnode *)fp->f_data; 2043 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2044 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2045 if (vp->v_mount->mnt_flag & MNT_RDONLY) 2046 error = EROFS; 2047 else { 2048 if ((SCARG(uap, uid) != -1 || SCARG(uap, gid) != -1) && 2049 (suser(p->p_ucred, &p->p_acflag) || suid_clear)) { 2050 error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); 2051 if (error) 2052 goto out; 2053 mode = vattr.va_mode & ~(VSUID | VSGID); 2054 if (mode == vattr.va_mode) 2055 mode = VNOVAL; 2056 } else 2057 mode = VNOVAL; 2058 VATTR_NULL(&vattr); 2059 vattr.va_uid = SCARG(uap, uid); 2060 vattr.va_gid = SCARG(uap, gid); 2061 vattr.va_mode = mode; 2062 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2063 } 2064out: 2065 VOP_UNLOCK(vp, 0, p); 2066 FRELE(fp); 2067 return (error); 2068} 2069 2070/* 2071 * Set the access and modification times given a path name. 2072 */ 2073/* ARGSUSED */ 2074int 2075sys_utimes(p, v, retval) 2076 struct proc *p; 2077 void *v; 2078 register_t *retval; 2079{ 2080 register struct sys_utimes_args /* { 2081 syscallarg(char *) path; 2082 syscallarg(struct timeval *) tptr; 2083 } */ *uap = v; 2084 register struct vnode *vp; 2085 struct timeval tv[2]; 2086 struct vattr vattr; 2087 int error; 2088 struct nameidata nd; 2089 2090 VATTR_NULL(&vattr); 2091 if (SCARG(uap, tptr) == NULL) { 2092 microtime(&tv[0]); 2093 tv[1] = tv[0]; 2094 vattr.va_vaflags |= VA_UTIMES_NULL; 2095 } else { 2096 error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 2097 sizeof (tv)); 2098 if (error) 2099 return (error); 2100 /* XXX workaround timeval matching the VFS constant VNOVAL */ 2101 if (tv[0].tv_sec == VNOVAL) 2102 tv[0].tv_sec = VNOVAL - 1; 2103 if (tv[1].tv_sec == VNOVAL) 2104 tv[1].tv_sec = VNOVAL - 1; 2105 } 2106 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2107 if ((error = namei(&nd)) != 0) 2108 return (error); 2109 vp = nd.ni_vp; 2110 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2111 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2112 if (vp->v_mount->mnt_flag & MNT_RDONLY) 2113 error = EROFS; 2114 else { 2115 vattr.va_atime.tv_sec = tv[0].tv_sec; 2116 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; 2117 vattr.va_mtime.tv_sec = tv[1].tv_sec; 2118 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; 2119 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2120 } 2121 vput(vp); 2122 return (error); 2123} 2124 2125 2126/* 2127 * Set the access and modification times given a file descriptor. 2128 */ 2129/* ARGSUSED */ 2130int 2131sys_futimes(p, v, retval) 2132 struct proc *p; 2133 void *v; 2134 register_t *retval; 2135{ 2136 register struct sys_futimes_args /* { 2137 syscallarg(int) fd; 2138 syscallarg(struct timeval *) tptr; 2139 } */ *uap = v; 2140 struct vnode *vp; 2141 struct timeval tv[2]; 2142 struct vattr vattr; 2143 int error; 2144 struct file *fp; 2145 2146 VATTR_NULL(&vattr); 2147 if (SCARG(uap, tptr) == NULL) { 2148 microtime(&tv[0]); 2149 tv[1] = tv[0]; 2150 vattr.va_vaflags |= VA_UTIMES_NULL; 2151 } else { 2152 error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 2153 sizeof (tv)); 2154 if (error) 2155 return (error); 2156 /* XXX workaround timeval matching the VFS constant VNOVAL */ 2157 if (tv[0].tv_sec == VNOVAL) 2158 tv[0].tv_sec = VNOVAL - 1; 2159 if (tv[1].tv_sec == VNOVAL) 2160 tv[1].tv_sec = VNOVAL - 1; 2161 } 2162 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2163 return (error); 2164 vp = (struct vnode *)fp->f_data; 2165 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2166 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2167 if (vp->v_mount->mnt_flag & MNT_RDONLY) 2168 error = EROFS; 2169 else { 2170 vattr.va_atime.tv_sec = tv[0].tv_sec; 2171 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; 2172 vattr.va_mtime.tv_sec = tv[1].tv_sec; 2173 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; 2174 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2175 } 2176 VOP_UNLOCK(vp, 0, p); 2177 FRELE(fp); 2178 return (error); 2179} 2180 2181/* 2182 * Truncate a file given its path name. 2183 */ 2184/* ARGSUSED */ 2185int 2186sys_truncate(p, v, retval) 2187 struct proc *p; 2188 void *v; 2189 register_t *retval; 2190{ 2191 register struct sys_truncate_args /* { 2192 syscallarg(char *) path; 2193 syscallarg(int) pad; 2194 syscallarg(off_t) length; 2195 } */ *uap = v; 2196 register struct vnode *vp; 2197 struct vattr vattr; 2198 int error; 2199 struct nameidata nd; 2200 2201 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2202 if ((error = namei(&nd)) != 0) 2203 return (error); 2204 vp = nd.ni_vp; 2205 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2206 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2207 if (vp->v_type == VDIR) 2208 error = EISDIR; 2209 else if ((error = vn_writechk(vp)) == 0 && 2210 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 2211 VATTR_NULL(&vattr); 2212 vattr.va_size = SCARG(uap, length); 2213 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2214 } 2215 vput(vp); 2216 return (error); 2217} 2218 2219/* 2220 * Truncate a file given a file descriptor. 2221 */ 2222/* ARGSUSED */ 2223int 2224sys_ftruncate(p, v, retval) 2225 struct proc *p; 2226 void *v; 2227 register_t *retval; 2228{ 2229 struct sys_ftruncate_args /* { 2230 syscallarg(int) fd; 2231 syscallarg(int) pad; 2232 syscallarg(off_t) length; 2233 } */ *uap = v; 2234 struct vattr vattr; 2235 struct vnode *vp; 2236 struct file *fp; 2237 int error; 2238 2239 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2240 return (error); 2241 if ((fp->f_flag & FWRITE) == 0) { 2242 error = EINVAL; 2243 goto bad; 2244 } 2245 vp = (struct vnode *)fp->f_data; 2246 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2247 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2248 if (vp->v_type == VDIR) 2249 error = EISDIR; 2250 else if ((error = vn_writechk(vp)) == 0) { 2251 VATTR_NULL(&vattr); 2252 vattr.va_size = SCARG(uap, length); 2253 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 2254 } 2255 VOP_UNLOCK(vp, 0, p); 2256bad: 2257 FRELE(fp); 2258 return (error); 2259} 2260 2261/* 2262 * Sync an open file. 2263 */ 2264/* ARGSUSED */ 2265int 2266sys_fsync(p, v, retval) 2267 struct proc *p; 2268 void *v; 2269 register_t *retval; 2270{ 2271 struct sys_fsync_args /* { 2272 syscallarg(int) fd; 2273 } */ *uap = v; 2274 struct vnode *vp; 2275 struct file *fp; 2276 int error; 2277 2278 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2279 return (error); 2280 vp = (struct vnode *)fp->f_data; 2281 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2282 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 2283 2284 VOP_UNLOCK(vp, 0, p); 2285 FRELE(fp); 2286 return (error); 2287} 2288 2289/* 2290 * Rename files. Source and destination must either both be directories, 2291 * or both not be directories. If target is a directory, it must be empty. 2292 */ 2293/* ARGSUSED */ 2294int 2295sys_rename(p, v, retval) 2296 struct proc *p; 2297 void *v; 2298 register_t *retval; 2299{ 2300 register struct sys_rename_args /* { 2301 syscallarg(char *) from; 2302 syscallarg(char *) to; 2303 } */ *uap = v; 2304 register struct vnode *tvp, *fvp, *tdvp; 2305 struct nameidata fromnd, tond; 2306 int error; 2307 int flags; 2308 2309 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 2310 SCARG(uap, from), p); 2311 if ((error = namei(&fromnd)) != 0) 2312 return (error); 2313 fvp = fromnd.ni_vp; 2314 2315 flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 2316 /* 2317 * rename("foo/", "bar/"); is OK 2318 */ 2319 if (fvp->v_type == VDIR) 2320 flags |= STRIPSLASHES; 2321 2322 NDINIT(&tond, RENAME, flags, 2323 UIO_USERSPACE, SCARG(uap, to), p); 2324 if ((error = namei(&tond)) != 0) { 2325 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2326 vrele(fromnd.ni_dvp); 2327 vrele(fvp); 2328 goto out1; 2329 } 2330 tdvp = tond.ni_dvp; 2331 tvp = tond.ni_vp; 2332 if (tvp != NULL) { 2333 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 2334 error = ENOTDIR; 2335 goto out; 2336 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 2337 error = EISDIR; 2338 goto out; 2339 } 2340 } 2341 if (fvp == tdvp) 2342 error = EINVAL; 2343 /* 2344 * If source is the same as the destination (that is the 2345 * same inode number) 2346 */ 2347 if (fvp == tvp) 2348 error = -1; 2349out: 2350 if (!error) { 2351 VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); 2352 if (fromnd.ni_dvp != tdvp) 2353 VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2354 if (tvp) { 2355 (void)uvm_vnp_uncache(tvp); 2356 VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); 2357 } 2358 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 2359 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 2360 } else { 2361 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 2362 if (tdvp == tvp) 2363 vrele(tdvp); 2364 else 2365 vput(tdvp); 2366 if (tvp) 2367 vput(tvp); 2368 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2369 vrele(fromnd.ni_dvp); 2370 vrele(fvp); 2371 } 2372 vrele(tond.ni_startdir); 2373 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 2374out1: 2375 if (fromnd.ni_startdir) 2376 vrele(fromnd.ni_startdir); 2377 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 2378 if (error == -1) 2379 return (0); 2380 return (error); 2381} 2382 2383/* 2384 * Make a directory file. 2385 */ 2386/* ARGSUSED */ 2387int 2388sys_mkdir(p, v, retval) 2389 struct proc *p; 2390 void *v; 2391 register_t *retval; 2392{ 2393 register struct sys_mkdir_args /* { 2394 syscallarg(char *) path; 2395 syscallarg(int) mode; 2396 } */ *uap = v; 2397 register struct vnode *vp; 2398 struct vattr vattr; 2399 int error; 2400 struct nameidata nd; 2401 2402 NDINIT(&nd, CREATE, LOCKPARENT | STRIPSLASHES, 2403 UIO_USERSPACE, SCARG(uap, path), p); 2404 if ((error = namei(&nd)) != 0) 2405 return (error); 2406 vp = nd.ni_vp; 2407 if (vp != NULL) { 2408 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2409 if (nd.ni_dvp == vp) 2410 vrele(nd.ni_dvp); 2411 else 2412 vput(nd.ni_dvp); 2413 vrele(vp); 2414 return (EEXIST); 2415 } 2416 VATTR_NULL(&vattr); 2417 vattr.va_type = VDIR; 2418 vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; 2419 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2420 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 2421 if (!error) 2422 vput(nd.ni_vp); 2423 return (error); 2424} 2425 2426/* 2427 * Remove a directory file. 2428 */ 2429/* ARGSUSED */ 2430int 2431sys_rmdir(p, v, retval) 2432 struct proc *p; 2433 void *v; 2434 register_t *retval; 2435{ 2436 struct sys_rmdir_args /* { 2437 syscallarg(char *) path; 2438 } */ *uap = v; 2439 register struct vnode *vp; 2440 int error; 2441 struct nameidata nd; 2442 2443 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 2444 SCARG(uap, path), p); 2445 if ((error = namei(&nd)) != 0) 2446 return (error); 2447 vp = nd.ni_vp; 2448 if (vp->v_type != VDIR) { 2449 error = ENOTDIR; 2450 goto out; 2451 } 2452 /* 2453 * No rmdir "." please. 2454 */ 2455 if (nd.ni_dvp == vp) { 2456 error = EBUSY; 2457 goto out; 2458 } 2459 /* 2460 * The root of a mounted filesystem cannot be deleted. 2461 */ 2462 if (vp->v_flag & VROOT) 2463 error = EBUSY; 2464out: 2465 if (!error) { 2466 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2467 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2468 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 2469 } else { 2470 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2471 if (nd.ni_dvp == vp) 2472 vrele(nd.ni_dvp); 2473 else 2474 vput(nd.ni_dvp); 2475 vput(vp); 2476 } 2477 return (error); 2478} 2479 2480/* 2481 * Read a block of directory entries in a file system independent format. 2482 */ 2483int 2484sys_getdirentries(p, v, retval) 2485 struct proc *p; 2486 void *v; 2487 register_t *retval; 2488{ 2489 struct sys_getdirentries_args /* { 2490 syscallarg(int) fd; 2491 syscallarg(char *) buf; 2492 syscallarg(int) count; 2493 syscallarg(long *) basep; 2494 } */ *uap = v; 2495 struct vnode *vp; 2496 struct file *fp; 2497 struct uio auio; 2498 struct iovec aiov; 2499 long loff; 2500 int error, eofflag; 2501 2502 if (SCARG(uap, count) < 0) 2503 return EINVAL; 2504 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2505 return (error); 2506 if ((fp->f_flag & FREAD) == 0) { 2507 error = EBADF; 2508 goto bad; 2509 } 2510 vp = (struct vnode *)fp->f_data; 2511unionread: 2512 if (vp->v_type != VDIR) { 2513 error = EINVAL; 2514 goto bad; 2515 } 2516 aiov.iov_base = SCARG(uap, buf); 2517 aiov.iov_len = SCARG(uap, count); 2518 auio.uio_iov = &aiov; 2519 auio.uio_iovcnt = 1; 2520 auio.uio_rw = UIO_READ; 2521 auio.uio_segflg = UIO_USERSPACE; 2522 auio.uio_procp = p; 2523 auio.uio_resid = SCARG(uap, count); 2524 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2525 loff = auio.uio_offset = fp->f_offset; 2526 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 0, 0); 2527 fp->f_offset = auio.uio_offset; 2528 VOP_UNLOCK(vp, 0, p); 2529 if (error) 2530 goto bad; 2531 if ((SCARG(uap, count) == auio.uio_resid) && 2532 union_check_p && 2533 (union_check_p(p, &vp, fp, auio, &error) != 0)) 2534 goto unionread; 2535 if (error) 2536 goto bad; 2537 2538 if ((SCARG(uap, count) == auio.uio_resid) && 2539 (vp->v_flag & VROOT) && 2540 (vp->v_mount->mnt_flag & MNT_UNION)) { 2541 struct vnode *tvp = vp; 2542 vp = vp->v_mount->mnt_vnodecovered; 2543 VREF(vp); 2544 fp->f_data = (caddr_t) vp; 2545 fp->f_offset = 0; 2546 vrele(tvp); 2547 goto unionread; 2548 } 2549 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 2550 sizeof(long)); 2551 *retval = SCARG(uap, count) - auio.uio_resid; 2552bad: 2553 FRELE(fp); 2554 return (error); 2555} 2556 2557/* 2558 * Set the mode mask for creation of filesystem nodes. 2559 */ 2560int 2561sys_umask(p, v, retval) 2562 struct proc *p; 2563 void *v; 2564 register_t *retval; 2565{ 2566 struct sys_umask_args /* { 2567 syscallarg(int) newmask; 2568 } */ *uap = v; 2569 register struct filedesc *fdp; 2570 2571 fdp = p->p_fd; 2572 *retval = fdp->fd_cmask; 2573 fdp->fd_cmask = SCARG(uap, newmask) & ACCESSPERMS; 2574 return (0); 2575} 2576 2577/* 2578 * Void all references to file by ripping underlying filesystem 2579 * away from vnode. 2580 */ 2581/* ARGSUSED */ 2582int 2583sys_revoke(p, v, retval) 2584 struct proc *p; 2585 void *v; 2586 register_t *retval; 2587{ 2588 register struct sys_revoke_args /* { 2589 syscallarg(char *) path; 2590 } */ *uap = v; 2591 register struct vnode *vp; 2592 struct vattr vattr; 2593 int error; 2594 struct nameidata nd; 2595 2596 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2597 if ((error = namei(&nd)) != 0) 2598 return (error); 2599 vp = nd.ni_vp; 2600 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0) 2601 goto out; 2602 if (p->p_ucred->cr_uid != vattr.va_uid && 2603 (error = suser(p->p_ucred, &p->p_acflag))) 2604 goto out; 2605 if (vp->v_usecount > 1 || (vp->v_flag & (VALIASED | VLAYER))) 2606 VOP_REVOKE(vp, REVOKEALL); 2607out: 2608 vrele(vp); 2609 return (error); 2610} 2611 2612/* 2613 * Convert a user file descriptor to a kernel file entry. 2614 * 2615 * On return *fpp is FREF:ed. 2616 */ 2617int 2618getvnode(fdp, fd, fpp) 2619 struct filedesc *fdp; 2620 struct file **fpp; 2621 int fd; 2622{ 2623 struct file *fp; 2624 2625 if ((fp = fd_getfile(fdp, fd)) == NULL) 2626 return (EBADF); 2627 if (fp->f_type != DTYPE_VNODE) 2628 return (EINVAL); 2629 FREF(fp); 2630 *fpp = fp; 2631 2632 return (0); 2633} 2634 2635/* 2636 * Positional read system call. 2637 */ 2638int 2639sys_pread(p, v, retval) 2640 struct proc *p; 2641 void *v; 2642 register_t *retval; 2643{ 2644 struct sys_pread_args /* { 2645 syscallarg(int) fd; 2646 syscallarg(void *) buf; 2647 syscallarg(size_t) nbyte; 2648 syscallarg(int) pad; 2649 syscallarg(off_t) offset; 2650 } */ *uap = v; 2651 struct filedesc *fdp = p->p_fd; 2652 struct file *fp; 2653 struct vnode *vp; 2654 off_t offset; 2655 int fd = SCARG(uap, fd); 2656 2657 if ((fp = fd_getfile(fdp, fd)) == NULL) 2658 return (EBADF); 2659 if ((fp->f_flag & FREAD) == 0) 2660 return (EBADF); 2661 2662 vp = (struct vnode *)fp->f_data; 2663 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 2664 return (ESPIPE); 2665 } 2666 2667 offset = SCARG(uap, offset); 2668 2669 FREF(fp); 2670 2671 /* dofileread() will FRELE the descriptor for us */ 2672 return (dofileread(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte), 2673 &offset, retval)); 2674} 2675 2676/* 2677 * Positional scatter read system call. 2678 */ 2679int 2680sys_preadv(p, v, retval) 2681 struct proc *p; 2682 void *v; 2683 register_t *retval; 2684{ 2685 struct sys_preadv_args /* { 2686 syscallarg(int) fd; 2687 syscallarg(const struct iovec *) iovp; 2688 syscallarg(int) iovcnt; 2689 syscallarg(int) pad; 2690 syscallarg(off_t) offset; 2691 } */ *uap = v; 2692 struct filedesc *fdp = p->p_fd; 2693 struct file *fp; 2694 struct vnode *vp; 2695 off_t offset; 2696 int fd = SCARG(uap, fd); 2697 2698 if ((fp = fd_getfile(fdp, fd)) == NULL) 2699 return (EBADF); 2700 if ((fp->f_flag & FREAD) == 0) 2701 return (EBADF); 2702 2703 vp = (struct vnode *)fp->f_data; 2704 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 2705 return (ESPIPE); 2706 } 2707 2708 FREF(fp); 2709 2710 offset = SCARG(uap, offset); 2711 2712 /* dofilereadv() will FRELE the descriptor for us */ 2713 return (dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 2714 &offset, retval)); 2715} 2716 2717/* 2718 * Positional write system call. 2719 */ 2720int 2721sys_pwrite(p, v, retval) 2722 struct proc *p; 2723 void *v; 2724 register_t *retval; 2725{ 2726 struct sys_pwrite_args /* { 2727 syscallarg(int) fd; 2728 syscallarg(const void *) buf; 2729 syscallarg(size_t) nbyte; 2730 syscallarg(int) pad; 2731 syscallarg(off_t) offset; 2732 } */ *uap = v; 2733 struct filedesc *fdp = p->p_fd; 2734 struct file *fp; 2735 struct vnode *vp; 2736 off_t offset; 2737 int fd = SCARG(uap, fd); 2738 2739 if ((fp = fd_getfile(fdp, fd)) == NULL) 2740 return (EBADF); 2741 if ((fp->f_flag & FWRITE) == 0) 2742 return (EBADF); 2743 2744 vp = (struct vnode *)fp->f_data; 2745 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 2746 return (ESPIPE); 2747 } 2748 2749 FREF(fp); 2750 2751 offset = SCARG(uap, offset); 2752 2753 /* dofilewrite() will FRELE the descriptor for us */ 2754 return (dofilewrite(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte), 2755 &offset, retval)); 2756} 2757 2758 2759/* 2760 * Positional gather write system call. 2761 */ 2762int 2763sys_pwritev(p, v, retval) 2764 struct proc *p; 2765 void *v; 2766 register_t *retval; 2767{ 2768 struct sys_pwritev_args /* { 2769 syscallarg(int) fd; 2770 syscallarg(const struct iovec *) iovp; 2771 syscallarg(int) iovcnt; 2772 syscallarg(int) pad; 2773 syscallarg(off_t) offset; 2774 } */ *uap = v; 2775 struct filedesc *fdp = p->p_fd; 2776 struct file *fp; 2777 struct vnode *vp; 2778 off_t offset; 2779 int fd = SCARG(uap, fd); 2780 2781 if ((fp = fd_getfile(fdp, fd)) == NULL) 2782 return (EBADF); 2783 if ((fp->f_flag & FWRITE) == 0) 2784 return (EBADF); 2785 2786 vp = (struct vnode *)fp->f_data; 2787 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 2788 return (ESPIPE); 2789 } 2790 2791 FREF(fp); 2792 2793 offset = SCARG(uap, offset); 2794 2795 /* dofilewritev() will FRELE the descriptor for us */ 2796 return (dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 2797 &offset, retval)); 2798} 2799 2800#ifdef UFS_EXTATTR 2801/* 2802 * Syscall to push extended attribute configuration information into the 2803 * VFS. Accepts a path, which it converts to a mountpoint, as well as 2804 * a command (int cmd), and attribute name and misc data. For now, the 2805 * attribute name is left in userspace for consumption by the VFS_op. 2806 * It will probably be changed to be copied into sysspace by the 2807 * syscall in the future, once issues with various consumers of the 2808 * attribute code have raised their hands. 2809 * 2810 * Currently this is used only by UFS Extended Attributes. 2811 */ 2812int 2813sys_extattrctl(struct proc *p, void *v, register_t *reval) 2814{ 2815 struct sys_extattrctl_args /* { 2816 syscallarg(const char *) path; 2817 syscallarg(int) cmd; 2818 syscallarg(const char *) filename; 2819 syscallarg(int) attrnamespace; 2820 syscallarg(const char *) attrname; 2821 } */ *uap = v; 2822 struct vnode *filename_vp; 2823 struct nameidata nd; 2824 struct mount *mp; 2825 char attrname[EXTATTR_MAXNAMELEN]; 2826 int error; 2827 2828 /* 2829 * SCARG(uap, attrname) not always defined. We check again later 2830 * when we invoke the VFS call so as to pass in NULL there if needed. 2831 */ 2832 if (SCARG(uap, attrname) != NULL) { 2833 error = copyinstr(SCARG(uap, attrname), attrname, 2834 EXTATTR_MAXNAMELEN, NULL); 2835 if (error) 2836 return (error); 2837 } 2838 2839 /* 2840 * SCARG(uap, filename) not always defined. If it is, grab 2841 * a vnode lock, which VFS_EXTATTRCTL() will later release. 2842 */ 2843 filename_vp = NULL; 2844 if (SCARG(uap, filename) != NULL) { 2845 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 2846 SCARG(uap, filename), p); 2847 if ((error = namei(&nd)) != 0) 2848 return (error); 2849 filename_vp = nd.ni_vp; 2850 } 2851 2852 /* SCARG(uap, path) always defined. */ 2853 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2854 if ((error = namei(&nd)) != 0) { 2855 if (filename_vp != NULL) 2856 vput(filename_vp); 2857 return (error); 2858 } 2859 2860 mp = nd.ni_vp->v_mount; 2861 if (error) { 2862 if (filename_vp != NULL) 2863 vput(filename_vp); 2864 return (error); 2865 } 2866 2867 if (SCARG(uap, attrname) != NULL) { 2868 error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp, 2869 SCARG(uap, attrnamespace), attrname, p); 2870 } else { 2871 error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp, 2872 SCARG(uap, attrnamespace), NULL, p); 2873 } 2874 2875 /* 2876 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, 2877 * filename_vp, so vrele it if it is defined. 2878 */ 2879 if (filename_vp != NULL) 2880 vrele(filename_vp); 2881 2882 return (error); 2883} 2884 2885/*- 2886 * Set a named extended attribute on a file or directory 2887 * 2888 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 2889 * kernelspace string pointer "attrname", userspace buffer 2890 * pointer "data", buffer length "nbytes", thread "td". 2891 * Returns: 0 on success, an error number otherwise 2892 * Locks: none 2893 * References: vp must be a valid reference for the duration of the call 2894 */ 2895static int 2896extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname, 2897 void *data, size_t nbytes, struct proc *p, register_t *retval) 2898{ 2899 struct uio auio; 2900 struct iovec aiov; 2901 ssize_t cnt; 2902 int error; 2903 2904 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2905 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2906 2907 aiov.iov_base = data; 2908 aiov.iov_len = nbytes; 2909 auio.uio_iov = &aiov; 2910 auio.uio_iovcnt = 1; 2911 auio.uio_offset = 0; 2912 if (nbytes > INT_MAX) { 2913 error = EINVAL; 2914 goto done; 2915 } 2916 auio.uio_resid = nbytes; 2917 auio.uio_rw = UIO_WRITE; 2918 auio.uio_segflg = UIO_USERSPACE; 2919 auio.uio_procp = p; 2920 cnt = nbytes; 2921 2922 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, 2923 p->p_ucred, p); 2924 cnt -= auio.uio_resid; 2925 retval[0] = cnt; 2926 2927done: 2928 VOP_UNLOCK(vp, 0, p); 2929 return (error); 2930} 2931 2932int 2933sys_extattr_set_file(struct proc *p, void *v, register_t *retval) 2934{ 2935 struct sys_extattr_set_file_args /* { 2936 syscallarg(const char *) path; 2937 syscallarg(int) attrnamespace; 2938 syscallarg(const char *) attrname; 2939 syscallarg(void *) data; 2940 syscallarg(size_t) nbytes; 2941 } */ *uap = v; 2942 struct nameidata nd; 2943 char attrname[EXTATTR_MAXNAMELEN]; 2944 int error; 2945 2946 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 2947 NULL); 2948 if (error) 2949 return (error); 2950 2951 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2952 if ((error = namei(&nd)) != 0) 2953 return (error); 2954 2955 error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname, 2956 SCARG(uap, data), SCARG(uap, nbytes), p, retval); 2957 2958 vrele(nd.ni_vp); 2959 return (error); 2960} 2961 2962int 2963sys_extattr_set_fd(struct proc *p, void *v, register_t *retval) 2964{ 2965 struct sys_extattr_set_fd_args /* { 2966 syscallarg(int) fd; 2967 syscallarg(int) attrnamespace; 2968 syscallarg(const char *) attrname; 2969 syscallarg(struct iovec *) iovp; 2970 syscallarg(int) iovcnt; 2971 } */ *uap = v; 2972 struct file *fp; 2973 char attrname[EXTATTR_MAXNAMELEN]; 2974 int error; 2975 2976 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 2977 NULL); 2978 if (error) 2979 return (error); 2980 2981 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2982 return (error); 2983 2984 error = extattr_set_vp((struct vnode *)fp->f_data, 2985 SCARG(uap, attrnamespace), attrname, SCARG(uap, data), 2986 SCARG(uap, nbytes), p, retval); 2987 FRELE(fp); 2988 2989 return (error); 2990} 2991 2992/*- 2993 * Get a named extended attribute on a file or directory 2994 * 2995 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 2996 * kernelspace string pointer "attrname", userspace buffer 2997 * pointer "data", buffer length "nbytes", thread "td". 2998 * Returns: 0 on success, an error number otherwise 2999 * Locks: none 3000 * References: vp must be a valid reference for the duration of the call 3001 */ 3002static int 3003extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, 3004 void *data, size_t nbytes, struct proc *p, register_t *retval) 3005{ 3006 struct uio auio; 3007 struct iovec aiov; 3008 ssize_t cnt; 3009 size_t size; 3010 int error; 3011 3012 VOP_LEASE(vp, p, p->p_ucred, LEASE_READ); 3013 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 3014 3015 /* 3016 * Slightly unusual semantics: if the user provides a NULL data 3017 * pointer, they don't want to receive the data, just the 3018 * maximum read length. 3019 */ 3020 if (data != NULL) { 3021 aiov.iov_base = data; 3022 aiov.iov_len = nbytes; 3023 auio.uio_iov = &aiov; 3024 auio.uio_offset = 0; 3025 if (nbytes > INT_MAX) { 3026 error = EINVAL; 3027 goto done; 3028 } 3029 auio.uio_resid = nbytes; 3030 auio.uio_rw = UIO_READ; 3031 auio.uio_segflg = UIO_USERSPACE; 3032 auio.uio_procp = p; 3033 cnt = nbytes; 3034 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio, 3035 NULL, p->p_ucred, p); 3036 cnt -= auio.uio_resid; 3037 retval[0] = cnt; 3038 } else { 3039 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL, 3040 &size, p->p_ucred, p); 3041 retval[0] = size; 3042 } 3043done: 3044 VOP_UNLOCK(vp, 0, p); 3045 return (error); 3046} 3047 3048int 3049sys_extattr_get_file(p, v, retval) 3050 struct proc *p; 3051 void *v; 3052 register_t *retval; 3053{ 3054 struct sys_extattr_get_file_args /* { 3055 syscallarg(const char *) path; 3056 syscallarg(int) attrnamespace; 3057 syscallarg(const char *) attrname; 3058 syscallarg(void *) data; 3059 syscallarg(size_t) nbytes; 3060 } */ *uap = v; 3061 struct nameidata nd; 3062 char attrname[EXTATTR_MAXNAMELEN]; 3063 int error; 3064 3065 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 3066 NULL); 3067 if (error) 3068 return (error); 3069 3070 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 3071 if ((error = namei(&nd)) != 0) 3072 return (error); 3073 3074 error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname, 3075 SCARG(uap, data), SCARG(uap, nbytes), p, retval); 3076 3077 vrele(nd.ni_vp); 3078 return (error); 3079} 3080 3081int 3082sys_extattr_get_fd(p, v, retval) 3083 struct proc *p; 3084 void *v; 3085 register_t *retval; 3086{ 3087 struct sys_extattr_get_fd_args /* { 3088 syscallarg(int) fd; 3089 syscallarg(int) attrnamespace; 3090 syscallarg(const char *) attrname; 3091 syscallarg(void *) data; 3092 syscallarg(size_t) nbytes; 3093 } */ *uap = v; 3094 struct file *fp; 3095 char attrname[EXTATTR_MAXNAMELEN]; 3096 int error; 3097 3098 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 3099 NULL); 3100 if (error) 3101 return (error); 3102 3103 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 3104 return (error); 3105 3106 error = extattr_get_vp((struct vnode *)fp->f_data, 3107 SCARG(uap, attrnamespace), attrname, SCARG(uap, data), 3108 SCARG(uap, nbytes), p, retval); 3109 FRELE(fp); 3110 3111 return (error); 3112} 3113 3114/* 3115 * extattr_delete_vp(): Delete a named extended attribute on a file or 3116 * directory 3117 * 3118 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 3119 * kernelspace string pointer "attrname", proc "p" 3120 * Returns: 0 on success, an error number otherwise 3121 * Locks: none 3122 * References: vp must be a valid reference for the duration of the call 3123 */ 3124static int 3125extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname, 3126 struct proc *p) 3127{ 3128 int error; 3129 3130 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 3131 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 3132 3133 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, 3134 p->p_ucred, p); 3135 3136 VOP_UNLOCK(vp, 0, p); 3137 return (error); 3138} 3139 3140int 3141sys_extattr_delete_file(p, v, retval) 3142 struct proc *p; 3143 void *v; 3144 register_t *retval; 3145{ 3146 struct sys_extattr_delete_file_args /* { 3147 syscallarg(int) fd; 3148 syscallarg(int) attrnamespace; 3149 syscallarg(const char *) attrname; 3150 } */ *uap = v; 3151 struct nameidata nd; 3152 char attrname[EXTATTR_MAXNAMELEN]; 3153 int error; 3154 3155 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 3156 NULL); 3157 if (error) 3158 return(error); 3159 3160 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 3161 if ((error = namei(&nd)) != 0) 3162 return(error); 3163 3164 error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace), 3165 attrname, p); 3166 3167 vrele(nd.ni_vp); 3168 return(error); 3169} 3170 3171int 3172sys_extattr_delete_fd(p, v, retval) 3173 struct proc *p; 3174 void *v; 3175 register_t *retval; 3176{ 3177 struct sys_extattr_delete_fd_args /* { 3178 syscallarg(int) fd; 3179 syscallarg(int) attrnamespace; 3180 syscallarg(const char *) attrname; 3181 } */ *uap = v; 3182 struct file *fp; 3183 char attrname[EXTATTR_MAXNAMELEN]; 3184 int error; 3185 3186 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 3187 NULL); 3188 if (error) 3189 return (error); 3190 3191 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 3192 return (error); 3193 3194 error = extattr_delete_vp((struct vnode *)fp->f_data, 3195 SCARG(uap, attrnamespace), attrname, p); 3196 FRELE(fp); 3197 3198 return (error); 3199} 3200#endif 3201