1*b819cea2SGordon Ross /* 2*b819cea2SGordon Ross * CDDL HEADER START 3*b819cea2SGordon Ross * 4*b819cea2SGordon Ross * The contents of this file are subject to the terms of the 5*b819cea2SGordon Ross * Common Development and Distribution License (the "License"). 6*b819cea2SGordon Ross * You may not use this file except in compliance with the License. 7*b819cea2SGordon Ross * 8*b819cea2SGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*b819cea2SGordon Ross * or http://www.opensolaris.org/os/licensing. 10*b819cea2SGordon Ross * See the License for the specific language governing permissions 11*b819cea2SGordon Ross * and limitations under the License. 12*b819cea2SGordon Ross * 13*b819cea2SGordon Ross * When distributing Covered Code, include this CDDL HEADER in each 14*b819cea2SGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*b819cea2SGordon Ross * If applicable, add the following below this CDDL HEADER, with the 16*b819cea2SGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying 17*b819cea2SGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner] 18*b819cea2SGordon Ross * 19*b819cea2SGordon Ross * CDDL HEADER END 20*b819cea2SGordon Ross */ 21*b819cea2SGordon Ross 22*b819cea2SGordon Ross /* 23*b819cea2SGordon Ross * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. 24*b819cea2SGordon Ross * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 25*b819cea2SGordon Ross */ 26*b819cea2SGordon Ross 27*b819cea2SGordon Ross /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28*b819cea2SGordon Ross /* All Rights Reserved */ 29*b819cea2SGordon Ross 30*b819cea2SGordon Ross /* 31*b819cea2SGordon Ross * University Copyright- Copyright (c) 1982, 1986, 1988 32*b819cea2SGordon Ross * The Regents of the University of California 33*b819cea2SGordon Ross * All Rights Reserved 34*b819cea2SGordon Ross * 35*b819cea2SGordon Ross * University Acknowledgment- Portions of this document are derived from 36*b819cea2SGordon Ross * software developed by the University of California, Berkeley, and its 37*b819cea2SGordon Ross * contributors. 38*b819cea2SGordon Ross */ 39*b819cea2SGordon Ross 40*b819cea2SGordon Ross #include <sys/types.h> 41*b819cea2SGordon Ross #include <sys/param.h> 42*b819cea2SGordon Ross #include <sys/systm.h> 43*b819cea2SGordon Ross #include <sys/file.h> 44*b819cea2SGordon Ross #include <sys/errno.h> 45*b819cea2SGordon Ross #include <sys/cred.h> 46*b819cea2SGordon Ross #include <sys/user.h> 47*b819cea2SGordon Ross #include <sys/uio.h> 48*b819cea2SGordon Ross #include <sys/vfs.h> 49*b819cea2SGordon Ross #include <sys/vnode.h> 50*b819cea2SGordon Ross #include <sys/pathname.h> 51*b819cea2SGordon Ross #include <sys/proc.h> 52*b819cea2SGordon Ross #include <sys/vtrace.h> 53*b819cea2SGordon Ross #include <sys/sysmacros.h> 54*b819cea2SGordon Ross #include <sys/debug.h> 55*b819cea2SGordon Ross #include <sys/dirent.h> 56*b819cea2SGordon Ross #include <sys/zone.h> 57*b819cea2SGordon Ross #include <sys/dnlc.h> 58*b819cea2SGordon Ross #include <sys/fs/snode.h> 59*b819cea2SGordon Ross 60*b819cea2SGordon Ross /* 61*b819cea2SGordon Ross * Starting at current directory, translate pathname pnp to end. 62*b819cea2SGordon Ross * Leave pathname of final component in pnp, return the vnode 63*b819cea2SGordon Ross * for the final component in *compvpp, and return the vnode 64*b819cea2SGordon Ross * for the parent of the final component in dirvpp. 65*b819cea2SGordon Ross * 66*b819cea2SGordon Ross * This is the central routine in pathname translation and handles 67*b819cea2SGordon Ross * multiple components in pathnames, separating them at /'s. It also 68*b819cea2SGordon Ross * implements mounted file systems and processes symbolic links. 69*b819cea2SGordon Ross * 70*b819cea2SGordon Ross * vp is the vnode where the directory search should start. 71*b819cea2SGordon Ross * 72*b819cea2SGordon Ross * Reference counts: vp must be held prior to calling this function. rootvp 73*b819cea2SGordon Ross * should only be held if rootvp != rootdir. 74*b819cea2SGordon Ross */ 75*b819cea2SGordon Ross int 76*b819cea2SGordon Ross lookuppnvp( 77*b819cea2SGordon Ross struct pathname *pnp, /* pathname to lookup */ 78*b819cea2SGordon Ross struct pathname *rpnp, /* if non-NULL, return resolved path */ 79*b819cea2SGordon Ross int flags, /* follow symlinks */ 80*b819cea2SGordon Ross vnode_t **dirvpp, /* ptr for parent vnode */ 81*b819cea2SGordon Ross vnode_t **compvpp, /* ptr for entry vnode */ 82*b819cea2SGordon Ross vnode_t *rootvp, /* rootvp */ 83*b819cea2SGordon Ross vnode_t *vp, /* directory to start search at */ 84*b819cea2SGordon Ross cred_t *cr) /* user's credential */ 85*b819cea2SGordon Ross { 86*b819cea2SGordon Ross vnode_t *cvp; /* current component vp */ 87*b819cea2SGordon Ross vnode_t *tvp; /* addressable temp ptr */ 88*b819cea2SGordon Ross char component[MAXNAMELEN]; /* buffer for component (incl null) */ 89*b819cea2SGordon Ross int error; 90*b819cea2SGordon Ross int nlink; 91*b819cea2SGordon Ross int lookup_flags; 92*b819cea2SGordon Ross struct pathname presrvd; /* case preserved name */ 93*b819cea2SGordon Ross struct pathname *pp = NULL; 94*b819cea2SGordon Ross vnode_t *startvp; 95*b819cea2SGordon Ross int must_be_directory = 0; 96*b819cea2SGordon Ross boolean_t retry_with_kcred; 97*b819cea2SGordon Ross 98*b819cea2SGordon Ross nlink = 0; 99*b819cea2SGordon Ross cvp = NULL; 100*b819cea2SGordon Ross if (rpnp) 101*b819cea2SGordon Ross rpnp->pn_pathlen = 0; 102*b819cea2SGordon Ross 103*b819cea2SGordon Ross lookup_flags = dirvpp ? LOOKUP_DIR : 0; 104*b819cea2SGordon Ross if (flags & FIGNORECASE) { 105*b819cea2SGordon Ross lookup_flags |= FIGNORECASE; 106*b819cea2SGordon Ross pn_alloc(&presrvd); 107*b819cea2SGordon Ross pp = &presrvd; 108*b819cea2SGordon Ross } 109*b819cea2SGordon Ross 110*b819cea2SGordon Ross /* 111*b819cea2SGordon Ross * Eliminate any trailing slashes in the pathname. 112*b819cea2SGordon Ross * If there are any, we must follow all symlinks. 113*b819cea2SGordon Ross * Also, we must guarantee that the last component is a directory. 114*b819cea2SGordon Ross */ 115*b819cea2SGordon Ross if (pn_fixslash(pnp)) { 116*b819cea2SGordon Ross flags |= FOLLOW; 117*b819cea2SGordon Ross must_be_directory = 1; 118*b819cea2SGordon Ross } 119*b819cea2SGordon Ross 120*b819cea2SGordon Ross startvp = vp; 121*b819cea2SGordon Ross next: 122*b819cea2SGordon Ross retry_with_kcred = B_FALSE; 123*b819cea2SGordon Ross 124*b819cea2SGordon Ross /* 125*b819cea2SGordon Ross * Make sure we have a directory. 126*b819cea2SGordon Ross */ 127*b819cea2SGordon Ross if (vp->v_type != VDIR) { 128*b819cea2SGordon Ross error = ENOTDIR; 129*b819cea2SGordon Ross goto bad; 130*b819cea2SGordon Ross } 131*b819cea2SGordon Ross 132*b819cea2SGordon Ross if (rpnp && VN_CMP(vp, rootvp)) 133*b819cea2SGordon Ross (void) pn_set(rpnp, "/"); 134*b819cea2SGordon Ross 135*b819cea2SGordon Ross /* 136*b819cea2SGordon Ross * Process the next component of the pathname. 137*b819cea2SGordon Ross */ 138*b819cea2SGordon Ross if (error = pn_getcomponent(pnp, component)) { 139*b819cea2SGordon Ross goto bad; 140*b819cea2SGordon Ross } 141*b819cea2SGordon Ross 142*b819cea2SGordon Ross /* 143*b819cea2SGordon Ross * Handle "..": two special cases. 144*b819cea2SGordon Ross * 1. If we're at the root directory (e.g. after chroot or 145*b819cea2SGordon Ross * zone_enter) then change ".." to "." so we can't get 146*b819cea2SGordon Ross * out of this subtree. 147*b819cea2SGordon Ross * 2. If this vnode is the root of a mounted file system, 148*b819cea2SGordon Ross * then replace it with the vnode that was mounted on 149*b819cea2SGordon Ross * so that we take the ".." in the other file system. 150*b819cea2SGordon Ross */ 151*b819cea2SGordon Ross if (component[0] == '.' && component[1] == '.' && component[2] == 0) { 152*b819cea2SGordon Ross checkforroot: 153*b819cea2SGordon Ross if (VN_CMP(vp, rootvp)) { 154*b819cea2SGordon Ross component[1] = '\0'; 155*b819cea2SGordon Ross } else if (vp->v_flag & VROOT) { 156*b819cea2SGordon Ross vfs_t *vfsp; 157*b819cea2SGordon Ross cvp = vp; 158*b819cea2SGordon Ross 159*b819cea2SGordon Ross /* 160*b819cea2SGordon Ross * While we deal with the vfs pointer from the vnode 161*b819cea2SGordon Ross * the filesystem could have been forcefully unmounted 162*b819cea2SGordon Ross * and the vnode's v_vfsp could have been invalidated 163*b819cea2SGordon Ross * by VFS_UNMOUNT. Hence, we cache v_vfsp and use it 164*b819cea2SGordon Ross * with vfs_rlock_wait/vfs_unlock. 165*b819cea2SGordon Ross * It is safe to use the v_vfsp even it is freed by 166*b819cea2SGordon Ross * VFS_UNMOUNT because vfs_rlock_wait/vfs_unlock 167*b819cea2SGordon Ross * do not dereference v_vfsp. It is just used as a 168*b819cea2SGordon Ross * magic cookie. 169*b819cea2SGordon Ross * One more corner case here is the memory getting 170*b819cea2SGordon Ross * reused for another vfs structure. In this case 171*b819cea2SGordon Ross * lookuppnvp's vfs_rlock_wait will succeed, domount's 172*b819cea2SGordon Ross * vfs_lock will fail and domount will bail out with an 173*b819cea2SGordon Ross * error (EBUSY). 174*b819cea2SGordon Ross */ 175*b819cea2SGordon Ross vfsp = cvp->v_vfsp; 176*b819cea2SGordon Ross 177*b819cea2SGordon Ross /* 178*b819cea2SGordon Ross * This lock is used to synchronize 179*b819cea2SGordon Ross * mounts/unmounts and lookups. 180*b819cea2SGordon Ross * Threads doing mounts/unmounts hold the 181*b819cea2SGordon Ross * writers version vfs_lock_wait(). 182*b819cea2SGordon Ross */ 183*b819cea2SGordon Ross 184*b819cea2SGordon Ross vfs_rlock_wait(vfsp); 185*b819cea2SGordon Ross 186*b819cea2SGordon Ross /* 187*b819cea2SGordon Ross * If this vnode is on a file system that 188*b819cea2SGordon Ross * has been forcibly unmounted, 189*b819cea2SGordon Ross * we can't proceed. Cancel this operation 190*b819cea2SGordon Ross * and return EIO. 191*b819cea2SGordon Ross * 192*b819cea2SGordon Ross * vfs_vnodecovered is NULL if unmounted. 193*b819cea2SGordon Ross * Currently, nfs uses VFS_UNMOUNTED to 194*b819cea2SGordon Ross * check if it's a forced-umount. Keep the 195*b819cea2SGordon Ross * same checking here as well even though it 196*b819cea2SGordon Ross * may not be needed. 197*b819cea2SGordon Ross */ 198*b819cea2SGordon Ross if (((vp = cvp->v_vfsp->vfs_vnodecovered) == NULL) || 199*b819cea2SGordon Ross (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) { 200*b819cea2SGordon Ross vfs_unlock(vfsp); 201*b819cea2SGordon Ross VN_RELE(cvp); 202*b819cea2SGordon Ross if (pp) 203*b819cea2SGordon Ross pn_free(pp); 204*b819cea2SGordon Ross return (EIO); 205*b819cea2SGordon Ross } 206*b819cea2SGordon Ross VN_HOLD(vp); 207*b819cea2SGordon Ross vfs_unlock(vfsp); 208*b819cea2SGordon Ross VN_RELE(cvp); 209*b819cea2SGordon Ross cvp = NULL; 210*b819cea2SGordon Ross /* 211*b819cea2SGordon Ross * Crossing mount points. For eg: We are doing 212*b819cea2SGordon Ross * a lookup of ".." for file systems root vnode 213*b819cea2SGordon Ross * mounted here, and VOP_LOOKUP() (with covered vnode) 214*b819cea2SGordon Ross * will be on underlying file systems mount point 215*b819cea2SGordon Ross * vnode. Set retry_with_kcred flag as we might end 216*b819cea2SGordon Ross * up doing VOP_LOOKUP() with kcred if required. 217*b819cea2SGordon Ross */ 218*b819cea2SGordon Ross retry_with_kcred = B_TRUE; 219*b819cea2SGordon Ross goto checkforroot; 220*b819cea2SGordon Ross } 221*b819cea2SGordon Ross } 222*b819cea2SGordon Ross 223*b819cea2SGordon Ross /* 224*b819cea2SGordon Ross * Perform a lookup in the current directory. 225*b819cea2SGordon Ross */ 226*b819cea2SGordon Ross error = VOP_LOOKUP(vp, component, &tvp, pnp, lookup_flags, 227*b819cea2SGordon Ross rootvp, cr, NULL, NULL, pp); 228*b819cea2SGordon Ross 229*b819cea2SGordon Ross /* 230*b819cea2SGordon Ross * Retry with kcred - If crossing mount points & error is EACCES. 231*b819cea2SGordon Ross * 232*b819cea2SGordon Ross * If we are crossing mount points here and doing ".." lookup, 233*b819cea2SGordon Ross * VOP_LOOKUP() might fail if the underlying file systems 234*b819cea2SGordon Ross * mount point has no execute permission. In cases like these, 235*b819cea2SGordon Ross * we retry VOP_LOOKUP() by giving as much privilage as possible 236*b819cea2SGordon Ross * by passing kcred credentials. 237*b819cea2SGordon Ross * 238*b819cea2SGordon Ross * In case of hierarchical file systems, passing kcred still may 239*b819cea2SGordon Ross * or may not work. 240*b819cea2SGordon Ross * For eg: UFS FS --> Mount NFS FS --> Again mount UFS on some 241*b819cea2SGordon Ross * directory inside NFS FS. 242*b819cea2SGordon Ross */ 243*b819cea2SGordon Ross if ((error == EACCES) && retry_with_kcred) 244*b819cea2SGordon Ross error = VOP_LOOKUP(vp, component, &tvp, pnp, lookup_flags, 245*b819cea2SGordon Ross rootvp, zone_kcred(), NULL, NULL, pp); 246*b819cea2SGordon Ross 247*b819cea2SGordon Ross cvp = tvp; 248*b819cea2SGordon Ross if (error) { 249*b819cea2SGordon Ross cvp = NULL; 250*b819cea2SGordon Ross /* 251*b819cea2SGordon Ross * On error, return hard error if 252*b819cea2SGordon Ross * (a) we're not at the end of the pathname yet, or 253*b819cea2SGordon Ross * (b) the caller didn't want the parent directory, or 254*b819cea2SGordon Ross * (c) we failed for some reason other than a missing entry. 255*b819cea2SGordon Ross */ 256*b819cea2SGordon Ross if (pn_pathleft(pnp) || dirvpp == NULL || error != ENOENT) 257*b819cea2SGordon Ross goto bad; 258*b819cea2SGordon Ross 259*b819cea2SGordon Ross pn_setlast(pnp); 260*b819cea2SGordon Ross /* 261*b819cea2SGordon Ross * We inform the caller that the desired entry must be 262*b819cea2SGordon Ross * a directory by adding a '/' to the component name. 263*b819cea2SGordon Ross */ 264*b819cea2SGordon Ross if (must_be_directory && (error = pn_addslash(pnp)) != 0) 265*b819cea2SGordon Ross goto bad; 266*b819cea2SGordon Ross *dirvpp = vp; 267*b819cea2SGordon Ross if (compvpp != NULL) 268*b819cea2SGordon Ross *compvpp = NULL; 269*b819cea2SGordon Ross if (rootvp != rootdir) 270*b819cea2SGordon Ross VN_RELE(rootvp); 271*b819cea2SGordon Ross if (pp) 272*b819cea2SGordon Ross pn_free(pp); 273*b819cea2SGordon Ross return (0); 274*b819cea2SGordon Ross } 275*b819cea2SGordon Ross 276*b819cea2SGordon Ross /* 277*b819cea2SGordon Ross * Traverse mount points. 278*b819cea2SGordon Ross */ 279*b819cea2SGordon Ross if (vn_mountedvfs(cvp) != NULL) { 280*b819cea2SGordon Ross tvp = cvp; 281*b819cea2SGordon Ross if ((error = traverse(&tvp)) != 0) { 282*b819cea2SGordon Ross /* 283*b819cea2SGordon Ross * It is required to assign cvp here, because 284*b819cea2SGordon Ross * traverse() will return a held vnode which 285*b819cea2SGordon Ross * may different than the vnode that was passed 286*b819cea2SGordon Ross * in (even in the error case). If traverse() 287*b819cea2SGordon Ross * changes the vnode it releases the original, 288*b819cea2SGordon Ross * and holds the new one. 289*b819cea2SGordon Ross */ 290*b819cea2SGordon Ross cvp = tvp; 291*b819cea2SGordon Ross goto bad; 292*b819cea2SGordon Ross } 293*b819cea2SGordon Ross cvp = tvp; 294*b819cea2SGordon Ross } 295*b819cea2SGordon Ross 296*b819cea2SGordon Ross /* 297*b819cea2SGordon Ross * If we hit a symbolic link and there is more path to be 298*b819cea2SGordon Ross * translated or this operation does not wish to apply 299*b819cea2SGordon Ross * to a link, then place the contents of the link at the 300*b819cea2SGordon Ross * front of the remaining pathname. 301*b819cea2SGordon Ross */ 302*b819cea2SGordon Ross if (cvp->v_type == VLNK && ((flags & FOLLOW) || pn_pathleft(pnp))) { 303*b819cea2SGordon Ross struct pathname linkpath; 304*b819cea2SGordon Ross 305*b819cea2SGordon Ross if (++nlink > MAXSYMLINKS) { 306*b819cea2SGordon Ross error = ELOOP; 307*b819cea2SGordon Ross goto bad; 308*b819cea2SGordon Ross } 309*b819cea2SGordon Ross pn_alloc(&linkpath); 310*b819cea2SGordon Ross if (error = pn_getsymlink(cvp, &linkpath, cr)) { 311*b819cea2SGordon Ross pn_free(&linkpath); 312*b819cea2SGordon Ross goto bad; 313*b819cea2SGordon Ross } 314*b819cea2SGordon Ross 315*b819cea2SGordon Ross if (pn_pathleft(&linkpath) == 0) 316*b819cea2SGordon Ross (void) pn_set(&linkpath, "."); 317*b819cea2SGordon Ross error = pn_insert(pnp, &linkpath, strlen(component)); 318*b819cea2SGordon Ross pn_free(&linkpath); 319*b819cea2SGordon Ross if (error) 320*b819cea2SGordon Ross goto bad; 321*b819cea2SGordon Ross VN_RELE(cvp); 322*b819cea2SGordon Ross cvp = NULL; 323*b819cea2SGordon Ross if (pnp->pn_pathlen == 0) { 324*b819cea2SGordon Ross error = ENOENT; 325*b819cea2SGordon Ross goto bad; 326*b819cea2SGordon Ross } 327*b819cea2SGordon Ross if (pnp->pn_path[0] == '/') { 328*b819cea2SGordon Ross do { 329*b819cea2SGordon Ross pnp->pn_path++; 330*b819cea2SGordon Ross pnp->pn_pathlen--; 331*b819cea2SGordon Ross } while (pnp->pn_path[0] == '/'); 332*b819cea2SGordon Ross VN_RELE(vp); 333*b819cea2SGordon Ross vp = rootvp; 334*b819cea2SGordon Ross VN_HOLD(vp); 335*b819cea2SGordon Ross } 336*b819cea2SGordon Ross if (pn_fixslash(pnp)) { 337*b819cea2SGordon Ross flags |= FOLLOW; 338*b819cea2SGordon Ross must_be_directory = 1; 339*b819cea2SGordon Ross } 340*b819cea2SGordon Ross goto next; 341*b819cea2SGordon Ross } 342*b819cea2SGordon Ross 343*b819cea2SGordon Ross /* 344*b819cea2SGordon Ross * If rpnp is non-NULL, remember the resolved path name therein. 345*b819cea2SGordon Ross * Do not include "." components. Collapse occurrences of 346*b819cea2SGordon Ross * "previous/..", so long as "previous" is not itself "..". 347*b819cea2SGordon Ross * Exhausting rpnp results in error ENAMETOOLONG. 348*b819cea2SGordon Ross */ 349*b819cea2SGordon Ross if (rpnp && strcmp(component, ".") != 0) { 350*b819cea2SGordon Ross size_t len; 351*b819cea2SGordon Ross 352*b819cea2SGordon Ross if (strcmp(component, "..") == 0 && 353*b819cea2SGordon Ross rpnp->pn_pathlen != 0 && 354*b819cea2SGordon Ross !((rpnp->pn_pathlen > 2 && 355*b819cea2SGordon Ross strncmp(rpnp->pn_path+rpnp->pn_pathlen-3, "/..", 3) == 0) || 356*b819cea2SGordon Ross (rpnp->pn_pathlen == 2 && 357*b819cea2SGordon Ross strncmp(rpnp->pn_path, "..", 2) == 0))) { 358*b819cea2SGordon Ross while (rpnp->pn_pathlen && 359*b819cea2SGordon Ross rpnp->pn_path[rpnp->pn_pathlen-1] != '/') 360*b819cea2SGordon Ross rpnp->pn_pathlen--; 361*b819cea2SGordon Ross if (rpnp->pn_pathlen > 1) 362*b819cea2SGordon Ross rpnp->pn_pathlen--; 363*b819cea2SGordon Ross rpnp->pn_path[rpnp->pn_pathlen] = '\0'; 364*b819cea2SGordon Ross } else { 365*b819cea2SGordon Ross if (rpnp->pn_pathlen != 0 && 366*b819cea2SGordon Ross rpnp->pn_path[rpnp->pn_pathlen-1] != '/') 367*b819cea2SGordon Ross rpnp->pn_path[rpnp->pn_pathlen++] = '/'; 368*b819cea2SGordon Ross if (flags & FIGNORECASE) { 369*b819cea2SGordon Ross /* 370*b819cea2SGordon Ross * Return the case-preserved name 371*b819cea2SGordon Ross * within the resolved path. 372*b819cea2SGordon Ross */ 373*b819cea2SGordon Ross error = copystr(pp->pn_buf, 374*b819cea2SGordon Ross rpnp->pn_path + rpnp->pn_pathlen, 375*b819cea2SGordon Ross rpnp->pn_bufsize - rpnp->pn_pathlen, &len); 376*b819cea2SGordon Ross } else { 377*b819cea2SGordon Ross error = copystr(component, 378*b819cea2SGordon Ross rpnp->pn_path + rpnp->pn_pathlen, 379*b819cea2SGordon Ross rpnp->pn_bufsize - rpnp->pn_pathlen, &len); 380*b819cea2SGordon Ross } 381*b819cea2SGordon Ross if (error) /* copystr() returns ENAMETOOLONG */ 382*b819cea2SGordon Ross goto bad; 383*b819cea2SGordon Ross rpnp->pn_pathlen += (len - 1); 384*b819cea2SGordon Ross ASSERT(rpnp->pn_bufsize > rpnp->pn_pathlen); 385*b819cea2SGordon Ross } 386*b819cea2SGordon Ross } 387*b819cea2SGordon Ross 388*b819cea2SGordon Ross /* 389*b819cea2SGordon Ross * If no more components, return last directory (if wanted) and 390*b819cea2SGordon Ross * last component (if wanted). 391*b819cea2SGordon Ross */ 392*b819cea2SGordon Ross if (pn_pathleft(pnp) == 0) { 393*b819cea2SGordon Ross /* 394*b819cea2SGordon Ross * If there was a trailing slash in the pathname, 395*b819cea2SGordon Ross * make sure the last component is a directory. 396*b819cea2SGordon Ross */ 397*b819cea2SGordon Ross if (must_be_directory && cvp->v_type != VDIR) { 398*b819cea2SGordon Ross error = ENOTDIR; 399*b819cea2SGordon Ross goto bad; 400*b819cea2SGordon Ross } 401*b819cea2SGordon Ross if (dirvpp != NULL) { 402*b819cea2SGordon Ross /* 403*b819cea2SGordon Ross * Check that we have the real parent and not 404*b819cea2SGordon Ross * an alias of the last component. 405*b819cea2SGordon Ross */ 406*b819cea2SGordon Ross if (vn_compare(vp, cvp)) { 407*b819cea2SGordon Ross pn_setlast(pnp); 408*b819cea2SGordon Ross VN_RELE(vp); 409*b819cea2SGordon Ross VN_RELE(cvp); 410*b819cea2SGordon Ross if (rootvp != rootdir) 411*b819cea2SGordon Ross VN_RELE(rootvp); 412*b819cea2SGordon Ross if (pp) 413*b819cea2SGordon Ross pn_free(pp); 414*b819cea2SGordon Ross return (EINVAL); 415*b819cea2SGordon Ross } 416*b819cea2SGordon Ross *dirvpp = vp; 417*b819cea2SGordon Ross } else 418*b819cea2SGordon Ross VN_RELE(vp); 419*b819cea2SGordon Ross if (pnp->pn_path == pnp->pn_buf) 420*b819cea2SGordon Ross (void) pn_set(pnp, "."); 421*b819cea2SGordon Ross else 422*b819cea2SGordon Ross pn_setlast(pnp); 423*b819cea2SGordon Ross if (rpnp) { 424*b819cea2SGordon Ross if (VN_CMP(cvp, rootvp)) 425*b819cea2SGordon Ross (void) pn_set(rpnp, "/"); 426*b819cea2SGordon Ross else if (rpnp->pn_pathlen == 0) 427*b819cea2SGordon Ross (void) pn_set(rpnp, "."); 428*b819cea2SGordon Ross } 429*b819cea2SGordon Ross 430*b819cea2SGordon Ross if (compvpp != NULL) 431*b819cea2SGordon Ross *compvpp = cvp; 432*b819cea2SGordon Ross else 433*b819cea2SGordon Ross VN_RELE(cvp); 434*b819cea2SGordon Ross if (rootvp != rootdir) 435*b819cea2SGordon Ross VN_RELE(rootvp); 436*b819cea2SGordon Ross if (pp) 437*b819cea2SGordon Ross pn_free(pp); 438*b819cea2SGordon Ross return (0); 439*b819cea2SGordon Ross } 440*b819cea2SGordon Ross 441*b819cea2SGordon Ross /* 442*b819cea2SGordon Ross * Skip over slashes from end of last component. 443*b819cea2SGordon Ross */ 444*b819cea2SGordon Ross while (pnp->pn_path[0] == '/') { 445*b819cea2SGordon Ross pnp->pn_path++; 446*b819cea2SGordon Ross pnp->pn_pathlen--; 447*b819cea2SGordon Ross } 448*b819cea2SGordon Ross 449*b819cea2SGordon Ross /* 450*b819cea2SGordon Ross * Searched through another level of directory: 451*b819cea2SGordon Ross * release previous directory handle and save new (result 452*b819cea2SGordon Ross * of lookup) as current directory. 453*b819cea2SGordon Ross */ 454*b819cea2SGordon Ross VN_RELE(vp); 455*b819cea2SGordon Ross vp = cvp; 456*b819cea2SGordon Ross cvp = NULL; 457*b819cea2SGordon Ross goto next; 458*b819cea2SGordon Ross 459*b819cea2SGordon Ross bad: 460*b819cea2SGordon Ross /* 461*b819cea2SGordon Ross * Error. Release vnodes and return. 462*b819cea2SGordon Ross */ 463*b819cea2SGordon Ross if (cvp) 464*b819cea2SGordon Ross VN_RELE(cvp); 465*b819cea2SGordon Ross /* 466*b819cea2SGordon Ross * If the error was ESTALE and the current directory to look in 467*b819cea2SGordon Ross * was the root for this lookup, the root for a mounted file 468*b819cea2SGordon Ross * system, or the starting directory for lookups, then 469*b819cea2SGordon Ross * return ENOENT instead of ESTALE. In this case, no recovery 470*b819cea2SGordon Ross * is possible by the higher level. If ESTALE was returned for 471*b819cea2SGordon Ross * some intermediate directory along the path, then recovery 472*b819cea2SGordon Ross * is potentially possible and retrying from the higher level 473*b819cea2SGordon Ross * will either correct the situation by purging stale cache 474*b819cea2SGordon Ross * entries or eventually get back to the point where no recovery 475*b819cea2SGordon Ross * is possible. 476*b819cea2SGordon Ross */ 477*b819cea2SGordon Ross if (error == ESTALE && 478*b819cea2SGordon Ross (VN_CMP(vp, rootvp) || (vp->v_flag & VROOT) || vp == startvp)) 479*b819cea2SGordon Ross error = ENOENT; 480*b819cea2SGordon Ross VN_RELE(vp); 481*b819cea2SGordon Ross if (rootvp != rootdir) 482*b819cea2SGordon Ross VN_RELE(rootvp); 483*b819cea2SGordon Ross if (pp) 484*b819cea2SGordon Ross pn_free(pp); 485*b819cea2SGordon Ross return (error); 486*b819cea2SGordon Ross } 487*b819cea2SGordon Ross 488*b819cea2SGordon Ross /* 489*b819cea2SGordon Ross * Traverse a mount point. Routine accepts a vnode pointer as a reference 490*b819cea2SGordon Ross * parameter and performs the indirection, releasing the original vnode. 491*b819cea2SGordon Ross */ 492*b819cea2SGordon Ross int 493*b819cea2SGordon Ross traverse(vnode_t **cvpp) 494*b819cea2SGordon Ross { 495*b819cea2SGordon Ross int error = 0; 496*b819cea2SGordon Ross vnode_t *cvp; 497*b819cea2SGordon Ross vnode_t *tvp; 498*b819cea2SGordon Ross vfs_t *vfsp; 499*b819cea2SGordon Ross 500*b819cea2SGordon Ross cvp = *cvpp; 501*b819cea2SGordon Ross 502*b819cea2SGordon Ross /* 503*b819cea2SGordon Ross * If this vnode is mounted on, then we transparently indirect 504*b819cea2SGordon Ross * to the vnode which is the root of the mounted file system. 505*b819cea2SGordon Ross * Before we do this we must check that an unmount is not in 506*b819cea2SGordon Ross * progress on this vnode. 507*b819cea2SGordon Ross */ 508*b819cea2SGordon Ross 509*b819cea2SGordon Ross for (;;) { 510*b819cea2SGordon Ross /* 511*b819cea2SGordon Ross * Used to try to read lock the vnode here. 512*b819cea2SGordon Ross */ 513*b819cea2SGordon Ross 514*b819cea2SGordon Ross /* 515*b819cea2SGordon Ross * Reached the end of the mount chain? 516*b819cea2SGordon Ross */ 517*b819cea2SGordon Ross vfsp = vn_mountedvfs(cvp); 518*b819cea2SGordon Ross if (vfsp == NULL) { 519*b819cea2SGordon Ross break; 520*b819cea2SGordon Ross } 521*b819cea2SGordon Ross 522*b819cea2SGordon Ross /* 523*b819cea2SGordon Ross * The read lock must be held across the call to VFS_ROOT() to 524*b819cea2SGordon Ross * prevent a concurrent unmount from destroying the vfs. 525*b819cea2SGordon Ross */ 526*b819cea2SGordon Ross error = VFS_ROOT(vfsp, &tvp); 527*b819cea2SGordon Ross if (error) 528*b819cea2SGordon Ross break; 529*b819cea2SGordon Ross 530*b819cea2SGordon Ross VN_RELE(cvp); 531*b819cea2SGordon Ross 532*b819cea2SGordon Ross cvp = tvp; 533*b819cea2SGordon Ross } 534*b819cea2SGordon Ross 535*b819cea2SGordon Ross *cvpp = cvp; 536*b819cea2SGordon Ross return (error); 537*b819cea2SGordon Ross } 538*b819cea2SGordon Ross 539*b819cea2SGordon Ross /* 540*b819cea2SGordon Ross * Get the vnode path, relative to the passed rootvp. 541*b819cea2SGordon Ross * Our vncache always fills in v_path, so this is easy. 542*b819cea2SGordon Ross */ 543*b819cea2SGordon Ross /* ARGSUSED */ 544*b819cea2SGordon Ross int 545*b819cea2SGordon Ross vnodetopath(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen, cred_t *cr) 546*b819cea2SGordon Ross { 547*b819cea2SGordon Ross int len, rvp_len = 0; 548*b819cea2SGordon Ross const char *p = vp->v_path; 549*b819cea2SGordon Ross 550*b819cea2SGordon Ross if (vrootp) 551*b819cea2SGordon Ross rvp_len = strlen(vrootp->v_path); 552*b819cea2SGordon Ross len = strlen(p); 553*b819cea2SGordon Ross if (rvp_len < len) 554*b819cea2SGordon Ross p += rvp_len; 555*b819cea2SGordon Ross else 556*b819cea2SGordon Ross p = "/"; 557*b819cea2SGordon Ross 558*b819cea2SGordon Ross (void) strlcpy(buf, p, buflen); 559*b819cea2SGordon Ross return (0); 560*b819cea2SGordon Ross } 561