vfs_extattr.c revision 92130
1/* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)vfs_syscalls.c 8.13 (Berkeley) 4/15/94 39 * $FreeBSD: head/sys/kern/vfs_extattr.c 92130 2002-03-12 04:00:11Z jeff $ 40 */ 41 42/* For 4.3 integer FS ID compatibility */ 43#include "opt_compat.h" 44#include "opt_ffs.h" 45 46#include <sys/param.h> 47#include <sys/systm.h> 48#include <sys/bio.h> 49#include <sys/buf.h> 50#include <sys/sysent.h> 51#include <sys/malloc.h> 52#include <sys/mount.h> 53#include <sys/mutex.h> 54#include <sys/sysproto.h> 55#include <sys/namei.h> 56#include <sys/filedesc.h> 57#include <sys/kernel.h> 58#include <sys/fcntl.h> 59#include <sys/file.h> 60#include <sys/linker.h> 61#include <sys/stat.h> 62#include <sys/sx.h> 63#include <sys/unistd.h> 64#include <sys/vnode.h> 65#include <sys/proc.h> 66#include <sys/dirent.h> 67#include <sys/extattr.h> 68#include <sys/jail.h> 69#include <sys/sysctl.h> 70 71#include <machine/limits.h> 72 73#include <vm/vm.h> 74#include <vm/vm_object.h> 75#include <vm/vm_zone.h> 76#include <vm/vm_page.h> 77 78static int change_dir __P((struct nameidata *ndp, struct thread *td)); 79static void checkdirs __P((struct vnode *olddp, struct vnode *newdp)); 80static int chroot_refuse_vdir_fds __P((struct filedesc *fdp)); 81static int getutimes __P((const struct timeval *, struct timespec *)); 82static int setfown __P((struct thread *td, struct vnode *, uid_t, gid_t)); 83static int setfmode __P((struct thread *td, struct vnode *, int)); 84static int setfflags __P((struct thread *td, struct vnode *, int)); 85static int setutimes __P((struct thread *td, struct vnode *, 86 const struct timespec *, int)); 87static int vn_access __P((struct vnode *vp, int user_flags, struct ucred *cred, 88 struct thread *td)); 89 90static int usermount = 0; /* if 1, non-root can mount fs. */ 91 92int (*union_dircheckp) __P((struct thread *td, struct vnode **, struct file *)); 93 94SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0, ""); 95 96/* 97 * Virtual File System System Calls 98 */ 99 100#ifndef _SYS_SYSPROTO_H_ 101struct nmount_args { 102 struct iovec *iovp; 103 unsigned int iovcnt; 104 int flags; 105 }; 106#endif 107/* ARGSUSED */ 108int 109nmount(td, uap) 110 struct thread *td; 111 struct nmount_args /* { 112 syscallarg(struct iovec *) iovp; 113 syscallarg(unsigned int) iovcnt; 114 syscallarg(int) flags; 115 } */ *uap; 116{ 117 118 return(EOPNOTSUPP); 119} 120 121/* 122 * Mount a file system. 123 */ 124#ifndef _SYS_SYSPROTO_H_ 125struct mount_args { 126 char *type; 127 char *path; 128 int flags; 129 caddr_t data; 130}; 131#endif 132/* ARGSUSED */ 133int 134mount(td, uap) 135 struct thread *td; 136 struct mount_args /* { 137 syscallarg(char *) type; 138 syscallarg(char *) path; 139 syscallarg(int) flags; 140 syscallarg(caddr_t) data; 141 } */ *uap; 142{ 143 char *fstype; 144 char *fspath; 145 int error; 146 147 fstype = malloc(MFSNAMELEN, M_TEMP, M_WAITOK | M_ZERO); 148 fspath = malloc(MNAMELEN, M_TEMP, M_WAITOK | M_ZERO); 149 150 /* 151 * vfs_mount() actually takes a kernel string for `type' and 152 * `path' now, so extract them. 153 */ 154 error = copyinstr(SCARG(uap, type), fstype, MFSNAMELEN, NULL); 155 if (error) 156 goto finish; 157 error = copyinstr(SCARG(uap, path), fspath, MNAMELEN, NULL); 158 if (error) 159 goto finish; 160 error = vfs_mount(td, fstype, fspath, SCARG(uap, flags), 161 SCARG(uap, data)); 162finish: 163 free(fstype, M_TEMP); 164 free(fspath, M_TEMP); 165 return (error); 166} 167 168/* 169 * vfs_mount(): actually attempt a filesystem mount. 170 * 171 * This routine is designed to be a "generic" entry point for routines 172 * that wish to mount a filesystem. All parameters except `fsdata' are 173 * pointers into kernel space. `fsdata' is currently still a pointer 174 * into userspace. 175 */ 176int 177vfs_mount(td, fstype, fspath, fsflags, fsdata) 178 struct thread *td; 179 const char *fstype; 180 char *fspath; 181 int fsflags; 182 void *fsdata; 183{ 184 struct vnode *vp; 185 struct mount *mp; 186 struct vfsconf *vfsp; 187 int error, flag = 0, flag2 = 0; 188 struct vattr va; 189 struct nameidata nd; 190 191 /* 192 * Be ultra-paranoid about making sure the type and fspath 193 * variables will fit in our mp buffers, including the 194 * terminating NUL. 195 */ 196 if ((strlen(fstype) >= MFSNAMELEN - 1) || 197 (strlen(fspath) >= MNAMELEN - 1)) 198 return (ENAMETOOLONG); 199 200 if (usermount == 0) { 201 error = suser_td(td); 202 if (error) 203 return (error); 204 } 205 /* 206 * Do not allow NFS export by non-root users. 207 */ 208 if (fsflags & MNT_EXPORTED) { 209 error = suser_td(td); 210 if (error) 211 return (error); 212 } 213 /* 214 * Silently enforce MNT_NOSUID and MNT_NODEV for non-root users 215 */ 216 if (suser_xxx(td->td_ucred, 0, 0)) 217 fsflags |= MNT_NOSUID | MNT_NODEV; 218 /* 219 * Get vnode to be covered 220 */ 221 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, td); 222 if ((error = namei(&nd)) != 0) 223 return (error); 224 NDFREE(&nd, NDF_ONLY_PNBUF); 225 vp = nd.ni_vp; 226 if (fsflags & MNT_UPDATE) { 227 if ((vp->v_flag & VROOT) == 0) { 228 vput(vp); 229 return (EINVAL); 230 } 231 mp = vp->v_mount; 232 flag = mp->mnt_flag; 233 flag2 = mp->mnt_kern_flag; 234 /* 235 * We only allow the filesystem to be reloaded if it 236 * is currently mounted read-only. 237 */ 238 if ((fsflags & MNT_RELOAD) && 239 ((mp->mnt_flag & MNT_RDONLY) == 0)) { 240 vput(vp); 241 return (EOPNOTSUPP); /* Needs translation */ 242 } 243 /* 244 * Only root, or the user that did the original mount is 245 * permitted to update it. 246 */ 247 if (mp->mnt_stat.f_owner != td->td_ucred->cr_uid) { 248 error = suser_td(td); 249 if (error) { 250 vput(vp); 251 return (error); 252 } 253 } 254 if (vfs_busy(mp, LK_NOWAIT, 0, td)) { 255 vput(vp); 256 return (EBUSY); 257 } 258 mtx_lock(&vp->v_interlock); 259 if ((vp->v_flag & VMOUNT) != 0 || 260 vp->v_mountedhere != NULL) { 261 mtx_unlock(&vp->v_interlock); 262 vfs_unbusy(mp, td); 263 vput(vp); 264 return (EBUSY); 265 } 266 vp->v_flag |= VMOUNT; 267 mtx_unlock(&vp->v_interlock); 268 mp->mnt_flag |= fsflags & 269 (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_SNAPSHOT); 270 VOP_UNLOCK(vp, 0, td); 271 goto update; 272 } 273 /* 274 * If the user is not root, ensure that they own the directory 275 * onto which we are attempting to mount. 276 */ 277 error = VOP_GETATTR(vp, &va, td->td_ucred, td); 278 if (error) { 279 vput(vp); 280 return (error); 281 } 282 if (va.va_uid != td->td_ucred->cr_uid) { 283 error = suser_td(td); 284 if (error) { 285 vput(vp); 286 return (error); 287 } 288 } 289 if ((error = vinvalbuf(vp, V_SAVE, td->td_ucred, td, 0, 0)) 290 != 0) { 291 vput(vp); 292 return (error); 293 } 294 if (vp->v_type != VDIR) { 295 vput(vp); 296 return (ENOTDIR); 297 } 298 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 299 if (!strcmp(vfsp->vfc_name, fstype)) 300 break; 301 if (vfsp == NULL) { 302 linker_file_t lf; 303 304 /* Only load modules for root (very important!) */ 305 error = suser_td(td); 306 if (error) { 307 vput(vp); 308 return error; 309 } 310 error = linker_load_file(fstype, &lf); 311 if (error || lf == NULL) { 312 vput(vp); 313 if (lf == NULL) 314 error = ENODEV; 315 return error; 316 } 317 lf->userrefs++; 318 /* lookup again, see if the VFS was loaded */ 319 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 320 if (!strcmp(vfsp->vfc_name, fstype)) 321 break; 322 if (vfsp == NULL) { 323 lf->userrefs--; 324 linker_file_unload(lf); 325 vput(vp); 326 return (ENODEV); 327 } 328 } 329 mtx_lock(&vp->v_interlock); 330 if ((vp->v_flag & VMOUNT) != 0 || 331 vp->v_mountedhere != NULL) { 332 mtx_unlock(&vp->v_interlock); 333 vput(vp); 334 return (EBUSY); 335 } 336 vp->v_flag |= VMOUNT; 337 mtx_unlock(&vp->v_interlock); 338 339 /* 340 * Allocate and initialize the filesystem. 341 */ 342 mp = malloc(sizeof(struct mount), M_MOUNT, M_WAITOK | M_ZERO); 343 TAILQ_INIT(&mp->mnt_nvnodelist); 344 TAILQ_INIT(&mp->mnt_reservedvnlist); 345 lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, LK_NOPAUSE); 346 (void)vfs_busy(mp, LK_NOWAIT, 0, td); 347 mp->mnt_op = vfsp->vfc_vfsops; 348 mp->mnt_vfc = vfsp; 349 vfsp->vfc_refcount++; 350 mp->mnt_stat.f_type = vfsp->vfc_typenum; 351 mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; 352 strncpy(mp->mnt_stat.f_fstypename, fstype, MFSNAMELEN); 353 mp->mnt_stat.f_fstypename[MFSNAMELEN - 1] = '\0'; 354 mp->mnt_vnodecovered = vp; 355 mp->mnt_stat.f_owner = td->td_ucred->cr_uid; 356 strncpy(mp->mnt_stat.f_mntonname, fspath, MNAMELEN); 357 mp->mnt_stat.f_mntonname[MNAMELEN - 1] = '\0'; 358 mp->mnt_iosize_max = DFLTPHYS; 359 VOP_UNLOCK(vp, 0, td); 360update: 361 /* 362 * Set the mount level flags. 363 */ 364 if (fsflags & MNT_RDONLY) 365 mp->mnt_flag |= MNT_RDONLY; 366 else if (mp->mnt_flag & MNT_RDONLY) 367 mp->mnt_kern_flag |= MNTK_WANTRDWR; 368 mp->mnt_flag &=~ MNT_UPDATEMASK; 369 mp->mnt_flag |= fsflags & (MNT_UPDATEMASK | MNT_FORCE); 370 /* 371 * Mount the filesystem. 372 * XXX The final recipients of VFS_MOUNT just overwrite the ndp they 373 * get. No freeing of cn_pnbuf. 374 */ 375 error = VFS_MOUNT(mp, fspath, fsdata, &nd, td); 376 if (mp->mnt_flag & MNT_UPDATE) { 377 if (mp->mnt_kern_flag & MNTK_WANTRDWR) 378 mp->mnt_flag &= ~MNT_RDONLY; 379 mp->mnt_flag &=~ 380 (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_SNAPSHOT); 381 mp->mnt_kern_flag &=~ MNTK_WANTRDWR; 382 if (error) { 383 mp->mnt_flag = flag; 384 mp->mnt_kern_flag = flag2; 385 } 386 if ((mp->mnt_flag & MNT_RDONLY) == 0) { 387 if (mp->mnt_syncer == NULL) 388 error = vfs_allocate_syncvnode(mp); 389 } else { 390 if (mp->mnt_syncer != NULL) 391 vrele(mp->mnt_syncer); 392 mp->mnt_syncer = NULL; 393 } 394 vfs_unbusy(mp, td); 395 mtx_lock(&vp->v_interlock); 396 vp->v_flag &= ~VMOUNT; 397 mtx_unlock(&vp->v_interlock); 398 vrele(vp); 399 return (error); 400 } 401 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 402 /* 403 * Put the new filesystem on the mount list after root. 404 */ 405 cache_purge(vp); 406 if (!error) { 407 struct vnode *newdp; 408 409 mtx_lock(&vp->v_interlock); 410 vp->v_flag &= ~VMOUNT; 411 vp->v_mountedhere = mp; 412 mtx_unlock(&vp->v_interlock); 413 mtx_lock(&mountlist_mtx); 414 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 415 mtx_unlock(&mountlist_mtx); 416 if (VFS_ROOT(mp, &newdp)) 417 panic("mount: lost mount"); 418 checkdirs(vp, newdp); 419 vput(newdp); 420 VOP_UNLOCK(vp, 0, td); 421 if ((mp->mnt_flag & MNT_RDONLY) == 0) 422 error = vfs_allocate_syncvnode(mp); 423 vfs_unbusy(mp, td); 424 if ((error = VFS_START(mp, 0, td)) != 0) 425 vrele(vp); 426 } else { 427 mtx_lock(&vp->v_interlock); 428 vp->v_flag &= ~VMOUNT; 429 mtx_unlock(&vp->v_interlock); 430 mp->mnt_vfc->vfc_refcount--; 431 vfs_unbusy(mp, td); 432 free((caddr_t)mp, M_MOUNT); 433 vput(vp); 434 } 435 return (error); 436} 437 438/* 439 * Scan all active processes to see if any of them have a current 440 * or root directory of `olddp'. If so, replace them with the new 441 * mount point. 442 */ 443static void 444checkdirs(olddp, newdp) 445 struct vnode *olddp, *newdp; 446{ 447 struct filedesc *fdp; 448 struct proc *p; 449 450 if (olddp->v_usecount == 1) 451 return; 452 sx_slock(&allproc_lock); 453 LIST_FOREACH(p, &allproc, p_list) { 454 fdp = p->p_fd; 455 if (fdp == NULL) 456 continue; 457 FILEDESC_LOCK(fdp); 458 if (fdp->fd_cdir == olddp) { 459 VREF(newdp); 460 fdp->fd_cdir = newdp; 461 FILEDESC_UNLOCK(fdp); 462 vrele(olddp); 463 FILEDESC_LOCK(fdp); 464 } 465 if (fdp->fd_rdir == olddp) { 466 VREF(newdp); 467 fdp->fd_rdir = newdp; 468 FILEDESC_UNLOCK(fdp); 469 vrele(olddp); 470 } else 471 FILEDESC_UNLOCK(fdp); 472 } 473 sx_sunlock(&allproc_lock); 474 if (rootvnode == olddp) { 475 vrele(rootvnode); 476 VREF(newdp); 477 rootvnode = newdp; 478 } 479} 480 481/* 482 * Unmount a file system. 483 * 484 * Note: unmount takes a path to the vnode mounted on as argument, 485 * not special file (as before). 486 */ 487#ifndef _SYS_SYSPROTO_H_ 488struct unmount_args { 489 char *path; 490 int flags; 491}; 492#endif 493/* ARGSUSED */ 494int 495unmount(td, uap) 496 struct thread *td; 497 register struct unmount_args /* { 498 syscallarg(char *) path; 499 syscallarg(int) flags; 500 } */ *uap; 501{ 502 register struct vnode *vp; 503 struct mount *mp; 504 int error; 505 struct nameidata nd; 506 507 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 508 SCARG(uap, path), td); 509 if ((error = namei(&nd)) != 0) 510 return (error); 511 vp = nd.ni_vp; 512 NDFREE(&nd, NDF_ONLY_PNBUF); 513 mp = vp->v_mount; 514 515 /* 516 * Only root, or the user that did the original mount is 517 * permitted to unmount this filesystem. 518 */ 519 if (mp->mnt_stat.f_owner != td->td_ucred->cr_uid) { 520 error = suser_td(td); 521 if (error) { 522 vput(vp); 523 return (error); 524 } 525 } 526 527 /* 528 * Don't allow unmounting the root file system. 529 */ 530 if (mp->mnt_flag & MNT_ROOTFS) { 531 vput(vp); 532 return (EINVAL); 533 } 534 535 /* 536 * Must be the root of the filesystem 537 */ 538 if ((vp->v_flag & VROOT) == 0) { 539 vput(vp); 540 return (EINVAL); 541 } 542 vput(vp); 543 return (dounmount(mp, SCARG(uap, flags), td)); 544} 545 546/* 547 * Do the actual file system unmount. 548 */ 549int 550dounmount(mp, flags, td) 551 struct mount *mp; 552 int flags; 553 struct thread *td; 554{ 555 struct vnode *coveredvp, *fsrootvp; 556 int error; 557 int async_flag; 558 559 mtx_lock(&mountlist_mtx); 560 mp->mnt_kern_flag |= MNTK_UNMOUNT; 561 error = lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK | 562 ((flags & MNT_FORCE) ? 0 : LK_NOWAIT), &mountlist_mtx, td); 563 if (error) { 564 mp->mnt_kern_flag &= ~MNTK_UNMOUNT; 565 if (mp->mnt_kern_flag & MNTK_MWAIT) 566 wakeup((caddr_t)mp); 567 return (error); 568 } 569 vn_start_write(NULL, &mp, V_WAIT); 570 571 if (mp->mnt_flag & MNT_EXPUBLIC) 572 vfs_setpublicfs(NULL, NULL, NULL); 573 574 vfs_msync(mp, MNT_WAIT); 575 async_flag = mp->mnt_flag & MNT_ASYNC; 576 mp->mnt_flag &=~ MNT_ASYNC; 577 cache_purgevfs(mp); /* remove cache entries for this file sys */ 578 if (mp->mnt_syncer != NULL) 579 vrele(mp->mnt_syncer); 580 /* Move process cdir/rdir refs on fs root to underlying vnode. */ 581 if (VFS_ROOT(mp, &fsrootvp) == 0) { 582 if (mp->mnt_vnodecovered != NULL) 583 checkdirs(fsrootvp, mp->mnt_vnodecovered); 584 if (fsrootvp == rootvnode) { 585 vrele(rootvnode); 586 rootvnode = NULL; 587 } 588 vput(fsrootvp); 589 } 590 if (((mp->mnt_flag & MNT_RDONLY) || 591 (error = VFS_SYNC(mp, MNT_WAIT, td->td_ucred, td)) == 0) || 592 (flags & MNT_FORCE)) { 593 error = VFS_UNMOUNT(mp, flags, td); 594 } 595 vn_finished_write(mp); 596 if (error) { 597 /* Undo cdir/rdir and rootvnode changes made above. */ 598 if (VFS_ROOT(mp, &fsrootvp) == 0) { 599 if (mp->mnt_vnodecovered != NULL) 600 checkdirs(mp->mnt_vnodecovered, fsrootvp); 601 if (rootvnode == NULL) { 602 rootvnode = fsrootvp; 603 vref(rootvnode); 604 } 605 vput(fsrootvp); 606 } 607 if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL) 608 (void) vfs_allocate_syncvnode(mp); 609 mtx_lock(&mountlist_mtx); 610 mp->mnt_kern_flag &= ~MNTK_UNMOUNT; 611 mp->mnt_flag |= async_flag; 612 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, 613 &mountlist_mtx, td); 614 if (mp->mnt_kern_flag & MNTK_MWAIT) 615 wakeup((caddr_t)mp); 616 return (error); 617 } 618 mtx_lock(&mountlist_mtx); 619 TAILQ_REMOVE(&mountlist, mp, mnt_list); 620 if ((coveredvp = mp->mnt_vnodecovered) != NULL) 621 coveredvp->v_mountedhere = NULL; 622 mp->mnt_vfc->vfc_refcount--; 623 if (!TAILQ_EMPTY(&mp->mnt_nvnodelist)) 624 panic("unmount: dangling vnode"); 625 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_mtx, td); 626 lockdestroy(&mp->mnt_lock); 627 if (coveredvp != NULL) 628 vrele(coveredvp); 629 if (mp->mnt_kern_flag & MNTK_MWAIT) 630 wakeup((caddr_t)mp); 631 free((caddr_t)mp, M_MOUNT); 632 return (0); 633} 634 635/* 636 * Sync each mounted filesystem. 637 */ 638#ifndef _SYS_SYSPROTO_H_ 639struct sync_args { 640 int dummy; 641}; 642#endif 643 644#ifdef DEBUG 645static int syncprt = 0; 646SYSCTL_INT(_debug, OID_AUTO, syncprt, CTLFLAG_RW, &syncprt, 0, ""); 647#endif 648 649/* ARGSUSED */ 650int 651sync(td, uap) 652 struct thread *td; 653 struct sync_args *uap; 654{ 655 struct mount *mp, *nmp; 656 int asyncflag; 657 658 mtx_lock(&mountlist_mtx); 659 for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { 660 if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) { 661 nmp = TAILQ_NEXT(mp, mnt_list); 662 continue; 663 } 664 if ((mp->mnt_flag & MNT_RDONLY) == 0 && 665 vn_start_write(NULL, &mp, V_NOWAIT) == 0) { 666 asyncflag = mp->mnt_flag & MNT_ASYNC; 667 mp->mnt_flag &= ~MNT_ASYNC; 668 vfs_msync(mp, MNT_NOWAIT); 669 VFS_SYNC(mp, MNT_NOWAIT, 670 ((td != NULL) ? td->td_ucred : NOCRED), td); 671 mp->mnt_flag |= asyncflag; 672 vn_finished_write(mp); 673 } 674 mtx_lock(&mountlist_mtx); 675 nmp = TAILQ_NEXT(mp, mnt_list); 676 vfs_unbusy(mp, td); 677 } 678 mtx_unlock(&mountlist_mtx); 679#if 0 680/* 681 * XXX don't call vfs_bufstats() yet because that routine 682 * was not imported in the Lite2 merge. 683 */ 684#ifdef DIAGNOSTIC 685 if (syncprt) 686 vfs_bufstats(); 687#endif /* DIAGNOSTIC */ 688#endif 689 return (0); 690} 691 692/* XXX PRISON: could be per prison flag */ 693static int prison_quotas; 694#if 0 695SYSCTL_INT(_kern_prison, OID_AUTO, quotas, CTLFLAG_RW, &prison_quotas, 0, ""); 696#endif 697 698/* 699 * Change filesystem quotas. 700 */ 701#ifndef _SYS_SYSPROTO_H_ 702struct quotactl_args { 703 char *path; 704 int cmd; 705 int uid; 706 caddr_t arg; 707}; 708#endif 709/* ARGSUSED */ 710int 711quotactl(td, uap) 712 struct thread *td; 713 register struct quotactl_args /* { 714 syscallarg(char *) path; 715 syscallarg(int) cmd; 716 syscallarg(int) uid; 717 syscallarg(caddr_t) arg; 718 } */ *uap; 719{ 720 struct mount *mp; 721 int error; 722 struct nameidata nd; 723 724 if (jailed(td->td_ucred) && !prison_quotas) 725 return (EPERM); 726 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); 727 if ((error = namei(&nd)) != 0) 728 return (error); 729 NDFREE(&nd, NDF_ONLY_PNBUF); 730 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 731 vrele(nd.ni_vp); 732 if (error) 733 return (error); 734 error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), 735 SCARG(uap, arg), td); 736 vn_finished_write(mp); 737 return (error); 738} 739 740/* 741 * Get filesystem statistics. 742 */ 743#ifndef _SYS_SYSPROTO_H_ 744struct statfs_args { 745 char *path; 746 struct statfs *buf; 747}; 748#endif 749/* ARGSUSED */ 750int 751statfs(td, uap) 752 struct thread *td; 753 register struct statfs_args /* { 754 syscallarg(char *) path; 755 syscallarg(struct statfs *) buf; 756 } */ *uap; 757{ 758 register struct mount *mp; 759 register struct statfs *sp; 760 int error; 761 struct nameidata nd; 762 struct statfs sb; 763 764 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); 765 if ((error = namei(&nd)) != 0) 766 return (error); 767 mp = nd.ni_vp->v_mount; 768 sp = &mp->mnt_stat; 769 NDFREE(&nd, NDF_ONLY_PNBUF); 770 vrele(nd.ni_vp); 771 error = VFS_STATFS(mp, sp, td); 772 if (error) 773 return (error); 774 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 775 if (suser_xxx(td->td_ucred, 0, 0)) { 776 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 777 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 778 sp = &sb; 779 } 780 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 781} 782 783/* 784 * Get filesystem statistics. 785 */ 786#ifndef _SYS_SYSPROTO_H_ 787struct fstatfs_args { 788 int fd; 789 struct statfs *buf; 790}; 791#endif 792/* ARGSUSED */ 793int 794fstatfs(td, uap) 795 struct thread *td; 796 register struct fstatfs_args /* { 797 syscallarg(int) fd; 798 syscallarg(struct statfs *) buf; 799 } */ *uap; 800{ 801 struct file *fp; 802 struct mount *mp; 803 register struct statfs *sp; 804 int error; 805 struct statfs sb; 806 807 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0) 808 return (error); 809 mp = ((struct vnode *)fp->f_data)->v_mount; 810 fdrop(fp, td); 811 if (mp == NULL) 812 return (EBADF); 813 sp = &mp->mnt_stat; 814 error = VFS_STATFS(mp, sp, td); 815 if (error) 816 return (error); 817 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 818 if (suser_xxx(td->td_ucred, 0, 0)) { 819 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 820 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 821 sp = &sb; 822 } 823 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 824} 825 826/* 827 * Get statistics on all filesystems. 828 */ 829#ifndef _SYS_SYSPROTO_H_ 830struct getfsstat_args { 831 struct statfs *buf; 832 long bufsize; 833 int flags; 834}; 835#endif 836int 837getfsstat(td, uap) 838 struct thread *td; 839 register struct getfsstat_args /* { 840 syscallarg(struct statfs *) buf; 841 syscallarg(long) bufsize; 842 syscallarg(int) flags; 843 } */ *uap; 844{ 845 register struct mount *mp, *nmp; 846 register struct statfs *sp; 847 caddr_t sfsp; 848 long count, maxcount, error; 849 850 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); 851 sfsp = (caddr_t)SCARG(uap, buf); 852 count = 0; 853 mtx_lock(&mountlist_mtx); 854 for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { 855 if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) { 856 nmp = TAILQ_NEXT(mp, mnt_list); 857 continue; 858 } 859 if (sfsp && count < maxcount) { 860 sp = &mp->mnt_stat; 861 /* 862 * If MNT_NOWAIT or MNT_LAZY is specified, do not 863 * refresh the fsstat cache. MNT_NOWAIT or MNT_LAZY 864 * overrides MNT_WAIT. 865 */ 866 if (((SCARG(uap, flags) & (MNT_LAZY|MNT_NOWAIT)) == 0 || 867 (SCARG(uap, flags) & MNT_WAIT)) && 868 (error = VFS_STATFS(mp, sp, td))) { 869 mtx_lock(&mountlist_mtx); 870 nmp = TAILQ_NEXT(mp, mnt_list); 871 vfs_unbusy(mp, td); 872 continue; 873 } 874 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 875 error = copyout((caddr_t)sp, sfsp, sizeof(*sp)); 876 if (error) { 877 vfs_unbusy(mp, td); 878 return (error); 879 } 880 sfsp += sizeof(*sp); 881 } 882 count++; 883 mtx_lock(&mountlist_mtx); 884 nmp = TAILQ_NEXT(mp, mnt_list); 885 vfs_unbusy(mp, td); 886 } 887 mtx_unlock(&mountlist_mtx); 888 if (sfsp && count > maxcount) 889 td->td_retval[0] = maxcount; 890 else 891 td->td_retval[0] = count; 892 return (0); 893} 894 895/* 896 * Change current working directory to a given file descriptor. 897 */ 898#ifndef _SYS_SYSPROTO_H_ 899struct fchdir_args { 900 int fd; 901}; 902#endif 903/* ARGSUSED */ 904int 905fchdir(td, uap) 906 struct thread *td; 907 struct fchdir_args /* { 908 syscallarg(int) fd; 909 } */ *uap; 910{ 911 register struct filedesc *fdp = td->td_proc->p_fd; 912 struct vnode *vp, *tdp, *vpold; 913 struct mount *mp; 914 struct file *fp; 915 int error; 916 917 if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0) 918 return (error); 919 vp = (struct vnode *)fp->f_data; 920 VREF(vp); 921 fdrop(fp, td); 922 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 923 if (vp->v_type != VDIR) 924 error = ENOTDIR; 925 else 926 error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td); 927 while (!error && (mp = vp->v_mountedhere) != NULL) { 928 if (vfs_busy(mp, 0, 0, td)) 929 continue; 930 error = VFS_ROOT(mp, &tdp); 931 vfs_unbusy(mp, td); 932 if (error) 933 break; 934 vput(vp); 935 vp = tdp; 936 } 937 if (error) { 938 vput(vp); 939 return (error); 940 } 941 VOP_UNLOCK(vp, 0, td); 942 FILEDESC_LOCK(fdp); 943 vpold = fdp->fd_cdir; 944 fdp->fd_cdir = vp; 945 FILEDESC_UNLOCK(fdp); 946 vrele(vpold); 947 return (0); 948} 949 950/* 951 * Change current working directory (``.''). 952 */ 953#ifndef _SYS_SYSPROTO_H_ 954struct chdir_args { 955 char *path; 956}; 957#endif 958/* ARGSUSED */ 959int 960chdir(td, uap) 961 struct thread *td; 962 struct chdir_args /* { 963 syscallarg(char *) path; 964 } */ *uap; 965{ 966 register struct filedesc *fdp = td->td_proc->p_fd; 967 int error; 968 struct nameidata nd; 969 struct vnode *vp; 970 971 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 972 SCARG(uap, path), td); 973 if ((error = change_dir(&nd, td)) != 0) 974 return (error); 975 NDFREE(&nd, NDF_ONLY_PNBUF); 976 FILEDESC_LOCK(fdp); 977 vp = fdp->fd_cdir; 978 fdp->fd_cdir = nd.ni_vp; 979 FILEDESC_UNLOCK(fdp); 980 vrele(vp); 981 return (0); 982} 983 984/* 985 * Helper function for raised chroot(2) security function: Refuse if 986 * any filedescriptors are open directories. 987 */ 988static int 989chroot_refuse_vdir_fds(fdp) 990 struct filedesc *fdp; 991{ 992 struct vnode *vp; 993 struct file *fp; 994 int fd; 995 996 FILEDESC_LOCK(fdp); 997 for (fd = 0; fd < fdp->fd_nfiles ; fd++) { 998 fp = fget_locked(fdp, fd); 999 if (fp == NULL) 1000 continue; 1001 if (fp->f_type == DTYPE_VNODE) { 1002 vp = (struct vnode *)fp->f_data; 1003 if (vp->v_type == VDIR) { 1004 FILEDESC_UNLOCK(fdp); 1005 return (EPERM); 1006 } 1007 } 1008 } 1009 FILEDESC_UNLOCK(fdp); 1010 return (0); 1011} 1012 1013/* 1014 * This sysctl determines if we will allow a process to chroot(2) if it 1015 * has a directory open: 1016 * 0: disallowed for all processes. 1017 * 1: allowed for processes that were not already chroot(2)'ed. 1018 * 2: allowed for all processes. 1019 */ 1020 1021static int chroot_allow_open_directories = 1; 1022 1023SYSCTL_INT(_kern, OID_AUTO, chroot_allow_open_directories, CTLFLAG_RW, 1024 &chroot_allow_open_directories, 0, ""); 1025 1026/* 1027 * Change notion of root (``/'') directory. 1028 */ 1029#ifndef _SYS_SYSPROTO_H_ 1030struct chroot_args { 1031 char *path; 1032}; 1033#endif 1034/* ARGSUSED */ 1035int 1036chroot(td, uap) 1037 struct thread *td; 1038 struct chroot_args /* { 1039 syscallarg(char *) path; 1040 } */ *uap; 1041{ 1042 register struct filedesc *fdp = td->td_proc->p_fd; 1043 int error; 1044 struct nameidata nd; 1045 struct vnode *vp; 1046 1047 error = suser_xxx(0, td->td_proc, PRISON_ROOT); 1048 if (error) 1049 return (error); 1050 FILEDESC_LOCK(fdp); 1051 if (chroot_allow_open_directories == 0 || 1052 (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) { 1053 FILEDESC_UNLOCK(fdp); 1054 error = chroot_refuse_vdir_fds(fdp); 1055 } else 1056 FILEDESC_UNLOCK(fdp); 1057 if (error) 1058 return (error); 1059 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1060 SCARG(uap, path), td); 1061 if ((error = change_dir(&nd, td)) != 0) 1062 return (error); 1063 NDFREE(&nd, NDF_ONLY_PNBUF); 1064 FILEDESC_LOCK(fdp); 1065 vp = fdp->fd_rdir; 1066 fdp->fd_rdir = nd.ni_vp; 1067 if (!fdp->fd_jdir) { 1068 fdp->fd_jdir = nd.ni_vp; 1069 VREF(fdp->fd_jdir); 1070 } 1071 FILEDESC_UNLOCK(fdp); 1072 vrele(vp); 1073 return (0); 1074} 1075 1076/* 1077 * Common routine for chroot and chdir. 1078 */ 1079static int 1080change_dir(ndp, td) 1081 register struct nameidata *ndp; 1082 struct thread *td; 1083{ 1084 struct vnode *vp; 1085 int error; 1086 1087 error = namei(ndp); 1088 if (error) 1089 return (error); 1090 vp = ndp->ni_vp; 1091 if (vp->v_type != VDIR) 1092 error = ENOTDIR; 1093 else 1094 error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td); 1095 if (error) 1096 vput(vp); 1097 else 1098 VOP_UNLOCK(vp, 0, td); 1099 return (error); 1100} 1101 1102/* 1103 * Check permissions, allocate an open file structure, 1104 * and call the device open routine if any. 1105 */ 1106#ifndef _SYS_SYSPROTO_H_ 1107struct open_args { 1108 char *path; 1109 int flags; 1110 int mode; 1111}; 1112#endif 1113int 1114open(td, uap) 1115 struct thread *td; 1116 register struct open_args /* { 1117 syscallarg(char *) path; 1118 syscallarg(int) flags; 1119 syscallarg(int) mode; 1120 } */ *uap; 1121{ 1122 struct proc *p = td->td_proc; 1123 struct filedesc *fdp = p->p_fd; 1124 struct file *fp; 1125 struct vnode *vp; 1126 struct vattr vat; 1127 struct mount *mp; 1128 int cmode, flags, oflags; 1129 struct file *nfp; 1130 int type, indx, error; 1131 struct flock lf; 1132 struct nameidata nd; 1133 1134 oflags = SCARG(uap, flags); 1135 if ((oflags & O_ACCMODE) == O_ACCMODE) 1136 return (EINVAL); 1137 flags = FFLAGS(oflags); 1138 error = falloc(td, &nfp, &indx); 1139 if (error) 1140 return (error); 1141 fp = nfp; 1142 FILEDESC_LOCK(fdp); 1143 cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 1144 FILEDESC_UNLOCK(fdp); 1145 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); 1146 td->td_dupfd = -indx - 1; /* XXX check for fdopen */ 1147 /* 1148 * Bump the ref count to prevent another process from closing 1149 * the descriptor while we are blocked in vn_open() 1150 */ 1151 fhold(fp); 1152 error = vn_open(&nd, &flags, cmode); 1153 if (error) { 1154 /* 1155 * release our own reference 1156 */ 1157 fdrop(fp, td); 1158 1159 /* 1160 * handle special fdopen() case. bleh. dupfdopen() is 1161 * responsible for dropping the old contents of ofiles[indx] 1162 * if it succeeds. 1163 */ 1164 if ((error == ENODEV || error == ENXIO) && 1165 td->td_dupfd >= 0 && /* XXX from fdopen */ 1166 (error = 1167 dupfdopen(td, fdp, indx, td->td_dupfd, flags, error)) == 0) { 1168 td->td_retval[0] = indx; 1169 return (0); 1170 } 1171 /* 1172 * Clean up the descriptor, but only if another thread hadn't 1173 * replaced or closed it. 1174 */ 1175 FILEDESC_LOCK(fdp); 1176 if (fdp->fd_ofiles[indx] == fp) { 1177 fdp->fd_ofiles[indx] = NULL; 1178 FILEDESC_UNLOCK(fdp); 1179 fdrop(fp, td); 1180 } else 1181 FILEDESC_UNLOCK(fdp); 1182 1183 if (error == ERESTART) 1184 error = EINTR; 1185 return (error); 1186 } 1187 td->td_dupfd = 0; 1188 NDFREE(&nd, NDF_ONLY_PNBUF); 1189 vp = nd.ni_vp; 1190 1191 /* 1192 * There should be 2 references on the file, one from the descriptor 1193 * table, and one for us. 1194 * 1195 * Handle the case where someone closed the file (via its file 1196 * descriptor) while we were blocked. The end result should look 1197 * like opening the file succeeded but it was immediately closed. 1198 */ 1199 FILEDESC_LOCK(fdp); 1200 FILE_LOCK(fp); 1201 if (fp->f_count == 1) { 1202 KASSERT(fdp->fd_ofiles[indx] != fp, 1203 ("Open file descriptor lost all refs")); 1204 FILEDESC_UNLOCK(fdp); 1205 FILE_UNLOCK(fp); 1206 VOP_UNLOCK(vp, 0, td); 1207 vn_close(vp, flags & FMASK, fp->f_cred, td); 1208 fdrop(fp, td); 1209 td->td_retval[0] = indx; 1210 return 0; 1211 } 1212 1213 fp->f_data = (caddr_t)vp; 1214 fp->f_flag = flags & FMASK; 1215 fp->f_ops = &vnops; 1216 fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE); 1217 FILEDESC_UNLOCK(fdp); 1218 FILE_UNLOCK(fp); 1219 VOP_UNLOCK(vp, 0, td); 1220 if (flags & (O_EXLOCK | O_SHLOCK)) { 1221 lf.l_whence = SEEK_SET; 1222 lf.l_start = 0; 1223 lf.l_len = 0; 1224 if (flags & O_EXLOCK) 1225 lf.l_type = F_WRLCK; 1226 else 1227 lf.l_type = F_RDLCK; 1228 type = F_FLOCK; 1229 if ((flags & FNONBLOCK) == 0) 1230 type |= F_WAIT; 1231 if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0) 1232 goto bad; 1233 fp->f_flag |= FHASLOCK; 1234 } 1235 if (flags & O_TRUNC) { 1236 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) 1237 goto bad; 1238 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 1239 VATTR_NULL(&vat); 1240 vat.va_size = 0; 1241 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 1242 error = VOP_SETATTR(vp, &vat, td->td_ucred, td); 1243 VOP_UNLOCK(vp, 0, td); 1244 vn_finished_write(mp); 1245 if (error) 1246 goto bad; 1247 } 1248 /* assert that vn_open created a backing object if one is needed */ 1249 KASSERT(!vn_canvmio(vp) || VOP_GETVOBJECT(vp, NULL) == 0, 1250 ("open: vmio vnode has no backing object after vn_open")); 1251 /* 1252 * Release our private reference, leaving the one associated with 1253 * the descriptor table intact. 1254 */ 1255 fdrop(fp, td); 1256 td->td_retval[0] = indx; 1257 return (0); 1258bad: 1259 FILEDESC_LOCK(fdp); 1260 if (fdp->fd_ofiles[indx] == fp) { 1261 fdp->fd_ofiles[indx] = NULL; 1262 FILEDESC_UNLOCK(fdp); 1263 fdrop(fp, td); 1264 } else 1265 FILEDESC_UNLOCK(fdp); 1266 return (error); 1267} 1268 1269#ifdef COMPAT_43 1270/* 1271 * Create a file. 1272 */ 1273#ifndef _SYS_SYSPROTO_H_ 1274struct ocreat_args { 1275 char *path; 1276 int mode; 1277}; 1278#endif 1279int 1280ocreat(td, uap) 1281 struct thread *td; 1282 register struct ocreat_args /* { 1283 syscallarg(char *) path; 1284 syscallarg(int) mode; 1285 } */ *uap; 1286{ 1287 struct open_args /* { 1288 syscallarg(char *) path; 1289 syscallarg(int) flags; 1290 syscallarg(int) mode; 1291 } */ nuap; 1292 1293 SCARG(&nuap, path) = SCARG(uap, path); 1294 SCARG(&nuap, mode) = SCARG(uap, mode); 1295 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; 1296 return (open(td, &nuap)); 1297} 1298#endif /* COMPAT_43 */ 1299 1300/* 1301 * Create a special file. 1302 */ 1303#ifndef _SYS_SYSPROTO_H_ 1304struct mknod_args { 1305 char *path; 1306 int mode; 1307 int dev; 1308}; 1309#endif 1310/* ARGSUSED */ 1311int 1312mknod(td, uap) 1313 struct thread *td; 1314 register struct mknod_args /* { 1315 syscallarg(char *) path; 1316 syscallarg(int) mode; 1317 syscallarg(int) dev; 1318 } */ *uap; 1319{ 1320 struct vnode *vp; 1321 struct mount *mp; 1322 struct vattr vattr; 1323 int error; 1324 int whiteout = 0; 1325 struct nameidata nd; 1326 1327 switch (SCARG(uap, mode) & S_IFMT) { 1328 case S_IFCHR: 1329 case S_IFBLK: 1330 error = suser_td(td); 1331 break; 1332 default: 1333 error = suser_xxx(0, td->td_proc, PRISON_ROOT); 1334 break; 1335 } 1336 if (error) 1337 return (error); 1338restart: 1339 bwillwrite(); 1340 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td); 1341 if ((error = namei(&nd)) != 0) 1342 return (error); 1343 vp = nd.ni_vp; 1344 if (vp != NULL) { 1345 vrele(vp); 1346 error = EEXIST; 1347 } else { 1348 VATTR_NULL(&vattr); 1349 FILEDESC_LOCK(td->td_proc->p_fd); 1350 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ td->td_proc->p_fd->fd_cmask; 1351 FILEDESC_UNLOCK(td->td_proc->p_fd); 1352 vattr.va_rdev = SCARG(uap, dev); 1353 whiteout = 0; 1354 1355 switch (SCARG(uap, mode) & S_IFMT) { 1356 case S_IFMT: /* used by badsect to flag bad sectors */ 1357 vattr.va_type = VBAD; 1358 break; 1359 case S_IFCHR: 1360 vattr.va_type = VCHR; 1361 break; 1362 case S_IFBLK: 1363 vattr.va_type = VBLK; 1364 break; 1365 case S_IFWHT: 1366 whiteout = 1; 1367 break; 1368 default: 1369 error = EINVAL; 1370 break; 1371 } 1372 } 1373 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { 1374 NDFREE(&nd, NDF_ONLY_PNBUF); 1375 vput(nd.ni_dvp); 1376 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) 1377 return (error); 1378 goto restart; 1379 } 1380 if (!error) { 1381 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE); 1382 if (whiteout) 1383 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 1384 else { 1385 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, 1386 &nd.ni_cnd, &vattr); 1387 if (error == 0) 1388 vput(nd.ni_vp); 1389 } 1390 } 1391 NDFREE(&nd, NDF_ONLY_PNBUF); 1392 vput(nd.ni_dvp); 1393 vn_finished_write(mp); 1394 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod"); 1395 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod"); 1396 return (error); 1397} 1398 1399/* 1400 * Create a named pipe. 1401 */ 1402#ifndef _SYS_SYSPROTO_H_ 1403struct mkfifo_args { 1404 char *path; 1405 int mode; 1406}; 1407#endif 1408/* ARGSUSED */ 1409int 1410mkfifo(td, uap) 1411 struct thread *td; 1412 register struct mkfifo_args /* { 1413 syscallarg(char *) path; 1414 syscallarg(int) mode; 1415 } */ *uap; 1416{ 1417 struct mount *mp; 1418 struct vattr vattr; 1419 int error; 1420 struct nameidata nd; 1421 1422restart: 1423 bwillwrite(); 1424 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td); 1425 if ((error = namei(&nd)) != 0) 1426 return (error); 1427 if (nd.ni_vp != NULL) { 1428 NDFREE(&nd, NDF_ONLY_PNBUF); 1429 vrele(nd.ni_vp); 1430 vput(nd.ni_dvp); 1431 return (EEXIST); 1432 } 1433 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { 1434 NDFREE(&nd, NDF_ONLY_PNBUF); 1435 vput(nd.ni_dvp); 1436 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) 1437 return (error); 1438 goto restart; 1439 } 1440 VATTR_NULL(&vattr); 1441 vattr.va_type = VFIFO; 1442 FILEDESC_LOCK(td->td_proc->p_fd); 1443 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ td->td_proc->p_fd->fd_cmask; 1444 FILEDESC_UNLOCK(td->td_proc->p_fd); 1445 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE); 1446 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 1447 if (error == 0) 1448 vput(nd.ni_vp); 1449 NDFREE(&nd, NDF_ONLY_PNBUF); 1450 vput(nd.ni_dvp); 1451 vn_finished_write(mp); 1452 return (error); 1453} 1454 1455/* 1456 * Make a hard file link. 1457 */ 1458#ifndef _SYS_SYSPROTO_H_ 1459struct link_args { 1460 char *path; 1461 char *link; 1462}; 1463#endif 1464/* ARGSUSED */ 1465int 1466link(td, uap) 1467 struct thread *td; 1468 register struct link_args /* { 1469 syscallarg(char *) path; 1470 syscallarg(char *) link; 1471 } */ *uap; 1472{ 1473 struct vnode *vp; 1474 struct mount *mp; 1475 struct nameidata nd; 1476 int error; 1477 1478 bwillwrite(); 1479 NDINIT(&nd, LOOKUP, FOLLOW|NOOBJ, UIO_USERSPACE, SCARG(uap, path), td); 1480 if ((error = namei(&nd)) != 0) 1481 return (error); 1482 NDFREE(&nd, NDF_ONLY_PNBUF); 1483 vp = nd.ni_vp; 1484 if (vp->v_type == VDIR) { 1485 vrele(vp); 1486 return (EPERM); /* POSIX */ 1487 } 1488 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) { 1489 vrele(vp); 1490 return (error); 1491 } 1492 NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), td); 1493 if ((error = namei(&nd)) == 0) { 1494 if (nd.ni_vp != NULL) { 1495 vrele(nd.ni_vp); 1496 error = EEXIST; 1497 } else { 1498 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE); 1499 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 1500 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 1501 } 1502 NDFREE(&nd, NDF_ONLY_PNBUF); 1503 vput(nd.ni_dvp); 1504 } 1505 vrele(vp); 1506 vn_finished_write(mp); 1507 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link"); 1508 ASSERT_VOP_UNLOCKED(nd.ni_vp, "link"); 1509 return (error); 1510} 1511 1512/* 1513 * Make a symbolic link. 1514 */ 1515#ifndef _SYS_SYSPROTO_H_ 1516struct symlink_args { 1517 char *path; 1518 char *link; 1519}; 1520#endif 1521/* ARGSUSED */ 1522int 1523symlink(td, uap) 1524 struct thread *td; 1525 register struct symlink_args /* { 1526 syscallarg(char *) path; 1527 syscallarg(char *) link; 1528 } */ *uap; 1529{ 1530 struct mount *mp; 1531 struct vattr vattr; 1532 char *path; 1533 int error; 1534 struct nameidata nd; 1535 1536 path = zalloc(namei_zone); 1537 if ((error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) != 0) 1538 goto out; 1539restart: 1540 bwillwrite(); 1541 NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), td); 1542 if ((error = namei(&nd)) != 0) 1543 goto out; 1544 if (nd.ni_vp) { 1545 NDFREE(&nd, NDF_ONLY_PNBUF); 1546 vrele(nd.ni_vp); 1547 vput(nd.ni_dvp); 1548 error = EEXIST; 1549 goto out; 1550 } 1551 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { 1552 NDFREE(&nd, NDF_ONLY_PNBUF); 1553 vput(nd.ni_dvp); 1554 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) 1555 return (error); 1556 goto restart; 1557 } 1558 VATTR_NULL(&vattr); 1559 FILEDESC_LOCK(td->td_proc->p_fd); 1560 vattr.va_mode = ACCESSPERMS &~ td->td_proc->p_fd->fd_cmask; 1561 FILEDESC_UNLOCK(td->td_proc->p_fd); 1562 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE); 1563 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 1564 NDFREE(&nd, NDF_ONLY_PNBUF); 1565 if (error == 0) 1566 vput(nd.ni_vp); 1567 vput(nd.ni_dvp); 1568 vn_finished_write(mp); 1569 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink"); 1570 ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink"); 1571out: 1572 zfree(namei_zone, path); 1573 return (error); 1574} 1575 1576/* 1577 * Delete a whiteout from the filesystem. 1578 */ 1579/* ARGSUSED */ 1580int 1581undelete(td, uap) 1582 struct thread *td; 1583 register struct undelete_args /* { 1584 syscallarg(char *) path; 1585 } */ *uap; 1586{ 1587 int error; 1588 struct mount *mp; 1589 struct nameidata nd; 1590 1591restart: 1592 bwillwrite(); 1593 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, 1594 SCARG(uap, path), td); 1595 error = namei(&nd); 1596 if (error) 1597 return (error); 1598 1599 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 1600 NDFREE(&nd, NDF_ONLY_PNBUF); 1601 if (nd.ni_vp) 1602 vrele(nd.ni_vp); 1603 vput(nd.ni_dvp); 1604 return (EEXIST); 1605 } 1606 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { 1607 NDFREE(&nd, NDF_ONLY_PNBUF); 1608 vput(nd.ni_dvp); 1609 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) 1610 return (error); 1611 goto restart; 1612 } 1613 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE); 1614 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE); 1615 NDFREE(&nd, NDF_ONLY_PNBUF); 1616 vput(nd.ni_dvp); 1617 vn_finished_write(mp); 1618 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete"); 1619 ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete"); 1620 return (error); 1621} 1622 1623/* 1624 * Delete a name from the filesystem. 1625 */ 1626#ifndef _SYS_SYSPROTO_H_ 1627struct unlink_args { 1628 char *path; 1629}; 1630#endif 1631/* ARGSUSED */ 1632int 1633unlink(td, uap) 1634 struct thread *td; 1635 struct unlink_args /* { 1636 syscallarg(char *) path; 1637 } */ *uap; 1638{ 1639 struct mount *mp; 1640 struct vnode *vp; 1641 int error; 1642 struct nameidata nd; 1643 1644restart: 1645 bwillwrite(); 1646 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td); 1647 if ((error = namei(&nd)) != 0) 1648 return (error); 1649 vp = nd.ni_vp; 1650 if (vp->v_type == VDIR) 1651 error = EPERM; /* POSIX */ 1652 else { 1653 /* 1654 * The root of a mounted filesystem cannot be deleted. 1655 * 1656 * XXX: can this only be a VDIR case? 1657 */ 1658 if (vp->v_flag & VROOT) 1659 error = EBUSY; 1660 } 1661 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { 1662 NDFREE(&nd, NDF_ONLY_PNBUF); 1663 vrele(vp); 1664 vput(nd.ni_dvp); 1665 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) 1666 return (error); 1667 goto restart; 1668 } 1669 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 1670 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 1671 if (!error) { 1672 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE); 1673 error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd); 1674 } 1675 NDFREE(&nd, NDF_ONLY_PNBUF); 1676 vput(nd.ni_dvp); 1677 vput(vp); 1678 vn_finished_write(mp); 1679 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink"); 1680 ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink"); 1681 return (error); 1682} 1683 1684/* 1685 * Reposition read/write file offset. 1686 */ 1687#ifndef _SYS_SYSPROTO_H_ 1688struct lseek_args { 1689 int fd; 1690 int pad; 1691 off_t offset; 1692 int whence; 1693}; 1694#endif 1695int 1696lseek(td, uap) 1697 struct thread *td; 1698 register struct lseek_args /* { 1699 syscallarg(int) fd; 1700 syscallarg(int) pad; 1701 syscallarg(off_t) offset; 1702 syscallarg(int) whence; 1703 } */ *uap; 1704{ 1705 struct ucred *cred = td->td_ucred; 1706 struct file *fp; 1707 struct vnode *vp; 1708 struct vattr vattr; 1709 off_t offset; 1710 int error, noneg; 1711 1712 if ((error = fget(td, uap->fd, &fp)) != 0) 1713 return (error); 1714 if (fp->f_type != DTYPE_VNODE) { 1715 fdrop(fp, td); 1716 return (ESPIPE); 1717 } 1718 vp = (struct vnode *)fp->f_data; 1719 noneg = (vp->v_type != VCHR); 1720 offset = SCARG(uap, offset); 1721 switch (SCARG(uap, whence)) { 1722 case L_INCR: 1723 if (noneg && 1724 (fp->f_offset < 0 || 1725 (offset > 0 && fp->f_offset > OFF_MAX - offset))) 1726 return (EOVERFLOW); 1727 offset += fp->f_offset; 1728 break; 1729 case L_XTND: 1730 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 1731 error = VOP_GETATTR(vp, &vattr, cred, td); 1732 VOP_UNLOCK(vp, 0, td); 1733 if (error) 1734 return (error); 1735 if (noneg && 1736 (vattr.va_size > OFF_MAX || 1737 (offset > 0 && vattr.va_size > OFF_MAX - offset))) 1738 return (EOVERFLOW); 1739 offset += vattr.va_size; 1740 break; 1741 case L_SET: 1742 break; 1743 default: 1744 fdrop(fp, td); 1745 return (EINVAL); 1746 } 1747 if (noneg && offset < 0) 1748 return (EINVAL); 1749 fp->f_offset = offset; 1750 *(off_t *)(td->td_retval) = fp->f_offset; 1751 fdrop(fp, td); 1752 return (0); 1753} 1754 1755#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1756/* 1757 * Reposition read/write file offset. 1758 */ 1759#ifndef _SYS_SYSPROTO_H_ 1760struct olseek_args { 1761 int fd; 1762 long offset; 1763 int whence; 1764}; 1765#endif 1766int 1767olseek(td, uap) 1768 struct thread *td; 1769 register struct olseek_args /* { 1770 syscallarg(int) fd; 1771 syscallarg(long) offset; 1772 syscallarg(int) whence; 1773 } */ *uap; 1774{ 1775 struct lseek_args /* { 1776 syscallarg(int) fd; 1777 syscallarg(int) pad; 1778 syscallarg(off_t) offset; 1779 syscallarg(int) whence; 1780 } */ nuap; 1781 int error; 1782 1783 SCARG(&nuap, fd) = SCARG(uap, fd); 1784 SCARG(&nuap, offset) = SCARG(uap, offset); 1785 SCARG(&nuap, whence) = SCARG(uap, whence); 1786 error = lseek(td, &nuap); 1787 return (error); 1788} 1789#endif /* COMPAT_43 */ 1790 1791/* 1792 * Check access permissions using passed credentials. 1793 */ 1794static int 1795vn_access(vp, user_flags, cred, td) 1796 struct vnode *vp; 1797 int user_flags; 1798 struct ucred *cred; 1799 struct thread *td; 1800{ 1801 int error, flags; 1802 1803 /* Flags == 0 means only check for existence. */ 1804 error = 0; 1805 if (user_flags) { 1806 flags = 0; 1807 if (user_flags & R_OK) 1808 flags |= VREAD; 1809 if (user_flags & W_OK) 1810 flags |= VWRITE; 1811 if (user_flags & X_OK) 1812 flags |= VEXEC; 1813 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 1814 error = VOP_ACCESS(vp, flags, cred, td); 1815 } 1816 return (error); 1817} 1818 1819/* 1820 * Check access permissions using "real" credentials. 1821 */ 1822#ifndef _SYS_SYSPROTO_H_ 1823struct access_args { 1824 char *path; 1825 int flags; 1826}; 1827#endif 1828int 1829access(td, uap) 1830 struct thread *td; 1831 register struct access_args /* { 1832 syscallarg(char *) path; 1833 syscallarg(int) flags; 1834 } */ *uap; 1835{ 1836 struct ucred *cred, *tmpcred; 1837 register struct vnode *vp; 1838 int error; 1839 struct nameidata nd; 1840 1841 /* 1842 * Create and modify a temporary credential instead of one that 1843 * is potentially shared. This could also mess up socket 1844 * buffer accounting which can run in an interrupt context. 1845 * 1846 * XXX - Depending on how "threads" are finally implemented, it 1847 * may be better to explicitly pass the credential to namei() 1848 * rather than to modify the potentially shared process structure. 1849 */ 1850 cred = td->td_ucred; 1851 tmpcred = crdup(cred); 1852 tmpcred->cr_uid = cred->cr_ruid; 1853 tmpcred->cr_groups[0] = cred->cr_rgid; 1854 td->td_ucred = tmpcred; 1855 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1856 SCARG(uap, path), td); 1857 if ((error = namei(&nd)) != 0) 1858 goto out1; 1859 vp = nd.ni_vp; 1860 1861 error = vn_access(vp, SCARG(uap, flags), tmpcred, td); 1862 NDFREE(&nd, NDF_ONLY_PNBUF); 1863 vput(vp); 1864out1: 1865 td->td_ucred = cred; 1866 crfree(tmpcred); 1867 return (error); 1868} 1869 1870/* 1871 * Check access permissions using "effective" credentials. 1872 */ 1873#ifndef _SYS_SYSPROTO_H_ 1874struct eaccess_args { 1875 char *path; 1876 int flags; 1877}; 1878#endif 1879int 1880eaccess(td, uap) 1881 struct thread *td; 1882 register struct eaccess_args /* { 1883 syscallarg(char *) path; 1884 syscallarg(int) flags; 1885 } */ *uap; 1886{ 1887 struct nameidata nd; 1888 struct vnode *vp; 1889 int error; 1890 1891 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1892 SCARG(uap, path), td); 1893 if ((error = namei(&nd)) != 0) 1894 return (error); 1895 vp = nd.ni_vp; 1896 1897 error = vn_access(vp, SCARG(uap, flags), td->td_ucred, td); 1898 NDFREE(&nd, NDF_ONLY_PNBUF); 1899 vput(vp); 1900 return (error); 1901} 1902 1903#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1904/* 1905 * Get file status; this version follows links. 1906 */ 1907#ifndef _SYS_SYSPROTO_H_ 1908struct ostat_args { 1909 char *path; 1910 struct ostat *ub; 1911}; 1912#endif 1913/* ARGSUSED */ 1914int 1915ostat(td, uap) 1916 struct thread *td; 1917 register struct ostat_args /* { 1918 syscallarg(char *) path; 1919 syscallarg(struct ostat *) ub; 1920 } */ *uap; 1921{ 1922 struct stat sb; 1923 struct ostat osb; 1924 int error; 1925 struct nameidata nd; 1926 1927 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1928 SCARG(uap, path), td); 1929 if ((error = namei(&nd)) != 0) 1930 return (error); 1931 NDFREE(&nd, NDF_ONLY_PNBUF); 1932 error = vn_stat(nd.ni_vp, &sb, td); 1933 vput(nd.ni_vp); 1934 if (error) 1935 return (error); 1936 cvtstat(&sb, &osb); 1937 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 1938 return (error); 1939} 1940 1941/* 1942 * Get file status; this version does not follow links. 1943 */ 1944#ifndef _SYS_SYSPROTO_H_ 1945struct olstat_args { 1946 char *path; 1947 struct ostat *ub; 1948}; 1949#endif 1950/* ARGSUSED */ 1951int 1952olstat(td, uap) 1953 struct thread *td; 1954 register struct olstat_args /* { 1955 syscallarg(char *) path; 1956 syscallarg(struct ostat *) ub; 1957 } */ *uap; 1958{ 1959 struct vnode *vp; 1960 struct stat sb; 1961 struct ostat osb; 1962 int error; 1963 struct nameidata nd; 1964 1965 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1966 SCARG(uap, path), td); 1967 if ((error = namei(&nd)) != 0) 1968 return (error); 1969 vp = nd.ni_vp; 1970 error = vn_stat(vp, &sb, td); 1971 NDFREE(&nd, NDF_ONLY_PNBUF); 1972 vput(vp); 1973 if (error) 1974 return (error); 1975 cvtstat(&sb, &osb); 1976 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 1977 return (error); 1978} 1979 1980/* 1981 * Convert from an old to a new stat structure. 1982 */ 1983void 1984cvtstat(st, ost) 1985 struct stat *st; 1986 struct ostat *ost; 1987{ 1988 1989 ost->st_dev = st->st_dev; 1990 ost->st_ino = st->st_ino; 1991 ost->st_mode = st->st_mode; 1992 ost->st_nlink = st->st_nlink; 1993 ost->st_uid = st->st_uid; 1994 ost->st_gid = st->st_gid; 1995 ost->st_rdev = st->st_rdev; 1996 if (st->st_size < (quad_t)1 << 32) 1997 ost->st_size = st->st_size; 1998 else 1999 ost->st_size = -2; 2000 ost->st_atime = st->st_atime; 2001 ost->st_mtime = st->st_mtime; 2002 ost->st_ctime = st->st_ctime; 2003 ost->st_blksize = st->st_blksize; 2004 ost->st_blocks = st->st_blocks; 2005 ost->st_flags = st->st_flags; 2006 ost->st_gen = st->st_gen; 2007} 2008#endif /* COMPAT_43 || COMPAT_SUNOS */ 2009 2010/* 2011 * Get file status; this version follows links. 2012 */ 2013#ifndef _SYS_SYSPROTO_H_ 2014struct stat_args { 2015 char *path; 2016 struct stat *ub; 2017}; 2018#endif 2019/* ARGSUSED */ 2020int 2021stat(td, uap) 2022 struct thread *td; 2023 register struct stat_args /* { 2024 syscallarg(char *) path; 2025 syscallarg(struct stat *) ub; 2026 } */ *uap; 2027{ 2028 struct stat sb; 2029 int error; 2030 struct nameidata nd; 2031 2032#ifdef LOOKUP_SHARED 2033 NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | NOOBJ, 2034 UIO_USERSPACE, SCARG(uap, path), td); 2035#else 2036 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 2037 SCARG(uap, path), td); 2038#endif 2039 if ((error = namei(&nd)) != 0) 2040 return (error); 2041 error = vn_stat(nd.ni_vp, &sb, td); 2042 NDFREE(&nd, NDF_ONLY_PNBUF); 2043 vput(nd.ni_vp); 2044 if (error) 2045 return (error); 2046 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 2047 return (error); 2048} 2049 2050/* 2051 * Get file status; this version does not follow links. 2052 */ 2053#ifndef _SYS_SYSPROTO_H_ 2054struct lstat_args { 2055 char *path; 2056 struct stat *ub; 2057}; 2058#endif 2059/* ARGSUSED */ 2060int 2061lstat(td, uap) 2062 struct thread *td; 2063 register struct lstat_args /* { 2064 syscallarg(char *) path; 2065 syscallarg(struct stat *) ub; 2066 } */ *uap; 2067{ 2068 int error; 2069 struct vnode *vp; 2070 struct stat sb; 2071 struct nameidata nd; 2072 2073 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 2074 SCARG(uap, path), td); 2075 if ((error = namei(&nd)) != 0) 2076 return (error); 2077 vp = nd.ni_vp; 2078 error = vn_stat(vp, &sb, td); 2079 NDFREE(&nd, NDF_ONLY_PNBUF); 2080 vput(vp); 2081 if (error) 2082 return (error); 2083 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 2084 return (error); 2085} 2086 2087/* 2088 * Implementation of the NetBSD stat() function. 2089 * XXX This should probably be collapsed with the FreeBSD version, 2090 * as the differences are only due to vn_stat() clearing spares at 2091 * the end of the structures. vn_stat could be split to avoid this, 2092 * and thus collapse the following to close to zero code. 2093 */ 2094void 2095cvtnstat(sb, nsb) 2096 struct stat *sb; 2097 struct nstat *nsb; 2098{ 2099 nsb->st_dev = sb->st_dev; 2100 nsb->st_ino = sb->st_ino; 2101 nsb->st_mode = sb->st_mode; 2102 nsb->st_nlink = sb->st_nlink; 2103 nsb->st_uid = sb->st_uid; 2104 nsb->st_gid = sb->st_gid; 2105 nsb->st_rdev = sb->st_rdev; 2106 nsb->st_atimespec = sb->st_atimespec; 2107 nsb->st_mtimespec = sb->st_mtimespec; 2108 nsb->st_ctimespec = sb->st_ctimespec; 2109 nsb->st_size = sb->st_size; 2110 nsb->st_blocks = sb->st_blocks; 2111 nsb->st_blksize = sb->st_blksize; 2112 nsb->st_flags = sb->st_flags; 2113 nsb->st_gen = sb->st_gen; 2114 nsb->st_qspare[0] = sb->st_qspare[0]; 2115 nsb->st_qspare[1] = sb->st_qspare[1]; 2116} 2117 2118#ifndef _SYS_SYSPROTO_H_ 2119struct nstat_args { 2120 char *path; 2121 struct nstat *ub; 2122}; 2123#endif 2124/* ARGSUSED */ 2125int 2126nstat(td, uap) 2127 struct thread *td; 2128 register struct nstat_args /* { 2129 syscallarg(char *) path; 2130 syscallarg(struct nstat *) ub; 2131 } */ *uap; 2132{ 2133 struct stat sb; 2134 struct nstat nsb; 2135 int error; 2136 struct nameidata nd; 2137 2138 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 2139 SCARG(uap, path), td); 2140 if ((error = namei(&nd)) != 0) 2141 return (error); 2142 NDFREE(&nd, NDF_ONLY_PNBUF); 2143 error = vn_stat(nd.ni_vp, &sb, td); 2144 vput(nd.ni_vp); 2145 if (error) 2146 return (error); 2147 cvtnstat(&sb, &nsb); 2148 error = copyout((caddr_t)&nsb, (caddr_t)SCARG(uap, ub), sizeof (nsb)); 2149 return (error); 2150} 2151 2152/* 2153 * NetBSD lstat. Get file status; this version does not follow links. 2154 */ 2155#ifndef _SYS_SYSPROTO_H_ 2156struct lstat_args { 2157 char *path; 2158 struct stat *ub; 2159}; 2160#endif 2161/* ARGSUSED */ 2162int 2163nlstat(td, uap) 2164 struct thread *td; 2165 register struct nlstat_args /* { 2166 syscallarg(char *) path; 2167 syscallarg(struct nstat *) ub; 2168 } */ *uap; 2169{ 2170 int error; 2171 struct vnode *vp; 2172 struct stat sb; 2173 struct nstat nsb; 2174 struct nameidata nd; 2175 2176 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 2177 SCARG(uap, path), td); 2178 if ((error = namei(&nd)) != 0) 2179 return (error); 2180 vp = nd.ni_vp; 2181 NDFREE(&nd, NDF_ONLY_PNBUF); 2182 error = vn_stat(vp, &sb, td); 2183 vput(vp); 2184 if (error) 2185 return (error); 2186 cvtnstat(&sb, &nsb); 2187 error = copyout((caddr_t)&nsb, (caddr_t)SCARG(uap, ub), sizeof (nsb)); 2188 return (error); 2189} 2190 2191/* 2192 * Get configurable pathname variables. 2193 */ 2194#ifndef _SYS_SYSPROTO_H_ 2195struct pathconf_args { 2196 char *path; 2197 int name; 2198}; 2199#endif 2200/* ARGSUSED */ 2201int 2202pathconf(td, uap) 2203 struct thread *td; 2204 register struct pathconf_args /* { 2205 syscallarg(char *) path; 2206 syscallarg(int) name; 2207 } */ *uap; 2208{ 2209 int error; 2210 struct nameidata nd; 2211 2212 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 2213 SCARG(uap, path), td); 2214 if ((error = namei(&nd)) != 0) 2215 return (error); 2216 NDFREE(&nd, NDF_ONLY_PNBUF); 2217 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), td->td_retval); 2218 vput(nd.ni_vp); 2219 return (error); 2220} 2221 2222/* 2223 * Return target name of a symbolic link. 2224 */ 2225#ifndef _SYS_SYSPROTO_H_ 2226struct readlink_args { 2227 char *path; 2228 char *buf; 2229 int count; 2230}; 2231#endif 2232/* ARGSUSED */ 2233int 2234readlink(td, uap) 2235 struct thread *td; 2236 register struct readlink_args /* { 2237 syscallarg(char *) path; 2238 syscallarg(char *) buf; 2239 syscallarg(int) count; 2240 } */ *uap; 2241{ 2242 register struct vnode *vp; 2243 struct iovec aiov; 2244 struct uio auio; 2245 int error; 2246 struct nameidata nd; 2247 2248 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 2249 SCARG(uap, path), td); 2250 if ((error = namei(&nd)) != 0) 2251 return (error); 2252 NDFREE(&nd, NDF_ONLY_PNBUF); 2253 vp = nd.ni_vp; 2254 if (vp->v_type != VLNK) 2255 error = EINVAL; 2256 else { 2257 aiov.iov_base = SCARG(uap, buf); 2258 aiov.iov_len = SCARG(uap, count); 2259 auio.uio_iov = &aiov; 2260 auio.uio_iovcnt = 1; 2261 auio.uio_offset = 0; 2262 auio.uio_rw = UIO_READ; 2263 auio.uio_segflg = UIO_USERSPACE; 2264 auio.uio_td = td; 2265 auio.uio_resid = SCARG(uap, count); 2266 error = VOP_READLINK(vp, &auio, td->td_ucred); 2267 } 2268 vput(vp); 2269 td->td_retval[0] = SCARG(uap, count) - auio.uio_resid; 2270 return (error); 2271} 2272 2273/* 2274 * Common implementation code for chflags() and fchflags(). 2275 */ 2276static int 2277setfflags(td, vp, flags) 2278 struct thread *td; 2279 struct vnode *vp; 2280 int flags; 2281{ 2282 int error; 2283 struct mount *mp; 2284 struct vattr vattr; 2285 2286 /* 2287 * Prevent non-root users from setting flags on devices. When 2288 * a device is reused, users can retain ownership of the device 2289 * if they are allowed to set flags and programs assume that 2290 * chown can't fail when done as root. 2291 */ 2292 if (vp->v_type == VCHR || vp->v_type == VBLK) { 2293 error = suser_xxx(td->td_ucred, td->td_proc, PRISON_ROOT); 2294 if (error) 2295 return (error); 2296 } 2297 2298 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) 2299 return (error); 2300 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 2301 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 2302 VATTR_NULL(&vattr); 2303 vattr.va_flags = flags; 2304 error = VOP_SETATTR(vp, &vattr, td->td_ucred, td); 2305 VOP_UNLOCK(vp, 0, td); 2306 vn_finished_write(mp); 2307 return (error); 2308} 2309 2310/* 2311 * Change flags of a file given a path name. 2312 */ 2313#ifndef _SYS_SYSPROTO_H_ 2314struct chflags_args { 2315 char *path; 2316 int flags; 2317}; 2318#endif 2319/* ARGSUSED */ 2320int 2321chflags(td, uap) 2322 struct thread *td; 2323 register struct chflags_args /* { 2324 syscallarg(char *) path; 2325 syscallarg(int) flags; 2326 } */ *uap; 2327{ 2328 int error; 2329 struct nameidata nd; 2330 2331 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); 2332 if ((error = namei(&nd)) != 0) 2333 return (error); 2334 NDFREE(&nd, NDF_ONLY_PNBUF); 2335 error = setfflags(td, nd.ni_vp, SCARG(uap, flags)); 2336 vrele(nd.ni_vp); 2337 return error; 2338} 2339 2340/* 2341 * Change flags of a file given a file descriptor. 2342 */ 2343#ifndef _SYS_SYSPROTO_H_ 2344struct fchflags_args { 2345 int fd; 2346 int flags; 2347}; 2348#endif 2349/* ARGSUSED */ 2350int 2351fchflags(td, uap) 2352 struct thread *td; 2353 register struct fchflags_args /* { 2354 syscallarg(int) fd; 2355 syscallarg(int) flags; 2356 } */ *uap; 2357{ 2358 struct file *fp; 2359 int error; 2360 2361 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0) 2362 return (error); 2363 error = setfflags(td, (struct vnode *) fp->f_data, SCARG(uap, flags)); 2364 fdrop(fp, td); 2365 return (error); 2366} 2367 2368/* 2369 * Common implementation code for chmod(), lchmod() and fchmod(). 2370 */ 2371static int 2372setfmode(td, vp, mode) 2373 struct thread *td; 2374 struct vnode *vp; 2375 int mode; 2376{ 2377 int error; 2378 struct mount *mp; 2379 struct vattr vattr; 2380 2381 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) 2382 return (error); 2383 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 2384 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 2385 VATTR_NULL(&vattr); 2386 vattr.va_mode = mode & ALLPERMS; 2387 error = VOP_SETATTR(vp, &vattr, td->td_ucred, td); 2388 VOP_UNLOCK(vp, 0, td); 2389 vn_finished_write(mp); 2390 return error; 2391} 2392 2393/* 2394 * Change mode of a file given path name. 2395 */ 2396#ifndef _SYS_SYSPROTO_H_ 2397struct chmod_args { 2398 char *path; 2399 int mode; 2400}; 2401#endif 2402/* ARGSUSED */ 2403int 2404chmod(td, uap) 2405 struct thread *td; 2406 register struct chmod_args /* { 2407 syscallarg(char *) path; 2408 syscallarg(int) mode; 2409 } */ *uap; 2410{ 2411 int error; 2412 struct nameidata nd; 2413 2414 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); 2415 if ((error = namei(&nd)) != 0) 2416 return (error); 2417 NDFREE(&nd, NDF_ONLY_PNBUF); 2418 error = setfmode(td, nd.ni_vp, SCARG(uap, mode)); 2419 vrele(nd.ni_vp); 2420 return error; 2421} 2422 2423/* 2424 * Change mode of a file given path name (don't follow links.) 2425 */ 2426#ifndef _SYS_SYSPROTO_H_ 2427struct lchmod_args { 2428 char *path; 2429 int mode; 2430}; 2431#endif 2432/* ARGSUSED */ 2433int 2434lchmod(td, uap) 2435 struct thread *td; 2436 register struct lchmod_args /* { 2437 syscallarg(char *) path; 2438 syscallarg(int) mode; 2439 } */ *uap; 2440{ 2441 int error; 2442 struct nameidata nd; 2443 2444 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td); 2445 if ((error = namei(&nd)) != 0) 2446 return (error); 2447 NDFREE(&nd, NDF_ONLY_PNBUF); 2448 error = setfmode(td, nd.ni_vp, SCARG(uap, mode)); 2449 vrele(nd.ni_vp); 2450 return error; 2451} 2452 2453/* 2454 * Change mode of a file given a file descriptor. 2455 */ 2456#ifndef _SYS_SYSPROTO_H_ 2457struct fchmod_args { 2458 int fd; 2459 int mode; 2460}; 2461#endif 2462/* ARGSUSED */ 2463int 2464fchmod(td, uap) 2465 struct thread *td; 2466 register struct fchmod_args /* { 2467 syscallarg(int) fd; 2468 syscallarg(int) mode; 2469 } */ *uap; 2470{ 2471 struct file *fp; 2472 struct vnode *vp; 2473 int error; 2474 2475 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0) 2476 return (error); 2477 vp = (struct vnode *)fp->f_data; 2478 error = setfmode(td, (struct vnode *)fp->f_data, SCARG(uap, mode)); 2479 fdrop(fp, td); 2480 return (error); 2481} 2482 2483/* 2484 * Common implementation for chown(), lchown(), and fchown() 2485 */ 2486static int 2487setfown(td, vp, uid, gid) 2488 struct thread *td; 2489 struct vnode *vp; 2490 uid_t uid; 2491 gid_t gid; 2492{ 2493 int error; 2494 struct mount *mp; 2495 struct vattr vattr; 2496 2497 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) 2498 return (error); 2499 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 2500 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 2501 VATTR_NULL(&vattr); 2502 vattr.va_uid = uid; 2503 vattr.va_gid = gid; 2504 error = VOP_SETATTR(vp, &vattr, td->td_ucred, td); 2505 VOP_UNLOCK(vp, 0, td); 2506 vn_finished_write(mp); 2507 return error; 2508} 2509 2510/* 2511 * Set ownership given a path name. 2512 */ 2513#ifndef _SYS_SYSPROTO_H_ 2514struct chown_args { 2515 char *path; 2516 int uid; 2517 int gid; 2518}; 2519#endif 2520/* ARGSUSED */ 2521int 2522chown(td, uap) 2523 struct thread *td; 2524 register struct chown_args /* { 2525 syscallarg(char *) path; 2526 syscallarg(int) uid; 2527 syscallarg(int) gid; 2528 } */ *uap; 2529{ 2530 int error; 2531 struct nameidata nd; 2532 2533 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); 2534 if ((error = namei(&nd)) != 0) 2535 return (error); 2536 NDFREE(&nd, NDF_ONLY_PNBUF); 2537 error = setfown(td, nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid)); 2538 vrele(nd.ni_vp); 2539 return (error); 2540} 2541 2542/* 2543 * Set ownership given a path name, do not cross symlinks. 2544 */ 2545#ifndef _SYS_SYSPROTO_H_ 2546struct lchown_args { 2547 char *path; 2548 int uid; 2549 int gid; 2550}; 2551#endif 2552/* ARGSUSED */ 2553int 2554lchown(td, uap) 2555 struct thread *td; 2556 register struct lchown_args /* { 2557 syscallarg(char *) path; 2558 syscallarg(int) uid; 2559 syscallarg(int) gid; 2560 } */ *uap; 2561{ 2562 int error; 2563 struct nameidata nd; 2564 2565 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td); 2566 if ((error = namei(&nd)) != 0) 2567 return (error); 2568 NDFREE(&nd, NDF_ONLY_PNBUF); 2569 error = setfown(td, nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid)); 2570 vrele(nd.ni_vp); 2571 return (error); 2572} 2573 2574/* 2575 * Set ownership given a file descriptor. 2576 */ 2577#ifndef _SYS_SYSPROTO_H_ 2578struct fchown_args { 2579 int fd; 2580 int uid; 2581 int gid; 2582}; 2583#endif 2584/* ARGSUSED */ 2585int 2586fchown(td, uap) 2587 struct thread *td; 2588 register struct fchown_args /* { 2589 syscallarg(int) fd; 2590 syscallarg(int) uid; 2591 syscallarg(int) gid; 2592 } */ *uap; 2593{ 2594 struct file *fp; 2595 struct vnode *vp; 2596 int error; 2597 2598 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0) 2599 return (error); 2600 vp = (struct vnode *)fp->f_data; 2601 error = setfown(td, (struct vnode *)fp->f_data, 2602 SCARG(uap, uid), SCARG(uap, gid)); 2603 fdrop(fp, td); 2604 return (error); 2605} 2606 2607/* 2608 * Common implementation code for utimes(), lutimes(), and futimes(). 2609 */ 2610static int 2611getutimes(usrtvp, tsp) 2612 const struct timeval *usrtvp; 2613 struct timespec *tsp; 2614{ 2615 struct timeval tv[2]; 2616 int error; 2617 2618 if (usrtvp == NULL) { 2619 microtime(&tv[0]); 2620 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]); 2621 tsp[1] = tsp[0]; 2622 } else { 2623 if ((error = copyin(usrtvp, tv, sizeof (tv))) != 0) 2624 return (error); 2625 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]); 2626 TIMEVAL_TO_TIMESPEC(&tv[1], &tsp[1]); 2627 } 2628 return 0; 2629} 2630 2631/* 2632 * Common implementation code for utimes(), lutimes(), and futimes(). 2633 */ 2634static int 2635setutimes(td, vp, ts, nullflag) 2636 struct thread *td; 2637 struct vnode *vp; 2638 const struct timespec *ts; 2639 int nullflag; 2640{ 2641 int error; 2642 struct mount *mp; 2643 struct vattr vattr; 2644 2645 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) 2646 return (error); 2647 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 2648 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 2649 VATTR_NULL(&vattr); 2650 vattr.va_atime = ts[0]; 2651 vattr.va_mtime = ts[1]; 2652 if (nullflag) 2653 vattr.va_vaflags |= VA_UTIMES_NULL; 2654 error = VOP_SETATTR(vp, &vattr, td->td_ucred, td); 2655 VOP_UNLOCK(vp, 0, td); 2656 vn_finished_write(mp); 2657 return error; 2658} 2659 2660/* 2661 * Set the access and modification times of a file. 2662 */ 2663#ifndef _SYS_SYSPROTO_H_ 2664struct utimes_args { 2665 char *path; 2666 struct timeval *tptr; 2667}; 2668#endif 2669/* ARGSUSED */ 2670int 2671utimes(td, uap) 2672 struct thread *td; 2673 register struct utimes_args /* { 2674 syscallarg(char *) path; 2675 syscallarg(struct timeval *) tptr; 2676 } */ *uap; 2677{ 2678 struct timespec ts[2]; 2679 struct timeval *usrtvp; 2680 int error; 2681 struct nameidata nd; 2682 2683 usrtvp = SCARG(uap, tptr); 2684 if ((error = getutimes(usrtvp, ts)) != 0) 2685 return (error); 2686 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); 2687 if ((error = namei(&nd)) != 0) 2688 return (error); 2689 NDFREE(&nd, NDF_ONLY_PNBUF); 2690 error = setutimes(td, nd.ni_vp, ts, usrtvp == NULL); 2691 vrele(nd.ni_vp); 2692 return (error); 2693} 2694 2695/* 2696 * Set the access and modification times of a file. 2697 */ 2698#ifndef _SYS_SYSPROTO_H_ 2699struct lutimes_args { 2700 char *path; 2701 struct timeval *tptr; 2702}; 2703#endif 2704/* ARGSUSED */ 2705int 2706lutimes(td, uap) 2707 struct thread *td; 2708 register struct lutimes_args /* { 2709 syscallarg(char *) path; 2710 syscallarg(struct timeval *) tptr; 2711 } */ *uap; 2712{ 2713 struct timespec ts[2]; 2714 struct timeval *usrtvp; 2715 int error; 2716 struct nameidata nd; 2717 2718 usrtvp = SCARG(uap, tptr); 2719 if ((error = getutimes(usrtvp, ts)) != 0) 2720 return (error); 2721 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td); 2722 if ((error = namei(&nd)) != 0) 2723 return (error); 2724 NDFREE(&nd, NDF_ONLY_PNBUF); 2725 error = setutimes(td, nd.ni_vp, ts, usrtvp == NULL); 2726 vrele(nd.ni_vp); 2727 return (error); 2728} 2729 2730/* 2731 * Set the access and modification times of a file. 2732 */ 2733#ifndef _SYS_SYSPROTO_H_ 2734struct futimes_args { 2735 int fd; 2736 struct timeval *tptr; 2737}; 2738#endif 2739/* ARGSUSED */ 2740int 2741futimes(td, uap) 2742 struct thread *td; 2743 register struct futimes_args /* { 2744 syscallarg(int ) fd; 2745 syscallarg(struct timeval *) tptr; 2746 } */ *uap; 2747{ 2748 struct timespec ts[2]; 2749 struct file *fp; 2750 struct timeval *usrtvp; 2751 int error; 2752 2753 usrtvp = SCARG(uap, tptr); 2754 if ((error = getutimes(usrtvp, ts)) != 0) 2755 return (error); 2756 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0) 2757 return (error); 2758 error = setutimes(td, (struct vnode *)fp->f_data, ts, usrtvp == NULL); 2759 fdrop(fp, td); 2760 return (error); 2761} 2762 2763/* 2764 * Truncate a file given its path name. 2765 */ 2766#ifndef _SYS_SYSPROTO_H_ 2767struct truncate_args { 2768 char *path; 2769 int pad; 2770 off_t length; 2771}; 2772#endif 2773/* ARGSUSED */ 2774int 2775truncate(td, uap) 2776 struct thread *td; 2777 register struct truncate_args /* { 2778 syscallarg(char *) path; 2779 syscallarg(int) pad; 2780 syscallarg(off_t) length; 2781 } */ *uap; 2782{ 2783 struct mount *mp; 2784 struct vnode *vp; 2785 struct vattr vattr; 2786 int error; 2787 struct nameidata nd; 2788 2789 if (uap->length < 0) 2790 return(EINVAL); 2791 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); 2792 if ((error = namei(&nd)) != 0) 2793 return (error); 2794 vp = nd.ni_vp; 2795 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) { 2796 vrele(vp); 2797 return (error); 2798 } 2799 NDFREE(&nd, NDF_ONLY_PNBUF); 2800 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 2801 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 2802 if (vp->v_type == VDIR) 2803 error = EISDIR; 2804 else if ((error = vn_writechk(vp)) == 0 && 2805 (error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td)) == 0) { 2806 VATTR_NULL(&vattr); 2807 vattr.va_size = SCARG(uap, length); 2808 error = VOP_SETATTR(vp, &vattr, td->td_ucred, td); 2809 } 2810 vput(vp); 2811 vn_finished_write(mp); 2812 return (error); 2813} 2814 2815/* 2816 * Truncate a file given a file descriptor. 2817 */ 2818#ifndef _SYS_SYSPROTO_H_ 2819struct ftruncate_args { 2820 int fd; 2821 int pad; 2822 off_t length; 2823}; 2824#endif 2825/* ARGSUSED */ 2826int 2827ftruncate(td, uap) 2828 struct thread *td; 2829 register struct ftruncate_args /* { 2830 syscallarg(int) fd; 2831 syscallarg(int) pad; 2832 syscallarg(off_t) length; 2833 } */ *uap; 2834{ 2835 struct mount *mp; 2836 struct vattr vattr; 2837 struct vnode *vp; 2838 struct file *fp; 2839 int error; 2840 2841 if (uap->length < 0) 2842 return(EINVAL); 2843 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0) 2844 return (error); 2845 if ((fp->f_flag & FWRITE) == 0) { 2846 fdrop(fp, td); 2847 return (EINVAL); 2848 } 2849 vp = (struct vnode *)fp->f_data; 2850 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) { 2851 fdrop(fp, td); 2852 return (error); 2853 } 2854 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 2855 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 2856 if (vp->v_type == VDIR) 2857 error = EISDIR; 2858 else if ((error = vn_writechk(vp)) == 0) { 2859 VATTR_NULL(&vattr); 2860 vattr.va_size = SCARG(uap, length); 2861 error = VOP_SETATTR(vp, &vattr, fp->f_cred, td); 2862 } 2863 VOP_UNLOCK(vp, 0, td); 2864 vn_finished_write(mp); 2865 fdrop(fp, td); 2866 return (error); 2867} 2868 2869#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 2870/* 2871 * Truncate a file given its path name. 2872 */ 2873#ifndef _SYS_SYSPROTO_H_ 2874struct otruncate_args { 2875 char *path; 2876 long length; 2877}; 2878#endif 2879/* ARGSUSED */ 2880int 2881otruncate(td, uap) 2882 struct thread *td; 2883 register struct otruncate_args /* { 2884 syscallarg(char *) path; 2885 syscallarg(long) length; 2886 } */ *uap; 2887{ 2888 struct truncate_args /* { 2889 syscallarg(char *) path; 2890 syscallarg(int) pad; 2891 syscallarg(off_t) length; 2892 } */ nuap; 2893 2894 SCARG(&nuap, path) = SCARG(uap, path); 2895 SCARG(&nuap, length) = SCARG(uap, length); 2896 return (truncate(td, &nuap)); 2897} 2898 2899/* 2900 * Truncate a file given a file descriptor. 2901 */ 2902#ifndef _SYS_SYSPROTO_H_ 2903struct oftruncate_args { 2904 int fd; 2905 long length; 2906}; 2907#endif 2908/* ARGSUSED */ 2909int 2910oftruncate(td, uap) 2911 struct thread *td; 2912 register struct oftruncate_args /* { 2913 syscallarg(int) fd; 2914 syscallarg(long) length; 2915 } */ *uap; 2916{ 2917 struct ftruncate_args /* { 2918 syscallarg(int) fd; 2919 syscallarg(int) pad; 2920 syscallarg(off_t) length; 2921 } */ nuap; 2922 2923 SCARG(&nuap, fd) = SCARG(uap, fd); 2924 SCARG(&nuap, length) = SCARG(uap, length); 2925 return (ftruncate(td, &nuap)); 2926} 2927#endif /* COMPAT_43 || COMPAT_SUNOS */ 2928 2929/* 2930 * Sync an open file. 2931 */ 2932#ifndef _SYS_SYSPROTO_H_ 2933struct fsync_args { 2934 int fd; 2935}; 2936#endif 2937/* ARGSUSED */ 2938int 2939fsync(td, uap) 2940 struct thread *td; 2941 struct fsync_args /* { 2942 syscallarg(int) fd; 2943 } */ *uap; 2944{ 2945 struct vnode *vp; 2946 struct mount *mp; 2947 struct file *fp; 2948 vm_object_t obj; 2949 int error; 2950 2951 GIANT_REQUIRED; 2952 2953 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0) 2954 return (error); 2955 vp = (struct vnode *)fp->f_data; 2956 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) { 2957 fdrop(fp, td); 2958 return (error); 2959 } 2960 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 2961 if (VOP_GETVOBJECT(vp, &obj) == 0) { 2962 vm_object_page_clean(obj, 0, 0, 0); 2963 } 2964 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, td); 2965#ifdef SOFTUPDATES 2966 if (error == 0 && vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP)) 2967 error = softdep_fsync(vp); 2968#endif 2969 2970 VOP_UNLOCK(vp, 0, td); 2971 vn_finished_write(mp); 2972 fdrop(fp, td); 2973 return (error); 2974} 2975 2976/* 2977 * Rename files. Source and destination must either both be directories, 2978 * or both not be directories. If target is a directory, it must be empty. 2979 */ 2980#ifndef _SYS_SYSPROTO_H_ 2981struct rename_args { 2982 char *from; 2983 char *to; 2984}; 2985#endif 2986/* ARGSUSED */ 2987int 2988rename(td, uap) 2989 struct thread *td; 2990 register struct rename_args /* { 2991 syscallarg(char *) from; 2992 syscallarg(char *) to; 2993 } */ *uap; 2994{ 2995 struct mount *mp; 2996 struct vnode *tvp, *fvp, *tdvp; 2997 struct nameidata fromnd, tond; 2998 int error; 2999 3000 bwillwrite(); 3001 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 3002 SCARG(uap, from), td); 3003 if ((error = namei(&fromnd)) != 0) 3004 return (error); 3005 fvp = fromnd.ni_vp; 3006 if ((error = vn_start_write(fvp, &mp, V_WAIT | PCATCH)) != 0) { 3007 NDFREE(&fromnd, NDF_ONLY_PNBUF); 3008 vrele(fromnd.ni_dvp); 3009 vrele(fvp); 3010 goto out1; 3011 } 3012 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | NOOBJ, 3013 UIO_USERSPACE, SCARG(uap, to), td); 3014 if (fromnd.ni_vp->v_type == VDIR) 3015 tond.ni_cnd.cn_flags |= WILLBEDIR; 3016 if ((error = namei(&tond)) != 0) { 3017 /* Translate error code for rename("dir1", "dir2/."). */ 3018 if (error == EISDIR && fvp->v_type == VDIR) 3019 error = EINVAL; 3020 NDFREE(&fromnd, NDF_ONLY_PNBUF); 3021 vrele(fromnd.ni_dvp); 3022 vrele(fvp); 3023 goto out1; 3024 } 3025 tdvp = tond.ni_dvp; 3026 tvp = tond.ni_vp; 3027 if (tvp != NULL) { 3028 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 3029 error = ENOTDIR; 3030 goto out; 3031 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 3032 error = EISDIR; 3033 goto out; 3034 } 3035 } 3036 if (fvp == tdvp) 3037 error = EINVAL; 3038 /* 3039 * If source is the same as the destination (that is the 3040 * same inode number with the same name in the same directory), 3041 * then there is nothing to do. 3042 */ 3043 if (fvp == tvp && fromnd.ni_dvp == tdvp && 3044 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 3045 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 3046 fromnd.ni_cnd.cn_namelen)) 3047 error = -1; 3048out: 3049 if (!error) { 3050 VOP_LEASE(tdvp, td, td->td_ucred, LEASE_WRITE); 3051 if (fromnd.ni_dvp != tdvp) { 3052 VOP_LEASE(fromnd.ni_dvp, td, td->td_ucred, LEASE_WRITE); 3053 } 3054 if (tvp) { 3055 VOP_LEASE(tvp, td, td->td_ucred, LEASE_WRITE); 3056 } 3057 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 3058 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 3059 NDFREE(&fromnd, NDF_ONLY_PNBUF); 3060 NDFREE(&tond, NDF_ONLY_PNBUF); 3061 } else { 3062 NDFREE(&fromnd, NDF_ONLY_PNBUF); 3063 NDFREE(&tond, NDF_ONLY_PNBUF); 3064 if (tdvp == tvp) 3065 vrele(tdvp); 3066 else 3067 vput(tdvp); 3068 if (tvp) 3069 vput(tvp); 3070 vrele(fromnd.ni_dvp); 3071 vrele(fvp); 3072 } 3073 vrele(tond.ni_startdir); 3074 vn_finished_write(mp); 3075 ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename"); 3076 ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename"); 3077 ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename"); 3078 ASSERT_VOP_UNLOCKED(tond.ni_vp, "rename"); 3079out1: 3080 if (fromnd.ni_startdir) 3081 vrele(fromnd.ni_startdir); 3082 if (error == -1) 3083 return (0); 3084 return (error); 3085} 3086 3087/* 3088 * Make a directory file. 3089 */ 3090#ifndef _SYS_SYSPROTO_H_ 3091struct mkdir_args { 3092 char *path; 3093 int mode; 3094}; 3095#endif 3096/* ARGSUSED */ 3097int 3098mkdir(td, uap) 3099 struct thread *td; 3100 register struct mkdir_args /* { 3101 syscallarg(char *) path; 3102 syscallarg(int) mode; 3103 } */ *uap; 3104{ 3105 3106 return vn_mkdir(uap->path, uap->mode, UIO_USERSPACE, td); 3107} 3108 3109int 3110vn_mkdir(path, mode, segflg, td) 3111 char *path; 3112 int mode; 3113 enum uio_seg segflg; 3114 struct thread *td; 3115{ 3116 struct mount *mp; 3117 struct vnode *vp; 3118 struct vattr vattr; 3119 int error; 3120 struct nameidata nd; 3121 3122restart: 3123 bwillwrite(); 3124 NDINIT(&nd, CREATE, LOCKPARENT, segflg, path, td); 3125 nd.ni_cnd.cn_flags |= WILLBEDIR; 3126 if ((error = namei(&nd)) != 0) 3127 return (error); 3128 vp = nd.ni_vp; 3129 if (vp != NULL) { 3130 NDFREE(&nd, NDF_ONLY_PNBUF); 3131 vrele(vp); 3132 vput(nd.ni_dvp); 3133 return (EEXIST); 3134 } 3135 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { 3136 NDFREE(&nd, NDF_ONLY_PNBUF); 3137 vput(nd.ni_dvp); 3138 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) 3139 return (error); 3140 goto restart; 3141 } 3142 VATTR_NULL(&vattr); 3143 vattr.va_type = VDIR; 3144 FILEDESC_LOCK(td->td_proc->p_fd); 3145 vattr.va_mode = (mode & ACCESSPERMS) &~ td->td_proc->p_fd->fd_cmask; 3146 FILEDESC_UNLOCK(td->td_proc->p_fd); 3147 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE); 3148 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 3149 NDFREE(&nd, NDF_ONLY_PNBUF); 3150 vput(nd.ni_dvp); 3151 if (!error) 3152 vput(nd.ni_vp); 3153 vn_finished_write(mp); 3154 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir"); 3155 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir"); 3156 return (error); 3157} 3158 3159/* 3160 * Remove a directory file. 3161 */ 3162#ifndef _SYS_SYSPROTO_H_ 3163struct rmdir_args { 3164 char *path; 3165}; 3166#endif 3167/* ARGSUSED */ 3168int 3169rmdir(td, uap) 3170 struct thread *td; 3171 struct rmdir_args /* { 3172 syscallarg(char *) path; 3173 } */ *uap; 3174{ 3175 struct mount *mp; 3176 struct vnode *vp; 3177 int error; 3178 struct nameidata nd; 3179 3180restart: 3181 bwillwrite(); 3182 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 3183 SCARG(uap, path), td); 3184 if ((error = namei(&nd)) != 0) 3185 return (error); 3186 vp = nd.ni_vp; 3187 if (vp->v_type != VDIR) { 3188 error = ENOTDIR; 3189 goto out; 3190 } 3191 /* 3192 * No rmdir "." please. 3193 */ 3194 if (nd.ni_dvp == vp) { 3195 error = EINVAL; 3196 goto out; 3197 } 3198 /* 3199 * The root of a mounted filesystem cannot be deleted. 3200 */ 3201 if (vp->v_flag & VROOT) { 3202 error = EBUSY; 3203 goto out; 3204 } 3205 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { 3206 NDFREE(&nd, NDF_ONLY_PNBUF); 3207 if (nd.ni_dvp == vp) 3208 vrele(nd.ni_dvp); 3209 else 3210 vput(nd.ni_dvp); 3211 vput(vp); 3212 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) 3213 return (error); 3214 goto restart; 3215 } 3216 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE); 3217 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 3218 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 3219 vn_finished_write(mp); 3220out: 3221 NDFREE(&nd, NDF_ONLY_PNBUF); 3222 if (nd.ni_dvp == vp) 3223 vrele(nd.ni_dvp); 3224 else 3225 vput(nd.ni_dvp); 3226 vput(vp); 3227 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir"); 3228 ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir"); 3229 return (error); 3230} 3231 3232#ifdef COMPAT_43 3233/* 3234 * Read a block of directory entries in a file system independent format. 3235 */ 3236#ifndef _SYS_SYSPROTO_H_ 3237struct ogetdirentries_args { 3238 int fd; 3239 char *buf; 3240 u_int count; 3241 long *basep; 3242}; 3243#endif 3244int 3245ogetdirentries(td, uap) 3246 struct thread *td; 3247 register struct ogetdirentries_args /* { 3248 syscallarg(int) fd; 3249 syscallarg(char *) buf; 3250 syscallarg(u_int) count; 3251 syscallarg(long *) basep; 3252 } */ *uap; 3253{ 3254 struct vnode *vp; 3255 struct file *fp; 3256 struct uio auio, kuio; 3257 struct iovec aiov, kiov; 3258 struct dirent *dp, *edp; 3259 caddr_t dirbuf; 3260 int error, eofflag, readcnt; 3261 long loff; 3262 3263 /* XXX arbitrary sanity limit on `count'. */ 3264 if (SCARG(uap, count) > 64 * 1024) 3265 return (EINVAL); 3266 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0) 3267 return (error); 3268 if ((fp->f_flag & FREAD) == 0) { 3269 fdrop(fp, td); 3270 return (EBADF); 3271 } 3272 vp = (struct vnode *)fp->f_data; 3273unionread: 3274 if (vp->v_type != VDIR) { 3275 fdrop(fp, td); 3276 return (EINVAL); 3277 } 3278 aiov.iov_base = SCARG(uap, buf); 3279 aiov.iov_len = SCARG(uap, count); 3280 auio.uio_iov = &aiov; 3281 auio.uio_iovcnt = 1; 3282 auio.uio_rw = UIO_READ; 3283 auio.uio_segflg = UIO_USERSPACE; 3284 auio.uio_td = td; 3285 auio.uio_resid = SCARG(uap, count); 3286 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 3287 loff = auio.uio_offset = fp->f_offset; 3288# if (BYTE_ORDER != LITTLE_ENDIAN) 3289 if (vp->v_mount->mnt_maxsymlinklen <= 0) { 3290 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 3291 NULL, NULL); 3292 fp->f_offset = auio.uio_offset; 3293 } else 3294# endif 3295 { 3296 kuio = auio; 3297 kuio.uio_iov = &kiov; 3298 kuio.uio_segflg = UIO_SYSSPACE; 3299 kiov.iov_len = SCARG(uap, count); 3300 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); 3301 kiov.iov_base = dirbuf; 3302 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 3303 NULL, NULL); 3304 fp->f_offset = kuio.uio_offset; 3305 if (error == 0) { 3306 readcnt = SCARG(uap, count) - kuio.uio_resid; 3307 edp = (struct dirent *)&dirbuf[readcnt]; 3308 for (dp = (struct dirent *)dirbuf; dp < edp; ) { 3309# if (BYTE_ORDER == LITTLE_ENDIAN) 3310 /* 3311 * The expected low byte of 3312 * dp->d_namlen is our dp->d_type. 3313 * The high MBZ byte of dp->d_namlen 3314 * is our dp->d_namlen. 3315 */ 3316 dp->d_type = dp->d_namlen; 3317 dp->d_namlen = 0; 3318# else 3319 /* 3320 * The dp->d_type is the high byte 3321 * of the expected dp->d_namlen, 3322 * so must be zero'ed. 3323 */ 3324 dp->d_type = 0; 3325# endif 3326 if (dp->d_reclen > 0) { 3327 dp = (struct dirent *) 3328 ((char *)dp + dp->d_reclen); 3329 } else { 3330 error = EIO; 3331 break; 3332 } 3333 } 3334 if (dp >= edp) 3335 error = uiomove(dirbuf, readcnt, &auio); 3336 } 3337 FREE(dirbuf, M_TEMP); 3338 } 3339 VOP_UNLOCK(vp, 0, td); 3340 if (error) { 3341 fdrop(fp, td); 3342 return (error); 3343 } 3344 if (SCARG(uap, count) == auio.uio_resid) { 3345 if (union_dircheckp) { 3346 error = union_dircheckp(td, &vp, fp); 3347 if (error == -1) 3348 goto unionread; 3349 if (error) { 3350 fdrop(fp, td); 3351 return (error); 3352 } 3353 } 3354 if ((vp->v_flag & VROOT) && 3355 (vp->v_mount->mnt_flag & MNT_UNION)) { 3356 struct vnode *tvp = vp; 3357 vp = vp->v_mount->mnt_vnodecovered; 3358 VREF(vp); 3359 fp->f_data = (caddr_t) vp; 3360 fp->f_offset = 0; 3361 vrele(tvp); 3362 goto unionread; 3363 } 3364 } 3365 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 3366 sizeof(long)); 3367 fdrop(fp, td); 3368 td->td_retval[0] = SCARG(uap, count) - auio.uio_resid; 3369 return (error); 3370} 3371#endif /* COMPAT_43 */ 3372 3373/* 3374 * Read a block of directory entries in a file system independent format. 3375 */ 3376#ifndef _SYS_SYSPROTO_H_ 3377struct getdirentries_args { 3378 int fd; 3379 char *buf; 3380 u_int count; 3381 long *basep; 3382}; 3383#endif 3384int 3385getdirentries(td, uap) 3386 struct thread *td; 3387 register struct getdirentries_args /* { 3388 syscallarg(int) fd; 3389 syscallarg(char *) buf; 3390 syscallarg(u_int) count; 3391 syscallarg(long *) basep; 3392 } */ *uap; 3393{ 3394 struct vnode *vp; 3395 struct file *fp; 3396 struct uio auio; 3397 struct iovec aiov; 3398 long loff; 3399 int error, eofflag; 3400 3401 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0) 3402 return (error); 3403 if ((fp->f_flag & FREAD) == 0) { 3404 fdrop(fp, td); 3405 return (EBADF); 3406 } 3407 vp = (struct vnode *)fp->f_data; 3408unionread: 3409 if (vp->v_type != VDIR) { 3410 fdrop(fp, td); 3411 return (EINVAL); 3412 } 3413 aiov.iov_base = SCARG(uap, buf); 3414 aiov.iov_len = SCARG(uap, count); 3415 auio.uio_iov = &aiov; 3416 auio.uio_iovcnt = 1; 3417 auio.uio_rw = UIO_READ; 3418 auio.uio_segflg = UIO_USERSPACE; 3419 auio.uio_td = td; 3420 auio.uio_resid = SCARG(uap, count); 3421 /* vn_lock(vp, LK_SHARED | LK_RETRY, td); */ 3422 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 3423 loff = auio.uio_offset = fp->f_offset; 3424 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL); 3425 fp->f_offset = auio.uio_offset; 3426 VOP_UNLOCK(vp, 0, td); 3427 if (error) { 3428 fdrop(fp, td); 3429 return (error); 3430 } 3431 if (SCARG(uap, count) == auio.uio_resid) { 3432 if (union_dircheckp) { 3433 error = union_dircheckp(td, &vp, fp); 3434 if (error == -1) 3435 goto unionread; 3436 if (error) { 3437 fdrop(fp, td); 3438 return (error); 3439 } 3440 } 3441 if ((vp->v_flag & VROOT) && 3442 (vp->v_mount->mnt_flag & MNT_UNION)) { 3443 struct vnode *tvp = vp; 3444 vp = vp->v_mount->mnt_vnodecovered; 3445 VREF(vp); 3446 fp->f_data = (caddr_t) vp; 3447 fp->f_offset = 0; 3448 vrele(tvp); 3449 goto unionread; 3450 } 3451 } 3452 if (SCARG(uap, basep) != NULL) { 3453 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 3454 sizeof(long)); 3455 } 3456 td->td_retval[0] = SCARG(uap, count) - auio.uio_resid; 3457 fdrop(fp, td); 3458 return (error); 3459} 3460#ifndef _SYS_SYSPROTO_H_ 3461struct getdents_args { 3462 int fd; 3463 char *buf; 3464 size_t count; 3465}; 3466#endif 3467int 3468getdents(td, uap) 3469 struct thread *td; 3470 register struct getdents_args /* { 3471 syscallarg(int) fd; 3472 syscallarg(char *) buf; 3473 syscallarg(u_int) count; 3474 } */ *uap; 3475{ 3476 struct getdirentries_args ap; 3477 ap.fd = uap->fd; 3478 ap.buf = uap->buf; 3479 ap.count = uap->count; 3480 ap.basep = NULL; 3481 return getdirentries(td, &ap); 3482} 3483 3484/* 3485 * Set the mode mask for creation of filesystem nodes. 3486 * 3487 * MP SAFE 3488 */ 3489#ifndef _SYS_SYSPROTO_H_ 3490struct umask_args { 3491 int newmask; 3492}; 3493#endif 3494int 3495umask(td, uap) 3496 struct thread *td; 3497 struct umask_args /* { 3498 syscallarg(int) newmask; 3499 } */ *uap; 3500{ 3501 register struct filedesc *fdp; 3502 3503 FILEDESC_LOCK(td->td_proc->p_fd); 3504 fdp = td->td_proc->p_fd; 3505 td->td_retval[0] = fdp->fd_cmask; 3506 fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS; 3507 FILEDESC_UNLOCK(td->td_proc->p_fd); 3508 return (0); 3509} 3510 3511/* 3512 * Void all references to file by ripping underlying filesystem 3513 * away from vnode. 3514 */ 3515#ifndef _SYS_SYSPROTO_H_ 3516struct revoke_args { 3517 char *path; 3518}; 3519#endif 3520/* ARGSUSED */ 3521int 3522revoke(td, uap) 3523 struct thread *td; 3524 register struct revoke_args /* { 3525 syscallarg(char *) path; 3526 } */ *uap; 3527{ 3528 struct mount *mp; 3529 struct vnode *vp; 3530 struct vattr vattr; 3531 int error; 3532 struct nameidata nd; 3533 3534 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, SCARG(uap, path), 3535 td); 3536 if ((error = namei(&nd)) != 0) 3537 return (error); 3538 vp = nd.ni_vp; 3539 NDFREE(&nd, NDF_ONLY_PNBUF); 3540 if (vp->v_type != VCHR) { 3541 vput(vp); 3542 return (EINVAL); 3543 } 3544 error = VOP_GETATTR(vp, &vattr, td->td_ucred, td); 3545 if (error) { 3546 vput(vp); 3547 return (error); 3548 } 3549 VOP_UNLOCK(vp, 0, td); 3550 if (td->td_ucred->cr_uid != vattr.va_uid) { 3551 error = suser_xxx(0, td->td_proc, PRISON_ROOT); 3552 if (error) 3553 goto out; 3554 } 3555 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) 3556 goto out; 3557 if (vcount(vp) > 1) 3558 VOP_REVOKE(vp, REVOKEALL); 3559 vn_finished_write(mp); 3560out: 3561 vrele(vp); 3562 return (error); 3563} 3564 3565/* 3566 * Convert a user file descriptor to a kernel file entry. 3567 * The file entry is locked upon returning. 3568 */ 3569int 3570getvnode(fdp, fd, fpp) 3571 struct filedesc *fdp; 3572 int fd; 3573 struct file **fpp; 3574{ 3575 int error; 3576 struct file *fp; 3577 3578 fp = NULL; 3579 if (fdp == NULL) 3580 error = EBADF; 3581 else { 3582 FILEDESC_LOCK(fdp); 3583 if ((u_int)fd >= fdp->fd_nfiles || 3584 (fp = fdp->fd_ofiles[fd]) == NULL) 3585 error = EBADF; 3586 else if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO) { 3587 fp = NULL; 3588 error = EINVAL; 3589 } else { 3590 fhold(fp); 3591 error = 0; 3592 } 3593 FILEDESC_UNLOCK(fdp); 3594 } 3595 *fpp = fp; 3596 return (error); 3597} 3598/* 3599 * Get (NFS) file handle 3600 */ 3601#ifndef _SYS_SYSPROTO_H_ 3602struct getfh_args { 3603 char *fname; 3604 fhandle_t *fhp; 3605}; 3606#endif 3607int 3608getfh(td, uap) 3609 struct thread *td; 3610 register struct getfh_args *uap; 3611{ 3612 struct nameidata nd; 3613 fhandle_t fh; 3614 register struct vnode *vp; 3615 int error; 3616 3617 /* 3618 * Must be super user 3619 */ 3620 error = suser_td(td); 3621 if (error) 3622 return (error); 3623 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, td); 3624 error = namei(&nd); 3625 if (error) 3626 return (error); 3627 NDFREE(&nd, NDF_ONLY_PNBUF); 3628 vp = nd.ni_vp; 3629 bzero(&fh, sizeof(fh)); 3630 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 3631 error = VFS_VPTOFH(vp, &fh.fh_fid); 3632 vput(vp); 3633 if (error) 3634 return (error); 3635 error = copyout(&fh, uap->fhp, sizeof (fh)); 3636 return (error); 3637} 3638 3639/* 3640 * syscall for the rpc.lockd to use to translate a NFS file handle into 3641 * an open descriptor. 3642 * 3643 * warning: do not remove the suser() call or this becomes one giant 3644 * security hole. 3645 */ 3646#ifndef _SYS_SYSPROTO_H_ 3647struct fhopen_args { 3648 const struct fhandle *u_fhp; 3649 int flags; 3650}; 3651#endif 3652int 3653fhopen(td, uap) 3654 struct thread *td; 3655 struct fhopen_args /* { 3656 syscallarg(const struct fhandle *) u_fhp; 3657 syscallarg(int) flags; 3658 } */ *uap; 3659{ 3660 struct proc *p = td->td_proc; 3661 struct mount *mp; 3662 struct vnode *vp; 3663 struct fhandle fhp; 3664 struct vattr vat; 3665 struct vattr *vap = &vat; 3666 struct flock lf; 3667 struct file *fp; 3668 register struct filedesc *fdp = p->p_fd; 3669 int fmode, mode, error, type; 3670 struct file *nfp; 3671 int indx; 3672 3673 /* 3674 * Must be super user 3675 */ 3676 error = suser_td(td); 3677 if (error) 3678 return (error); 3679 3680 fmode = FFLAGS(SCARG(uap, flags)); 3681 /* why not allow a non-read/write open for our lockd? */ 3682 if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT)) 3683 return (EINVAL); 3684 error = copyin(SCARG(uap,u_fhp), &fhp, sizeof(fhp)); 3685 if (error) 3686 return(error); 3687 /* find the mount point */ 3688 mp = vfs_getvfs(&fhp.fh_fsid); 3689 if (mp == NULL) 3690 return (ESTALE); 3691 /* now give me my vnode, it gets returned to me locked */ 3692 error = VFS_FHTOVP(mp, &fhp.fh_fid, &vp); 3693 if (error) 3694 return (error); 3695 /* 3696 * from now on we have to make sure not 3697 * to forget about the vnode 3698 * any error that causes an abort must vput(vp) 3699 * just set error = err and 'goto bad;'. 3700 */ 3701 3702 /* 3703 * from vn_open 3704 */ 3705 if (vp->v_type == VLNK) { 3706 error = EMLINK; 3707 goto bad; 3708 } 3709 if (vp->v_type == VSOCK) { 3710 error = EOPNOTSUPP; 3711 goto bad; 3712 } 3713 mode = 0; 3714 if (fmode & (FWRITE | O_TRUNC)) { 3715 if (vp->v_type == VDIR) { 3716 error = EISDIR; 3717 goto bad; 3718 } 3719 error = vn_writechk(vp); 3720 if (error) 3721 goto bad; 3722 mode |= VWRITE; 3723 } 3724 if (fmode & FREAD) 3725 mode |= VREAD; 3726 if (mode) { 3727 error = VOP_ACCESS(vp, mode, td->td_ucred, td); 3728 if (error) 3729 goto bad; 3730 } 3731 if (fmode & O_TRUNC) { 3732 VOP_UNLOCK(vp, 0, td); /* XXX */ 3733 if ((error = vn_start_write(NULL, &mp, V_WAIT | PCATCH)) != 0) { 3734 vrele(vp); 3735 return (error); 3736 } 3737 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 3738 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); /* XXX */ 3739 VATTR_NULL(vap); 3740 vap->va_size = 0; 3741 error = VOP_SETATTR(vp, vap, td->td_ucred, td); 3742 vn_finished_write(mp); 3743 if (error) 3744 goto bad; 3745 } 3746 error = VOP_OPEN(vp, fmode, td->td_ucred, td); 3747 if (error) 3748 goto bad; 3749 /* 3750 * Make sure that a VM object is created for VMIO support. 3751 */ 3752 if (vn_canvmio(vp) == TRUE) { 3753 if ((error = vfs_object_create(vp, td, td->td_ucred)) != 0) 3754 goto bad; 3755 } 3756 if (fmode & FWRITE) 3757 vp->v_writecount++; 3758 3759 /* 3760 * end of vn_open code 3761 */ 3762 3763 if ((error = falloc(td, &nfp, &indx)) != 0) { 3764 if (fmode & FWRITE) 3765 vp->v_writecount--; 3766 goto bad; 3767 } 3768 fp = nfp; 3769 3770 /* 3771 * Hold an extra reference to avoid having fp ripped out 3772 * from under us while we block in the lock op 3773 */ 3774 fhold(fp); 3775 nfp->f_data = (caddr_t)vp; 3776 nfp->f_flag = fmode & FMASK; 3777 nfp->f_ops = &vnops; 3778 nfp->f_type = DTYPE_VNODE; 3779 if (fmode & (O_EXLOCK | O_SHLOCK)) { 3780 lf.l_whence = SEEK_SET; 3781 lf.l_start = 0; 3782 lf.l_len = 0; 3783 if (fmode & O_EXLOCK) 3784 lf.l_type = F_WRLCK; 3785 else 3786 lf.l_type = F_RDLCK; 3787 type = F_FLOCK; 3788 if ((fmode & FNONBLOCK) == 0) 3789 type |= F_WAIT; 3790 VOP_UNLOCK(vp, 0, td); 3791 if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0) { 3792 /* 3793 * The lock request failed. Normally close the 3794 * descriptor but handle the case where someone might 3795 * have dup()d or close()d it when we weren't looking. 3796 */ 3797 FILEDESC_LOCK(fdp); 3798 if (fdp->fd_ofiles[indx] == fp) { 3799 fdp->fd_ofiles[indx] = NULL; 3800 FILEDESC_UNLOCK(fdp); 3801 fdrop(fp, td); 3802 } else 3803 FILEDESC_UNLOCK(fdp); 3804 /* 3805 * release our private reference 3806 */ 3807 fdrop(fp, td); 3808 return(error); 3809 } 3810 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 3811 fp->f_flag |= FHASLOCK; 3812 } 3813 if ((vp->v_type == VREG) && (VOP_GETVOBJECT(vp, NULL) != 0)) 3814 vfs_object_create(vp, td, td->td_ucred); 3815 3816 VOP_UNLOCK(vp, 0, td); 3817 fdrop(fp, td); 3818 td->td_retval[0] = indx; 3819 return (0); 3820 3821bad: 3822 vput(vp); 3823 return (error); 3824} 3825 3826/* 3827 * Stat an (NFS) file handle. 3828 */ 3829#ifndef _SYS_SYSPROTO_H_ 3830struct fhstat_args { 3831 struct fhandle *u_fhp; 3832 struct stat *sb; 3833}; 3834#endif 3835int 3836fhstat(td, uap) 3837 struct thread *td; 3838 register struct fhstat_args /* { 3839 syscallarg(struct fhandle *) u_fhp; 3840 syscallarg(struct stat *) sb; 3841 } */ *uap; 3842{ 3843 struct stat sb; 3844 fhandle_t fh; 3845 struct mount *mp; 3846 struct vnode *vp; 3847 int error; 3848 3849 /* 3850 * Must be super user 3851 */ 3852 error = suser_td(td); 3853 if (error) 3854 return (error); 3855 3856 error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t)); 3857 if (error) 3858 return (error); 3859 3860 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) 3861 return (ESTALE); 3862 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) 3863 return (error); 3864 error = vn_stat(vp, &sb, td); 3865 vput(vp); 3866 if (error) 3867 return (error); 3868 error = copyout(&sb, SCARG(uap, sb), sizeof(sb)); 3869 return (error); 3870} 3871 3872/* 3873 * Implement fstatfs() for (NFS) file handles. 3874 */ 3875#ifndef _SYS_SYSPROTO_H_ 3876struct fhstatfs_args { 3877 struct fhandle *u_fhp; 3878 struct statfs *buf; 3879}; 3880#endif 3881int 3882fhstatfs(td, uap) 3883 struct thread *td; 3884 struct fhstatfs_args /* { 3885 syscallarg(struct fhandle) *u_fhp; 3886 syscallarg(struct statfs) *buf; 3887 } */ *uap; 3888{ 3889 struct statfs *sp; 3890 struct mount *mp; 3891 struct vnode *vp; 3892 struct statfs sb; 3893 fhandle_t fh; 3894 int error; 3895 3896 /* 3897 * Must be super user 3898 */ 3899 error = suser_td(td); 3900 if (error) 3901 return (error); 3902 3903 if ((error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t))) != 0) 3904 return (error); 3905 3906 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) 3907 return (ESTALE); 3908 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) 3909 return (error); 3910 mp = vp->v_mount; 3911 sp = &mp->mnt_stat; 3912 vput(vp); 3913 if ((error = VFS_STATFS(mp, sp, td)) != 0) 3914 return (error); 3915 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 3916 if (suser_xxx(td->td_ucred, 0, 0)) { 3917 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 3918 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 3919 sp = &sb; 3920 } 3921 return (copyout(sp, SCARG(uap, buf), sizeof(*sp))); 3922} 3923 3924/* 3925 * Syscall to push extended attribute configuration information into the 3926 * VFS. Accepts a path, which it converts to a mountpoint, as well as 3927 * a command (int cmd), and attribute name and misc data. For now, the 3928 * attribute name is left in userspace for consumption by the VFS_op. 3929 * It will probably be changed to be copied into sysspace by the 3930 * syscall in the future, once issues with various consumers of the 3931 * attribute code have raised their hands. 3932 * 3933 * Currently this is used only by UFS Extended Attributes. 3934 */ 3935int 3936extattrctl(td, uap) 3937 struct thread *td; 3938 struct extattrctl_args *uap; 3939{ 3940 struct vnode *filename_vp; 3941 struct nameidata nd; 3942 struct mount *mp, *mp_writable; 3943 char attrname[EXTATTR_MAXNAMELEN]; 3944 int error; 3945 3946 /* 3947 * SCARG(uap, attrname) not always defined. We check again later 3948 * when we invoke the VFS call so as to pass in NULL there if needed. 3949 */ 3950 if (SCARG(uap, attrname) != NULL) { 3951 error = copyinstr(SCARG(uap, attrname), attrname, 3952 EXTATTR_MAXNAMELEN, NULL); 3953 if (error) 3954 return (error); 3955 } 3956 3957 /* 3958 * SCARG(uap, filename) not always defined. If it is, grab 3959 * a vnode lock, which VFS_EXTATTRCTL() will later release. 3960 */ 3961 filename_vp = NULL; 3962 if (SCARG(uap, filename) != NULL) { 3963 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 3964 SCARG(uap, filename), td); 3965 if ((error = namei(&nd)) != 0) 3966 return (error); 3967 filename_vp = nd.ni_vp; 3968 NDFREE(&nd, NDF_NO_VP_RELE | NDF_NO_VP_UNLOCK); 3969 } 3970 3971 /* SCARG(uap, path) always defined. */ 3972 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); 3973 if ((error = namei(&nd)) != 0) { 3974 if (filename_vp != NULL) 3975 vput(filename_vp); 3976 return (error); 3977 } 3978 mp = nd.ni_vp->v_mount; 3979 error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH); 3980 NDFREE(&nd, 0); 3981 if (error) { 3982 if (filename_vp != NULL) 3983 vput(filename_vp); 3984 return (error); 3985 } 3986 3987 if (SCARG(uap, attrname) != NULL) { 3988 error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp, 3989 SCARG(uap, attrnamespace), attrname, td); 3990 } else { 3991 error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp, 3992 SCARG(uap, attrnamespace), NULL, td); 3993 } 3994 3995 vn_finished_write(mp_writable); 3996 /* 3997 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, 3998 * filename_vp, so vrele it if it is defined. 3999 */ 4000 if (filename_vp != NULL) 4001 vrele(filename_vp); 4002 4003 return (error); 4004} 4005 4006/*- 4007 * Set a named extended attribute on a file or directory 4008 * 4009 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 4010 * kernelspace string pointer "attrname", userspace buffer 4011 * pointer "data", buffer length "nbytes", thread "td". 4012 * Returns: 0 on success, an error number otherwise 4013 * Locks: none 4014 * References: vp must be a valid reference for the duration of the call 4015 */ 4016static int 4017extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname, 4018 void *data, size_t nbytes, struct thread *td) 4019{ 4020 struct mount *mp; 4021 struct uio auio; 4022 struct iovec aiov; 4023 ssize_t cnt; 4024 int error; 4025 4026 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) 4027 return (error); 4028 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 4029 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 4030 4031 aiov.iov_base = data; 4032 aiov.iov_len = nbytes; 4033 auio.uio_iov = &aiov; 4034 auio.uio_iovcnt = 1; 4035 auio.uio_offset = 0; 4036 if (nbytes > INT_MAX) { 4037 error = EINVAL; 4038 goto done; 4039 } 4040 auio.uio_resid = nbytes; 4041 auio.uio_rw = UIO_WRITE; 4042 auio.uio_segflg = UIO_USERSPACE; 4043 auio.uio_td = td; 4044 cnt = nbytes; 4045 4046 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, 4047 td->td_ucred, td); 4048 cnt -= auio.uio_resid; 4049 td->td_retval[0] = cnt; 4050 4051done: 4052 VOP_UNLOCK(vp, 0, td); 4053 vn_finished_write(mp); 4054 return (error); 4055} 4056 4057int 4058extattr_set_file(td, uap) 4059 struct thread *td; 4060 struct extattr_set_file_args *uap; 4061{ 4062 struct nameidata nd; 4063 char attrname[EXTATTR_MAXNAMELEN]; 4064 int error; 4065 4066 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 4067 NULL); 4068 if (error) 4069 return (error); 4070 4071 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); 4072 if ((error = namei(&nd)) != 0) 4073 return (error); 4074 NDFREE(&nd, NDF_ONLY_PNBUF); 4075 4076 error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname, 4077 SCARG(uap, data), SCARG(uap, nbytes), td); 4078 4079 vrele(nd.ni_vp); 4080 return (error); 4081} 4082 4083int 4084extattr_set_fd(td, uap) 4085 struct thread *td; 4086 struct extattr_set_fd_args *uap; 4087{ 4088 struct file *fp; 4089 char attrname[EXTATTR_MAXNAMELEN]; 4090 int error; 4091 4092 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 4093 NULL); 4094 if (error) 4095 return (error); 4096 4097 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0) 4098 return (error); 4099 4100 error = extattr_set_vp((struct vnode *)fp->f_data, 4101 SCARG(uap, attrnamespace), attrname, SCARG(uap, data), 4102 SCARG(uap, nbytes), td); 4103 fdrop(fp, td); 4104 4105 return (error); 4106} 4107 4108/*- 4109 * Get a named extended attribute on a file or directory 4110 * 4111 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 4112 * kernelspace string pointer "attrname", userspace buffer 4113 * pointer "data", buffer length "nbytes", thread "td". 4114 * Returns: 0 on success, an error number otherwise 4115 * Locks: none 4116 * References: vp must be a valid reference for the duration of the call 4117 */ 4118static int 4119extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, 4120 void *data, size_t nbytes, struct thread *td) 4121{ 4122 struct uio auio; 4123 struct iovec aiov; 4124 ssize_t cnt; 4125 size_t size; 4126 int error; 4127 4128 VOP_LEASE(vp, td, td->td_ucred, LEASE_READ); 4129 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 4130 4131 /* 4132 * Slightly unusual semantics: if the user provides a NULL data 4133 * pointer, they don't want to receive the data, just the 4134 * maximum read length. 4135 */ 4136 if (data != NULL) { 4137 aiov.iov_base = data; 4138 aiov.iov_len = nbytes; 4139 auio.uio_iov = &aiov; 4140 auio.uio_offset = 0; 4141 if (nbytes > INT_MAX) { 4142 error = EINVAL; 4143 goto done; 4144 } 4145 auio.uio_resid = nbytes; 4146 auio.uio_rw = UIO_READ; 4147 auio.uio_segflg = UIO_USERSPACE; 4148 auio.uio_td = td; 4149 cnt = nbytes; 4150 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio, 4151 NULL, td->td_ucred, td); 4152 cnt -= auio.uio_resid; 4153 td->td_retval[0] = cnt; 4154 } else { 4155 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL, 4156 &size, td->td_ucred, td); 4157 td->td_retval[0] = size; 4158 } 4159done: 4160 VOP_UNLOCK(vp, 0, td); 4161 return (error); 4162} 4163 4164int 4165extattr_get_file(td, uap) 4166 struct thread *td; 4167 struct extattr_get_file_args *uap; 4168{ 4169 struct nameidata nd; 4170 char attrname[EXTATTR_MAXNAMELEN]; 4171 int error; 4172 4173 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 4174 NULL); 4175 if (error) 4176 return (error); 4177 4178 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); 4179 if ((error = namei(&nd)) != 0) 4180 return (error); 4181 NDFREE(&nd, NDF_ONLY_PNBUF); 4182 4183 error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname, 4184 SCARG(uap, data), SCARG(uap, nbytes), td); 4185 4186 vrele(nd.ni_vp); 4187 return (error); 4188} 4189 4190int 4191extattr_get_fd(td, uap) 4192 struct thread *td; 4193 struct extattr_get_fd_args *uap; 4194{ 4195 struct file *fp; 4196 char attrname[EXTATTR_MAXNAMELEN]; 4197 int error; 4198 4199 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 4200 NULL); 4201 if (error) 4202 return (error); 4203 4204 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0) 4205 return (error); 4206 4207 error = extattr_get_vp((struct vnode *)fp->f_data, 4208 SCARG(uap, attrnamespace), attrname, SCARG(uap, data), 4209 SCARG(uap, nbytes), td); 4210 4211 fdrop(fp, td); 4212 return (error); 4213} 4214 4215/* 4216 * extattr_delete_vp(): Delete a named extended attribute on a file or 4217 * directory 4218 * 4219 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 4220 * kernelspace string pointer "attrname", proc "p" 4221 * Returns: 0 on success, an error number otherwise 4222 * Locks: none 4223 * References: vp must be a valid reference for the duration of the call 4224 */ 4225static int 4226extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname, 4227 struct thread *td) 4228{ 4229 struct mount *mp; 4230 int error; 4231 4232 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) 4233 return (error); 4234 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 4235 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 4236 4237 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, td->td_ucred, 4238 td); 4239 4240 VOP_UNLOCK(vp, 0, td); 4241 vn_finished_write(mp); 4242 return (error); 4243} 4244 4245int 4246extattr_delete_file(td, uap) 4247 struct thread *td; 4248 struct extattr_delete_file_args *uap; 4249{ 4250 struct nameidata nd; 4251 char attrname[EXTATTR_MAXNAMELEN]; 4252 int error; 4253 4254 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 4255 NULL); 4256 if (error) 4257 return(error); 4258 4259 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); 4260 if ((error = namei(&nd)) != 0) 4261 return(error); 4262 NDFREE(&nd, NDF_ONLY_PNBUF); 4263 4264 error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace), 4265 attrname, td); 4266 4267 vrele(nd.ni_vp); 4268 return(error); 4269} 4270 4271int 4272extattr_delete_fd(td, uap) 4273 struct thread *td; 4274 struct extattr_delete_fd_args *uap; 4275{ 4276 struct file *fp; 4277 struct vnode *vp; 4278 char attrname[EXTATTR_MAXNAMELEN]; 4279 int error; 4280 4281 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 4282 NULL); 4283 if (error) 4284 return (error); 4285 4286 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0) 4287 return (error); 4288 vp = (struct vnode *)fp->f_data; 4289 4290 error = extattr_delete_vp((struct vnode *)fp->f_data, 4291 SCARG(uap, attrnamespace), attrname, td); 4292 4293 fdrop(fp, td); 4294 return (error); 4295} 4296