vfs_syscalls.c revision 33168
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.91 1998/02/06 12:13:32 eivind 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 if (fdp->fd_rdir != NULL) 808 vrele(fdp->fd_rdir); 809 fdp->fd_rdir = nd.ni_vp; 810 return (0); 811} 812 813/* 814 * Common routine for chroot and chdir. 815 */ 816static int 817change_dir(ndp, p) 818 register struct nameidata *ndp; 819 struct proc *p; 820{ 821 struct vnode *vp; 822 int error; 823 824 error = namei(ndp); 825 if (error) 826 return (error); 827 vp = ndp->ni_vp; 828 if (vp->v_type != VDIR) 829 error = ENOTDIR; 830 else 831 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 832 if (error) 833 vput(vp); 834 else 835 VOP_UNLOCK(vp, 0, p); 836 return (error); 837} 838 839/* 840 * Check permissions, allocate an open file structure, 841 * and call the device open routine if any. 842 */ 843#ifndef _SYS_SYSPROTO_H_ 844struct open_args { 845 char *path; 846 int flags; 847 int mode; 848}; 849#endif 850int 851open(p, uap) 852 struct proc *p; 853 register struct open_args /* { 854 syscallarg(char *) path; 855 syscallarg(int) flags; 856 syscallarg(int) mode; 857 } */ *uap; 858{ 859 register struct filedesc *fdp = p->p_fd; 860 register struct file *fp; 861 register struct vnode *vp; 862 int cmode, flags, oflags; 863 struct file *nfp; 864 int type, indx, error; 865 struct flock lf; 866 struct nameidata nd; 867 868 oflags = SCARG(uap, flags); 869 if ((oflags & O_ACCMODE) == O_ACCMODE) 870 return (EINVAL); 871 flags = FFLAGS(oflags); 872 error = falloc(p, &nfp, &indx); 873 if (error) 874 return (error); 875 fp = nfp; 876 cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 877 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 878 p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 879 error = vn_open(&nd, flags, cmode); 880 if (error) { 881 ffree(fp); 882 if ((error == ENODEV || error == ENXIO) && 883 p->p_dupfd >= 0 && /* XXX from fdopen */ 884 (error = 885 dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 886 p->p_retval[0] = indx; 887 return (0); 888 } 889 if (error == ERESTART) 890 error = EINTR; 891 fdp->fd_ofiles[indx] = NULL; 892 return (error); 893 } 894 p->p_dupfd = 0; 895 vp = nd.ni_vp; 896 897 fp->f_flag = flags & FMASK; 898 fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE); 899 fp->f_ops = &vnops; 900 fp->f_data = (caddr_t)vp; 901 if (flags & (O_EXLOCK | O_SHLOCK)) { 902 lf.l_whence = SEEK_SET; 903 lf.l_start = 0; 904 lf.l_len = 0; 905 if (flags & O_EXLOCK) 906 lf.l_type = F_WRLCK; 907 else 908 lf.l_type = F_RDLCK; 909 type = F_FLOCK; 910 if ((flags & FNONBLOCK) == 0) 911 type |= F_WAIT; 912 VOP_UNLOCK(vp, 0, p); 913 if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 914 (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 915 ffree(fp); 916 fdp->fd_ofiles[indx] = NULL; 917 return (error); 918 } 919 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 920 fp->f_flag |= FHASLOCK; 921 } 922 if ((vp->v_type == VREG) && (vp->v_object == NULL)) 923 vfs_object_create(vp, p, p->p_ucred, TRUE); 924 VOP_UNLOCK(vp, 0, p); 925 p->p_retval[0] = indx; 926 return (0); 927} 928 929#ifdef COMPAT_43 930/* 931 * Create a file. 932 */ 933#ifndef _SYS_SYSPROTO_H_ 934struct ocreat_args { 935 char *path; 936 int mode; 937}; 938#endif 939int 940ocreat(p, uap) 941 struct proc *p; 942 register struct ocreat_args /* { 943 syscallarg(char *) path; 944 syscallarg(int) mode; 945 } */ *uap; 946{ 947 struct open_args /* { 948 syscallarg(char *) path; 949 syscallarg(int) flags; 950 syscallarg(int) mode; 951 } */ nuap; 952 953 SCARG(&nuap, path) = SCARG(uap, path); 954 SCARG(&nuap, mode) = SCARG(uap, mode); 955 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; 956 return (open(p, &nuap)); 957} 958#endif /* COMPAT_43 */ 959 960/* 961 * Create a special file. 962 */ 963#ifndef _SYS_SYSPROTO_H_ 964struct mknod_args { 965 char *path; 966 int mode; 967 int dev; 968}; 969#endif 970/* ARGSUSED */ 971int 972mknod(p, uap) 973 struct proc *p; 974 register struct mknod_args /* { 975 syscallarg(char *) path; 976 syscallarg(int) mode; 977 syscallarg(int) dev; 978 } */ *uap; 979{ 980 register struct vnode *vp; 981 struct vattr vattr; 982 int error; 983 int whiteout; 984 struct nameidata nd; 985 986 error = suser(p->p_ucred, &p->p_acflag); 987 if (error) 988 return (error); 989 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 990 if (error = namei(&nd)) 991 return (error); 992 vp = nd.ni_vp; 993 if (vp != NULL) 994 error = EEXIST; 995 else { 996 VATTR_NULL(&vattr); 997 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 998 vattr.va_rdev = SCARG(uap, dev); 999 whiteout = 0; 1000 1001 switch (SCARG(uap, mode) & S_IFMT) { 1002 case S_IFMT: /* used by badsect to flag bad sectors */ 1003 vattr.va_type = VBAD; 1004 break; 1005 case S_IFCHR: 1006 vattr.va_type = VCHR; 1007 break; 1008 case S_IFBLK: 1009 vattr.va_type = VBLK; 1010 break; 1011 case S_IFWHT: 1012 whiteout = 1; 1013 break; 1014 default: 1015 error = EINVAL; 1016 break; 1017 } 1018 } 1019 if (!error) { 1020 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1021 if (whiteout) { 1022 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 1023 if (error) 1024 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1025 vput(nd.ni_dvp); 1026 } else { 1027 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, 1028 &nd.ni_cnd, &vattr); 1029 } 1030 } else { 1031 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1032 if (nd.ni_dvp == vp) 1033 vrele(nd.ni_dvp); 1034 else 1035 vput(nd.ni_dvp); 1036 if (vp) 1037 vrele(vp); 1038 } 1039 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod"); 1040 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod"); 1041 return (error); 1042} 1043 1044/* 1045 * Create a named pipe. 1046 */ 1047#ifndef _SYS_SYSPROTO_H_ 1048struct mkfifo_args { 1049 char *path; 1050 int mode; 1051}; 1052#endif 1053/* ARGSUSED */ 1054int 1055mkfifo(p, uap) 1056 struct proc *p; 1057 register struct mkfifo_args /* { 1058 syscallarg(char *) path; 1059 syscallarg(int) mode; 1060 } */ *uap; 1061{ 1062 struct vattr vattr; 1063 int error; 1064 struct nameidata nd; 1065 1066 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1067 if (error = namei(&nd)) 1068 return (error); 1069 if (nd.ni_vp != NULL) { 1070 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1071 if (nd.ni_dvp == nd.ni_vp) 1072 vrele(nd.ni_dvp); 1073 else 1074 vput(nd.ni_dvp); 1075 vrele(nd.ni_vp); 1076 return (EEXIST); 1077 } 1078 VATTR_NULL(&vattr); 1079 vattr.va_type = VFIFO; 1080 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 1081 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1082 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 1083} 1084 1085/* 1086 * Make a hard file link. 1087 */ 1088#ifndef _SYS_SYSPROTO_H_ 1089struct link_args { 1090 char *path; 1091 char *link; 1092}; 1093#endif 1094/* ARGSUSED */ 1095int 1096link(p, uap) 1097 struct proc *p; 1098 register struct link_args /* { 1099 syscallarg(char *) path; 1100 syscallarg(char *) link; 1101 } */ *uap; 1102{ 1103 register struct vnode *vp; 1104 struct nameidata nd; 1105 int error; 1106 1107 NDINIT(&nd, LOOKUP, FOLLOW|NOOBJ, UIO_USERSPACE, SCARG(uap, path), p); 1108 if (error = namei(&nd)) 1109 return (error); 1110 vp = nd.ni_vp; 1111 if (vp->v_type == VDIR) 1112 error = EPERM; /* POSIX */ 1113 else { 1114 NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), p); 1115 error = namei(&nd); 1116 if (!error) { 1117 if (nd.ni_vp != NULL) { 1118 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1119 if (nd.ni_dvp == nd.ni_vp) 1120 vrele(nd.ni_dvp); 1121 else 1122 vput(nd.ni_dvp); 1123 if (nd.ni_vp) 1124 vrele(nd.ni_vp); 1125 error = EEXIST; 1126 } else { 1127 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, 1128 LEASE_WRITE); 1129 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1130 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 1131 } 1132 } 1133 } 1134 vrele(vp); 1135 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link"); 1136 ASSERT_VOP_UNLOCKED(nd.ni_vp, "link"); 1137 return (error); 1138} 1139 1140/* 1141 * Make a symbolic link. 1142 */ 1143#ifndef _SYS_SYSPROTO_H_ 1144struct symlink_args { 1145 char *path; 1146 char *link; 1147}; 1148#endif 1149/* ARGSUSED */ 1150int 1151symlink(p, uap) 1152 struct proc *p; 1153 register struct symlink_args /* { 1154 syscallarg(char *) path; 1155 syscallarg(char *) link; 1156 } */ *uap; 1157{ 1158 struct vattr vattr; 1159 char *path; 1160 int error; 1161 struct nameidata nd; 1162 1163 path = zalloc(namei_zone); 1164 if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) 1165 goto out; 1166 NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), p); 1167 if (error = namei(&nd)) 1168 goto out; 1169 if (nd.ni_vp) { 1170 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1171 if (nd.ni_dvp == nd.ni_vp) 1172 vrele(nd.ni_dvp); 1173 else 1174 vput(nd.ni_dvp); 1175 vrele(nd.ni_vp); 1176 error = EEXIST; 1177 goto out; 1178 } 1179 VATTR_NULL(&vattr); 1180 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 1181 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1182 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 1183 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink"); 1184 ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink"); 1185out: 1186 zfree(namei_zone, path); 1187 return (error); 1188} 1189 1190/* 1191 * Delete a whiteout from the filesystem. 1192 */ 1193/* ARGSUSED */ 1194int 1195undelete(p, uap) 1196 struct proc *p; 1197 register struct undelete_args /* { 1198 syscallarg(char *) path; 1199 } */ *uap; 1200{ 1201 int error; 1202 struct nameidata nd; 1203 1204 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, 1205 SCARG(uap, path), p); 1206 error = namei(&nd); 1207 if (error) 1208 return (error); 1209 1210 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 1211 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1212 if (nd.ni_dvp == nd.ni_vp) 1213 vrele(nd.ni_dvp); 1214 else 1215 vput(nd.ni_dvp); 1216 if (nd.ni_vp) 1217 vrele(nd.ni_vp); 1218 return (EEXIST); 1219 } 1220 1221 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1222 if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) 1223 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1224 vput(nd.ni_dvp); 1225 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete"); 1226 ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete"); 1227 return (error); 1228} 1229 1230/* 1231 * Delete a name from the filesystem. 1232 */ 1233#ifndef _SYS_SYSPROTO_H_ 1234struct unlink_args { 1235 char *path; 1236}; 1237#endif 1238/* ARGSUSED */ 1239int 1240unlink(p, uap) 1241 struct proc *p; 1242 struct unlink_args /* { 1243 syscallarg(char *) path; 1244 } */ *uap; 1245{ 1246 register struct vnode *vp; 1247 int error; 1248 struct nameidata nd; 1249 1250 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1251 if (error = namei(&nd)) 1252 return (error); 1253 vp = nd.ni_vp; 1254 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1255 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1256 1257 if (vp->v_type == VDIR) 1258 error = EPERM; /* POSIX */ 1259 else { 1260 /* 1261 * The root of a mounted filesystem cannot be deleted. 1262 * 1263 * XXX: can this only be a VDIR case? 1264 */ 1265 if (vp->v_flag & VROOT) 1266 error = EBUSY; 1267 } 1268 1269 if (!error) { 1270 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1271 error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd); 1272 } else { 1273 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1274 if (nd.ni_dvp == vp) 1275 vrele(nd.ni_dvp); 1276 else 1277 vput(nd.ni_dvp); 1278 if (vp != NULLVP) 1279 vput(vp); 1280 } 1281 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink"); 1282 ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink"); 1283 return (error); 1284} 1285 1286/* 1287 * Reposition read/write file offset. 1288 */ 1289#ifndef _SYS_SYSPROTO_H_ 1290struct lseek_args { 1291 int fd; 1292 int pad; 1293 off_t offset; 1294 int whence; 1295}; 1296#endif 1297int 1298lseek(p, uap) 1299 struct proc *p; 1300 register struct lseek_args /* { 1301 syscallarg(int) fd; 1302 syscallarg(int) pad; 1303 syscallarg(off_t) offset; 1304 syscallarg(int) whence; 1305 } */ *uap; 1306{ 1307 struct ucred *cred = p->p_ucred; 1308 register struct filedesc *fdp = p->p_fd; 1309 register struct file *fp; 1310 struct vattr vattr; 1311 int error; 1312 1313 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 1314 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) 1315 return (EBADF); 1316 if (fp->f_type != DTYPE_VNODE) 1317 return (ESPIPE); 1318 switch (SCARG(uap, whence)) { 1319 case L_INCR: 1320 fp->f_offset += SCARG(uap, offset); 1321 break; 1322 case L_XTND: 1323 error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p); 1324 if (error) 1325 return (error); 1326 fp->f_offset = SCARG(uap, offset) + vattr.va_size; 1327 break; 1328 case L_SET: 1329 fp->f_offset = SCARG(uap, offset); 1330 break; 1331 default: 1332 return (EINVAL); 1333 } 1334 *(off_t *)(p->p_retval) = fp->f_offset; 1335 return (0); 1336} 1337 1338#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1339/* 1340 * Reposition read/write file offset. 1341 */ 1342#ifndef _SYS_SYSPROTO_H_ 1343struct olseek_args { 1344 int fd; 1345 long offset; 1346 int whence; 1347}; 1348#endif 1349int 1350olseek(p, uap) 1351 struct proc *p; 1352 register struct olseek_args /* { 1353 syscallarg(int) fd; 1354 syscallarg(long) offset; 1355 syscallarg(int) whence; 1356 } */ *uap; 1357{ 1358 struct lseek_args /* { 1359 syscallarg(int) fd; 1360 syscallarg(int) pad; 1361 syscallarg(off_t) offset; 1362 syscallarg(int) whence; 1363 } */ nuap; 1364 int error; 1365 1366 SCARG(&nuap, fd) = SCARG(uap, fd); 1367 SCARG(&nuap, offset) = SCARG(uap, offset); 1368 SCARG(&nuap, whence) = SCARG(uap, whence); 1369 error = lseek(p, &nuap); 1370 return (error); 1371} 1372#endif /* COMPAT_43 */ 1373 1374/* 1375 * Check access permissions. 1376 */ 1377#ifndef _SYS_SYSPROTO_H_ 1378struct access_args { 1379 char *path; 1380 int flags; 1381}; 1382#endif 1383int 1384access(p, uap) 1385 struct proc *p; 1386 register struct access_args /* { 1387 syscallarg(char *) path; 1388 syscallarg(int) flags; 1389 } */ *uap; 1390{ 1391 register struct ucred *cred = p->p_ucred; 1392 register struct vnode *vp; 1393 int error, flags, t_gid, t_uid; 1394 struct nameidata nd; 1395 1396 t_uid = cred->cr_uid; 1397 t_gid = cred->cr_groups[0]; 1398 cred->cr_uid = p->p_cred->p_ruid; 1399 cred->cr_groups[0] = p->p_cred->p_rgid; 1400 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1401 SCARG(uap, path), p); 1402 if (error = namei(&nd)) 1403 goto out1; 1404 vp = nd.ni_vp; 1405 1406 /* Flags == 0 means only check for existence. */ 1407 if (SCARG(uap, flags)) { 1408 flags = 0; 1409 if (SCARG(uap, flags) & R_OK) 1410 flags |= VREAD; 1411 if (SCARG(uap, flags) & W_OK) 1412 flags |= VWRITE; 1413 if (SCARG(uap, flags) & X_OK) 1414 flags |= VEXEC; 1415 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 1416 error = VOP_ACCESS(vp, flags, cred, p); 1417 } 1418 vput(vp); 1419out1: 1420 cred->cr_uid = t_uid; 1421 cred->cr_groups[0] = t_gid; 1422 return (error); 1423} 1424 1425#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1426/* 1427 * Get file status; this version follows links. 1428 */ 1429#ifndef _SYS_SYSPROTO_H_ 1430struct ostat_args { 1431 char *path; 1432 struct ostat *ub; 1433}; 1434#endif 1435/* ARGSUSED */ 1436int 1437ostat(p, uap) 1438 struct proc *p; 1439 register struct ostat_args /* { 1440 syscallarg(char *) path; 1441 syscallarg(struct ostat *) ub; 1442 } */ *uap; 1443{ 1444 struct stat sb; 1445 struct ostat osb; 1446 int error; 1447 struct nameidata nd; 1448 1449 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1450 SCARG(uap, path), p); 1451 if (error = namei(&nd)) 1452 return (error); 1453 error = vn_stat(nd.ni_vp, &sb, p); 1454 vput(nd.ni_vp); 1455 if (error) 1456 return (error); 1457 cvtstat(&sb, &osb); 1458 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 1459 return (error); 1460} 1461 1462/* 1463 * Get file status; this version does not follow links. 1464 */ 1465#ifndef _SYS_SYSPROTO_H_ 1466struct olstat_args { 1467 char *path; 1468 struct ostat *ub; 1469}; 1470#endif 1471/* ARGSUSED */ 1472int 1473olstat(p, uap) 1474 struct proc *p; 1475 register struct olstat_args /* { 1476 syscallarg(char *) path; 1477 syscallarg(struct ostat *) ub; 1478 } */ *uap; 1479{ 1480 struct vnode *vp; 1481 struct stat sb; 1482 struct ostat osb; 1483 int error; 1484 struct nameidata nd; 1485 1486 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1487 SCARG(uap, path), p); 1488 if (error = namei(&nd)) 1489 return (error); 1490 vp = nd.ni_vp; 1491 error = vn_stat(vp, &sb, p); 1492 if (vp->v_type == VLNK) 1493 sb.st_mode |= S_IFLNK | ACCESSPERMS; /* 0777 */ 1494 vput(vp); 1495 if (error) 1496 return (error); 1497 cvtstat(&sb, &osb); 1498 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 1499 return (error); 1500} 1501 1502/* 1503 * Convert from an old to a new stat structure. 1504 */ 1505void 1506cvtstat(st, ost) 1507 struct stat *st; 1508 struct ostat *ost; 1509{ 1510 1511 ost->st_dev = st->st_dev; 1512 ost->st_ino = st->st_ino; 1513 ost->st_mode = st->st_mode; 1514 ost->st_nlink = st->st_nlink; 1515 ost->st_uid = st->st_uid; 1516 ost->st_gid = st->st_gid; 1517 ost->st_rdev = st->st_rdev; 1518 if (st->st_size < (quad_t)1 << 32) 1519 ost->st_size = st->st_size; 1520 else 1521 ost->st_size = -2; 1522 ost->st_atime = st->st_atime; 1523 ost->st_mtime = st->st_mtime; 1524 ost->st_ctime = st->st_ctime; 1525 ost->st_blksize = st->st_blksize; 1526 ost->st_blocks = st->st_blocks; 1527 ost->st_flags = st->st_flags; 1528 ost->st_gen = st->st_gen; 1529} 1530#endif /* COMPAT_43 || COMPAT_SUNOS */ 1531 1532/* 1533 * Get file status; this version follows links. 1534 */ 1535#ifndef _SYS_SYSPROTO_H_ 1536struct stat_args { 1537 char *path; 1538 struct stat *ub; 1539}; 1540#endif 1541/* ARGSUSED */ 1542int 1543stat(p, uap) 1544 struct proc *p; 1545 register struct stat_args /* { 1546 syscallarg(char *) path; 1547 syscallarg(struct stat *) ub; 1548 } */ *uap; 1549{ 1550 struct stat sb; 1551 int error; 1552 struct nameidata nd; 1553 1554 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1555 SCARG(uap, path), p); 1556 if (error = namei(&nd)) 1557 return (error); 1558 error = vn_stat(nd.ni_vp, &sb, p); 1559 vput(nd.ni_vp); 1560 if (error) 1561 return (error); 1562 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1563 return (error); 1564} 1565 1566/* 1567 * Get file status; this version does not follow links. 1568 */ 1569#ifndef _SYS_SYSPROTO_H_ 1570struct lstat_args { 1571 char *path; 1572 struct stat *ub; 1573}; 1574#endif 1575/* ARGSUSED */ 1576int 1577lstat(p, uap) 1578 struct proc *p; 1579 register struct lstat_args /* { 1580 syscallarg(char *) path; 1581 syscallarg(struct stat *) ub; 1582 } */ *uap; 1583{ 1584 int error; 1585 struct vnode *vp; 1586 struct stat sb; 1587 struct nameidata nd; 1588 1589 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1590 SCARG(uap, path), p); 1591 if (error = namei(&nd)) 1592 return (error); 1593 vp = nd.ni_vp; 1594 error = vn_stat(vp, &sb, p); 1595 if (vp->v_type == VLNK) 1596 sb.st_mode |= S_IFLNK | ACCESSPERMS; /* 0777 */ 1597 vput(vp); 1598 if (error) 1599 return (error); 1600 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1601 return (error); 1602} 1603 1604/* 1605 * Get configurable pathname variables. 1606 */ 1607#ifndef _SYS_SYSPROTO_H_ 1608struct pathconf_args { 1609 char *path; 1610 int name; 1611}; 1612#endif 1613/* ARGSUSED */ 1614int 1615pathconf(p, uap) 1616 struct proc *p; 1617 register struct pathconf_args /* { 1618 syscallarg(char *) path; 1619 syscallarg(int) name; 1620 } */ *uap; 1621{ 1622 int error; 1623 struct nameidata nd; 1624 1625 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1626 SCARG(uap, path), p); 1627 if (error = namei(&nd)) 1628 return (error); 1629 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), p->p_retval); 1630 vput(nd.ni_vp); 1631 return (error); 1632} 1633 1634/* 1635 * Return target name of a symbolic link. 1636 */ 1637#ifndef _SYS_SYSPROTO_H_ 1638struct readlink_args { 1639 char *path; 1640 char *buf; 1641 int count; 1642}; 1643#endif 1644/* ARGSUSED */ 1645int 1646readlink(p, uap) 1647 struct proc *p; 1648 register struct readlink_args /* { 1649 syscallarg(char *) path; 1650 syscallarg(char *) buf; 1651 syscallarg(int) count; 1652 } */ *uap; 1653{ 1654 register struct vnode *vp; 1655 struct iovec aiov; 1656 struct uio auio; 1657 int error; 1658 struct nameidata nd; 1659 1660 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1661 SCARG(uap, path), p); 1662 if (error = namei(&nd)) 1663 return (error); 1664 vp = nd.ni_vp; 1665 if (vp->v_type != VLNK) 1666 error = EINVAL; 1667 else { 1668 aiov.iov_base = SCARG(uap, buf); 1669 aiov.iov_len = SCARG(uap, count); 1670 auio.uio_iov = &aiov; 1671 auio.uio_iovcnt = 1; 1672 auio.uio_offset = 0; 1673 auio.uio_rw = UIO_READ; 1674 auio.uio_segflg = UIO_USERSPACE; 1675 auio.uio_procp = p; 1676 auio.uio_resid = SCARG(uap, count); 1677 error = VOP_READLINK(vp, &auio, p->p_ucred); 1678 } 1679 vput(vp); 1680 p->p_retval[0] = SCARG(uap, count) - auio.uio_resid; 1681 return (error); 1682} 1683 1684/* 1685 * Change flags of a file given a path name. 1686 */ 1687#ifndef _SYS_SYSPROTO_H_ 1688struct chflags_args { 1689 char *path; 1690 int flags; 1691}; 1692#endif 1693/* ARGSUSED */ 1694int 1695chflags(p, uap) 1696 struct proc *p; 1697 register struct chflags_args /* { 1698 syscallarg(char *) path; 1699 syscallarg(int) flags; 1700 } */ *uap; 1701{ 1702 register struct vnode *vp; 1703 struct vattr vattr; 1704 int error; 1705 struct nameidata nd; 1706 1707 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1708 if (error = namei(&nd)) 1709 return (error); 1710 vp = nd.ni_vp; 1711 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1712 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1713 VATTR_NULL(&vattr); 1714 vattr.va_flags = SCARG(uap, flags); 1715 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1716 vput(vp); 1717 return (error); 1718} 1719 1720/* 1721 * Change flags of a file given a file descriptor. 1722 */ 1723#ifndef _SYS_SYSPROTO_H_ 1724struct fchflags_args { 1725 int fd; 1726 int flags; 1727}; 1728#endif 1729/* ARGSUSED */ 1730int 1731fchflags(p, uap) 1732 struct proc *p; 1733 register struct fchflags_args /* { 1734 syscallarg(int) fd; 1735 syscallarg(int) flags; 1736 } */ *uap; 1737{ 1738 struct vattr vattr; 1739 struct vnode *vp; 1740 struct file *fp; 1741 int error; 1742 1743 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1744 return (error); 1745 vp = (struct vnode *)fp->f_data; 1746 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1747 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1748 VATTR_NULL(&vattr); 1749 vattr.va_flags = SCARG(uap, flags); 1750 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1751 VOP_UNLOCK(vp, 0, p); 1752 return (error); 1753} 1754 1755/* 1756 * Change mode of a file given path name. 1757 */ 1758#ifndef _SYS_SYSPROTO_H_ 1759struct chmod_args { 1760 char *path; 1761 int mode; 1762}; 1763#endif 1764/* ARGSUSED */ 1765int 1766chmod(p, uap) 1767 struct proc *p; 1768 register struct chmod_args /* { 1769 syscallarg(char *) path; 1770 syscallarg(int) mode; 1771 } */ *uap; 1772{ 1773 register struct vnode *vp; 1774 struct vattr vattr; 1775 int error; 1776 struct nameidata nd; 1777 1778 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1779 if (error = namei(&nd)) 1780 return (error); 1781 vp = nd.ni_vp; 1782 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1783 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1784 VATTR_NULL(&vattr); 1785 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1786 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1787 vput(vp); 1788 return (error); 1789} 1790 1791/* 1792 * Change mode of a file given a file descriptor. 1793 */ 1794#ifndef _SYS_SYSPROTO_H_ 1795struct fchmod_args { 1796 int fd; 1797 int mode; 1798}; 1799#endif 1800/* ARGSUSED */ 1801int 1802fchmod(p, uap) 1803 struct proc *p; 1804 register struct fchmod_args /* { 1805 syscallarg(int) fd; 1806 syscallarg(int) mode; 1807 } */ *uap; 1808{ 1809 struct vattr vattr; 1810 struct vnode *vp; 1811 struct file *fp; 1812 int error; 1813 1814 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1815 return (error); 1816 vp = (struct vnode *)fp->f_data; 1817 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1818 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1819 VATTR_NULL(&vattr); 1820 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1821 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1822 VOP_UNLOCK(vp, 0, p); 1823 return (error); 1824} 1825 1826/* 1827 * Set ownership given a path name. 1828 */ 1829#ifndef _SYS_SYSPROTO_H_ 1830struct chown_args { 1831 char *path; 1832 int uid; 1833 int gid; 1834}; 1835#endif 1836/* ARGSUSED */ 1837int 1838chown(p, uap) 1839 struct proc *p; 1840 register struct chown_args /* { 1841 syscallarg(char *) path; 1842 syscallarg(int) uid; 1843 syscallarg(int) gid; 1844 } */ *uap; 1845{ 1846 register struct vnode *vp; 1847 struct vattr vattr; 1848 int error; 1849 struct nameidata nd; 1850 1851 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1852 if (error = namei(&nd)) 1853 return (error); 1854 vp = nd.ni_vp; 1855 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1856 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1857 VATTR_NULL(&vattr); 1858 vattr.va_uid = SCARG(uap, uid); 1859 vattr.va_gid = SCARG(uap, gid); 1860 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1861 vput(vp); 1862 return (error); 1863} 1864 1865/* 1866 * Set ownership given a path name, do not cross symlinks. 1867 */ 1868#ifndef _SYS_SYSPROTO_H_ 1869struct lchown_args { 1870 char *path; 1871 int uid; 1872 int gid; 1873}; 1874#endif 1875/* ARGSUSED */ 1876int 1877lchown(p, uap) 1878 struct proc *p; 1879 register struct lchown_args /* { 1880 syscallarg(char *) path; 1881 syscallarg(int) uid; 1882 syscallarg(int) gid; 1883 } */ *uap; 1884{ 1885 register struct vnode *vp; 1886 struct vattr vattr; 1887 int error; 1888 struct nameidata nd; 1889 1890 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1891 if (error = namei(&nd)) 1892 return (error); 1893 vp = nd.ni_vp; 1894 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1895 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1896 VATTR_NULL(&vattr); 1897 vattr.va_uid = SCARG(uap, uid); 1898 vattr.va_gid = SCARG(uap, gid); 1899 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1900 vput(vp); 1901 return (error); 1902} 1903 1904/* 1905 * Set ownership given a file descriptor. 1906 */ 1907#ifndef _SYS_SYSPROTO_H_ 1908struct fchown_args { 1909 int fd; 1910 int uid; 1911 int gid; 1912}; 1913#endif 1914/* ARGSUSED */ 1915int 1916fchown(p, uap) 1917 struct proc *p; 1918 register struct fchown_args /* { 1919 syscallarg(int) fd; 1920 syscallarg(int) uid; 1921 syscallarg(int) gid; 1922 } */ *uap; 1923{ 1924 struct vattr vattr; 1925 struct vnode *vp; 1926 struct file *fp; 1927 int error; 1928 1929 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1930 return (error); 1931 vp = (struct vnode *)fp->f_data; 1932 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1933 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1934 VATTR_NULL(&vattr); 1935 vattr.va_uid = SCARG(uap, uid); 1936 vattr.va_gid = SCARG(uap, gid); 1937 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1938 VOP_UNLOCK(vp, 0, p); 1939 return (error); 1940} 1941 1942/* 1943 * Set the access and modification times of a file. 1944 */ 1945#ifndef _SYS_SYSPROTO_H_ 1946struct utimes_args { 1947 char *path; 1948 struct timeval *tptr; 1949}; 1950#endif 1951/* ARGSUSED */ 1952int 1953utimes(p, uap) 1954 struct proc *p; 1955 register struct utimes_args /* { 1956 syscallarg(char *) path; 1957 syscallarg(struct timeval *) tptr; 1958 } */ *uap; 1959{ 1960 register struct vnode *vp; 1961 struct timeval tv[2]; 1962 struct vattr vattr; 1963 int error; 1964 struct nameidata nd; 1965 1966 VATTR_NULL(&vattr); 1967 if (SCARG(uap, tptr) == NULL) { 1968 microtime(&tv[0]); 1969 tv[1] = tv[0]; 1970 vattr.va_vaflags |= VA_UTIMES_NULL; 1971 } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 1972 sizeof (tv))) 1973 return (error); 1974 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1975 if (error = namei(&nd)) 1976 return (error); 1977 vp = nd.ni_vp; 1978 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1979 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1980 vattr.va_atime.tv_sec = tv[0].tv_sec; 1981 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; 1982 vattr.va_mtime.tv_sec = tv[1].tv_sec; 1983 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; 1984 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1985 vput(vp); 1986 return (error); 1987} 1988 1989/* 1990 * Truncate a file given its path name. 1991 */ 1992#ifndef _SYS_SYSPROTO_H_ 1993struct truncate_args { 1994 char *path; 1995 int pad; 1996 off_t length; 1997}; 1998#endif 1999/* ARGSUSED */ 2000int 2001truncate(p, uap) 2002 struct proc *p; 2003 register struct truncate_args /* { 2004 syscallarg(char *) path; 2005 syscallarg(int) pad; 2006 syscallarg(off_t) length; 2007 } */ *uap; 2008{ 2009 register struct vnode *vp; 2010 struct vattr vattr; 2011 int error; 2012 struct nameidata nd; 2013 2014 if (uap->length < 0) 2015 return(EINVAL); 2016 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2017 if (error = namei(&nd)) 2018 return (error); 2019 vp = nd.ni_vp; 2020 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2021 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2022 if (vp->v_type == VDIR) 2023 error = EISDIR; 2024 else if ((error = vn_writechk(vp)) == 0 && 2025 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 2026 VATTR_NULL(&vattr); 2027 vattr.va_size = SCARG(uap, length); 2028 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2029 } 2030 vput(vp); 2031 return (error); 2032} 2033 2034/* 2035 * Truncate a file given a file descriptor. 2036 */ 2037#ifndef _SYS_SYSPROTO_H_ 2038struct ftruncate_args { 2039 int fd; 2040 int pad; 2041 off_t length; 2042}; 2043#endif 2044/* ARGSUSED */ 2045int 2046ftruncate(p, uap) 2047 struct proc *p; 2048 register struct ftruncate_args /* { 2049 syscallarg(int) fd; 2050 syscallarg(int) pad; 2051 syscallarg(off_t) length; 2052 } */ *uap; 2053{ 2054 struct vattr vattr; 2055 struct vnode *vp; 2056 struct file *fp; 2057 int error; 2058 2059 if (uap->length < 0) 2060 return(EINVAL); 2061 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2062 return (error); 2063 if ((fp->f_flag & FWRITE) == 0) 2064 return (EINVAL); 2065 vp = (struct vnode *)fp->f_data; 2066 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2067 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2068 if (vp->v_type == VDIR) 2069 error = EISDIR; 2070 else if ((error = vn_writechk(vp)) == 0) { 2071 VATTR_NULL(&vattr); 2072 vattr.va_size = SCARG(uap, length); 2073 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 2074 } 2075 VOP_UNLOCK(vp, 0, p); 2076 return (error); 2077} 2078 2079#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 2080/* 2081 * Truncate a file given its path name. 2082 */ 2083#ifndef _SYS_SYSPROTO_H_ 2084struct otruncate_args { 2085 char *path; 2086 long length; 2087}; 2088#endif 2089/* ARGSUSED */ 2090int 2091otruncate(p, uap) 2092 struct proc *p; 2093 register struct otruncate_args /* { 2094 syscallarg(char *) path; 2095 syscallarg(long) length; 2096 } */ *uap; 2097{ 2098 struct truncate_args /* { 2099 syscallarg(char *) path; 2100 syscallarg(int) pad; 2101 syscallarg(off_t) length; 2102 } */ nuap; 2103 2104 SCARG(&nuap, path) = SCARG(uap, path); 2105 SCARG(&nuap, length) = SCARG(uap, length); 2106 return (truncate(p, &nuap)); 2107} 2108 2109/* 2110 * Truncate a file given a file descriptor. 2111 */ 2112#ifndef _SYS_SYSPROTO_H_ 2113struct oftruncate_args { 2114 int fd; 2115 long length; 2116}; 2117#endif 2118/* ARGSUSED */ 2119int 2120oftruncate(p, uap) 2121 struct proc *p; 2122 register struct oftruncate_args /* { 2123 syscallarg(int) fd; 2124 syscallarg(long) length; 2125 } */ *uap; 2126{ 2127 struct ftruncate_args /* { 2128 syscallarg(int) fd; 2129 syscallarg(int) pad; 2130 syscallarg(off_t) length; 2131 } */ nuap; 2132 2133 SCARG(&nuap, fd) = SCARG(uap, fd); 2134 SCARG(&nuap, length) = SCARG(uap, length); 2135 return (ftruncate(p, &nuap)); 2136} 2137#endif /* COMPAT_43 || COMPAT_SUNOS */ 2138 2139/* 2140 * Sync an open file. 2141 */ 2142#ifndef _SYS_SYSPROTO_H_ 2143struct fsync_args { 2144 int fd; 2145}; 2146#endif 2147/* ARGSUSED */ 2148int 2149fsync(p, uap) 2150 struct proc *p; 2151 struct fsync_args /* { 2152 syscallarg(int) fd; 2153 } */ *uap; 2154{ 2155 register struct vnode *vp; 2156 struct file *fp; 2157 int error; 2158 2159 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2160 return (error); 2161 vp = (struct vnode *)fp->f_data; 2162 if ((error = vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, p)) == NULL) { 2163 if (vp->v_object) { 2164 vm_object_page_clean(vp->v_object, 0, 0 ,0); 2165 } 2166 error = VOP_FSYNC(vp, fp->f_cred, 2167 (vp->v_mount && (vp->v_mount->mnt_flag & MNT_ASYNC)) ? 2168 MNT_NOWAIT : MNT_WAIT, p); 2169 VOP_UNLOCK(vp, 0, p); 2170 } 2171 return (error); 2172} 2173 2174/* 2175 * Rename files. Source and destination must either both be directories, 2176 * or both not be directories. If target is a directory, it must be empty. 2177 */ 2178#ifndef _SYS_SYSPROTO_H_ 2179struct rename_args { 2180 char *from; 2181 char *to; 2182}; 2183#endif 2184/* ARGSUSED */ 2185int 2186rename(p, uap) 2187 struct proc *p; 2188 register struct rename_args /* { 2189 syscallarg(char *) from; 2190 syscallarg(char *) to; 2191 } */ *uap; 2192{ 2193 register struct vnode *tvp, *fvp, *tdvp; 2194 struct nameidata fromnd, tond; 2195 int error; 2196 2197 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 2198 SCARG(uap, from), p); 2199 if (error = namei(&fromnd)) 2200 return (error); 2201 fvp = fromnd.ni_vp; 2202 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | NOOBJ, 2203 UIO_USERSPACE, SCARG(uap, to), p); 2204 if (fromnd.ni_vp->v_type == VDIR) 2205 tond.ni_cnd.cn_flags |= WILLBEDIR; 2206 if (error = namei(&tond)) { 2207 /* Translate error code for rename("dir1", "dir2/."). */ 2208 if (error == EISDIR && fvp->v_type == VDIR) 2209 error = EINVAL; 2210 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2211 vrele(fromnd.ni_dvp); 2212 vrele(fvp); 2213 goto out1; 2214 } 2215 tdvp = tond.ni_dvp; 2216 tvp = tond.ni_vp; 2217 if (tvp != NULL) { 2218 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 2219 error = ENOTDIR; 2220 goto out; 2221 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 2222 error = EISDIR; 2223 goto out; 2224 } 2225 } 2226 if (fvp == tdvp) 2227 error = EINVAL; 2228 /* 2229 * If source is the same as the destination (that is the 2230 * same inode number with the same name in the same directory), 2231 * then there is nothing to do. 2232 */ 2233 if (fvp == tvp && fromnd.ni_dvp == tdvp && 2234 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 2235 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 2236 fromnd.ni_cnd.cn_namelen)) 2237 error = -1; 2238out: 2239 if (!error) { 2240 VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); 2241 if (fromnd.ni_dvp != tdvp) { 2242 VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2243 } 2244 if (tvp) { 2245 VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); 2246 } 2247 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 2248 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 2249 } else { 2250 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 2251 if (tdvp == tvp) 2252 vrele(tdvp); 2253 else 2254 vput(tdvp); 2255 if (tvp) 2256 vput(tvp); 2257 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2258 vrele(fromnd.ni_dvp); 2259 vrele(fvp); 2260 } 2261 vrele(tond.ni_startdir); 2262 ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename"); 2263 ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename"); 2264 ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename"); 2265 ASSERT_VOP_UNLOCKED(tond.ni_vp, "rename"); 2266 zfree(namei_zone, tond.ni_cnd.cn_pnbuf); 2267out1: 2268 if (fromnd.ni_startdir) 2269 vrele(fromnd.ni_startdir); 2270 zfree(namei_zone, fromnd.ni_cnd.cn_pnbuf); 2271 if (error == -1) 2272 return (0); 2273 return (error); 2274} 2275 2276/* 2277 * Make a directory file. 2278 */ 2279#ifndef _SYS_SYSPROTO_H_ 2280struct mkdir_args { 2281 char *path; 2282 int mode; 2283}; 2284#endif 2285/* ARGSUSED */ 2286int 2287mkdir(p, uap) 2288 struct proc *p; 2289 register struct mkdir_args /* { 2290 syscallarg(char *) path; 2291 syscallarg(int) mode; 2292 } */ *uap; 2293{ 2294 register struct vnode *vp; 2295 struct vattr vattr; 2296 int error; 2297 struct nameidata nd; 2298 2299 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 2300 nd.ni_cnd.cn_flags |= WILLBEDIR; 2301 if (error = namei(&nd)) 2302 return (error); 2303 vp = nd.ni_vp; 2304 if (vp != NULL) { 2305 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2306 if (nd.ni_dvp == vp) 2307 vrele(nd.ni_dvp); 2308 else 2309 vput(nd.ni_dvp); 2310 vrele(vp); 2311 return (EEXIST); 2312 } 2313 VATTR_NULL(&vattr); 2314 vattr.va_type = VDIR; 2315 vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; 2316 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2317 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 2318 if (!error) 2319 vput(nd.ni_vp); 2320 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir"); 2321 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir"); 2322 return (error); 2323} 2324 2325/* 2326 * Remove a directory file. 2327 */ 2328#ifndef _SYS_SYSPROTO_H_ 2329struct rmdir_args { 2330 char *path; 2331}; 2332#endif 2333/* ARGSUSED */ 2334int 2335rmdir(p, uap) 2336 struct proc *p; 2337 struct rmdir_args /* { 2338 syscallarg(char *) path; 2339 } */ *uap; 2340{ 2341 register struct vnode *vp; 2342 int error; 2343 struct nameidata nd; 2344 2345 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 2346 SCARG(uap, path), p); 2347 if (error = namei(&nd)) 2348 return (error); 2349 vp = nd.ni_vp; 2350 if (vp->v_type != VDIR) { 2351 error = ENOTDIR; 2352 goto out; 2353 } 2354 /* 2355 * No rmdir "." please. 2356 */ 2357 if (nd.ni_dvp == vp) { 2358 error = EINVAL; 2359 goto out; 2360 } 2361 /* 2362 * The root of a mounted filesystem cannot be deleted. 2363 */ 2364 if (vp->v_flag & VROOT) 2365 error = EBUSY; 2366out: 2367 if (!error) { 2368 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2369 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2370 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 2371 } else { 2372 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2373 if (nd.ni_dvp == vp) 2374 vrele(nd.ni_dvp); 2375 else 2376 vput(nd.ni_dvp); 2377 vput(vp); 2378 } 2379 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir"); 2380 ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir"); 2381 return (error); 2382} 2383 2384#ifdef COMPAT_43 2385/* 2386 * Read a block of directory entries in a file system independent format. 2387 */ 2388#ifndef _SYS_SYSPROTO_H_ 2389struct ogetdirentries_args { 2390 int fd; 2391 char *buf; 2392 u_int count; 2393 long *basep; 2394}; 2395#endif 2396int 2397ogetdirentries(p, uap) 2398 struct proc *p; 2399 register struct ogetdirentries_args /* { 2400 syscallarg(int) fd; 2401 syscallarg(char *) buf; 2402 syscallarg(u_int) count; 2403 syscallarg(long *) basep; 2404 } */ *uap; 2405{ 2406 register struct vnode *vp; 2407 struct file *fp; 2408 struct uio auio, kuio; 2409 struct iovec aiov, kiov; 2410 struct dirent *dp, *edp; 2411 caddr_t dirbuf; 2412 int error, eofflag, readcnt; 2413 long loff; 2414 2415 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2416 return (error); 2417 if ((fp->f_flag & FREAD) == 0) 2418 return (EBADF); 2419 vp = (struct vnode *)fp->f_data; 2420unionread: 2421 if (vp->v_type != VDIR) 2422 return (EINVAL); 2423 aiov.iov_base = SCARG(uap, buf); 2424 aiov.iov_len = SCARG(uap, count); 2425 auio.uio_iov = &aiov; 2426 auio.uio_iovcnt = 1; 2427 auio.uio_rw = UIO_READ; 2428 auio.uio_segflg = UIO_USERSPACE; 2429 auio.uio_procp = p; 2430 auio.uio_resid = SCARG(uap, count); 2431 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2432 loff = auio.uio_offset = fp->f_offset; 2433# if (BYTE_ORDER != LITTLE_ENDIAN) 2434 if (vp->v_mount->mnt_maxsymlinklen <= 0) { 2435 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 2436 NULL, NULL); 2437 fp->f_offset = auio.uio_offset; 2438 } else 2439# endif 2440 { 2441 kuio = auio; 2442 kuio.uio_iov = &kiov; 2443 kuio.uio_segflg = UIO_SYSSPACE; 2444 kiov.iov_len = SCARG(uap, count); 2445 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); 2446 kiov.iov_base = dirbuf; 2447 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 2448 NULL, NULL); 2449 fp->f_offset = kuio.uio_offset; 2450 if (error == 0) { 2451 readcnt = SCARG(uap, count) - kuio.uio_resid; 2452 edp = (struct dirent *)&dirbuf[readcnt]; 2453 for (dp = (struct dirent *)dirbuf; dp < edp; ) { 2454# if (BYTE_ORDER == LITTLE_ENDIAN) 2455 /* 2456 * The expected low byte of 2457 * dp->d_namlen is our dp->d_type. 2458 * The high MBZ byte of dp->d_namlen 2459 * is our dp->d_namlen. 2460 */ 2461 dp->d_type = dp->d_namlen; 2462 dp->d_namlen = 0; 2463# else 2464 /* 2465 * The dp->d_type is the high byte 2466 * of the expected dp->d_namlen, 2467 * so must be zero'ed. 2468 */ 2469 dp->d_type = 0; 2470# endif 2471 if (dp->d_reclen > 0) { 2472 dp = (struct dirent *) 2473 ((char *)dp + dp->d_reclen); 2474 } else { 2475 error = EIO; 2476 break; 2477 } 2478 } 2479 if (dp >= edp) 2480 error = uiomove(dirbuf, readcnt, &auio); 2481 } 2482 FREE(dirbuf, M_TEMP); 2483 } 2484 VOP_UNLOCK(vp, 0, p); 2485 if (error) 2486 return (error); 2487 2488#ifdef UNION 2489{ 2490 if ((SCARG(uap, count) == auio.uio_resid) && 2491 (vp->v_op == union_vnodeop_p)) { 2492 struct vnode *lvp; 2493 2494 lvp = union_dircache(vp, p); 2495 if (lvp != NULLVP) { 2496 struct vattr va; 2497 2498 /* 2499 * If the directory is opaque, 2500 * then don't show lower entries 2501 */ 2502 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 2503 if (va.va_flags & OPAQUE) { 2504 vput(lvp); 2505 lvp = NULL; 2506 } 2507 } 2508 2509 if (lvp != NULLVP) { 2510 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 2511 if (error) { 2512 vput(lvp); 2513 return (error); 2514 } 2515 VOP_UNLOCK(lvp, 0, p); 2516 fp->f_data = (caddr_t) lvp; 2517 fp->f_offset = 0; 2518 error = vn_close(vp, FREAD, fp->f_cred, p); 2519 if (error) 2520 return (error); 2521 vp = lvp; 2522 goto unionread; 2523 } 2524 } 2525} 2526#endif /* UNION */ 2527 2528 if ((SCARG(uap, count) == auio.uio_resid) && 2529 (vp->v_flag & VROOT) && 2530 (vp->v_mount->mnt_flag & MNT_UNION)) { 2531 struct vnode *tvp = vp; 2532 vp = vp->v_mount->mnt_vnodecovered; 2533 VREF(vp); 2534 fp->f_data = (caddr_t) vp; 2535 fp->f_offset = 0; 2536 vrele(tvp); 2537 goto unionread; 2538 } 2539 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 2540 sizeof(long)); 2541 p->p_retval[0] = SCARG(uap, count) - auio.uio_resid; 2542 return (error); 2543} 2544#endif /* COMPAT_43 */ 2545 2546/* 2547 * Read a block of directory entries in a file system independent format. 2548 */ 2549#ifndef _SYS_SYSPROTO_H_ 2550struct getdirentries_args { 2551 int fd; 2552 char *buf; 2553 u_int count; 2554 long *basep; 2555}; 2556#endif 2557int 2558getdirentries(p, uap) 2559 struct proc *p; 2560 register struct getdirentries_args /* { 2561 syscallarg(int) fd; 2562 syscallarg(char *) buf; 2563 syscallarg(u_int) count; 2564 syscallarg(long *) basep; 2565 } */ *uap; 2566{ 2567 register struct vnode *vp; 2568 struct file *fp; 2569 struct uio auio; 2570 struct iovec aiov; 2571 long loff; 2572 int error, eofflag; 2573 2574 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2575 return (error); 2576 if ((fp->f_flag & FREAD) == 0) 2577 return (EBADF); 2578 vp = (struct vnode *)fp->f_data; 2579unionread: 2580 if (vp->v_type != VDIR) 2581 return (EINVAL); 2582 aiov.iov_base = SCARG(uap, buf); 2583 aiov.iov_len = SCARG(uap, count); 2584 auio.uio_iov = &aiov; 2585 auio.uio_iovcnt = 1; 2586 auio.uio_rw = UIO_READ; 2587 auio.uio_segflg = UIO_USERSPACE; 2588 auio.uio_procp = p; 2589 auio.uio_resid = SCARG(uap, count); 2590 /* vn_lock(vp, LK_SHARED | LK_RETRY, p); */ 2591 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2592 loff = auio.uio_offset = fp->f_offset; 2593 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL); 2594 fp->f_offset = auio.uio_offset; 2595 VOP_UNLOCK(vp, 0, p); 2596 if (error) 2597 return (error); 2598 2599#ifdef UNION 2600{ 2601 if ((SCARG(uap, count) == auio.uio_resid) && 2602 (vp->v_op == union_vnodeop_p)) { 2603 struct vnode *lvp; 2604 2605 lvp = union_dircache(vp, p); 2606 if (lvp != NULLVP) { 2607 struct vattr va; 2608 2609 /* 2610 * If the directory is opaque, 2611 * then don't show lower entries 2612 */ 2613 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 2614 if (va.va_flags & OPAQUE) { 2615 vput(lvp); 2616 lvp = NULL; 2617 } 2618 } 2619 2620 if (lvp != NULLVP) { 2621 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 2622 if (error) { 2623 vput(lvp); 2624 return (error); 2625 } 2626 VOP_UNLOCK(lvp, 0, p); 2627 fp->f_data = (caddr_t) lvp; 2628 fp->f_offset = 0; 2629 error = vn_close(vp, FREAD, fp->f_cred, p); 2630 if (error) 2631 return (error); 2632 vp = lvp; 2633 goto unionread; 2634 } 2635 } 2636} 2637#endif /* UNION */ 2638 2639 if ((SCARG(uap, count) == auio.uio_resid) && 2640 (vp->v_flag & VROOT) && 2641 (vp->v_mount->mnt_flag & MNT_UNION)) { 2642 struct vnode *tvp = vp; 2643 vp = vp->v_mount->mnt_vnodecovered; 2644 VREF(vp); 2645 fp->f_data = (caddr_t) vp; 2646 fp->f_offset = 0; 2647 vrele(tvp); 2648 goto unionread; 2649 } 2650 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 2651 sizeof(long)); 2652 p->p_retval[0] = SCARG(uap, count) - auio.uio_resid; 2653 return (error); 2654} 2655 2656/* 2657 * Set the mode mask for creation of filesystem nodes. 2658 */ 2659#ifndef _SYS_SYSPROTO_H_ 2660struct umask_args { 2661 int newmask; 2662}; 2663#endif 2664int 2665umask(p, uap) 2666 struct proc *p; 2667 struct umask_args /* { 2668 syscallarg(int) newmask; 2669 } */ *uap; 2670{ 2671 register struct filedesc *fdp; 2672 2673 fdp = p->p_fd; 2674 p->p_retval[0] = fdp->fd_cmask; 2675 fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS; 2676 return (0); 2677} 2678 2679/* 2680 * Void all references to file by ripping underlying filesystem 2681 * away from vnode. 2682 */ 2683#ifndef _SYS_SYSPROTO_H_ 2684struct revoke_args { 2685 char *path; 2686}; 2687#endif 2688/* ARGSUSED */ 2689int 2690revoke(p, uap) 2691 struct proc *p; 2692 register struct revoke_args /* { 2693 syscallarg(char *) path; 2694 } */ *uap; 2695{ 2696 register struct vnode *vp; 2697 struct vattr vattr; 2698 int error; 2699 struct nameidata nd; 2700 2701 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2702 if (error = namei(&nd)) 2703 return (error); 2704 vp = nd.ni_vp; 2705 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 2706 goto out; 2707 if (p->p_ucred->cr_uid != vattr.va_uid && 2708 (error = suser(p->p_ucred, &p->p_acflag))) 2709 goto out; 2710 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 2711 VOP_REVOKE(vp, REVOKEALL); 2712out: 2713 vrele(vp); 2714 return (error); 2715} 2716 2717/* 2718 * Convert a user file descriptor to a kernel file entry. 2719 */ 2720int 2721getvnode(fdp, fd, fpp) 2722 struct filedesc *fdp; 2723 int fd; 2724 struct file **fpp; 2725{ 2726 struct file *fp; 2727 2728 if ((u_int)fd >= fdp->fd_nfiles || 2729 (fp = fdp->fd_ofiles[fd]) == NULL) 2730 return (EBADF); 2731 if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO) 2732 return (EINVAL); 2733 *fpp = fp; 2734 return (0); 2735} 2736#ifndef _SYS_SYSPROTO_H_ 2737struct __getcwd_args { 2738 u_char *buf; 2739 u_int buflen; 2740}; 2741#endif 2742#define STATNODE(mode, name, var) \ 2743 SYSCTL_INT(_vfs_cache, OID_AUTO, name, mode, var, 0, ""); 2744 2745static int disablecwd; 2746SYSCTL_INT(_debug, OID_AUTO, disablecwd, CTLFLAG_RW, &disablecwd, 0, ""); 2747 2748static u_long numcwdcalls; STATNODE(CTLFLAG_RD, numcwdcalls, &numcwdcalls); 2749static u_long numcwdfail1; STATNODE(CTLFLAG_RD, numcwdfail1, &numcwdfail1); 2750static u_long numcwdfail2; STATNODE(CTLFLAG_RD, numcwdfail2, &numcwdfail2); 2751static u_long numcwdfail3; STATNODE(CTLFLAG_RD, numcwdfail3, &numcwdfail3); 2752static u_long numcwdfail4; STATNODE(CTLFLAG_RD, numcwdfail4, &numcwdfail4); 2753static u_long numcwdfound; STATNODE(CTLFLAG_RD, numcwdfound, &numcwdfound); 2754int 2755__getcwd(p, uap) 2756 struct proc *p; 2757 struct __getcwd_args *uap; 2758{ 2759 char *bp, *buf; 2760 int error, i, slash_prefixed; 2761 struct filedesc *fdp; 2762 struct namecache *ncp; 2763 struct vnode *vp; 2764 2765 numcwdcalls++; 2766 if (disablecwd) 2767 return (ENODEV); 2768 if (uap->buflen < 2) 2769 return (EINVAL); 2770 if (uap->buflen > MAXPATHLEN) 2771 uap->buflen = MAXPATHLEN; 2772 buf = bp = malloc(uap->buflen, M_TEMP, M_WAITOK); 2773 bp += uap->buflen - 1; 2774 *bp = '\0'; 2775 fdp = p->p_fd; 2776 slash_prefixed = 0; 2777 for (vp = fdp->fd_cdir; vp != fdp->fd_rdir && vp != rootvnode;) { 2778 if (vp->v_flag & VROOT) { 2779 vp = vp->v_mount->mnt_vnodecovered; 2780 continue; 2781 } 2782 if (vp->v_dd->v_id != vp->v_ddid) { 2783 numcwdfail1++; 2784 free(buf, M_TEMP); 2785 return (ENOTDIR); 2786 } 2787 ncp = TAILQ_FIRST(&vp->v_cache_dst); 2788 if (!ncp) { 2789 numcwdfail2++; 2790 free(buf, M_TEMP); 2791 return (ENOENT); 2792 } 2793 if (ncp->nc_dvp != vp->v_dd) { 2794 numcwdfail3++; 2795 free(buf, M_TEMP); 2796 return (EBADF); 2797 } 2798 for (i = ncp->nc_nlen - 1; i >= 0; i--) { 2799 if (bp == buf) { 2800 numcwdfail4++; 2801 free(buf, M_TEMP); 2802 return (ENOMEM); 2803 } 2804 *--bp = ncp->nc_name[i]; 2805 } 2806 if (bp == buf) { 2807 numcwdfail4++; 2808 free(buf, M_TEMP); 2809 return (ENOMEM); 2810 } 2811 *--bp = '/'; 2812 slash_prefixed = 1; 2813 vp = vp->v_dd; 2814 } 2815 if (!slash_prefixed) { 2816 if (bp == buf) { 2817 numcwdfail4++; 2818 free(buf, M_TEMP); 2819 return (ENOMEM); 2820 } 2821 *--bp = '/'; 2822 } 2823 numcwdfound++; 2824 error = copyout(bp, uap->buf, strlen(bp) + 1); 2825 free(buf, M_TEMP); 2826 return (error); 2827} 2828