1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * University Copyright- Copyright (c) 1982, 1986, 1988 31 * The Regents of the University of California 32 * All Rights Reserved 33 * 34 * University Acknowledgment- Portions of this document are derived from 35 * software developed by the University of California, Berkeley, and its 36 * contributors. 37 */ 38 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 #include <sys/types.h> 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/cpuvar.h> 46 #include <sys/errno.h> 47 #include <sys/cred.h> 48 #include <sys/user.h> 49 #include <sys/uio.h> 50 #include <sys/vfs.h> 51 #include <sys/vnode.h> 52 #include <sys/pathname.h> 53 #include <sys/proc.h> 54 #include <sys/vtrace.h> 55 #include <sys/sysmacros.h> 56 #include <sys/debug.h> 57 #include <sys/dirent.h> 58 #include <c2/audit.h> 59 #include <sys/zone.h> 60 #include <sys/dnlc.h> 61 #include <sys/fs/snode.h> 62 63 /* Controls whether paths are stored with vnodes. */ 64 int vfs_vnode_path = 1; 65 66 int 67 lookupname( 68 char *fnamep, 69 enum uio_seg seg, 70 enum symfollow followlink, 71 vnode_t **dirvpp, 72 vnode_t **compvpp) 73 { 74 return (lookupnameat(fnamep, seg, followlink, dirvpp, compvpp, NULL)); 75 } 76 77 78 /* 79 * Lookup the user file name, 80 * Handle allocation and freeing of pathname buffer, return error. 81 */ 82 int 83 lookupnameat( 84 char *fnamep, /* user pathname */ 85 enum uio_seg seg, /* addr space that name is in */ 86 enum symfollow followlink, /* follow sym links */ 87 vnode_t **dirvpp, /* ret for ptr to parent dir vnode */ 88 vnode_t **compvpp, /* ret for ptr to component vnode */ 89 vnode_t *startvp) /* start path search from vp */ 90 { 91 char namebuf[TYPICALMAXPATHLEN]; 92 struct pathname lookpn; 93 int error; 94 95 error = pn_get_buf(fnamep, seg, &lookpn, namebuf, sizeof (namebuf)); 96 if (error == 0) { 97 if (audit_active) 98 audit_lookupname(); 99 error = lookuppnat(&lookpn, NULL, followlink, 100 dirvpp, compvpp, startvp); 101 } 102 if (error == ENAMETOOLONG) { 103 /* 104 * This thread used a pathname > TYPICALMAXPATHLEN bytes long. 105 */ 106 if (error = pn_get(fnamep, seg, &lookpn)) 107 return (error); 108 error = lookuppnat(&lookpn, NULL, followlink, 109 dirvpp, compvpp, startvp); 110 pn_free(&lookpn); 111 } 112 113 return (error); 114 } 115 116 /* 117 * Lookup the user file name from a given vp, 118 */ 119 int 120 lookuppn( 121 struct pathname *pnp, 122 struct pathname *rpnp, 123 enum symfollow followlink, 124 vnode_t **dirvpp, 125 vnode_t **compvpp) 126 { 127 return (lookuppnat(pnp, rpnp, followlink, dirvpp, compvpp, NULL)); 128 } 129 130 int 131 lookuppnat( 132 struct pathname *pnp, /* pathname to lookup */ 133 struct pathname *rpnp, /* if non-NULL, return resolved path */ 134 enum symfollow followlink, /* (don't) follow sym links */ 135 vnode_t **dirvpp, /* ptr for parent vnode */ 136 vnode_t **compvpp, /* ptr for entry vnode */ 137 vnode_t *startvp) /* start search from this vp */ 138 { 139 vnode_t *vp; /* current directory vp */ 140 vnode_t *rootvp; 141 proc_t *p = curproc; 142 143 if (pnp->pn_pathlen == 0) 144 return (ENOENT); 145 146 mutex_enter(&p->p_lock); /* for u_rdir and u_cdir */ 147 if ((rootvp = PTOU(p)->u_rdir) == NULL) 148 rootvp = rootdir; 149 else if (rootvp != rootdir) /* no need to VN_HOLD rootdir */ 150 VN_HOLD(rootvp); 151 152 if (pnp->pn_path[0] == '/') { 153 vp = rootvp; 154 } else { 155 vp = (startvp == NULL) ? PTOU(p)->u_cdir : startvp; 156 } 157 VN_HOLD(vp); 158 mutex_exit(&p->p_lock); 159 160 /* 161 * Skip over leading slashes 162 */ 163 if (pnp->pn_path[0] == '/') { 164 do { 165 pnp->pn_path++; 166 pnp->pn_pathlen--; 167 } while (pnp->pn_path[0] == '/'); 168 } 169 170 return (lookuppnvp(pnp, rpnp, followlink, dirvpp, 171 compvpp, rootvp, vp, CRED())); 172 } 173 174 /* Private flag to do our getcwd() dirty work */ 175 #define LOOKUP_CHECKREAD 0x10 176 #define LOOKUP_MASK (~LOOKUP_CHECKREAD) 177 178 /* 179 * Starting at current directory, translate pathname pnp to end. 180 * Leave pathname of final component in pnp, return the vnode 181 * for the final component in *compvpp, and return the vnode 182 * for the parent of the final component in dirvpp. 183 * 184 * This is the central routine in pathname translation and handles 185 * multiple components in pathnames, separating them at /'s. It also 186 * implements mounted file systems and processes symbolic links. 187 * 188 * vp is the vnode where the directory search should start. 189 * 190 * Reference counts: vp must be held prior to calling this function. rootvp 191 * should only be held if rootvp != rootdir. 192 */ 193 int 194 lookuppnvp( 195 struct pathname *pnp, /* pathname to lookup */ 196 struct pathname *rpnp, /* if non-NULL, return resolved path */ 197 int flags, /* follow symlinks */ 198 vnode_t **dirvpp, /* ptr for parent vnode */ 199 vnode_t **compvpp, /* ptr for entry vnode */ 200 vnode_t *rootvp, /* rootvp */ 201 vnode_t *vp, /* directory to start search at */ 202 cred_t *cr) /* user's credential */ 203 { 204 vnode_t *cvp; /* current component vp */ 205 vnode_t *tvp; /* addressable temp ptr */ 206 char component[MAXNAMELEN]; /* buffer for component (incl null) */ 207 int error; 208 int nlink; 209 int lookup_flags; 210 struct pathname presrvd; /* case preserved name */ 211 struct pathname *pp = NULL; 212 vnode_t *startvp; 213 vnode_t *zonevp = curproc->p_zone->zone_rootvp; /* zone root */ 214 int must_be_directory = 0; 215 boolean_t retry_with_kcred = B_FALSE; 216 217 CPU_STATS_ADDQ(CPU, sys, namei, 1); 218 nlink = 0; 219 cvp = NULL; 220 if (rpnp) 221 rpnp->pn_pathlen = 0; 222 223 lookup_flags = dirvpp ? LOOKUP_DIR : 0; 224 if (flags & FIGNORECASE) { 225 lookup_flags |= FIGNORECASE; 226 pn_alloc(&presrvd); 227 pp = &presrvd; 228 } 229 230 if (audit_active) 231 audit_anchorpath(pnp, vp == rootvp); 232 233 /* 234 * Eliminate any trailing slashes in the pathname. 235 * If there are any, we must follow all symlinks. 236 * Also, we must guarantee that the last component is a directory. 237 */ 238 if (pn_fixslash(pnp)) { 239 flags |= FOLLOW; 240 must_be_directory = 1; 241 } 242 243 startvp = vp; 244 next: 245 /* 246 * Make sure we have a directory. 247 */ 248 if (vp->v_type != VDIR) { 249 error = ENOTDIR; 250 goto bad; 251 } 252 253 if (rpnp && VN_CMP(vp, rootvp)) 254 (void) pn_set(rpnp, "/"); 255 256 /* 257 * Process the next component of the pathname. 258 */ 259 if (error = pn_getcomponent(pnp, component)) { 260 if (audit_active) 261 audit_addcomponent(pnp); 262 goto bad; 263 } 264 265 /* 266 * Handle "..": two special cases. 267 * 1. If we're at the root directory (e.g. after chroot or 268 * zone_enter) then change ".." to "." so we can't get 269 * out of this subtree. 270 * 2. If this vnode is the root of a mounted file system, 271 * then replace it with the vnode that was mounted on 272 * so that we take the ".." in the other file system. 273 */ 274 if (component[0] == '.' && component[1] == '.' && component[2] == 0) { 275 checkforroot: 276 if (VN_CMP(vp, rootvp) || VN_CMP(vp, zonevp)) { 277 component[1] = '\0'; 278 } else if (vp->v_flag & VROOT) { 279 vfs_t *vfsp; 280 cvp = vp; 281 282 /* 283 * While we deal with the vfs pointer from the vnode 284 * the filesystem could have been forcefully unmounted 285 * and the vnode's v_vfsp could have been invalidated 286 * by VFS_UNMOUNT. Hence, we cache v_vfsp and use it 287 * with vfs_rlock_wait/vfs_unlock. 288 * It is safe to use the v_vfsp even it is freed by 289 * VFS_UNMOUNT because vfs_rlock_wait/vfs_unlock 290 * do not dereference v_vfsp. It is just used as a 291 * magic cookie. 292 * One more corner case here is the memory getting 293 * reused for another vfs structure. In this case 294 * lookuppnvp's vfs_rlock_wait will succeed, domount's 295 * vfs_lock will fail and domount will bail out with an 296 * error (EBUSY). 297 */ 298 vfsp = cvp->v_vfsp; 299 300 /* 301 * This lock is used to synchronize 302 * mounts/unmounts and lookups. 303 * Threads doing mounts/unmounts hold the 304 * writers version vfs_lock_wait(). 305 */ 306 307 vfs_rlock_wait(vfsp); 308 309 /* 310 * If this vnode is on a file system that 311 * has been forcibly unmounted, 312 * we can't proceed. Cancel this operation 313 * and return EIO. 314 * 315 * vfs_vnodecovered is NULL if unmounted. 316 * Currently, nfs uses VFS_UNMOUNTED to 317 * check if it's a forced-umount. Keep the 318 * same checking here as well even though it 319 * may not be needed. 320 */ 321 if (((vp = cvp->v_vfsp->vfs_vnodecovered) == NULL) || 322 (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) { 323 vfs_unlock(vfsp); 324 VN_RELE(cvp); 325 if (pp) 326 pn_free(pp); 327 return (EIO); 328 } 329 VN_HOLD(vp); 330 vfs_unlock(vfsp); 331 VN_RELE(cvp); 332 cvp = NULL; 333 /* 334 * Crossing mount points. For eg: We are doing 335 * a lookup of ".." for file systems root vnode 336 * mounted here, and VOP_LOOKUP() (with covered vnode) 337 * will be on underlying file systems mount point 338 * vnode. Set retry_with_kcred flag as we might end 339 * up doing VOP_LOOKUP() with kcred if required. 340 */ 341 retry_with_kcred = B_TRUE; 342 goto checkforroot; 343 } 344 } 345 346 /* 347 * LOOKUP_CHECKREAD is a private flag used by vnodetopath() to indicate 348 * that we need to have read permission on every directory in the entire 349 * path. This is used to ensure that a forward-lookup of a cached value 350 * has the same effect as a reverse-lookup when the cached value cannot 351 * be found. 352 */ 353 if ((flags & LOOKUP_CHECKREAD) && 354 (error = VOP_ACCESS(vp, VREAD, 0, cr, NULL)) != 0) 355 goto bad; 356 357 /* 358 * Perform a lookup in the current directory. 359 */ 360 error = VOP_LOOKUP(vp, component, &tvp, pnp, lookup_flags, 361 rootvp, cr, NULL, NULL, pp); 362 363 /* 364 * Retry with kcred - If crossing mount points & error is EACCES. 365 * 366 * If we are crossing mount points here and doing ".." lookup, 367 * VOP_LOOKUP() might fail if the underlying file systems 368 * mount point has no execute permission. In cases like these, 369 * we retry VOP_LOOKUP() by giving as much privilage as possible 370 * by passing kcred credentials. 371 * 372 * In case of hierarchical file systems, passing kcred still may 373 * or may not work. 374 * For eg: UFS FS --> Mount NFS FS --> Again mount UFS on some 375 * directory inside NFS FS. 376 */ 377 if ((error == EACCES) && retry_with_kcred) 378 error = VOP_LOOKUP(vp, component, &tvp, pnp, lookup_flags, 379 rootvp, zone_kcred(), NULL, NULL, pp); 380 381 cvp = tvp; 382 if (error) { 383 cvp = NULL; 384 /* 385 * On error, return hard error if 386 * (a) we're not at the end of the pathname yet, or 387 * (b) the caller didn't want the parent directory, or 388 * (c) we failed for some reason other than a missing entry. 389 */ 390 if (pn_pathleft(pnp) || dirvpp == NULL || error != ENOENT) 391 goto bad; 392 if (audit_active) { /* directory access */ 393 if (error = audit_savepath(pnp, vp, error, cr)) 394 goto bad_noaudit; 395 } 396 pn_setlast(pnp); 397 /* 398 * We inform the caller that the desired entry must be 399 * a directory by adding a '/' to the component name. 400 */ 401 if (must_be_directory && (error = pn_addslash(pnp)) != 0) 402 goto bad; 403 *dirvpp = vp; 404 if (compvpp != NULL) 405 *compvpp = NULL; 406 if (rootvp != rootdir) 407 VN_RELE(rootvp); 408 if (pp) 409 pn_free(pp); 410 return (0); 411 } 412 413 /* 414 * Traverse mount points. 415 * XXX why don't we need to hold a read lock here (call vn_vfsrlock)? 416 * What prevents a concurrent update to v_vfsmountedhere? 417 * Possible answer: if mounting, we might not see the mount 418 * if it is concurrently coming into existence, but that's 419 * really not much different from the thread running a bit slower. 420 * If unmounting, we may get into traverse() when we shouldn't, 421 * but traverse() will catch this case for us. 422 * (For this to work, fetching v_vfsmountedhere had better 423 * be atomic!) 424 */ 425 if (vn_mountedvfs(cvp) != NULL) { 426 tvp = cvp; 427 if ((error = traverse(&tvp)) != 0) { 428 /* 429 * It is required to assign cvp here, because 430 * traverse() will return a held vnode which 431 * may different than the vnode that was passed 432 * in (even in the error case). If traverse() 433 * changes the vnode it releases the original, 434 * and holds the new one. 435 */ 436 cvp = tvp; 437 goto bad; 438 } 439 cvp = tvp; 440 } 441 442 /* 443 * If we hit a symbolic link and there is more path to be 444 * translated or this operation does not wish to apply 445 * to a link, then place the contents of the link at the 446 * front of the remaining pathname. 447 */ 448 if (cvp->v_type == VLNK && ((flags & FOLLOW) || pn_pathleft(pnp))) { 449 struct pathname linkpath; 450 if (audit_active) { 451 if (error = audit_pathcomp(pnp, cvp, cr)) 452 goto bad; 453 } 454 455 if (++nlink > MAXSYMLINKS) { 456 error = ELOOP; 457 goto bad; 458 } 459 pn_alloc(&linkpath); 460 if (error = pn_getsymlink(cvp, &linkpath, cr)) { 461 pn_free(&linkpath); 462 goto bad; 463 } 464 465 if (audit_active) 466 audit_symlink(pnp, &linkpath); 467 468 if (pn_pathleft(&linkpath) == 0) 469 (void) pn_set(&linkpath, "."); 470 error = pn_insert(pnp, &linkpath, strlen(component)); 471 pn_free(&linkpath); 472 if (error) 473 goto bad; 474 VN_RELE(cvp); 475 cvp = NULL; 476 if (pnp->pn_pathlen == 0) { 477 error = ENOENT; 478 goto bad; 479 } 480 if (pnp->pn_path[0] == '/') { 481 do { 482 pnp->pn_path++; 483 pnp->pn_pathlen--; 484 } while (pnp->pn_path[0] == '/'); 485 VN_RELE(vp); 486 vp = rootvp; 487 VN_HOLD(vp); 488 } 489 if (audit_active) 490 audit_anchorpath(pnp, vp == rootvp); 491 if (pn_fixslash(pnp)) { 492 flags |= FOLLOW; 493 must_be_directory = 1; 494 } 495 goto next; 496 } 497 498 /* 499 * If rpnp is non-NULL, remember the resolved path name therein. 500 * Do not include "." components. Collapse occurrences of 501 * "previous/..", so long as "previous" is not itself "..". 502 * Exhausting rpnp results in error ENAMETOOLONG. 503 */ 504 if (rpnp && strcmp(component, ".") != 0) { 505 size_t len; 506 507 if (strcmp(component, "..") == 0 && 508 rpnp->pn_pathlen != 0 && 509 !((rpnp->pn_pathlen > 2 && 510 strncmp(rpnp->pn_path+rpnp->pn_pathlen-3, "/..", 3) == 0) || 511 (rpnp->pn_pathlen == 2 && 512 strncmp(rpnp->pn_path, "..", 2) == 0))) { 513 while (rpnp->pn_pathlen && 514 rpnp->pn_path[rpnp->pn_pathlen-1] != '/') 515 rpnp->pn_pathlen--; 516 if (rpnp->pn_pathlen > 1) 517 rpnp->pn_pathlen--; 518 rpnp->pn_path[rpnp->pn_pathlen] = '\0'; 519 } else { 520 if (rpnp->pn_pathlen != 0 && 521 rpnp->pn_path[rpnp->pn_pathlen-1] != '/') 522 rpnp->pn_path[rpnp->pn_pathlen++] = '/'; 523 if (flags & FIGNORECASE) { 524 /* 525 * Return the case-preserved name 526 * within the resolved path. 527 */ 528 error = copystr(pp->pn_buf, 529 rpnp->pn_path + rpnp->pn_pathlen, 530 rpnp->pn_bufsize - rpnp->pn_pathlen, &len); 531 } else { 532 error = copystr(component, 533 rpnp->pn_path + rpnp->pn_pathlen, 534 rpnp->pn_bufsize - rpnp->pn_pathlen, &len); 535 } 536 if (error) /* copystr() returns ENAMETOOLONG */ 537 goto bad; 538 rpnp->pn_pathlen += (len - 1); 539 ASSERT(rpnp->pn_bufsize > rpnp->pn_pathlen); 540 } 541 } 542 543 /* 544 * If no more components, return last directory (if wanted) and 545 * last component (if wanted). 546 */ 547 if (pn_pathleft(pnp) == 0) { 548 /* 549 * If there was a trailing slash in the pathname, 550 * make sure the last component is a directory. 551 */ 552 if (must_be_directory && cvp->v_type != VDIR) { 553 error = ENOTDIR; 554 goto bad; 555 } 556 if (dirvpp != NULL) { 557 /* 558 * Check that we have the real parent and not 559 * an alias of the last component. 560 */ 561 if (vn_compare(vp, cvp)) { 562 if (audit_active) 563 (void) audit_savepath(pnp, cvp, 564 EINVAL, cr); 565 pn_setlast(pnp); 566 VN_RELE(vp); 567 VN_RELE(cvp); 568 if (rootvp != rootdir) 569 VN_RELE(rootvp); 570 if (pp) 571 pn_free(pp); 572 return (EINVAL); 573 } 574 if (audit_active) { 575 if (error = audit_pathcomp(pnp, vp, cr)) 576 goto bad; 577 } 578 *dirvpp = vp; 579 } else 580 VN_RELE(vp); 581 if (audit_active) 582 (void) audit_savepath(pnp, cvp, 0, cr); 583 if (pnp->pn_path == pnp->pn_buf) 584 (void) pn_set(pnp, "."); 585 else 586 pn_setlast(pnp); 587 if (rpnp) { 588 if (VN_CMP(cvp, rootvp)) 589 (void) pn_set(rpnp, "/"); 590 else if (rpnp->pn_pathlen == 0) 591 (void) pn_set(rpnp, "."); 592 } 593 594 if (compvpp != NULL) 595 *compvpp = cvp; 596 else 597 VN_RELE(cvp); 598 if (rootvp != rootdir) 599 VN_RELE(rootvp); 600 if (pp) 601 pn_free(pp); 602 return (0); 603 } 604 605 if (audit_active) { 606 if (error = audit_pathcomp(pnp, cvp, cr)) 607 goto bad; 608 } 609 610 /* 611 * Skip over slashes from end of last component. 612 */ 613 while (pnp->pn_path[0] == '/') { 614 pnp->pn_path++; 615 pnp->pn_pathlen--; 616 } 617 618 /* 619 * Searched through another level of directory: 620 * release previous directory handle and save new (result 621 * of lookup) as current directory. 622 */ 623 VN_RELE(vp); 624 vp = cvp; 625 cvp = NULL; 626 goto next; 627 628 bad: 629 if (audit_active) /* reached end of path */ 630 (void) audit_savepath(pnp, cvp, error, cr); 631 bad_noaudit: 632 /* 633 * Error. Release vnodes and return. 634 */ 635 if (cvp) 636 VN_RELE(cvp); 637 /* 638 * If the error was ESTALE and the current directory to look in 639 * was the root for this lookup, the root for a mounted file 640 * system, or the starting directory for lookups, then 641 * return ENOENT instead of ESTALE. In this case, no recovery 642 * is possible by the higher level. If ESTALE was returned for 643 * some intermediate directory along the path, then recovery 644 * is potentially possible and retrying from the higher level 645 * will either correct the situation by purging stale cache 646 * entries or eventually get back to the point where no recovery 647 * is possible. 648 */ 649 if (error == ESTALE && 650 (VN_CMP(vp, rootvp) || (vp->v_flag & VROOT) || vp == startvp)) 651 error = ENOENT; 652 VN_RELE(vp); 653 if (rootvp != rootdir) 654 VN_RELE(rootvp); 655 if (pp) 656 pn_free(pp); 657 return (error); 658 } 659 660 /* 661 * Traverse a mount point. Routine accepts a vnode pointer as a reference 662 * parameter and performs the indirection, releasing the original vnode. 663 */ 664 int 665 traverse(vnode_t **cvpp) 666 { 667 int error = 0; 668 vnode_t *cvp; 669 vnode_t *tvp; 670 vfs_t *vfsp; 671 672 cvp = *cvpp; 673 674 /* 675 * If this vnode is mounted on, then we transparently indirect 676 * to the vnode which is the root of the mounted file system. 677 * Before we do this we must check that an unmount is not in 678 * progress on this vnode. 679 */ 680 681 for (;;) { 682 /* 683 * Try to read lock the vnode. If this fails because 684 * the vnode is already write locked, then check to 685 * see whether it is the current thread which locked 686 * the vnode. If it is not, then read lock the vnode 687 * by waiting to acquire the lock. 688 * 689 * The code path in domount() is an example of support 690 * which needs to look up two pathnames and locks one 691 * of them in between the two lookups. 692 */ 693 error = vn_vfsrlock(cvp); 694 if (error) { 695 if (!vn_vfswlock_held(cvp)) 696 error = vn_vfsrlock_wait(cvp); 697 if (error != 0) { 698 /* 699 * lookuppn() expects a held vnode to be 700 * returned because it promptly calls 701 * VN_RELE after the error return 702 */ 703 *cvpp = cvp; 704 return (error); 705 } 706 } 707 708 /* 709 * Reached the end of the mount chain? 710 */ 711 vfsp = vn_mountedvfs(cvp); 712 if (vfsp == NULL) { 713 vn_vfsunlock(cvp); 714 break; 715 } 716 717 /* 718 * The read lock must be held across the call to VFS_ROOT() to 719 * prevent a concurrent unmount from destroying the vfs. 720 */ 721 error = VFS_ROOT(vfsp, &tvp); 722 vn_vfsunlock(cvp); 723 724 if (error) 725 break; 726 727 VN_RELE(cvp); 728 729 cvp = tvp; 730 } 731 732 *cvpp = cvp; 733 return (error); 734 } 735 736 /* 737 * Return the lowermost vnode if this is a mountpoint. 738 */ 739 static vnode_t * 740 vn_under(vnode_t *vp) 741 { 742 vnode_t *uvp; 743 vfs_t *vfsp; 744 745 while (vp->v_flag & VROOT) { 746 747 vfsp = vp->v_vfsp; 748 vfs_rlock_wait(vfsp); 749 if ((uvp = vfsp->vfs_vnodecovered) == NULL || 750 (vfsp->vfs_flag & VFS_UNMOUNTED)) { 751 vfs_unlock(vfsp); 752 break; 753 } 754 VN_HOLD(uvp); 755 vfs_unlock(vfsp); 756 VN_RELE(vp); 757 vp = uvp; 758 } 759 760 return (vp); 761 } 762 763 static int 764 vnode_match(vnode_t *v1, vnode_t *v2, cred_t *cr) 765 { 766 vattr_t v1attr, v2attr; 767 768 /* 769 * If we have a device file, check to see if is a cloned open of the 770 * same device. For self-cloning devices, the major numbers will match. 771 * For devices cloned through the 'clone' driver, the minor number of 772 * the source device will be the same as the major number of the cloned 773 * device. 774 */ 775 if ((v1->v_type == VCHR || v1->v_type == VBLK) && 776 v1->v_type == v2->v_type) { 777 if ((spec_is_selfclone(v1) || spec_is_selfclone(v2)) && 778 getmajor(v1->v_rdev) == getmajor(v2->v_rdev)) 779 return (1); 780 781 if (spec_is_clone(v1) && 782 getmajor(v1->v_rdev) == getminor(v2->v_rdev)) 783 return (1); 784 785 if (spec_is_clone(v2) && 786 getmajor(v2->v_rdev) == getminor(v1->v_rdev)) 787 return (1); 788 } 789 790 v1attr.va_mask = v2attr.va_mask = AT_TYPE; 791 792 /* 793 * This check for symbolic links handles the pseudo-symlinks in procfs. 794 * These particular links have v_type of VDIR, but the attributes have a 795 * type of VLNK. We need to avoid these links because otherwise if we 796 * are currently in '/proc/self/fd', then '/proc/self/cwd' will compare 797 * as the same vnode. 798 */ 799 if (VOP_GETATTR(v1, &v1attr, 0, cr, NULL) != 0 || 800 VOP_GETATTR(v2, &v2attr, 0, cr, NULL) != 0 || 801 v1attr.va_type == VLNK || v2attr.va_type == VLNK) 802 return (0); 803 804 v1attr.va_mask = v2attr.va_mask = AT_TYPE | AT_FSID | AT_NODEID; 805 806 if (VOP_GETATTR(v1, &v1attr, ATTR_REAL, cr, NULL) != 0 || 807 VOP_GETATTR(v2, &v2attr, ATTR_REAL, cr, NULL) != 0) 808 return (0); 809 810 return (v1attr.va_fsid == v2attr.va_fsid && 811 v1attr.va_nodeid == v2attr.va_nodeid); 812 } 813 814 815 /* 816 * Find the entry in the directory corresponding to the target vnode. 817 */ 818 int 819 dirfindvp(vnode_t *vrootp, vnode_t *dvp, vnode_t *tvp, cred_t *cr, char *dbuf, 820 size_t dlen, dirent64_t **rdp) 821 { 822 size_t dbuflen; 823 struct iovec iov; 824 struct uio uio; 825 int error; 826 int eof; 827 vnode_t *cmpvp; 828 struct dirent64 *dp; 829 pathname_t pnp; 830 831 ASSERT(dvp->v_type == VDIR); 832 833 /* 834 * This is necessary because of the strange semantics of VOP_LOOKUP(). 835 */ 836 bzero(&pnp, sizeof (pnp)); 837 838 eof = 0; 839 840 uio.uio_iov = &iov; 841 uio.uio_iovcnt = 1; 842 uio.uio_segflg = UIO_SYSSPACE; 843 uio.uio_fmode = 0; 844 uio.uio_extflg = UIO_COPY_CACHED; 845 uio.uio_loffset = 0; 846 847 if ((error = VOP_ACCESS(dvp, VREAD, 0, cr, NULL)) != 0) 848 return (error); 849 850 while (!eof) { 851 uio.uio_resid = dlen; 852 iov.iov_base = dbuf; 853 iov.iov_len = dlen; 854 855 (void) VOP_RWLOCK(dvp, V_WRITELOCK_FALSE, NULL); 856 error = VOP_READDIR(dvp, &uio, cr, &eof, NULL, 0); 857 VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL); 858 859 dbuflen = dlen - uio.uio_resid; 860 861 if (error || dbuflen == 0) 862 break; 863 864 dp = (dirent64_t *)dbuf; 865 while ((intptr_t)dp < (intptr_t)dbuf + dbuflen) { 866 /* 867 * Ignore '.' and '..' entries 868 */ 869 if (strcmp(dp->d_name, ".") == 0 || 870 strcmp(dp->d_name, "..") == 0) { 871 dp = (dirent64_t *)((intptr_t)dp + 872 dp->d_reclen); 873 continue; 874 } 875 876 error = VOP_LOOKUP(dvp, dp->d_name, &cmpvp, &pnp, 0, 877 vrootp, cr, NULL, NULL, NULL); 878 879 /* 880 * We only want to bail out if there was an error other 881 * than ENOENT. Otherwise, it could be that someone 882 * just removed an entry since the readdir() call, and 883 * the entry we want is further on in the directory. 884 */ 885 if (error == 0) { 886 if (vnode_match(tvp, cmpvp, cr)) { 887 VN_RELE(cmpvp); 888 *rdp = dp; 889 return (0); 890 } 891 892 VN_RELE(cmpvp); 893 } else if (error != ENOENT) { 894 return (error); 895 } 896 897 dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen); 898 } 899 } 900 901 /* 902 * Something strange has happened, this directory does not contain the 903 * specified vnode. This should never happen in the normal case, since 904 * we ensured that dvp is the parent of vp. This is possible in some 905 * rare conditions (races and the special .zfs directory). 906 */ 907 if (error == 0) { 908 error = VOP_LOOKUP(dvp, ".zfs", &cmpvp, &pnp, 0, vrootp, cr, 909 NULL, NULL, NULL); 910 if (error == 0) { 911 if (vnode_match(tvp, cmpvp, cr)) { 912 (void) strcpy(dp->d_name, ".zfs"); 913 dp->d_reclen = strlen(".zfs"); 914 dp->d_off = 2; 915 dp->d_ino = 1; 916 *rdp = dp; 917 } else { 918 error = ENOENT; 919 } 920 VN_RELE(cmpvp); 921 } 922 } 923 924 return (error); 925 } 926 927 /* 928 * Given a global path (from rootdir), and a vnode that is the current root, 929 * return the portion of the path that is beneath the current root or NULL on 930 * failure. The path MUST be a resolved path (no '..' entries or symlinks), 931 * otherwise this function will fail. 932 */ 933 static char * 934 localpath(char *path, struct vnode *vrootp, cred_t *cr) 935 { 936 vnode_t *vp; 937 vnode_t *cvp; 938 char component[MAXNAMELEN]; 939 char *ret = NULL; 940 pathname_t pn; 941 942 /* 943 * We use vn_compare() instead of VN_CMP() in order to detect lofs 944 * mounts and stacked vnodes. 945 */ 946 if (vn_compare(vrootp, rootdir)) 947 return (path); 948 949 if (pn_get(path, UIO_SYSSPACE, &pn) != 0) 950 return (NULL); 951 952 vp = rootdir; 953 VN_HOLD(vp); 954 955 while (pn_pathleft(&pn)) { 956 pn_skipslash(&pn); 957 958 if (pn_getcomponent(&pn, component) != 0) 959 break; 960 961 if (vn_ismntpt(vp) && traverse(&vp) != 0) 962 break; 963 964 if (VOP_LOOKUP(vp, component, &cvp, &pn, 0, rootdir, cr, 965 NULL, NULL, NULL) != 0) 966 break; 967 968 VN_RELE(vp); 969 vp = cvp; 970 971 if (vn_compare(vp, vrootp)) { 972 ret = path + (pn.pn_path - pn.pn_buf); 973 break; 974 } 975 } 976 977 VN_RELE(vp); 978 pn_free(&pn); 979 980 return (ret); 981 } 982 983 /* 984 * Given a directory, return the full, resolved path. This looks up "..", 985 * searches for the given vnode in the parent, appends the component, etc. It 986 * is used to implement vnodetopath() and getcwd() when the cached path fails 987 * (or vfs_vnode_path is not set). 988 */ 989 static int 990 dirtopath(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen, cred_t *cr) 991 { 992 pathname_t pn, rpn, emptypn; 993 vnode_t *cmpvp, *pvp = NULL; 994 vnode_t *startvp = vp; 995 int err = 0; 996 size_t complen; 997 char *dbuf; 998 dirent64_t *dp; 999 char *bufloc; 1000 size_t dlen = DIRENT64_RECLEN(MAXPATHLEN); 1001 refstr_t *mntpt; 1002 1003 /* Operation only allowed on directories */ 1004 ASSERT(vp->v_type == VDIR); 1005 1006 /* We must have at least enough space for "/" */ 1007 if (buflen < 2) 1008 return (ENAMETOOLONG); 1009 1010 /* Start at end of string with terminating null */ 1011 bufloc = &buf[buflen - 1]; 1012 *bufloc = '\0'; 1013 1014 pn_alloc(&pn); 1015 pn_alloc(&rpn); 1016 dbuf = kmem_alloc(dlen, KM_SLEEP); 1017 bzero(&emptypn, sizeof (emptypn)); 1018 1019 /* 1020 * Begin with an additional reference on vp. This will be decremented 1021 * during the loop. 1022 */ 1023 VN_HOLD(vp); 1024 1025 for (;;) { 1026 /* 1027 * Return if we've reached the root. If the buffer is empty, 1028 * return '/'. We explicitly don't use vn_compare(), since it 1029 * compares the real vnodes. A lofs mount of '/' would produce 1030 * incorrect results otherwise. 1031 */ 1032 if (VN_CMP(vrootp, vp)) { 1033 if (*bufloc == '\0') 1034 *--bufloc = '/'; 1035 break; 1036 } 1037 1038 /* 1039 * If we've reached the VFS root, something has gone wrong. We 1040 * should have reached the root in the above check. The only 1041 * explantation is that 'vp' is not contained withing the given 1042 * root, in which case we return EPERM. 1043 */ 1044 if (VN_CMP(rootdir, vp)) { 1045 err = EPERM; 1046 goto out; 1047 } 1048 1049 /* 1050 * Shortcut: see if this vnode is a mountpoint. If so, 1051 * grab the path information from the vfs_t. 1052 */ 1053 if (vp->v_flag & VROOT) { 1054 1055 mntpt = vfs_getmntpoint(vp->v_vfsp); 1056 if ((err = pn_set(&pn, (char *)refstr_value(mntpt))) 1057 == 0) { 1058 refstr_rele(mntpt); 1059 rpn.pn_path = rpn.pn_buf; 1060 1061 /* 1062 * Ensure the mointpoint still exists. 1063 */ 1064 VN_HOLD(vrootp); 1065 if (vrootp != rootdir) 1066 VN_HOLD(vrootp); 1067 if (lookuppnvp(&pn, &rpn, 0, NULL, 1068 &cmpvp, vrootp, vrootp, cr) == 0) { 1069 1070 if (VN_CMP(vp, cmpvp)) { 1071 VN_RELE(cmpvp); 1072 1073 complen = strlen(rpn.pn_path); 1074 bufloc -= complen; 1075 if (bufloc < buf) { 1076 err = ERANGE; 1077 goto out; 1078 } 1079 bcopy(rpn.pn_path, bufloc, 1080 complen); 1081 break; 1082 } else { 1083 VN_RELE(cmpvp); 1084 } 1085 } 1086 } else { 1087 refstr_rele(mntpt); 1088 } 1089 } 1090 1091 /* 1092 * Shortcuts failed, search for this vnode in its parent. If 1093 * this is a mountpoint, then get the vnode underneath. 1094 */ 1095 if (vp->v_flag & VROOT) 1096 vp = vn_under(vp); 1097 if ((err = VOP_LOOKUP(vp, "..", &pvp, &emptypn, 0, vrootp, cr, 1098 NULL, NULL, NULL)) != 0) 1099 goto out; 1100 1101 /* 1102 * With extended attributes, it's possible for a directory to 1103 * have a parent that is a regular file. Check for that here. 1104 */ 1105 if (pvp->v_type != VDIR) { 1106 err = ENOTDIR; 1107 goto out; 1108 } 1109 1110 /* 1111 * If this is true, something strange has happened. This is 1112 * only true if we are the root of a filesystem, which should 1113 * have been caught by the check above. 1114 */ 1115 if (VN_CMP(pvp, vp)) { 1116 err = ENOENT; 1117 goto out; 1118 } 1119 1120 /* 1121 * Search the parent directory for the entry corresponding to 1122 * this vnode. 1123 */ 1124 if ((err = dirfindvp(vrootp, pvp, vp, cr, dbuf, dlen, &dp)) 1125 != 0) 1126 goto out; 1127 complen = strlen(dp->d_name); 1128 bufloc -= complen; 1129 if (bufloc <= buf) { 1130 err = ENAMETOOLONG; 1131 goto out; 1132 } 1133 bcopy(dp->d_name, bufloc, complen); 1134 1135 /* Prepend a slash to the current path. */ 1136 *--bufloc = '/'; 1137 1138 /* And continue with the next component */ 1139 VN_RELE(vp); 1140 vp = pvp; 1141 pvp = NULL; 1142 } 1143 1144 /* 1145 * Place the path at the beginning of the buffer. 1146 */ 1147 if (bufloc != buf) 1148 ovbcopy(bufloc, buf, buflen - (bufloc - buf)); 1149 1150 out: 1151 /* 1152 * If the error was ESTALE and the current directory to look in 1153 * was the root for this lookup, the root for a mounted file 1154 * system, or the starting directory for lookups, then 1155 * return ENOENT instead of ESTALE. In this case, no recovery 1156 * is possible by the higher level. If ESTALE was returned for 1157 * some intermediate directory along the path, then recovery 1158 * is potentially possible and retrying from the higher level 1159 * will either correct the situation by purging stale cache 1160 * entries or eventually get back to the point where no recovery 1161 * is possible. 1162 */ 1163 if (err == ESTALE && 1164 (VN_CMP(vp, vrootp) || (vp->v_flag & VROOT) || vp == startvp)) 1165 err = ENOENT; 1166 1167 kmem_free(dbuf, dlen); 1168 VN_RELE(vp); 1169 if (pvp) 1170 VN_RELE(pvp); 1171 pn_free(&pn); 1172 pn_free(&rpn); 1173 1174 return (err); 1175 } 1176 1177 /* 1178 * The additional flag, LOOKUP_CHECKREAD, is ued to enforce artificial 1179 * constraints in order to be standards compliant. For example, if we have 1180 * the cached path of '/foo/bar', and '/foo' has permissions 100 (execute 1181 * only), then we can legitimately look up the path to the current working 1182 * directory without needing read permission. Existing standards tests, 1183 * however, assume that we are determining the path by repeatedly looking up 1184 * "..". We need to keep this behavior in order to maintain backwards 1185 * compatibility. 1186 */ 1187 static int 1188 vnodetopath_common(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen, 1189 cred_t *cr, int flags) 1190 { 1191 pathname_t pn, rpn; 1192 int ret, len; 1193 vnode_t *compvp, *pvp, *realvp; 1194 proc_t *p = curproc; 1195 char path[MAXNAMELEN]; 1196 int doclose = 0; 1197 1198 /* 1199 * If vrootp is NULL, get the root for curproc. Callers with any other 1200 * requirements should pass in a different vrootp. 1201 */ 1202 if (vrootp == NULL) { 1203 mutex_enter(&p->p_lock); 1204 if ((vrootp = PTOU(p)->u_rdir) == NULL) 1205 vrootp = rootdir; 1206 VN_HOLD(vrootp); 1207 mutex_exit(&p->p_lock); 1208 } else { 1209 VN_HOLD(vrootp); 1210 } 1211 1212 /* 1213 * This is to get around an annoying artifact of the /proc filesystem, 1214 * which is the behavior of {cwd/root}. Trying to resolve this path 1215 * will result in /proc/pid/cwd instead of whatever the real working 1216 * directory is. We can't rely on VOP_REALVP(), since that will break 1217 * lofs. The only difference between procfs and lofs is that opening 1218 * the file will return the underling vnode in the case of procfs. 1219 */ 1220 if (vp->v_type == VDIR && VOP_REALVP(vp, &realvp, NULL) == 0 && 1221 realvp != vp) { 1222 VN_HOLD(vp); 1223 if (VOP_OPEN(&vp, FREAD, cr, NULL) == 0) 1224 doclose = 1; 1225 else 1226 VN_RELE(vp); 1227 } 1228 1229 pn_alloc(&pn); 1230 1231 /* 1232 * Check to see if we have a cached path in the vnode. 1233 */ 1234 mutex_enter(&vp->v_lock); 1235 if (vp->v_path != NULL) { 1236 (void) pn_set(&pn, vp->v_path); 1237 mutex_exit(&vp->v_lock); 1238 1239 pn_alloc(&rpn); 1240 1241 /* We should only cache absolute paths */ 1242 ASSERT(pn.pn_buf[0] == '/'); 1243 1244 /* 1245 * If we are in a zone or a chroot environment, then we have to 1246 * take additional steps, since the path to the root might not 1247 * be readable with the current credentials, even though the 1248 * process can legitmately access the file. In this case, we 1249 * do the following: 1250 * 1251 * lookuppnvp() with all privileges to get the resolved path. 1252 * call localpath() to get the local portion of the path, and 1253 * continue as normal. 1254 * 1255 * If the the conversion to a local path fails, then we continue 1256 * as normal. This is a heuristic to make process object file 1257 * paths available from within a zone. Because lofs doesn't 1258 * support page operations, the vnode stored in the seg_t is 1259 * actually the underlying real vnode, not the lofs node itself. 1260 * Most of the time, the lofs path is the same as the underlying 1261 * vnode (for example, /usr/lib/libc.so.1). 1262 */ 1263 if (vrootp != rootdir) { 1264 char *local = NULL; 1265 VN_HOLD(rootdir); 1266 if (lookuppnvp(&pn, &rpn, FOLLOW, 1267 NULL, &compvp, rootdir, rootdir, kcred) == 0) { 1268 local = localpath(rpn.pn_path, vrootp, 1269 kcred); 1270 VN_RELE(compvp); 1271 } 1272 1273 /* 1274 * The original pn was changed through lookuppnvp(), so 1275 * reset it. 1276 */ 1277 if (local) { 1278 (void) pn_set(&pn, local); 1279 } else { 1280 mutex_enter(&vp->v_lock); 1281 if (vp->v_path != NULL) { 1282 (void) pn_set(&pn, vp->v_path); 1283 mutex_exit(&vp->v_lock); 1284 } else { 1285 mutex_exit(&vp->v_lock); 1286 goto notcached; 1287 } 1288 } 1289 } 1290 1291 /* 1292 * We should have a local path at this point, so start the 1293 * search from the root of the current process. 1294 */ 1295 VN_HOLD(vrootp); 1296 if (vrootp != rootdir) 1297 VN_HOLD(vrootp); 1298 ret = lookuppnvp(&pn, &rpn, FOLLOW | flags, NULL, 1299 &compvp, vrootp, vrootp, cr); 1300 if (ret == 0) { 1301 /* 1302 * Check to see if the returned vnode is the same as 1303 * the one we expect. If not, give up. 1304 */ 1305 if (!vn_compare(vp, compvp) && 1306 !vnode_match(vp, compvp, cr)) { 1307 VN_RELE(compvp); 1308 goto notcached; 1309 } 1310 1311 VN_RELE(compvp); 1312 1313 /* 1314 * Return the result. 1315 */ 1316 if (buflen <= rpn.pn_pathlen) 1317 goto notcached; 1318 1319 bcopy(rpn.pn_path, buf, rpn.pn_pathlen + 1); 1320 pn_free(&pn); 1321 pn_free(&rpn); 1322 VN_RELE(vrootp); 1323 if (doclose) { 1324 (void) VOP_CLOSE(vp, FREAD, 1, 0, cr, NULL); 1325 VN_RELE(vp); 1326 } 1327 return (0); 1328 } 1329 1330 notcached: 1331 pn_free(&rpn); 1332 } else { 1333 mutex_exit(&vp->v_lock); 1334 } 1335 1336 pn_free(&pn); 1337 1338 if (vp->v_type != VDIR) { 1339 /* 1340 * If we don't have a directory, try to find it in the dnlc via 1341 * reverse lookup. Once this is found, we can use the regular 1342 * directory search to find the full path. 1343 */ 1344 if ((pvp = dnlc_reverse_lookup(vp, path, MAXNAMELEN)) != NULL) { 1345 ret = dirtopath(vrootp, pvp, buf, buflen, cr); 1346 if (ret == 0) { 1347 len = strlen(buf); 1348 if (len + strlen(path) + 1 >= buflen) { 1349 ret = ENAMETOOLONG; 1350 } else { 1351 if (buf[len - 1] != '/') 1352 buf[len++] = '/'; 1353 bcopy(path, buf + len, 1354 strlen(path) + 1); 1355 } 1356 } 1357 1358 VN_RELE(pvp); 1359 } else 1360 ret = ENOENT; 1361 } else 1362 ret = dirtopath(vrootp, vp, buf, buflen, cr); 1363 1364 VN_RELE(vrootp); 1365 if (doclose) { 1366 (void) VOP_CLOSE(vp, FREAD, 1, 0, cr, NULL); 1367 VN_RELE(vp); 1368 } 1369 1370 return (ret); 1371 } 1372 1373 int 1374 vnodetopath(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen, cred_t *cr) 1375 { 1376 return (vnodetopath_common(vrootp, vp, buf, buflen, cr, 0)); 1377 } 1378 1379 int 1380 dogetcwd(char *buf, size_t buflen) 1381 { 1382 int ret; 1383 vnode_t *vp; 1384 vnode_t *compvp; 1385 refstr_t *cwd, *oldcwd; 1386 const char *value; 1387 pathname_t rpnp, pnp; 1388 proc_t *p = curproc; 1389 1390 /* 1391 * Check to see if there is a cached version of the cwd. If so, lookup 1392 * the cached value and make sure it is the same vnode. 1393 */ 1394 mutex_enter(&p->p_lock); 1395 if ((cwd = PTOU(p)->u_cwd) != NULL) 1396 refstr_hold(cwd); 1397 vp = PTOU(p)->u_cdir; 1398 VN_HOLD(vp); 1399 mutex_exit(&p->p_lock); 1400 1401 /* 1402 * Make sure we have permission to access the current directory. 1403 */ 1404 if ((ret = VOP_ACCESS(vp, VEXEC, 0, CRED(), NULL)) != 0) { 1405 if (cwd != NULL) 1406 refstr_rele(cwd); 1407 VN_RELE(vp); 1408 return (ret); 1409 } 1410 1411 if (cwd) { 1412 value = refstr_value(cwd); 1413 if ((ret = pn_get((char *)value, UIO_SYSSPACE, &pnp)) != 0) { 1414 refstr_rele(cwd); 1415 VN_RELE(vp); 1416 return (ret); 1417 } 1418 1419 pn_alloc(&rpnp); 1420 1421 if (lookuppn(&pnp, &rpnp, NO_FOLLOW, NULL, &compvp) == 0) { 1422 1423 if (VN_CMP(vp, compvp) && 1424 strcmp(value, rpnp.pn_path) == 0) { 1425 VN_RELE(compvp); 1426 VN_RELE(vp); 1427 pn_free(&pnp); 1428 pn_free(&rpnp); 1429 if (strlen(value) + 1 > buflen) { 1430 refstr_rele(cwd); 1431 return (ENAMETOOLONG); 1432 } 1433 bcopy(value, buf, strlen(value) + 1); 1434 refstr_rele(cwd); 1435 return (0); 1436 } 1437 1438 VN_RELE(compvp); 1439 } 1440 1441 pn_free(&rpnp); 1442 pn_free(&pnp); 1443 1444 refstr_rele(cwd); 1445 } 1446 1447 ret = vnodetopath_common(NULL, vp, buf, buflen, CRED(), 1448 LOOKUP_CHECKREAD); 1449 1450 VN_RELE(vp); 1451 1452 /* 1453 * Store the new cwd and replace the existing cached copy. 1454 */ 1455 if (ret == 0) 1456 cwd = refstr_alloc(buf); 1457 else 1458 cwd = NULL; 1459 1460 mutex_enter(&p->p_lock); 1461 oldcwd = PTOU(p)->u_cwd; 1462 PTOU(p)->u_cwd = cwd; 1463 mutex_exit(&p->p_lock); 1464 1465 if (oldcwd) 1466 refstr_rele(oldcwd); 1467 1468 return (ret); 1469 } 1470