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