vfs_extattr.c revision 33360
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 * $Id: vfs_syscalls.c,v 1.92 1998/02/08 01:41:33 dyson Exp $ 40 */ 41 42/* For 4.3 integer FS ID compatibility */ 43#include "opt_compat.h" 44 45/* 46 * XXX - The following is required because of some magic done 47 * in getdirentries() below which is only done if the translucent 48 * filesystem `UNION' is compiled into the kernel. This is broken, 49 * but I don't have time to study the code deeply enough to understand 50 * what's going on and determine an appropriate fix. -GAW 51 */ 52#include "opt_union.h" 53 54#include <sys/param.h> 55#include <sys/systm.h> 56#include <sys/sysent.h> 57#include <sys/sysproto.h> 58#include <sys/namei.h> 59#include <sys/filedesc.h> 60#include <sys/kernel.h> 61#include <sys/fcntl.h> 62#include <sys/file.h> 63#include <sys/stat.h> 64#include <sys/unistd.h> 65#include <sys/vnode.h> 66#include <sys/malloc.h> 67#include <sys/mount.h> 68#include <sys/proc.h> 69#include <sys/dirent.h> 70 71#ifdef UNION 72#include <miscfs/union/union.h> 73#endif 74 75#include <vm/vm.h> 76#include <vm/vm_object.h> 77#include <vm/vm_extern.h> 78#include <vm/vm_zone.h> 79#include <sys/sysctl.h> 80 81static int change_dir __P((struct nameidata *ndp, struct proc *p)); 82static void checkdirs __P((struct vnode *olddp)); 83 84static int usermount = 0; /* if 1, non-root can mount fs. */ 85 86SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0, ""); 87 88/* 89 * Virtual File System System Calls 90 */ 91 92/* 93 * Mount a file system. 94 */ 95#ifndef _SYS_SYSPROTO_H_ 96struct mount_args { 97 char *type; 98 char *path; 99 int flags; 100 caddr_t data; 101}; 102#endif 103/* ARGSUSED */ 104int 105mount(p, uap) 106 struct proc *p; 107 register struct mount_args /* { 108 syscallarg(char *) type; 109 syscallarg(char *) path; 110 syscallarg(int) flags; 111 syscallarg(caddr_t) data; 112 } */ *uap; 113{ 114 struct vnode *vp; 115 struct mount *mp; 116 struct vfsconf *vfsp; 117 int error, flag = 0, flag2 = 0; 118 struct vattr va; 119 u_long fstypenum; 120 struct nameidata nd; 121 char fstypename[MFSNAMELEN]; 122 123 if (usermount == 0 && (error = suser(p->p_ucred, &p->p_acflag))) 124 return (error); 125 126 /* 127 * Get vnode to be covered 128 */ 129 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 130 SCARG(uap, path), p); 131 if (error = namei(&nd)) 132 return (error); 133 vp = nd.ni_vp; 134 if (SCARG(uap, flags) & MNT_UPDATE) { 135 if ((vp->v_flag & VROOT) == 0) { 136 vput(vp); 137 return (EINVAL); 138 } 139 mp = vp->v_mount; 140 flag = mp->mnt_flag; 141 flag2 = mp->mnt_kern_flag; 142 /* 143 * We only allow the filesystem to be reloaded if it 144 * is currently mounted read-only. 145 */ 146 if ((SCARG(uap, flags) & MNT_RELOAD) && 147 ((mp->mnt_flag & MNT_RDONLY) == 0)) { 148 vput(vp); 149 return (EOPNOTSUPP); /* Needs translation */ 150 } 151 mp->mnt_flag |= 152 SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 153 /* 154 * Only root, or the user that did the original mount is 155 * permitted to update it. 156 */ 157 if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && 158 (error = suser(p->p_ucred, &p->p_acflag))) { 159 vput(vp); 160 return (error); 161 } 162 /* 163 * Do not allow NFS export by non-root users. Silently 164 * enforce MNT_NOSUID and MNT_NODEV for non-root users. 165 */ 166 if (p->p_ucred->cr_uid != 0) { 167 if (SCARG(uap, flags) & MNT_EXPORTED) { 168 vput(vp); 169 return (EPERM); 170 } 171 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 172 } 173 if (vfs_busy(mp, LK_NOWAIT, 0, p)) { 174 vput(vp); 175 return (EBUSY); 176 } 177 VOP_UNLOCK(vp, 0, p); 178 goto update; 179 } 180 /* 181 * If the user is not root, ensure that they own the directory 182 * onto which we are attempting to mount. 183 */ 184 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || 185 (va.va_uid != p->p_ucred->cr_uid && 186 (error = suser(p->p_ucred, &p->p_acflag)))) { 187 vput(vp); 188 return (error); 189 } 190 /* 191 * Do not allow NFS export by non-root users. Silently 192 * enforce MNT_NOSUID and MNT_NODEV for non-root users. 193 */ 194 if (p->p_ucred->cr_uid != 0) { 195 if (SCARG(uap, flags) & MNT_EXPORTED) { 196 vput(vp); 197 return (EPERM); 198 } 199 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 200 } 201 if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) 202 return (error); 203 if (vp->v_type != VDIR) { 204 vput(vp); 205 return (ENOTDIR); 206 } 207#ifdef COMPAT_43 208 /* 209 * Historically filesystem types were identified by number. If we 210 * get an integer for the filesystem type instead of a string, we 211 * check to see if it matches one of the historic filesystem types. 212 */ 213 fstypenum = (u_long)SCARG(uap, type); 214 if (fstypenum < maxvfsconf) { 215 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 216 if (vfsp->vfc_typenum == fstypenum) 217 break; 218 if (vfsp == NULL) { 219 vput(vp); 220 return (ENODEV); 221 } 222 strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN); 223 } else 224#endif /* COMPAT_43 */ 225 if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) { 226 vput(vp); 227 return (error); 228 } 229 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 230 if (!strcmp(vfsp->vfc_name, fstypename)) 231 break; 232 if (vfsp == NULL) { 233 vput(vp); 234 return (ENODEV); 235 } 236 if (vp->v_mountedhere != NULL) { 237 vput(vp); 238 return (EBUSY); 239 } 240 241 /* 242 * Allocate and initialize the filesystem. 243 */ 244 mp = (struct mount *)malloc((u_long)sizeof(struct mount), 245 M_MOUNT, M_WAITOK); 246 bzero((char *)mp, (u_long)sizeof(struct mount)); 247 lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0); 248 (void)vfs_busy(mp, LK_NOWAIT, 0, p); 249 mp->mnt_op = vfsp->vfc_vfsops; 250 mp->mnt_vfc = vfsp; 251 vfsp->vfc_refcount++; 252 mp->mnt_stat.f_type = vfsp->vfc_typenum; 253 mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; 254 strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); 255 vp->v_mountedhere = mp; 256 mp->mnt_vnodecovered = vp; 257 mp->mnt_stat.f_owner = p->p_ucred->cr_uid; 258update: 259 /* 260 * Set the mount level flags. 261 */ 262 if (SCARG(uap, flags) & MNT_RDONLY) 263 mp->mnt_flag |= MNT_RDONLY; 264 else if (mp->mnt_flag & MNT_RDONLY) 265 mp->mnt_kern_flag |= MNTK_WANTRDWR; 266 mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 267 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME | 268 MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR); 269 mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC | 270 MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE | 271 MNT_NOATIME | MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR); 272 /* 273 * Mount the filesystem. 274 */ 275 error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p); 276 if (mp->mnt_flag & MNT_UPDATE) { 277 vrele(vp); 278 if (mp->mnt_kern_flag & MNTK_WANTRDWR) 279 mp->mnt_flag &= ~MNT_RDONLY; 280 mp->mnt_flag &=~ (MNT_UPDATE | MNT_RELOAD | MNT_FORCE); 281 mp->mnt_kern_flag &=~ MNTK_WANTRDWR; 282 if (error) { 283 mp->mnt_flag = flag; 284 mp->mnt_kern_flag = flag2; 285 } 286 vfs_unbusy(mp, p); 287 return (error); 288 } 289 /* 290 * Put the new filesystem on the mount list after root. 291 */ 292 cache_purge(vp); 293 if (!error) { 294 simple_lock(&mountlist_slock); 295 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 296 simple_unlock(&mountlist_slock); 297 checkdirs(vp); 298 VOP_UNLOCK(vp, 0, p); 299 vfs_unbusy(mp, p); 300 if (error = VFS_START(mp, 0, p)) 301 vrele(vp); 302 } else { 303 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 304 mp->mnt_vfc->vfc_refcount--; 305 vfs_unbusy(mp, p); 306 free((caddr_t)mp, M_MOUNT); 307 vput(vp); 308 } 309 return (error); 310} 311 312/* 313 * Scan all active processes to see if any of them have a current 314 * or root directory onto which the new filesystem has just been 315 * mounted. If so, replace them with the new mount point. 316 */ 317static void 318checkdirs(olddp) 319 struct vnode *olddp; 320{ 321 struct filedesc *fdp; 322 struct vnode *newdp; 323 struct proc *p; 324 325 if (olddp->v_usecount == 1) 326 return; 327 if (VFS_ROOT(olddp->v_mountedhere, &newdp)) 328 panic("mount: lost mount"); 329 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 330 fdp = p->p_fd; 331 if (fdp->fd_cdir == olddp) { 332 vrele(fdp->fd_cdir); 333 VREF(newdp); 334 fdp->fd_cdir = newdp; 335 } 336 if (fdp->fd_rdir == olddp) { 337 vrele(fdp->fd_rdir); 338 VREF(newdp); 339 fdp->fd_rdir = newdp; 340 } 341 } 342 if (rootvnode == olddp) { 343 vrele(rootvnode); 344 VREF(newdp); 345 rootvnode = newdp; 346 } 347 vput(newdp); 348} 349 350/* 351 * Unmount a file system. 352 * 353 * Note: unmount takes a path to the vnode mounted on as argument, 354 * not special file (as before). 355 */ 356#ifndef _SYS_SYSPROTO_H_ 357struct unmount_args { 358 char *path; 359 int flags; 360}; 361#endif 362/* ARGSUSED */ 363int 364unmount(p, uap) 365 struct proc *p; 366 register struct unmount_args /* { 367 syscallarg(char *) path; 368 syscallarg(int) flags; 369 } */ *uap; 370{ 371 register struct vnode *vp; 372 struct mount *mp; 373 int error; 374 struct nameidata nd; 375 376 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 377 SCARG(uap, path), p); 378 if (error = namei(&nd)) 379 return (error); 380 vp = nd.ni_vp; 381 mp = vp->v_mount; 382 383 /* 384 * Only root, or the user that did the original mount is 385 * permitted to unmount this filesystem. 386 */ 387 if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && 388 (error = suser(p->p_ucred, &p->p_acflag))) { 389 vput(vp); 390 return (error); 391 } 392 393 /* 394 * Don't allow unmounting the root file system. 395 */ 396 if (mp->mnt_flag & MNT_ROOTFS) { 397 vput(vp); 398 return (EINVAL); 399 } 400 401 /* 402 * Must be the root of the filesystem 403 */ 404 if ((vp->v_flag & VROOT) == 0) { 405 vput(vp); 406 return (EINVAL); 407 } 408 vput(vp); 409 return (dounmount(mp, SCARG(uap, flags), p)); 410} 411 412/* 413 * Do the actual file system unmount. 414 */ 415int 416dounmount(mp, flags, p) 417 register struct mount *mp; 418 int flags; 419 struct proc *p; 420{ 421 struct vnode *coveredvp; 422 int error; 423 424 simple_lock(&mountlist_slock); 425 mp->mnt_kern_flag |= MNTK_UNMOUNT; 426 lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p); 427 428 if (mp->mnt_flag & MNT_EXPUBLIC) 429 vfs_setpublicfs(NULL, NULL, NULL); 430 431 vfs_msync(mp, MNT_WAIT); 432 mp->mnt_flag &=~ MNT_ASYNC; 433 cache_purgevfs(mp); /* remove cache entries for this file sys */ 434 if (((mp->mnt_flag & MNT_RDONLY) || 435 (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) || 436 (flags & MNT_FORCE)) 437 error = VFS_UNMOUNT(mp, flags, p); 438 simple_lock(&mountlist_slock); 439 if (error) { 440 mp->mnt_kern_flag &= ~MNTK_UNMOUNT; 441 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE, 442 &mountlist_slock, p); 443 return (error); 444 } 445 CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); 446 if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) { 447 coveredvp->v_mountedhere = (struct mount *)0; 448 vrele(coveredvp); 449 } 450 mp->mnt_vfc->vfc_refcount--; 451 if (mp->mnt_vnodelist.lh_first != NULL) 452 panic("unmount: dangling vnode"); 453 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p); 454 if (mp->mnt_kern_flag & MNTK_MWAIT) 455 wakeup((caddr_t)mp); 456 free((caddr_t)mp, M_MOUNT); 457 return (0); 458} 459 460/* 461 * Sync each mounted filesystem. 462 */ 463#ifndef _SYS_SYSPROTO_H_ 464struct sync_args { 465 int dummy; 466}; 467#endif 468 469#ifdef DEBUG 470static int syncprt = 0; 471SYSCTL_INT(_debug, OID_AUTO, syncprt, CTLFLAG_RW, &syncprt, 0, ""); 472#endif 473 474/* ARGSUSED */ 475int 476sync(p, uap) 477 struct proc *p; 478 struct sync_args *uap; 479{ 480 register struct mount *mp, *nmp; 481 int asyncflag; 482 483 simple_lock(&mountlist_slock); 484 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 485 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { 486 nmp = mp->mnt_list.cqe_next; 487 continue; 488 } 489 if ((mp->mnt_flag & MNT_RDONLY) == 0) { 490 asyncflag = mp->mnt_flag & MNT_ASYNC; 491 mp->mnt_flag &= ~MNT_ASYNC; 492 vfs_msync(mp, MNT_NOWAIT); 493 VFS_SYNC(mp, MNT_NOWAIT, p != NULL ? p->p_ucred : NOCRED, p); 494 if (asyncflag) 495 mp->mnt_flag |= MNT_ASYNC; 496 } 497 simple_lock(&mountlist_slock); 498 nmp = mp->mnt_list.cqe_next; 499 vfs_unbusy(mp, p); 500 } 501 simple_unlock(&mountlist_slock); 502#if 0 503/* 504 * XXX don't call vfs_bufstats() yet because that routine 505 * was not imported in the Lite2 merge. 506 */ 507#ifdef DIAGNOSTIC 508 if (syncprt) 509 vfs_bufstats(); 510#endif /* DIAGNOSTIC */ 511#endif 512 return (0); 513} 514 515/* 516 * Change filesystem quotas. 517 */ 518#ifndef _SYS_SYSPROTO_H_ 519struct quotactl_args { 520 char *path; 521 int cmd; 522 int uid; 523 caddr_t arg; 524}; 525#endif 526/* ARGSUSED */ 527int 528quotactl(p, uap) 529 struct proc *p; 530 register struct quotactl_args /* { 531 syscallarg(char *) path; 532 syscallarg(int) cmd; 533 syscallarg(int) uid; 534 syscallarg(caddr_t) arg; 535 } */ *uap; 536{ 537 register struct mount *mp; 538 int error; 539 struct nameidata nd; 540 541 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 542 if (error = namei(&nd)) 543 return (error); 544 mp = nd.ni_vp->v_mount; 545 vrele(nd.ni_vp); 546 return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), 547 SCARG(uap, arg), p)); 548} 549 550/* 551 * Get filesystem statistics. 552 */ 553#ifndef _SYS_SYSPROTO_H_ 554struct statfs_args { 555 char *path; 556 struct statfs *buf; 557}; 558#endif 559/* ARGSUSED */ 560int 561statfs(p, uap) 562 struct proc *p; 563 register struct statfs_args /* { 564 syscallarg(char *) path; 565 syscallarg(struct statfs *) buf; 566 } */ *uap; 567{ 568 register struct mount *mp; 569 register struct statfs *sp; 570 int error; 571 struct nameidata nd; 572 struct statfs sb; 573 574 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 575 if (error = namei(&nd)) 576 return (error); 577 mp = nd.ni_vp->v_mount; 578 sp = &mp->mnt_stat; 579 vrele(nd.ni_vp); 580 error = VFS_STATFS(mp, sp, p); 581 if (error) 582 return (error); 583 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 584 if (p->p_ucred->cr_uid != 0) { 585 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 586 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 587 sp = &sb; 588 } 589 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 590} 591 592/* 593 * Get filesystem statistics. 594 */ 595#ifndef _SYS_SYSPROTO_H_ 596struct fstatfs_args { 597 int fd; 598 struct statfs *buf; 599}; 600#endif 601/* ARGSUSED */ 602int 603fstatfs(p, uap) 604 struct proc *p; 605 register struct fstatfs_args /* { 606 syscallarg(int) fd; 607 syscallarg(struct statfs *) buf; 608 } */ *uap; 609{ 610 struct file *fp; 611 struct mount *mp; 612 register struct statfs *sp; 613 int error; 614 struct statfs sb; 615 616 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 617 return (error); 618 mp = ((struct vnode *)fp->f_data)->v_mount; 619 sp = &mp->mnt_stat; 620 error = VFS_STATFS(mp, sp, p); 621 if (error) 622 return (error); 623 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 624 if (p->p_ucred->cr_uid != 0) { 625 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 626 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 627 sp = &sb; 628 } 629 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 630} 631 632/* 633 * Get statistics on all filesystems. 634 */ 635#ifndef _SYS_SYSPROTO_H_ 636struct getfsstat_args { 637 struct statfs *buf; 638 long bufsize; 639 int flags; 640}; 641#endif 642int 643getfsstat(p, uap) 644 struct proc *p; 645 register struct getfsstat_args /* { 646 syscallarg(struct statfs *) buf; 647 syscallarg(long) bufsize; 648 syscallarg(int) flags; 649 } */ *uap; 650{ 651 register struct mount *mp, *nmp; 652 register struct statfs *sp; 653 caddr_t sfsp; 654 long count, maxcount, error; 655 656 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); 657 sfsp = (caddr_t)SCARG(uap, buf); 658 count = 0; 659 simple_lock(&mountlist_slock); 660 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 661 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { 662 nmp = mp->mnt_list.cqe_next; 663 continue; 664 } 665 if (sfsp && count < maxcount) { 666 sp = &mp->mnt_stat; 667 /* 668 * If MNT_NOWAIT is specified, do not refresh the 669 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 670 */ 671 if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 || 672 (SCARG(uap, flags) & MNT_WAIT)) && 673 (error = VFS_STATFS(mp, sp, p))) { 674 simple_lock(&mountlist_slock); 675 nmp = mp->mnt_list.cqe_next; 676 vfs_unbusy(mp, p); 677 continue; 678 } 679 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 680 error = copyout((caddr_t)sp, sfsp, sizeof(*sp)); 681 if (error) { 682 vfs_unbusy(mp, p); 683 return (error); 684 } 685 sfsp += sizeof(*sp); 686 } 687 count++; 688 simple_lock(&mountlist_slock); 689 nmp = mp->mnt_list.cqe_next; 690 vfs_unbusy(mp, p); 691 } 692 simple_unlock(&mountlist_slock); 693 if (sfsp && count > maxcount) 694 p->p_retval[0] = maxcount; 695 else 696 p->p_retval[0] = count; 697 return (0); 698} 699 700/* 701 * Change current working directory to a given file descriptor. 702 */ 703#ifndef _SYS_SYSPROTO_H_ 704struct fchdir_args { 705 int fd; 706}; 707#endif 708/* ARGSUSED */ 709int 710fchdir(p, uap) 711 struct proc *p; 712 struct fchdir_args /* { 713 syscallarg(int) fd; 714 } */ *uap; 715{ 716 register struct filedesc *fdp = p->p_fd; 717 struct vnode *vp, *tdp; 718 struct mount *mp; 719 struct file *fp; 720 int error; 721 722 if (error = getvnode(fdp, SCARG(uap, fd), &fp)) 723 return (error); 724 vp = (struct vnode *)fp->f_data; 725 VREF(vp); 726 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 727 if (vp->v_type != VDIR) 728 error = ENOTDIR; 729 else 730 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 731 while (!error && (mp = vp->v_mountedhere) != NULL) { 732 if (vfs_busy(mp, 0, 0, p)) 733 continue; 734 error = VFS_ROOT(mp, &tdp); 735 vfs_unbusy(mp, p); 736 if (error) 737 break; 738 vput(vp); 739 vp = tdp; 740 } 741 if (error) { 742 vput(vp); 743 return (error); 744 } 745 VOP_UNLOCK(vp, 0, p); 746 vrele(fdp->fd_cdir); 747 fdp->fd_cdir = vp; 748 return (0); 749} 750 751/* 752 * Change current working directory (``.''). 753 */ 754#ifndef _SYS_SYSPROTO_H_ 755struct chdir_args { 756 char *path; 757}; 758#endif 759/* ARGSUSED */ 760int 761chdir(p, uap) 762 struct proc *p; 763 struct chdir_args /* { 764 syscallarg(char *) path; 765 } */ *uap; 766{ 767 register struct filedesc *fdp = p->p_fd; 768 int error; 769 struct nameidata nd; 770 771 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 772 SCARG(uap, path), p); 773 if (error = change_dir(&nd, p)) 774 return (error); 775 vrele(fdp->fd_cdir); 776 fdp->fd_cdir = nd.ni_vp; 777 return (0); 778} 779 780/* 781 * Change notion of root (``/'') directory. 782 */ 783#ifndef _SYS_SYSPROTO_H_ 784struct chroot_args { 785 char *path; 786}; 787#endif 788/* ARGSUSED */ 789int 790chroot(p, uap) 791 struct proc *p; 792 struct chroot_args /* { 793 syscallarg(char *) path; 794 } */ *uap; 795{ 796 register struct filedesc *fdp = p->p_fd; 797 int error; 798 struct nameidata nd; 799 800 error = suser(p->p_ucred, &p->p_acflag); 801 if (error) 802 return (error); 803 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 804 SCARG(uap, path), p); 805 if (error = change_dir(&nd, p)) 806 return (error); 807 vrele(fdp->fd_rdir); 808 fdp->fd_rdir = nd.ni_vp; 809 return (0); 810} 811 812/* 813 * Common routine for chroot and chdir. 814 */ 815static int 816change_dir(ndp, p) 817 register struct nameidata *ndp; 818 struct proc *p; 819{ 820 struct vnode *vp; 821 int error; 822 823 error = namei(ndp); 824 if (error) 825 return (error); 826 vp = ndp->ni_vp; 827 if (vp->v_type != VDIR) 828 error = ENOTDIR; 829 else 830 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 831 if (error) 832 vput(vp); 833 else 834 VOP_UNLOCK(vp, 0, p); 835 return (error); 836} 837 838/* 839 * Check permissions, allocate an open file structure, 840 * and call the device open routine if any. 841 */ 842#ifndef _SYS_SYSPROTO_H_ 843struct open_args { 844 char *path; 845 int flags; 846 int mode; 847}; 848#endif 849int 850open(p, uap) 851 struct proc *p; 852 register struct open_args /* { 853 syscallarg(char *) path; 854 syscallarg(int) flags; 855 syscallarg(int) mode; 856 } */ *uap; 857{ 858 register struct filedesc *fdp = p->p_fd; 859 register struct file *fp; 860 register struct vnode *vp; 861 int cmode, flags, oflags; 862 struct file *nfp; 863 int type, indx, error; 864 struct flock lf; 865 struct nameidata nd; 866 867 oflags = SCARG(uap, flags); 868 if ((oflags & O_ACCMODE) == O_ACCMODE) 869 return (EINVAL); 870 flags = FFLAGS(oflags); 871 error = falloc(p, &nfp, &indx); 872 if (error) 873 return (error); 874 fp = nfp; 875 cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 876 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 877 p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 878 error = vn_open(&nd, flags, cmode); 879 if (error) { 880 ffree(fp); 881 if ((error == ENODEV || error == ENXIO) && 882 p->p_dupfd >= 0 && /* XXX from fdopen */ 883 (error = 884 dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 885 p->p_retval[0] = indx; 886 return (0); 887 } 888 if (error == ERESTART) 889 error = EINTR; 890 fdp->fd_ofiles[indx] = NULL; 891 return (error); 892 } 893 p->p_dupfd = 0; 894 vp = nd.ni_vp; 895 896 fp->f_flag = flags & FMASK; 897 fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE); 898 fp->f_ops = &vnops; 899 fp->f_data = (caddr_t)vp; 900 if (flags & (O_EXLOCK | O_SHLOCK)) { 901 lf.l_whence = SEEK_SET; 902 lf.l_start = 0; 903 lf.l_len = 0; 904 if (flags & O_EXLOCK) 905 lf.l_type = F_WRLCK; 906 else 907 lf.l_type = F_RDLCK; 908 type = F_FLOCK; 909 if ((flags & FNONBLOCK) == 0) 910 type |= F_WAIT; 911 VOP_UNLOCK(vp, 0, p); 912 if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 913 (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 914 ffree(fp); 915 fdp->fd_ofiles[indx] = NULL; 916 return (error); 917 } 918 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 919 fp->f_flag |= FHASLOCK; 920 } 921 if ((vp->v_type == VREG) && (vp->v_object == NULL)) 922 vfs_object_create(vp, p, p->p_ucred, TRUE); 923 VOP_UNLOCK(vp, 0, p); 924 p->p_retval[0] = indx; 925 return (0); 926} 927 928#ifdef COMPAT_43 929/* 930 * Create a file. 931 */ 932#ifndef _SYS_SYSPROTO_H_ 933struct ocreat_args { 934 char *path; 935 int mode; 936}; 937#endif 938int 939ocreat(p, uap) 940 struct proc *p; 941 register struct ocreat_args /* { 942 syscallarg(char *) path; 943 syscallarg(int) mode; 944 } */ *uap; 945{ 946 struct open_args /* { 947 syscallarg(char *) path; 948 syscallarg(int) flags; 949 syscallarg(int) mode; 950 } */ nuap; 951 952 SCARG(&nuap, path) = SCARG(uap, path); 953 SCARG(&nuap, mode) = SCARG(uap, mode); 954 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; 955 return (open(p, &nuap)); 956} 957#endif /* COMPAT_43 */ 958 959/* 960 * Create a special file. 961 */ 962#ifndef _SYS_SYSPROTO_H_ 963struct mknod_args { 964 char *path; 965 int mode; 966 int dev; 967}; 968#endif 969/* ARGSUSED */ 970int 971mknod(p, uap) 972 struct proc *p; 973 register struct mknod_args /* { 974 syscallarg(char *) path; 975 syscallarg(int) mode; 976 syscallarg(int) dev; 977 } */ *uap; 978{ 979 register struct vnode *vp; 980 struct vattr vattr; 981 int error; 982 int whiteout; 983 struct nameidata nd; 984 985 error = suser(p->p_ucred, &p->p_acflag); 986 if (error) 987 return (error); 988 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 989 if (error = namei(&nd)) 990 return (error); 991 vp = nd.ni_vp; 992 if (vp != NULL) 993 error = EEXIST; 994 else { 995 VATTR_NULL(&vattr); 996 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 997 vattr.va_rdev = SCARG(uap, dev); 998 whiteout = 0; 999 1000 switch (SCARG(uap, mode) & S_IFMT) { 1001 case S_IFMT: /* used by badsect to flag bad sectors */ 1002 vattr.va_type = VBAD; 1003 break; 1004 case S_IFCHR: 1005 vattr.va_type = VCHR; 1006 break; 1007 case S_IFBLK: 1008 vattr.va_type = VBLK; 1009 break; 1010 case S_IFWHT: 1011 whiteout = 1; 1012 break; 1013 default: 1014 error = EINVAL; 1015 break; 1016 } 1017 } 1018 if (!error) { 1019 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1020 if (whiteout) { 1021 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 1022 if (error) 1023 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1024 vput(nd.ni_dvp); 1025 } else { 1026 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, 1027 &nd.ni_cnd, &vattr); 1028 } 1029 } else { 1030 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1031 if (nd.ni_dvp == vp) 1032 vrele(nd.ni_dvp); 1033 else 1034 vput(nd.ni_dvp); 1035 if (vp) 1036 vrele(vp); 1037 } 1038 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod"); 1039 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod"); 1040 return (error); 1041} 1042 1043/* 1044 * Create a named pipe. 1045 */ 1046#ifndef _SYS_SYSPROTO_H_ 1047struct mkfifo_args { 1048 char *path; 1049 int mode; 1050}; 1051#endif 1052/* ARGSUSED */ 1053int 1054mkfifo(p, uap) 1055 struct proc *p; 1056 register struct mkfifo_args /* { 1057 syscallarg(char *) path; 1058 syscallarg(int) mode; 1059 } */ *uap; 1060{ 1061 struct vattr vattr; 1062 int error; 1063 struct nameidata nd; 1064 1065 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1066 if (error = namei(&nd)) 1067 return (error); 1068 if (nd.ni_vp != NULL) { 1069 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1070 if (nd.ni_dvp == nd.ni_vp) 1071 vrele(nd.ni_dvp); 1072 else 1073 vput(nd.ni_dvp); 1074 vrele(nd.ni_vp); 1075 return (EEXIST); 1076 } 1077 VATTR_NULL(&vattr); 1078 vattr.va_type = VFIFO; 1079 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 1080 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1081 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 1082} 1083 1084/* 1085 * Make a hard file link. 1086 */ 1087#ifndef _SYS_SYSPROTO_H_ 1088struct link_args { 1089 char *path; 1090 char *link; 1091}; 1092#endif 1093/* ARGSUSED */ 1094int 1095link(p, uap) 1096 struct proc *p; 1097 register struct link_args /* { 1098 syscallarg(char *) path; 1099 syscallarg(char *) link; 1100 } */ *uap; 1101{ 1102 register struct vnode *vp; 1103 struct nameidata nd; 1104 int error; 1105 1106 NDINIT(&nd, LOOKUP, FOLLOW|NOOBJ, UIO_USERSPACE, SCARG(uap, path), p); 1107 if (error = namei(&nd)) 1108 return (error); 1109 vp = nd.ni_vp; 1110 if (vp->v_type == VDIR) 1111 error = EPERM; /* POSIX */ 1112 else { 1113 NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), p); 1114 error = namei(&nd); 1115 if (!error) { 1116 if (nd.ni_vp != NULL) { 1117 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1118 if (nd.ni_dvp == nd.ni_vp) 1119 vrele(nd.ni_dvp); 1120 else 1121 vput(nd.ni_dvp); 1122 if (nd.ni_vp) 1123 vrele(nd.ni_vp); 1124 error = EEXIST; 1125 } else { 1126 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, 1127 LEASE_WRITE); 1128 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1129 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 1130 } 1131 } 1132 } 1133 vrele(vp); 1134 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link"); 1135 ASSERT_VOP_UNLOCKED(nd.ni_vp, "link"); 1136 return (error); 1137} 1138 1139/* 1140 * Make a symbolic link. 1141 */ 1142#ifndef _SYS_SYSPROTO_H_ 1143struct symlink_args { 1144 char *path; 1145 char *link; 1146}; 1147#endif 1148/* ARGSUSED */ 1149int 1150symlink(p, uap) 1151 struct proc *p; 1152 register struct symlink_args /* { 1153 syscallarg(char *) path; 1154 syscallarg(char *) link; 1155 } */ *uap; 1156{ 1157 struct vattr vattr; 1158 char *path; 1159 int error; 1160 struct nameidata nd; 1161 1162 path = zalloc(namei_zone); 1163 if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) 1164 goto out; 1165 NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), p); 1166 if (error = namei(&nd)) 1167 goto out; 1168 if (nd.ni_vp) { 1169 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1170 if (nd.ni_dvp == nd.ni_vp) 1171 vrele(nd.ni_dvp); 1172 else 1173 vput(nd.ni_dvp); 1174 vrele(nd.ni_vp); 1175 error = EEXIST; 1176 goto out; 1177 } 1178 VATTR_NULL(&vattr); 1179 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 1180 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1181 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 1182 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink"); 1183 ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink"); 1184out: 1185 zfree(namei_zone, path); 1186 return (error); 1187} 1188 1189/* 1190 * Delete a whiteout from the filesystem. 1191 */ 1192/* ARGSUSED */ 1193int 1194undelete(p, uap) 1195 struct proc *p; 1196 register struct undelete_args /* { 1197 syscallarg(char *) path; 1198 } */ *uap; 1199{ 1200 int error; 1201 struct nameidata nd; 1202 1203 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, 1204 SCARG(uap, path), p); 1205 error = namei(&nd); 1206 if (error) 1207 return (error); 1208 1209 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 1210 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1211 if (nd.ni_dvp == nd.ni_vp) 1212 vrele(nd.ni_dvp); 1213 else 1214 vput(nd.ni_dvp); 1215 if (nd.ni_vp) 1216 vrele(nd.ni_vp); 1217 return (EEXIST); 1218 } 1219 1220 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1221 if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) 1222 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1223 vput(nd.ni_dvp); 1224 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete"); 1225 ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete"); 1226 return (error); 1227} 1228 1229/* 1230 * Delete a name from the filesystem. 1231 */ 1232#ifndef _SYS_SYSPROTO_H_ 1233struct unlink_args { 1234 char *path; 1235}; 1236#endif 1237/* ARGSUSED */ 1238int 1239unlink(p, uap) 1240 struct proc *p; 1241 struct unlink_args /* { 1242 syscallarg(char *) path; 1243 } */ *uap; 1244{ 1245 register struct vnode *vp; 1246 int error; 1247 struct nameidata nd; 1248 1249 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1250 if (error = namei(&nd)) 1251 return (error); 1252 vp = nd.ni_vp; 1253 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1254 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1255 1256 if (vp->v_type == VDIR) 1257 error = EPERM; /* POSIX */ 1258 else { 1259 /* 1260 * The root of a mounted filesystem cannot be deleted. 1261 * 1262 * XXX: can this only be a VDIR case? 1263 */ 1264 if (vp->v_flag & VROOT) 1265 error = EBUSY; 1266 } 1267 1268 if (!error) { 1269 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1270 error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd); 1271 } else { 1272 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1273 if (nd.ni_dvp == vp) 1274 vrele(nd.ni_dvp); 1275 else 1276 vput(nd.ni_dvp); 1277 if (vp != NULLVP) 1278 vput(vp); 1279 } 1280 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink"); 1281 ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink"); 1282 return (error); 1283} 1284 1285/* 1286 * Reposition read/write file offset. 1287 */ 1288#ifndef _SYS_SYSPROTO_H_ 1289struct lseek_args { 1290 int fd; 1291 int pad; 1292 off_t offset; 1293 int whence; 1294}; 1295#endif 1296int 1297lseek(p, uap) 1298 struct proc *p; 1299 register struct lseek_args /* { 1300 syscallarg(int) fd; 1301 syscallarg(int) pad; 1302 syscallarg(off_t) offset; 1303 syscallarg(int) whence; 1304 } */ *uap; 1305{ 1306 struct ucred *cred = p->p_ucred; 1307 register struct filedesc *fdp = p->p_fd; 1308 register struct file *fp; 1309 struct vattr vattr; 1310 int error; 1311 1312 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 1313 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) 1314 return (EBADF); 1315 if (fp->f_type != DTYPE_VNODE) 1316 return (ESPIPE); 1317 switch (SCARG(uap, whence)) { 1318 case L_INCR: 1319 fp->f_offset += SCARG(uap, offset); 1320 break; 1321 case L_XTND: 1322 error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p); 1323 if (error) 1324 return (error); 1325 fp->f_offset = SCARG(uap, offset) + vattr.va_size; 1326 break; 1327 case L_SET: 1328 fp->f_offset = SCARG(uap, offset); 1329 break; 1330 default: 1331 return (EINVAL); 1332 } 1333 *(off_t *)(p->p_retval) = fp->f_offset; 1334 return (0); 1335} 1336 1337#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1338/* 1339 * Reposition read/write file offset. 1340 */ 1341#ifndef _SYS_SYSPROTO_H_ 1342struct olseek_args { 1343 int fd; 1344 long offset; 1345 int whence; 1346}; 1347#endif 1348int 1349olseek(p, uap) 1350 struct proc *p; 1351 register struct olseek_args /* { 1352 syscallarg(int) fd; 1353 syscallarg(long) offset; 1354 syscallarg(int) whence; 1355 } */ *uap; 1356{ 1357 struct lseek_args /* { 1358 syscallarg(int) fd; 1359 syscallarg(int) pad; 1360 syscallarg(off_t) offset; 1361 syscallarg(int) whence; 1362 } */ nuap; 1363 int error; 1364 1365 SCARG(&nuap, fd) = SCARG(uap, fd); 1366 SCARG(&nuap, offset) = SCARG(uap, offset); 1367 SCARG(&nuap, whence) = SCARG(uap, whence); 1368 error = lseek(p, &nuap); 1369 return (error); 1370} 1371#endif /* COMPAT_43 */ 1372 1373/* 1374 * Check access permissions. 1375 */ 1376#ifndef _SYS_SYSPROTO_H_ 1377struct access_args { 1378 char *path; 1379 int flags; 1380}; 1381#endif 1382int 1383access(p, uap) 1384 struct proc *p; 1385 register struct access_args /* { 1386 syscallarg(char *) path; 1387 syscallarg(int) flags; 1388 } */ *uap; 1389{ 1390 register struct ucred *cred = p->p_ucred; 1391 register struct vnode *vp; 1392 int error, flags, t_gid, t_uid; 1393 struct nameidata nd; 1394 1395 t_uid = cred->cr_uid; 1396 t_gid = cred->cr_groups[0]; 1397 cred->cr_uid = p->p_cred->p_ruid; 1398 cred->cr_groups[0] = p->p_cred->p_rgid; 1399 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1400 SCARG(uap, path), p); 1401 if (error = namei(&nd)) 1402 goto out1; 1403 vp = nd.ni_vp; 1404 1405 /* Flags == 0 means only check for existence. */ 1406 if (SCARG(uap, flags)) { 1407 flags = 0; 1408 if (SCARG(uap, flags) & R_OK) 1409 flags |= VREAD; 1410 if (SCARG(uap, flags) & W_OK) 1411 flags |= VWRITE; 1412 if (SCARG(uap, flags) & X_OK) 1413 flags |= VEXEC; 1414 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 1415 error = VOP_ACCESS(vp, flags, cred, p); 1416 } 1417 vput(vp); 1418out1: 1419 cred->cr_uid = t_uid; 1420 cred->cr_groups[0] = t_gid; 1421 return (error); 1422} 1423 1424#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1425/* 1426 * Get file status; this version follows links. 1427 */ 1428#ifndef _SYS_SYSPROTO_H_ 1429struct ostat_args { 1430 char *path; 1431 struct ostat *ub; 1432}; 1433#endif 1434/* ARGSUSED */ 1435int 1436ostat(p, uap) 1437 struct proc *p; 1438 register struct ostat_args /* { 1439 syscallarg(char *) path; 1440 syscallarg(struct ostat *) ub; 1441 } */ *uap; 1442{ 1443 struct stat sb; 1444 struct ostat osb; 1445 int error; 1446 struct nameidata nd; 1447 1448 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1449 SCARG(uap, path), p); 1450 if (error = namei(&nd)) 1451 return (error); 1452 error = vn_stat(nd.ni_vp, &sb, p); 1453 vput(nd.ni_vp); 1454 if (error) 1455 return (error); 1456 cvtstat(&sb, &osb); 1457 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 1458 return (error); 1459} 1460 1461/* 1462 * Get file status; this version does not follow links. 1463 */ 1464#ifndef _SYS_SYSPROTO_H_ 1465struct olstat_args { 1466 char *path; 1467 struct ostat *ub; 1468}; 1469#endif 1470/* ARGSUSED */ 1471int 1472olstat(p, uap) 1473 struct proc *p; 1474 register struct olstat_args /* { 1475 syscallarg(char *) path; 1476 syscallarg(struct ostat *) ub; 1477 } */ *uap; 1478{ 1479 struct vnode *vp; 1480 struct stat sb; 1481 struct ostat osb; 1482 int error; 1483 struct nameidata nd; 1484 1485 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1486 SCARG(uap, path), p); 1487 if (error = namei(&nd)) 1488 return (error); 1489 vp = nd.ni_vp; 1490 error = vn_stat(vp, &sb, p); 1491 if (vp->v_type == VLNK) 1492 sb.st_mode |= S_IFLNK | ACCESSPERMS; /* 0777 */ 1493 vput(vp); 1494 if (error) 1495 return (error); 1496 cvtstat(&sb, &osb); 1497 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 1498 return (error); 1499} 1500 1501/* 1502 * Convert from an old to a new stat structure. 1503 */ 1504void 1505cvtstat(st, ost) 1506 struct stat *st; 1507 struct ostat *ost; 1508{ 1509 1510 ost->st_dev = st->st_dev; 1511 ost->st_ino = st->st_ino; 1512 ost->st_mode = st->st_mode; 1513 ost->st_nlink = st->st_nlink; 1514 ost->st_uid = st->st_uid; 1515 ost->st_gid = st->st_gid; 1516 ost->st_rdev = st->st_rdev; 1517 if (st->st_size < (quad_t)1 << 32) 1518 ost->st_size = st->st_size; 1519 else 1520 ost->st_size = -2; 1521 ost->st_atime = st->st_atime; 1522 ost->st_mtime = st->st_mtime; 1523 ost->st_ctime = st->st_ctime; 1524 ost->st_blksize = st->st_blksize; 1525 ost->st_blocks = st->st_blocks; 1526 ost->st_flags = st->st_flags; 1527 ost->st_gen = st->st_gen; 1528} 1529#endif /* COMPAT_43 || COMPAT_SUNOS */ 1530 1531/* 1532 * Get file status; this version follows links. 1533 */ 1534#ifndef _SYS_SYSPROTO_H_ 1535struct stat_args { 1536 char *path; 1537 struct stat *ub; 1538}; 1539#endif 1540/* ARGSUSED */ 1541int 1542stat(p, uap) 1543 struct proc *p; 1544 register struct stat_args /* { 1545 syscallarg(char *) path; 1546 syscallarg(struct stat *) ub; 1547 } */ *uap; 1548{ 1549 struct stat sb; 1550 int error; 1551 struct nameidata nd; 1552 1553 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1554 SCARG(uap, path), p); 1555 if (error = namei(&nd)) 1556 return (error); 1557 error = vn_stat(nd.ni_vp, &sb, p); 1558 vput(nd.ni_vp); 1559 if (error) 1560 return (error); 1561 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1562 return (error); 1563} 1564 1565/* 1566 * Get file status; this version does not follow links. 1567 */ 1568#ifndef _SYS_SYSPROTO_H_ 1569struct lstat_args { 1570 char *path; 1571 struct stat *ub; 1572}; 1573#endif 1574/* ARGSUSED */ 1575int 1576lstat(p, uap) 1577 struct proc *p; 1578 register struct lstat_args /* { 1579 syscallarg(char *) path; 1580 syscallarg(struct stat *) ub; 1581 } */ *uap; 1582{ 1583 int error; 1584 struct vnode *vp; 1585 struct stat sb; 1586 struct nameidata nd; 1587 1588 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1589 SCARG(uap, path), p); 1590 if (error = namei(&nd)) 1591 return (error); 1592 vp = nd.ni_vp; 1593 error = vn_stat(vp, &sb, p); 1594 if (vp->v_type == VLNK) 1595 sb.st_mode |= S_IFLNK | ACCESSPERMS; /* 0777 */ 1596 vput(vp); 1597 if (error) 1598 return (error); 1599 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1600 return (error); 1601} 1602 1603/* 1604 * Get configurable pathname variables. 1605 */ 1606#ifndef _SYS_SYSPROTO_H_ 1607struct pathconf_args { 1608 char *path; 1609 int name; 1610}; 1611#endif 1612/* ARGSUSED */ 1613int 1614pathconf(p, uap) 1615 struct proc *p; 1616 register struct pathconf_args /* { 1617 syscallarg(char *) path; 1618 syscallarg(int) name; 1619 } */ *uap; 1620{ 1621 int error; 1622 struct nameidata nd; 1623 1624 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1625 SCARG(uap, path), p); 1626 if (error = namei(&nd)) 1627 return (error); 1628 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), p->p_retval); 1629 vput(nd.ni_vp); 1630 return (error); 1631} 1632 1633/* 1634 * Return target name of a symbolic link. 1635 */ 1636#ifndef _SYS_SYSPROTO_H_ 1637struct readlink_args { 1638 char *path; 1639 char *buf; 1640 int count; 1641}; 1642#endif 1643/* ARGSUSED */ 1644int 1645readlink(p, uap) 1646 struct proc *p; 1647 register struct readlink_args /* { 1648 syscallarg(char *) path; 1649 syscallarg(char *) buf; 1650 syscallarg(int) count; 1651 } */ *uap; 1652{ 1653 register struct vnode *vp; 1654 struct iovec aiov; 1655 struct uio auio; 1656 int error; 1657 struct nameidata nd; 1658 1659 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1660 SCARG(uap, path), p); 1661 if (error = namei(&nd)) 1662 return (error); 1663 vp = nd.ni_vp; 1664 if (vp->v_type != VLNK) 1665 error = EINVAL; 1666 else { 1667 aiov.iov_base = SCARG(uap, buf); 1668 aiov.iov_len = SCARG(uap, count); 1669 auio.uio_iov = &aiov; 1670 auio.uio_iovcnt = 1; 1671 auio.uio_offset = 0; 1672 auio.uio_rw = UIO_READ; 1673 auio.uio_segflg = UIO_USERSPACE; 1674 auio.uio_procp = p; 1675 auio.uio_resid = SCARG(uap, count); 1676 error = VOP_READLINK(vp, &auio, p->p_ucred); 1677 } 1678 vput(vp); 1679 p->p_retval[0] = SCARG(uap, count) - auio.uio_resid; 1680 return (error); 1681} 1682 1683/* 1684 * Change flags of a file given a path name. 1685 */ 1686#ifndef _SYS_SYSPROTO_H_ 1687struct chflags_args { 1688 char *path; 1689 int flags; 1690}; 1691#endif 1692/* ARGSUSED */ 1693int 1694chflags(p, uap) 1695 struct proc *p; 1696 register struct chflags_args /* { 1697 syscallarg(char *) path; 1698 syscallarg(int) flags; 1699 } */ *uap; 1700{ 1701 register struct vnode *vp; 1702 struct vattr vattr; 1703 int error; 1704 struct nameidata nd; 1705 1706 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1707 if (error = namei(&nd)) 1708 return (error); 1709 vp = nd.ni_vp; 1710 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1711 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1712 VATTR_NULL(&vattr); 1713 vattr.va_flags = SCARG(uap, flags); 1714 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1715 vput(vp); 1716 return (error); 1717} 1718 1719/* 1720 * Change flags of a file given a file descriptor. 1721 */ 1722#ifndef _SYS_SYSPROTO_H_ 1723struct fchflags_args { 1724 int fd; 1725 int flags; 1726}; 1727#endif 1728/* ARGSUSED */ 1729int 1730fchflags(p, uap) 1731 struct proc *p; 1732 register struct fchflags_args /* { 1733 syscallarg(int) fd; 1734 syscallarg(int) flags; 1735 } */ *uap; 1736{ 1737 struct vattr vattr; 1738 struct vnode *vp; 1739 struct file *fp; 1740 int error; 1741 1742 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1743 return (error); 1744 vp = (struct vnode *)fp->f_data; 1745 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1746 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1747 VATTR_NULL(&vattr); 1748 vattr.va_flags = SCARG(uap, flags); 1749 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1750 VOP_UNLOCK(vp, 0, p); 1751 return (error); 1752} 1753 1754/* 1755 * Change mode of a file given path name. 1756 */ 1757#ifndef _SYS_SYSPROTO_H_ 1758struct chmod_args { 1759 char *path; 1760 int mode; 1761}; 1762#endif 1763/* ARGSUSED */ 1764int 1765chmod(p, uap) 1766 struct proc *p; 1767 register struct chmod_args /* { 1768 syscallarg(char *) path; 1769 syscallarg(int) mode; 1770 } */ *uap; 1771{ 1772 register struct vnode *vp; 1773 struct vattr vattr; 1774 int error; 1775 struct nameidata nd; 1776 1777 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1778 if (error = namei(&nd)) 1779 return (error); 1780 vp = nd.ni_vp; 1781 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1782 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1783 VATTR_NULL(&vattr); 1784 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1785 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1786 vput(vp); 1787 return (error); 1788} 1789 1790/* 1791 * Change mode of a file given a file descriptor. 1792 */ 1793#ifndef _SYS_SYSPROTO_H_ 1794struct fchmod_args { 1795 int fd; 1796 int mode; 1797}; 1798#endif 1799/* ARGSUSED */ 1800int 1801fchmod(p, uap) 1802 struct proc *p; 1803 register struct fchmod_args /* { 1804 syscallarg(int) fd; 1805 syscallarg(int) mode; 1806 } */ *uap; 1807{ 1808 struct vattr vattr; 1809 struct vnode *vp; 1810 struct file *fp; 1811 int error; 1812 1813 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1814 return (error); 1815 vp = (struct vnode *)fp->f_data; 1816 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1817 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1818 VATTR_NULL(&vattr); 1819 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1820 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1821 VOP_UNLOCK(vp, 0, p); 1822 return (error); 1823} 1824 1825/* 1826 * Set ownership given a path name. 1827 */ 1828#ifndef _SYS_SYSPROTO_H_ 1829struct chown_args { 1830 char *path; 1831 int uid; 1832 int gid; 1833}; 1834#endif 1835/* ARGSUSED */ 1836int 1837chown(p, uap) 1838 struct proc *p; 1839 register struct chown_args /* { 1840 syscallarg(char *) path; 1841 syscallarg(int) uid; 1842 syscallarg(int) gid; 1843 } */ *uap; 1844{ 1845 register struct vnode *vp; 1846 struct vattr vattr; 1847 int error; 1848 struct nameidata nd; 1849 1850 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1851 if (error = namei(&nd)) 1852 return (error); 1853 vp = nd.ni_vp; 1854 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1855 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1856 VATTR_NULL(&vattr); 1857 vattr.va_uid = SCARG(uap, uid); 1858 vattr.va_gid = SCARG(uap, gid); 1859 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1860 vput(vp); 1861 return (error); 1862} 1863 1864/* 1865 * Set ownership given a path name, do not cross symlinks. 1866 */ 1867#ifndef _SYS_SYSPROTO_H_ 1868struct lchown_args { 1869 char *path; 1870 int uid; 1871 int gid; 1872}; 1873#endif 1874/* ARGSUSED */ 1875int 1876lchown(p, uap) 1877 struct proc *p; 1878 register struct lchown_args /* { 1879 syscallarg(char *) path; 1880 syscallarg(int) uid; 1881 syscallarg(int) gid; 1882 } */ *uap; 1883{ 1884 register struct vnode *vp; 1885 struct vattr vattr; 1886 int error; 1887 struct nameidata nd; 1888 1889 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1890 if (error = namei(&nd)) 1891 return (error); 1892 vp = nd.ni_vp; 1893 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1894 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1895 VATTR_NULL(&vattr); 1896 vattr.va_uid = SCARG(uap, uid); 1897 vattr.va_gid = SCARG(uap, gid); 1898 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1899 vput(vp); 1900 return (error); 1901} 1902 1903/* 1904 * Set ownership given a file descriptor. 1905 */ 1906#ifndef _SYS_SYSPROTO_H_ 1907struct fchown_args { 1908 int fd; 1909 int uid; 1910 int gid; 1911}; 1912#endif 1913/* ARGSUSED */ 1914int 1915fchown(p, uap) 1916 struct proc *p; 1917 register struct fchown_args /* { 1918 syscallarg(int) fd; 1919 syscallarg(int) uid; 1920 syscallarg(int) gid; 1921 } */ *uap; 1922{ 1923 struct vattr vattr; 1924 struct vnode *vp; 1925 struct file *fp; 1926 int error; 1927 1928 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1929 return (error); 1930 vp = (struct vnode *)fp->f_data; 1931 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1932 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1933 VATTR_NULL(&vattr); 1934 vattr.va_uid = SCARG(uap, uid); 1935 vattr.va_gid = SCARG(uap, gid); 1936 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1937 VOP_UNLOCK(vp, 0, p); 1938 return (error); 1939} 1940 1941/* 1942 * Set the access and modification times of a file. 1943 */ 1944#ifndef _SYS_SYSPROTO_H_ 1945struct utimes_args { 1946 char *path; 1947 struct timeval *tptr; 1948}; 1949#endif 1950/* ARGSUSED */ 1951int 1952utimes(p, uap) 1953 struct proc *p; 1954 register struct utimes_args /* { 1955 syscallarg(char *) path; 1956 syscallarg(struct timeval *) tptr; 1957 } */ *uap; 1958{ 1959 register struct vnode *vp; 1960 struct timeval tv[2]; 1961 struct vattr vattr; 1962 int error; 1963 struct nameidata nd; 1964 1965 VATTR_NULL(&vattr); 1966 if (SCARG(uap, tptr) == NULL) { 1967 microtime(&tv[0]); 1968 tv[1] = tv[0]; 1969 vattr.va_vaflags |= VA_UTIMES_NULL; 1970 } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 1971 sizeof (tv))) 1972 return (error); 1973 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1974 if (error = namei(&nd)) 1975 return (error); 1976 vp = nd.ni_vp; 1977 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1978 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1979 vattr.va_atime.tv_sec = tv[0].tv_sec; 1980 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; 1981 vattr.va_mtime.tv_sec = tv[1].tv_sec; 1982 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; 1983 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1984 vput(vp); 1985 return (error); 1986} 1987 1988/* 1989 * Truncate a file given its path name. 1990 */ 1991#ifndef _SYS_SYSPROTO_H_ 1992struct truncate_args { 1993 char *path; 1994 int pad; 1995 off_t length; 1996}; 1997#endif 1998/* ARGSUSED */ 1999int 2000truncate(p, uap) 2001 struct proc *p; 2002 register struct truncate_args /* { 2003 syscallarg(char *) path; 2004 syscallarg(int) pad; 2005 syscallarg(off_t) length; 2006 } */ *uap; 2007{ 2008 register struct vnode *vp; 2009 struct vattr vattr; 2010 int error; 2011 struct nameidata nd; 2012 2013 if (uap->length < 0) 2014 return(EINVAL); 2015 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2016 if (error = namei(&nd)) 2017 return (error); 2018 vp = nd.ni_vp; 2019 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2020 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2021 if (vp->v_type == VDIR) 2022 error = EISDIR; 2023 else if ((error = vn_writechk(vp)) == 0 && 2024 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 2025 VATTR_NULL(&vattr); 2026 vattr.va_size = SCARG(uap, length); 2027 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2028 } 2029 vput(vp); 2030 return (error); 2031} 2032 2033/* 2034 * Truncate a file given a file descriptor. 2035 */ 2036#ifndef _SYS_SYSPROTO_H_ 2037struct ftruncate_args { 2038 int fd; 2039 int pad; 2040 off_t length; 2041}; 2042#endif 2043/* ARGSUSED */ 2044int 2045ftruncate(p, uap) 2046 struct proc *p; 2047 register struct ftruncate_args /* { 2048 syscallarg(int) fd; 2049 syscallarg(int) pad; 2050 syscallarg(off_t) length; 2051 } */ *uap; 2052{ 2053 struct vattr vattr; 2054 struct vnode *vp; 2055 struct file *fp; 2056 int error; 2057 2058 if (uap->length < 0) 2059 return(EINVAL); 2060 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2061 return (error); 2062 if ((fp->f_flag & FWRITE) == 0) 2063 return (EINVAL); 2064 vp = (struct vnode *)fp->f_data; 2065 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2066 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2067 if (vp->v_type == VDIR) 2068 error = EISDIR; 2069 else if ((error = vn_writechk(vp)) == 0) { 2070 VATTR_NULL(&vattr); 2071 vattr.va_size = SCARG(uap, length); 2072 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 2073 } 2074 VOP_UNLOCK(vp, 0, p); 2075 return (error); 2076} 2077 2078#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 2079/* 2080 * Truncate a file given its path name. 2081 */ 2082#ifndef _SYS_SYSPROTO_H_ 2083struct otruncate_args { 2084 char *path; 2085 long length; 2086}; 2087#endif 2088/* ARGSUSED */ 2089int 2090otruncate(p, uap) 2091 struct proc *p; 2092 register struct otruncate_args /* { 2093 syscallarg(char *) path; 2094 syscallarg(long) length; 2095 } */ *uap; 2096{ 2097 struct truncate_args /* { 2098 syscallarg(char *) path; 2099 syscallarg(int) pad; 2100 syscallarg(off_t) length; 2101 } */ nuap; 2102 2103 SCARG(&nuap, path) = SCARG(uap, path); 2104 SCARG(&nuap, length) = SCARG(uap, length); 2105 return (truncate(p, &nuap)); 2106} 2107 2108/* 2109 * Truncate a file given a file descriptor. 2110 */ 2111#ifndef _SYS_SYSPROTO_H_ 2112struct oftruncate_args { 2113 int fd; 2114 long length; 2115}; 2116#endif 2117/* ARGSUSED */ 2118int 2119oftruncate(p, uap) 2120 struct proc *p; 2121 register struct oftruncate_args /* { 2122 syscallarg(int) fd; 2123 syscallarg(long) length; 2124 } */ *uap; 2125{ 2126 struct ftruncate_args /* { 2127 syscallarg(int) fd; 2128 syscallarg(int) pad; 2129 syscallarg(off_t) length; 2130 } */ nuap; 2131 2132 SCARG(&nuap, fd) = SCARG(uap, fd); 2133 SCARG(&nuap, length) = SCARG(uap, length); 2134 return (ftruncate(p, &nuap)); 2135} 2136#endif /* COMPAT_43 || COMPAT_SUNOS */ 2137 2138/* 2139 * Sync an open file. 2140 */ 2141#ifndef _SYS_SYSPROTO_H_ 2142struct fsync_args { 2143 int fd; 2144}; 2145#endif 2146/* ARGSUSED */ 2147int 2148fsync(p, uap) 2149 struct proc *p; 2150 struct fsync_args /* { 2151 syscallarg(int) fd; 2152 } */ *uap; 2153{ 2154 register struct vnode *vp; 2155 struct file *fp; 2156 int error; 2157 2158 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2159 return (error); 2160 vp = (struct vnode *)fp->f_data; 2161 if ((error = vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, p)) == NULL) { 2162 if (vp->v_object) { 2163 vm_object_page_clean(vp->v_object, 0, 0 ,0); 2164 } 2165 error = VOP_FSYNC(vp, fp->f_cred, 2166 (vp->v_mount && (vp->v_mount->mnt_flag & MNT_ASYNC)) ? 2167 MNT_NOWAIT : MNT_WAIT, p); 2168 VOP_UNLOCK(vp, 0, p); 2169 } 2170 return (error); 2171} 2172 2173/* 2174 * Rename files. Source and destination must either both be directories, 2175 * or both not be directories. If target is a directory, it must be empty. 2176 */ 2177#ifndef _SYS_SYSPROTO_H_ 2178struct rename_args { 2179 char *from; 2180 char *to; 2181}; 2182#endif 2183/* ARGSUSED */ 2184int 2185rename(p, uap) 2186 struct proc *p; 2187 register struct rename_args /* { 2188 syscallarg(char *) from; 2189 syscallarg(char *) to; 2190 } */ *uap; 2191{ 2192 register struct vnode *tvp, *fvp, *tdvp; 2193 struct nameidata fromnd, tond; 2194 int error; 2195 2196 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 2197 SCARG(uap, from), p); 2198 if (error = namei(&fromnd)) 2199 return (error); 2200 fvp = fromnd.ni_vp; 2201 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | NOOBJ, 2202 UIO_USERSPACE, SCARG(uap, to), p); 2203 if (fromnd.ni_vp->v_type == VDIR) 2204 tond.ni_cnd.cn_flags |= WILLBEDIR; 2205 if (error = namei(&tond)) { 2206 /* Translate error code for rename("dir1", "dir2/."). */ 2207 if (error == EISDIR && fvp->v_type == VDIR) 2208 error = EINVAL; 2209 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2210 vrele(fromnd.ni_dvp); 2211 vrele(fvp); 2212 goto out1; 2213 } 2214 tdvp = tond.ni_dvp; 2215 tvp = tond.ni_vp; 2216 if (tvp != NULL) { 2217 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 2218 error = ENOTDIR; 2219 goto out; 2220 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 2221 error = EISDIR; 2222 goto out; 2223 } 2224 } 2225 if (fvp == tdvp) 2226 error = EINVAL; 2227 /* 2228 * If source is the same as the destination (that is the 2229 * same inode number with the same name in the same directory), 2230 * then there is nothing to do. 2231 */ 2232 if (fvp == tvp && fromnd.ni_dvp == tdvp && 2233 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 2234 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 2235 fromnd.ni_cnd.cn_namelen)) 2236 error = -1; 2237out: 2238 if (!error) { 2239 VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); 2240 if (fromnd.ni_dvp != tdvp) { 2241 VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2242 } 2243 if (tvp) { 2244 VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); 2245 } 2246 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 2247 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 2248 } else { 2249 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 2250 if (tdvp == tvp) 2251 vrele(tdvp); 2252 else 2253 vput(tdvp); 2254 if (tvp) 2255 vput(tvp); 2256 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2257 vrele(fromnd.ni_dvp); 2258 vrele(fvp); 2259 } 2260 vrele(tond.ni_startdir); 2261 ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename"); 2262 ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename"); 2263 ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename"); 2264 ASSERT_VOP_UNLOCKED(tond.ni_vp, "rename"); 2265 zfree(namei_zone, tond.ni_cnd.cn_pnbuf); 2266out1: 2267 if (fromnd.ni_startdir) 2268 vrele(fromnd.ni_startdir); 2269 zfree(namei_zone, fromnd.ni_cnd.cn_pnbuf); 2270 if (error == -1) 2271 return (0); 2272 return (error); 2273} 2274 2275/* 2276 * Make a directory file. 2277 */ 2278#ifndef _SYS_SYSPROTO_H_ 2279struct mkdir_args { 2280 char *path; 2281 int mode; 2282}; 2283#endif 2284/* ARGSUSED */ 2285int 2286mkdir(p, uap) 2287 struct proc *p; 2288 register struct mkdir_args /* { 2289 syscallarg(char *) path; 2290 syscallarg(int) mode; 2291 } */ *uap; 2292{ 2293 register struct vnode *vp; 2294 struct vattr vattr; 2295 int error; 2296 struct nameidata nd; 2297 2298 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 2299 nd.ni_cnd.cn_flags |= WILLBEDIR; 2300 if (error = namei(&nd)) 2301 return (error); 2302 vp = nd.ni_vp; 2303 if (vp != NULL) { 2304 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2305 if (nd.ni_dvp == vp) 2306 vrele(nd.ni_dvp); 2307 else 2308 vput(nd.ni_dvp); 2309 vrele(vp); 2310 return (EEXIST); 2311 } 2312 VATTR_NULL(&vattr); 2313 vattr.va_type = VDIR; 2314 vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; 2315 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2316 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 2317 if (!error) 2318 vput(nd.ni_vp); 2319 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir"); 2320 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir"); 2321 return (error); 2322} 2323 2324/* 2325 * Remove a directory file. 2326 */ 2327#ifndef _SYS_SYSPROTO_H_ 2328struct rmdir_args { 2329 char *path; 2330}; 2331#endif 2332/* ARGSUSED */ 2333int 2334rmdir(p, uap) 2335 struct proc *p; 2336 struct rmdir_args /* { 2337 syscallarg(char *) path; 2338 } */ *uap; 2339{ 2340 register struct vnode *vp; 2341 int error; 2342 struct nameidata nd; 2343 2344 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 2345 SCARG(uap, path), p); 2346 if (error = namei(&nd)) 2347 return (error); 2348 vp = nd.ni_vp; 2349 if (vp->v_type != VDIR) { 2350 error = ENOTDIR; 2351 goto out; 2352 } 2353 /* 2354 * No rmdir "." please. 2355 */ 2356 if (nd.ni_dvp == vp) { 2357 error = EINVAL; 2358 goto out; 2359 } 2360 /* 2361 * The root of a mounted filesystem cannot be deleted. 2362 */ 2363 if (vp->v_flag & VROOT) 2364 error = EBUSY; 2365out: 2366 if (!error) { 2367 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2368 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2369 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 2370 } else { 2371 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2372 if (nd.ni_dvp == vp) 2373 vrele(nd.ni_dvp); 2374 else 2375 vput(nd.ni_dvp); 2376 vput(vp); 2377 } 2378 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir"); 2379 ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir"); 2380 return (error); 2381} 2382 2383#ifdef COMPAT_43 2384/* 2385 * Read a block of directory entries in a file system independent format. 2386 */ 2387#ifndef _SYS_SYSPROTO_H_ 2388struct ogetdirentries_args { 2389 int fd; 2390 char *buf; 2391 u_int count; 2392 long *basep; 2393}; 2394#endif 2395int 2396ogetdirentries(p, uap) 2397 struct proc *p; 2398 register struct ogetdirentries_args /* { 2399 syscallarg(int) fd; 2400 syscallarg(char *) buf; 2401 syscallarg(u_int) count; 2402 syscallarg(long *) basep; 2403 } */ *uap; 2404{ 2405 register struct vnode *vp; 2406 struct file *fp; 2407 struct uio auio, kuio; 2408 struct iovec aiov, kiov; 2409 struct dirent *dp, *edp; 2410 caddr_t dirbuf; 2411 int error, eofflag, readcnt; 2412 long loff; 2413 2414 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2415 return (error); 2416 if ((fp->f_flag & FREAD) == 0) 2417 return (EBADF); 2418 vp = (struct vnode *)fp->f_data; 2419unionread: 2420 if (vp->v_type != VDIR) 2421 return (EINVAL); 2422 aiov.iov_base = SCARG(uap, buf); 2423 aiov.iov_len = SCARG(uap, count); 2424 auio.uio_iov = &aiov; 2425 auio.uio_iovcnt = 1; 2426 auio.uio_rw = UIO_READ; 2427 auio.uio_segflg = UIO_USERSPACE; 2428 auio.uio_procp = p; 2429 auio.uio_resid = SCARG(uap, count); 2430 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2431 loff = auio.uio_offset = fp->f_offset; 2432# if (BYTE_ORDER != LITTLE_ENDIAN) 2433 if (vp->v_mount->mnt_maxsymlinklen <= 0) { 2434 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 2435 NULL, NULL); 2436 fp->f_offset = auio.uio_offset; 2437 } else 2438# endif 2439 { 2440 kuio = auio; 2441 kuio.uio_iov = &kiov; 2442 kuio.uio_segflg = UIO_SYSSPACE; 2443 kiov.iov_len = SCARG(uap, count); 2444 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); 2445 kiov.iov_base = dirbuf; 2446 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 2447 NULL, NULL); 2448 fp->f_offset = kuio.uio_offset; 2449 if (error == 0) { 2450 readcnt = SCARG(uap, count) - kuio.uio_resid; 2451 edp = (struct dirent *)&dirbuf[readcnt]; 2452 for (dp = (struct dirent *)dirbuf; dp < edp; ) { 2453# if (BYTE_ORDER == LITTLE_ENDIAN) 2454 /* 2455 * The expected low byte of 2456 * dp->d_namlen is our dp->d_type. 2457 * The high MBZ byte of dp->d_namlen 2458 * is our dp->d_namlen. 2459 */ 2460 dp->d_type = dp->d_namlen; 2461 dp->d_namlen = 0; 2462# else 2463 /* 2464 * The dp->d_type is the high byte 2465 * of the expected dp->d_namlen, 2466 * so must be zero'ed. 2467 */ 2468 dp->d_type = 0; 2469# endif 2470 if (dp->d_reclen > 0) { 2471 dp = (struct dirent *) 2472 ((char *)dp + dp->d_reclen); 2473 } else { 2474 error = EIO; 2475 break; 2476 } 2477 } 2478 if (dp >= edp) 2479 error = uiomove(dirbuf, readcnt, &auio); 2480 } 2481 FREE(dirbuf, M_TEMP); 2482 } 2483 VOP_UNLOCK(vp, 0, p); 2484 if (error) 2485 return (error); 2486 2487#ifdef UNION 2488{ 2489 if ((SCARG(uap, count) == auio.uio_resid) && 2490 (vp->v_op == union_vnodeop_p)) { 2491 struct vnode *lvp; 2492 2493 lvp = union_dircache(vp, p); 2494 if (lvp != NULLVP) { 2495 struct vattr va; 2496 2497 /* 2498 * If the directory is opaque, 2499 * then don't show lower entries 2500 */ 2501 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 2502 if (va.va_flags & OPAQUE) { 2503 vput(lvp); 2504 lvp = NULL; 2505 } 2506 } 2507 2508 if (lvp != NULLVP) { 2509 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 2510 if (error) { 2511 vput(lvp); 2512 return (error); 2513 } 2514 VOP_UNLOCK(lvp, 0, p); 2515 fp->f_data = (caddr_t) lvp; 2516 fp->f_offset = 0; 2517 error = vn_close(vp, FREAD, fp->f_cred, p); 2518 if (error) 2519 return (error); 2520 vp = lvp; 2521 goto unionread; 2522 } 2523 } 2524} 2525#endif /* UNION */ 2526 2527 if ((SCARG(uap, count) == auio.uio_resid) && 2528 (vp->v_flag & VROOT) && 2529 (vp->v_mount->mnt_flag & MNT_UNION)) { 2530 struct vnode *tvp = vp; 2531 vp = vp->v_mount->mnt_vnodecovered; 2532 VREF(vp); 2533 fp->f_data = (caddr_t) vp; 2534 fp->f_offset = 0; 2535 vrele(tvp); 2536 goto unionread; 2537 } 2538 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 2539 sizeof(long)); 2540 p->p_retval[0] = SCARG(uap, count) - auio.uio_resid; 2541 return (error); 2542} 2543#endif /* COMPAT_43 */ 2544 2545/* 2546 * Read a block of directory entries in a file system independent format. 2547 */ 2548#ifndef _SYS_SYSPROTO_H_ 2549struct getdirentries_args { 2550 int fd; 2551 char *buf; 2552 u_int count; 2553 long *basep; 2554}; 2555#endif 2556int 2557getdirentries(p, uap) 2558 struct proc *p; 2559 register struct getdirentries_args /* { 2560 syscallarg(int) fd; 2561 syscallarg(char *) buf; 2562 syscallarg(u_int) count; 2563 syscallarg(long *) basep; 2564 } */ *uap; 2565{ 2566 register struct vnode *vp; 2567 struct file *fp; 2568 struct uio auio; 2569 struct iovec aiov; 2570 long loff; 2571 int error, eofflag; 2572 2573 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2574 return (error); 2575 if ((fp->f_flag & FREAD) == 0) 2576 return (EBADF); 2577 vp = (struct vnode *)fp->f_data; 2578unionread: 2579 if (vp->v_type != VDIR) 2580 return (EINVAL); 2581 aiov.iov_base = SCARG(uap, buf); 2582 aiov.iov_len = SCARG(uap, count); 2583 auio.uio_iov = &aiov; 2584 auio.uio_iovcnt = 1; 2585 auio.uio_rw = UIO_READ; 2586 auio.uio_segflg = UIO_USERSPACE; 2587 auio.uio_procp = p; 2588 auio.uio_resid = SCARG(uap, count); 2589 /* vn_lock(vp, LK_SHARED | LK_RETRY, p); */ 2590 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2591 loff = auio.uio_offset = fp->f_offset; 2592 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL); 2593 fp->f_offset = auio.uio_offset; 2594 VOP_UNLOCK(vp, 0, p); 2595 if (error) 2596 return (error); 2597 2598#ifdef UNION 2599{ 2600 if ((SCARG(uap, count) == auio.uio_resid) && 2601 (vp->v_op == union_vnodeop_p)) { 2602 struct vnode *lvp; 2603 2604 lvp = union_dircache(vp, p); 2605 if (lvp != NULLVP) { 2606 struct vattr va; 2607 2608 /* 2609 * If the directory is opaque, 2610 * then don't show lower entries 2611 */ 2612 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 2613 if (va.va_flags & OPAQUE) { 2614 vput(lvp); 2615 lvp = NULL; 2616 } 2617 } 2618 2619 if (lvp != NULLVP) { 2620 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 2621 if (error) { 2622 vput(lvp); 2623 return (error); 2624 } 2625 VOP_UNLOCK(lvp, 0, p); 2626 fp->f_data = (caddr_t) lvp; 2627 fp->f_offset = 0; 2628 error = vn_close(vp, FREAD, fp->f_cred, p); 2629 if (error) 2630 return (error); 2631 vp = lvp; 2632 goto unionread; 2633 } 2634 } 2635} 2636#endif /* UNION */ 2637 2638 if ((SCARG(uap, count) == auio.uio_resid) && 2639 (vp->v_flag & VROOT) && 2640 (vp->v_mount->mnt_flag & MNT_UNION)) { 2641 struct vnode *tvp = vp; 2642 vp = vp->v_mount->mnt_vnodecovered; 2643 VREF(vp); 2644 fp->f_data = (caddr_t) vp; 2645 fp->f_offset = 0; 2646 vrele(tvp); 2647 goto unionread; 2648 } 2649 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 2650 sizeof(long)); 2651 p->p_retval[0] = SCARG(uap, count) - auio.uio_resid; 2652 return (error); 2653} 2654 2655/* 2656 * Set the mode mask for creation of filesystem nodes. 2657 */ 2658#ifndef _SYS_SYSPROTO_H_ 2659struct umask_args { 2660 int newmask; 2661}; 2662#endif 2663int 2664umask(p, uap) 2665 struct proc *p; 2666 struct umask_args /* { 2667 syscallarg(int) newmask; 2668 } */ *uap; 2669{ 2670 register struct filedesc *fdp; 2671 2672 fdp = p->p_fd; 2673 p->p_retval[0] = fdp->fd_cmask; 2674 fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS; 2675 return (0); 2676} 2677 2678/* 2679 * Void all references to file by ripping underlying filesystem 2680 * away from vnode. 2681 */ 2682#ifndef _SYS_SYSPROTO_H_ 2683struct revoke_args { 2684 char *path; 2685}; 2686#endif 2687/* ARGSUSED */ 2688int 2689revoke(p, uap) 2690 struct proc *p; 2691 register struct revoke_args /* { 2692 syscallarg(char *) path; 2693 } */ *uap; 2694{ 2695 register struct vnode *vp; 2696 struct vattr vattr; 2697 int error; 2698 struct nameidata nd; 2699 2700 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2701 if (error = namei(&nd)) 2702 return (error); 2703 vp = nd.ni_vp; 2704 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 2705 goto out; 2706 if (p->p_ucred->cr_uid != vattr.va_uid && 2707 (error = suser(p->p_ucred, &p->p_acflag))) 2708 goto out; 2709 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 2710 VOP_REVOKE(vp, REVOKEALL); 2711out: 2712 vrele(vp); 2713 return (error); 2714} 2715 2716/* 2717 * Convert a user file descriptor to a kernel file entry. 2718 */ 2719int 2720getvnode(fdp, fd, fpp) 2721 struct filedesc *fdp; 2722 int fd; 2723 struct file **fpp; 2724{ 2725 struct file *fp; 2726 2727 if ((u_int)fd >= fdp->fd_nfiles || 2728 (fp = fdp->fd_ofiles[fd]) == NULL) 2729 return (EBADF); 2730 if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO) 2731 return (EINVAL); 2732 *fpp = fp; 2733 return (0); 2734} 2735#ifndef _SYS_SYSPROTO_H_ 2736struct __getcwd_args { 2737 u_char *buf; 2738 u_int buflen; 2739}; 2740#endif 2741#define STATNODE(mode, name, var) \ 2742 SYSCTL_INT(_vfs_cache, OID_AUTO, name, mode, var, 0, ""); 2743 2744static int disablecwd; 2745SYSCTL_INT(_debug, OID_AUTO, disablecwd, CTLFLAG_RW, &disablecwd, 0, ""); 2746 2747static u_long numcwdcalls; STATNODE(CTLFLAG_RD, numcwdcalls, &numcwdcalls); 2748static u_long numcwdfail1; STATNODE(CTLFLAG_RD, numcwdfail1, &numcwdfail1); 2749static u_long numcwdfail2; STATNODE(CTLFLAG_RD, numcwdfail2, &numcwdfail2); 2750static u_long numcwdfail3; STATNODE(CTLFLAG_RD, numcwdfail3, &numcwdfail3); 2751static u_long numcwdfail4; STATNODE(CTLFLAG_RD, numcwdfail4, &numcwdfail4); 2752static u_long numcwdfound; STATNODE(CTLFLAG_RD, numcwdfound, &numcwdfound); 2753int 2754__getcwd(p, uap) 2755 struct proc *p; 2756 struct __getcwd_args *uap; 2757{ 2758 char *bp, *buf; 2759 int error, i, slash_prefixed; 2760 struct filedesc *fdp; 2761 struct namecache *ncp; 2762 struct vnode *vp; 2763 2764 numcwdcalls++; 2765 if (disablecwd) 2766 return (ENODEV); 2767 if (uap->buflen < 2) 2768 return (EINVAL); 2769 if (uap->buflen > MAXPATHLEN) 2770 uap->buflen = MAXPATHLEN; 2771 buf = bp = malloc(uap->buflen, M_TEMP, M_WAITOK); 2772 bp += uap->buflen - 1; 2773 *bp = '\0'; 2774 fdp = p->p_fd; 2775 slash_prefixed = 0; 2776 for (vp = fdp->fd_cdir; vp != fdp->fd_rdir && vp != rootvnode;) { 2777 if (vp->v_flag & VROOT) { 2778 vp = vp->v_mount->mnt_vnodecovered; 2779 continue; 2780 } 2781 if (vp->v_dd->v_id != vp->v_ddid) { 2782 numcwdfail1++; 2783 free(buf, M_TEMP); 2784 return (ENOTDIR); 2785 } 2786 ncp = TAILQ_FIRST(&vp->v_cache_dst); 2787 if (!ncp) { 2788 numcwdfail2++; 2789 free(buf, M_TEMP); 2790 return (ENOENT); 2791 } 2792 if (ncp->nc_dvp != vp->v_dd) { 2793 numcwdfail3++; 2794 free(buf, M_TEMP); 2795 return (EBADF); 2796 } 2797 for (i = ncp->nc_nlen - 1; i >= 0; i--) { 2798 if (bp == buf) { 2799 numcwdfail4++; 2800 free(buf, M_TEMP); 2801 return (ENOMEM); 2802 } 2803 *--bp = ncp->nc_name[i]; 2804 } 2805 if (bp == buf) { 2806 numcwdfail4++; 2807 free(buf, M_TEMP); 2808 return (ENOMEM); 2809 } 2810 *--bp = '/'; 2811 slash_prefixed = 1; 2812 vp = vp->v_dd; 2813 } 2814 if (!slash_prefixed) { 2815 if (bp == buf) { 2816 numcwdfail4++; 2817 free(buf, M_TEMP); 2818 return (ENOMEM); 2819 } 2820 *--bp = '/'; 2821 } 2822 numcwdfound++; 2823 error = copyout(bp, uap->buf, strlen(bp) + 1); 2824 free(buf, M_TEMP); 2825 return (error); 2826} 2827