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