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