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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* 27 * Copyright (c) 2013, Joyent, Inc. All rights reserved. 28 * Copyright (c) 2013 by Delphix. All rights reserved. 29 */ 30 31 #include <assert.h> 32 #include <dlfcn.h> 33 #include <errno.h> 34 #include <libzonecfg.h> 35 #include <link.h> 36 #include <string.h> 37 #include <strings.h> 38 #include <sys/list.h> 39 #include <sys/types.h> 40 #include <sys/mkdev.h> 41 #include <sys/mman.h> 42 #include <sys/mnttab.h> 43 44 #include "Pcontrol.h" 45 46 struct path_node { 47 struct path_node *pn_next; 48 char *pn_path; 49 }; 50 typedef struct path_node path_node_t; 51 52 /* 53 * Parameters of the lofs lookup cache. 54 */ 55 static struct stat64 lofs_mstat; /* last stat() of MNTTAB */ 56 static struct lofs_mnttab { /* linked list of all lofs mount points */ 57 struct lofs_mnttab *l_next; 58 char *l_special; /* extracted from MNTTAB */ 59 char *l_mountp; /* ditto */ 60 } *lofs_mnttab = NULL; 61 static mutex_t lofs_lock = DEFAULTMUTEX; /* protects the lofs cache */ 62 63 static void 64 rebuild_lofs_cache(void) 65 { 66 struct mnttab mt; 67 struct mnttab mt_find; 68 struct lofs_mnttab *lmt; 69 struct lofs_mnttab *next; 70 FILE *fp; 71 72 assert(MUTEX_HELD(&lofs_lock)); 73 74 /* destroy the old cache */ 75 for (lmt = lofs_mnttab; lmt != NULL; lmt = next) { 76 next = lmt->l_next; 77 free(lmt->l_special); 78 free(lmt->l_mountp); 79 free(lmt); 80 } 81 lofs_mnttab = NULL; 82 83 /* prepare to create the new cache */ 84 if ((fp = fopen(MNTTAB, "r")) == NULL) 85 return; 86 87 /* 88 * We only care about lofs mount points. But we need to 89 * ignore lofs mounts where the source path is the same 90 * as the target path. (This can happen when a non-global 91 * zone has a lofs mount of a global zone filesystem, since 92 * the source path can't expose information about global 93 * zone paths to the non-global zone.) 94 */ 95 bzero(&mt_find, sizeof (mt_find)); 96 mt_find.mnt_fstype = "lofs"; 97 while (getmntany(fp, &mt, &mt_find) == 0 && 98 (strcmp(mt.mnt_fstype, "lofs") == 0) && 99 (strcmp(mt.mnt_special, mt.mnt_mountp) != 0)) { 100 if ((lmt = malloc(sizeof (struct lofs_mnttab))) == NULL) 101 break; 102 lmt->l_special = strdup(mt.mnt_special); 103 lmt->l_mountp = strdup(mt.mnt_mountp); 104 lmt->l_next = lofs_mnttab; 105 lofs_mnttab = lmt; 106 } 107 108 (void) fclose(fp); 109 } 110 111 static const char * 112 lookup_lofs_mount_point(const char *mountp) 113 { 114 struct lofs_mnttab *lmt; 115 116 assert(MUTEX_HELD(&lofs_lock)); 117 118 for (lmt = lofs_mnttab; lmt != NULL; lmt = lmt->l_next) { 119 if (strcmp(lmt->l_mountp, mountp) == 0) 120 return (lmt->l_special); 121 } 122 return (NULL); 123 } 124 125 static path_node_t * 126 pn_push(path_node_t **pnp, char *path) 127 { 128 path_node_t *pn; 129 130 if ((pn = calloc(sizeof (path_node_t), 1)) == NULL) 131 return (NULL); 132 133 if ((pn->pn_path = strdup(path)) == NULL) { 134 free(pn); 135 return (NULL); 136 } 137 pn->pn_next = *pnp; 138 return (*pnp = pn); 139 } 140 141 static void 142 pn_free(path_node_t **pnp) 143 { 144 path_node_t *pn; 145 146 while (*pnp != NULL) { 147 pn = *pnp; 148 *pnp = pn->pn_next; 149 free(pn->pn_path); 150 free(pn); 151 } 152 } 153 154 static void 155 pn_free2(path_node_t **pn1, path_node_t **pn2) 156 { 157 pn_free(pn1); 158 pn_free(pn2); 159 } 160 161 static char * 162 pn_pop(path_node_t **pnp, char *path) 163 { 164 path_node_t *pn; 165 166 if (*pnp == NULL) 167 return (NULL); 168 169 pn = *pnp; 170 *pnp = pn->pn_next; 171 pn->pn_next = NULL; 172 173 if (path == NULL) { 174 pn_free(&pn); 175 return (NULL); 176 } 177 (void) strlcpy(path, pn->pn_path, PATH_MAX); 178 pn_free(&pn); 179 return (path); 180 } 181 182 183 /* 184 * Libzonecfg.so links against libproc, so libproc can't link against 185 * libzonecfg.so. Also, libzonecfg.so is optional and might not be 186 * installed. Hence instead of relying on linking to access libzonecfg.so, 187 * we'll try dlopening it here. This trick is borrowed from 188 * libc`zone_get_id(), see that function for more detailed comments. 189 */ 190 static int 191 i_zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz) 192 { 193 typedef int (*zone_get_zonepath_t)(char *, char *, size_t); 194 static zone_get_zonepath_t zone_get_zonepath_fp = NULL; 195 196 if (zone_get_zonepath_fp == NULL) { 197 /* There's no harm in doing this multiple times. */ 198 void *dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY); 199 void *sym = (void *)(-1); 200 if (dlhandle != NULL && 201 (sym = dlsym(dlhandle, "zone_get_zonepath")) == NULL) { 202 sym = (void *)(-1); 203 (void) dlclose(dlhandle); 204 } 205 zone_get_zonepath_fp = (zone_get_zonepath_t)sym; 206 } 207 208 /* If we've successfully loaded it, call the real function */ 209 if (zone_get_zonepath_fp != (zone_get_zonepath_t)(-1)) 210 return (zone_get_zonepath_fp(zone_name, zonepath, rp_sz)); 211 return (Z_NO_ZONE); 212 } 213 214 char * 215 Pbrandname(struct ps_prochandle *P, char *buf, size_t buflen) 216 { 217 long addr; 218 219 if ((addr = Pgetauxval(P, AT_SUN_BRANDNAME)) == -1) 220 return (NULL); 221 222 if (Pread_string(P, buf, buflen, addr) == -1) 223 return (NULL); 224 225 return (buf); 226 } 227 228 /* 229 * Get the zone name from the core file if we have it; look up the 230 * name based on the zone id if this is a live process. 231 */ 232 char * 233 Pzonename(struct ps_prochandle *P, char *s, size_t n) 234 { 235 return (P->ops.pop_zonename(P, s, n, P->data)); 236 } 237 238 char * 239 Pzoneroot(struct ps_prochandle *P, char *s, size_t n) 240 { 241 char zname[ZONENAME_MAX], zpath[PATH_MAX], tmp[PATH_MAX]; 242 int rv; 243 244 if (P->zoneroot != NULL) { 245 (void) strlcpy(s, P->zoneroot, n); 246 return (s); 247 } 248 249 if ((Pzonename(P, zname, sizeof (zname)) == NULL) || 250 (strcmp(zname, GLOBAL_ZONENAME) == 0)) { 251 if ((P->zoneroot = strdup("")) == NULL) { 252 errno = ENOMEM; 253 return (NULL); 254 } 255 dprintf("Pzoneroot defaulting to '%s'\n", GLOBAL_ZONENAME); 256 (void) strlcpy(s, P->zoneroot, n); 257 return (s); 258 } 259 260 if (i_zone_get_zonepath(zname, zpath, sizeof (zpath)) != Z_OK) { 261 if ((P->zoneroot = strdup("")) == NULL) { 262 errno = ENOMEM; 263 return (NULL); 264 } 265 dprintf( 266 "Pzoneroot zone not found '%s', defaulting to '%s'\n", 267 zname, GLOBAL_ZONENAME); 268 (void) strlcpy(s, P->zoneroot, n); 269 return (s); 270 } 271 (void) strlcat(zpath, "/root", sizeof (zpath)); 272 273 if ((rv = resolvepath(zpath, tmp, sizeof (tmp) - 1)) < 0) { 274 if ((P->zoneroot = strdup("")) == NULL) { 275 errno = ENOMEM; 276 return (NULL); 277 } 278 dprintf( 279 "Pzoneroot can't access '%s:%s', defaulting to '%s'\n", 280 zname, zpath, GLOBAL_ZONENAME); 281 (void) strlcpy(s, P->zoneroot, n); 282 return (s); 283 } 284 tmp[rv] = '\0'; 285 (void) strlcpy(zpath, tmp, sizeof (zpath)); 286 287 if ((P->zoneroot = strdup(zpath)) == NULL) { 288 errno = ENOMEM; 289 return (NULL); 290 } 291 dprintf("Pzoneroot found zone root '%s:%s'\n", zname, zpath); 292 (void) strlcpy(s, P->zoneroot, n); 293 return (s); 294 } 295 296 /* 297 * Plofspath() takes a path, "path", and removes any lofs components from 298 * that path. The resultant path (if different from the starting path) 299 * is placed in "s", which is limited to "n" characters, and the return 300 * value is the pointer s. If there are no lofs components in the path 301 * the NULL is returned and s is not modified. It's ok for "path" and 302 * "s" to be the same pointer. (ie, the results can be stored directly 303 * in the input buffer.) The path that is passed in must be an absolute 304 * path. 305 * 306 * Example: 307 * if "path" == "/foo/bar", and "/candy/" is lofs mounted on "/foo/" 308 * then "/candy/bar/" will be written into "s" and "s" will be returned. 309 */ 310 char * 311 Plofspath(const char *path, char *s, size_t n) 312 { 313 char tmp[PATH_MAX + 1]; 314 struct stat64 statb; 315 const char *special; 316 char *p, *p2; 317 int rv; 318 319 dprintf("Plofspath path '%s'\n", path); 320 321 /* We only deal with absolute paths */ 322 if (path[0] != '/') 323 return (NULL); 324 325 /* Make a copy of the path so that we can muck with it */ 326 (void) strlcpy(tmp, path, sizeof (tmp) - 1); 327 328 /* 329 * Use resolvepath() to make sure there are no consecutive or 330 * trailing '/'s in the path. 331 */ 332 if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0) 333 tmp[rv] = '\0'; 334 335 (void) mutex_lock(&lofs_lock); 336 337 /* 338 * If /etc/mnttab has been modified since the last time 339 * we looked, then rebuild the lofs lookup cache. 340 */ 341 if (stat64(MNTTAB, &statb) == 0 && 342 (statb.st_mtim.tv_sec != lofs_mstat.st_mtim.tv_sec || 343 statb.st_mtim.tv_nsec != lofs_mstat.st_mtim.tv_nsec || 344 statb.st_ctim.tv_sec != lofs_mstat.st_ctim.tv_sec || 345 statb.st_ctim.tv_nsec != lofs_mstat.st_ctim.tv_nsec)) { 346 lofs_mstat = statb; 347 rebuild_lofs_cache(); 348 } 349 350 /* 351 * So now we're going to search the path for any components that 352 * might be lofs mounts. We'll start out search from the full 353 * path and then step back through each parent directly till 354 * we reach the root. If we find a lofs mount point in the path 355 * then we'll replace the initial portion of the path (up 356 * to that mount point) with the source of that mount point 357 * and then start our search over again. 358 * 359 * Here's some of the variables we're going to use: 360 * 361 * tmp - A pointer to our working copy of the path. Sometimes 362 * this path will be divided into two strings by a 363 * '\0' (NUL) character. The first string is the 364 * component we're currently checking and the second 365 * string is the path components we've already checked. 366 * 367 * p - A pointer to the last '/' seen in the string. 368 * 369 * p[1] - A pointer to the component of the string we've already 370 * checked. 371 * 372 * Initially, p will point to the end of our path and p[1] will point 373 * to an extra '\0' (NUL) that we'll append to the end of the string. 374 * (This is why we declared tmp with a size of PATH_MAX + 1). 375 */ 376 p = &tmp[strlen(tmp)]; 377 p[1] = '\0'; 378 for (;;) { 379 if ((special = lookup_lofs_mount_point(tmp)) != NULL) { 380 char tmp2[PATH_MAX + 1]; 381 382 /* 383 * We found a lofs mount. Update the path that we're 384 * checking and start over. This means append the 385 * portion of the path we've already checked to the 386 * source of the lofs mount and re-start this entire 387 * lofs resolution loop. Use resolvepath() to make 388 * sure there are no consecutive or trailing '/'s 389 * in the path. 390 */ 391 (void) strlcpy(tmp2, special, sizeof (tmp2) - 1); 392 (void) strlcat(tmp2, "/", sizeof (tmp2) - 1); 393 (void) strlcat(tmp2, &p[1], sizeof (tmp2) - 1); 394 (void) strlcpy(tmp, tmp2, sizeof (tmp) - 1); 395 if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0) 396 tmp[rv] = '\0'; 397 p = &tmp[strlen(tmp)]; 398 p[1] = '\0'; 399 continue; 400 } 401 402 /* No lofs mount found */ 403 if ((p2 = strrchr(tmp, '/')) == NULL) { 404 char tmp2[PATH_MAX]; 405 406 (void) mutex_unlock(&lofs_lock); 407 408 /* 409 * We know that tmp was an absolute path, so if we 410 * made it here we know that (p == tmp) and that 411 * (*p == '\0'). This means that we've managed 412 * to check the whole path and so we're done. 413 */ 414 assert(p == tmp); 415 assert(p[0] == '\0'); 416 417 /* Restore the leading '/' in the path */ 418 p[0] = '/'; 419 420 if (strcmp(tmp, path) == 0) { 421 /* The path didn't change */ 422 return (NULL); 423 } 424 425 /* 426 * It's possible that lofs source path we just 427 * obtained contains a symbolic link. Use 428 * resolvepath() to clean it up. 429 */ 430 (void) strlcpy(tmp2, tmp, sizeof (tmp2)); 431 if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0) 432 tmp[rv] = '\0'; 433 434 /* 435 * It's always possible that our lofs source path is 436 * actually another lofs mount. So call ourselves 437 * recursively to resolve that path. 438 */ 439 (void) Plofspath(tmp, tmp, PATH_MAX); 440 441 /* Copy out our final resolved lofs source path */ 442 (void) strlcpy(s, tmp, n); 443 dprintf("Plofspath path result '%s'\n", s); 444 return (s); 445 } 446 447 /* 448 * So the path we just checked is not a lofs mount. Next we 449 * want to check the parent path component for a lofs mount. 450 * 451 * First, restore any '/' that we replaced with a '\0' (NUL). 452 * We can determine if we should do this by looking at p[1]. 453 * If p[1] points to a '\0' (NUL) then we know that p points 454 * to the end of the string and there is no '/' to restore. 455 * if p[1] doesn't point to a '\0' (NUL) then it points to 456 * the part of the path that we've already verified so there 457 * is a '/' to restore. 458 */ 459 if (p[1] != '\0') 460 p[0] = '/'; 461 462 /* 463 * Second, replace the last '/' in the part of the path 464 * that we've already checked with a '\0' (NUL) so that 465 * when we loop around we check the parent component of the 466 * path. 467 */ 468 p2[0] = '\0'; 469 p = p2; 470 } 471 /*NOTREACHED*/ 472 } 473 474 /* 475 * Pzonepath() - Way too much code to attempt to derive the full path of 476 * an object within a zone. 477 * 478 * Pzonepath() takes a path and attempts to resolve it relative to the 479 * root associated with the current process handle. If it fails it will 480 * not update the results string. It is safe to specify the same pointer 481 * for the file string and the results string. 482 * 483 * Doing this resolution is more difficult than it initially sounds. 484 * We can't simply append the file path to the zone root, because in 485 * a root directory, '..' is treated the same as '.'. Also, symbolic 486 * links that specify an absolute path need to be interpreted relative 487 * to the zone root. 488 * 489 * It seems like perhaps we could do a chroot(<zone root>) followed by a 490 * resolvepath(). But we can't do this because chroot requires special 491 * privileges and affects the entire process. Perhaps if there was a 492 * special version of resolvepath() which took an addition root path 493 * we could use that, but this isn't ideal either. The reason is 494 * that we want to have special handling for native paths. (A native path 495 * is a path that begins with "/native/" or "/.SUNWnative/".) Native 496 * paths could be passed explicity to this function or could be embedded 497 * in a symlink that is part of the path passed into this function. 498 * These paths are always lofs mounts of global zone paths, but lofs 499 * mounts only exist when a zone is booted. So if we were to try to do 500 * a resolvepath() on a native path when the zone wasn't booted the 501 * resolvepath() would fail even though we know that the components 502 * exists in the global zone. 503 * 504 * Given all these constraints, we just implement a path walking function 505 * that resolves a file path relative to a zone root by manually inspecting 506 * each of the path components and verifying its existence. This means that 507 * we must have access to the zone and that all the components of the 508 * path must exist for this operation to succeed. 509 */ 510 char * 511 Pzonepath(struct ps_prochandle *P, const char *path, char *s, size_t n) 512 { 513 char zroot[PATH_MAX], zpath[PATH_MAX], tmp[PATH_MAX], link[PATH_MAX]; 514 path_node_t *pn_stack = NULL, *pn_links = NULL, *pn; 515 struct stat64 sb; 516 char *p; 517 int i, rv; 518 519 dprintf("Pzonepath lookup '%s'\n", path); 520 521 /* First lookup the zone root */ 522 if (Pzoneroot(P, zroot, sizeof (zroot)) == NULL) 523 return (NULL); 524 525 /* 526 * Make a temporary copy of the path specified. 527 * If it's a relative path then make it into an absolute path. 528 */ 529 tmp[0] = '\0'; 530 if (path[0] != '/') 531 (void) strlcat(tmp, "/", sizeof (tmp)); 532 (void) strlcat(tmp, path, sizeof (tmp)); 533 534 /* 535 * If the path that was passed in is the zone root, we're done. 536 * If the path that was passed in already contains the zone root 537 * then strip the zone root out and verify the rest of the path. 538 */ 539 if (strcmp(tmp, zroot) == 0) { 540 (void) Plofspath(zroot, zroot, sizeof (zroot)); 541 dprintf("Pzonepath found zone path (1) '%s'\n", zroot); 542 (void) strlcpy(s, zroot, n); 543 return (s); 544 } 545 i = strlen(zroot); 546 if ((strncmp(tmp, zroot, i) == 0) && (tmp[i] == '/')) 547 (void) memmove(tmp, tmp + i, strlen(tmp + i) + 1); 548 549 /* If no path is passed in, then it maps to the zone root */ 550 if (strlen(tmp) == 0) { 551 (void) Plofspath(zroot, zroot, sizeof (zroot)); 552 dprintf("Pzonepath found zone path (2) '%s'\n", zroot); 553 (void) strlcpy(s, zroot, n); 554 return (s); 555 } 556 557 /* 558 * Push each path component that we plan to verify onto a stack of 559 * path components, with parent components at the top of the stack. 560 * So for example, if we're going to verify the path /foo/bar/bang 561 * then our stack will look like: 562 * foo (top) 563 * bar 564 * bang (bottom) 565 */ 566 while ((p = strrchr(tmp, '/')) != NULL) { 567 *p = '\0'; 568 if (pn_push(&pn_stack, &p[1]) != NULL) 569 continue; 570 pn_free(&pn_stack); 571 return (NULL); 572 } 573 574 /* We're going to store the final zone relative path in zpath */ 575 *zpath = '\0'; 576 577 while (pn_pop(&pn_stack, tmp) != NULL) { 578 /* 579 * Drop zero length path components (which come from 580 * consecutive '/'s) and '.' path components. 581 */ 582 if ((strlen(tmp) == 0) || (strcmp(tmp, ".") == 0)) 583 continue; 584 585 /* 586 * Check the current path component for '..', if found 587 * drop any previous path component. 588 */ 589 if (strcmp(tmp, "..") == 0) { 590 if ((p = strrchr(zpath, '/')) != NULL) 591 *p = '\0'; 592 continue; 593 } 594 595 /* The path we want to verify now is zpath + / + tmp. */ 596 (void) strlcat(zpath, "/", sizeof (zpath)); 597 (void) strlcat(zpath, tmp, sizeof (zpath)); 598 599 /* 600 * Check if this is a native object. A native object is an 601 * object from the global zone that is running in a branded 602 * zone. These objects are lofs mounted into a zone. So if a 603 * branded zone is not booted then lofs mounts won't be setup 604 * so we won't be able to find these objects. Luckily, we know 605 * that they exist in the global zone with the same path sans 606 * the initial native component, so we'll just strip out the 607 * native component here. 608 */ 609 if ((strncmp(zpath, "/native", sizeof ("/native")) == 0) || 610 (strncmp(zpath, "/.SUNWnative", 611 sizeof ("/.SUNWnative")) == 0)) { 612 613 /* Free any cached symlink paths */ 614 pn_free(&pn_links); 615 616 /* Reconstruct the path from our path component stack */ 617 *zpath = '\0'; 618 while (pn_pop(&pn_stack, tmp) != NULL) { 619 (void) strlcat(zpath, "/", sizeof (zpath)); 620 (void) strlcat(zpath, tmp, sizeof (zpath)); 621 } 622 623 /* Verify that the path actually exists */ 624 rv = resolvepath(zpath, tmp, sizeof (tmp) - 1); 625 if (rv < 0) { 626 dprintf("Pzonepath invalid native path '%s'\n", 627 zpath); 628 return (NULL); 629 } 630 tmp[rv] = '\0'; 631 632 /* Return the path */ 633 dprintf("Pzonepath found native path '%s'\n", tmp); 634 (void) Plofspath(tmp, tmp, sizeof (tmp)); 635 (void) strlcpy(s, tmp, n); 636 return (s); 637 } 638 639 /* 640 * Check if the path points to a symlink. We do this 641 * explicitly since any absolute symlink needs to be 642 * interpreted relativly to the zone root and not "/". 643 */ 644 (void) strlcpy(tmp, zroot, sizeof (tmp)); 645 (void) strlcat(tmp, zpath, sizeof (tmp)); 646 if (lstat64(tmp, &sb) != 0) { 647 pn_free2(&pn_stack, &pn_links); 648 return (NULL); 649 } 650 if (!S_ISLNK(sb.st_mode)) { 651 /* 652 * Since the lstat64() above succeeded we know that 653 * zpath exists, since this is not a symlink loop 654 * around and check the next path component. 655 */ 656 continue; 657 } 658 659 /* 660 * Symlink allow for paths with loops. Make sure 661 * we're not stuck in a loop. 662 */ 663 for (pn = pn_links; pn != NULL; pn = pn->pn_next) { 664 if (strcmp(zpath, pn->pn_path) != 0) 665 continue; 666 667 /* We have a loop. Fail. */ 668 dprintf("Pzonepath symlink loop '%s'\n", zpath); 669 pn_free2(&pn_stack, &pn_links); 670 return (NULL); 671 } 672 673 /* Save this symlink path for future loop checks */ 674 if (pn_push(&pn_links, zpath) == NULL) { 675 /* Out of memory */ 676 pn_free2(&pn_stack, &pn_links); 677 return (NULL); 678 } 679 680 /* Now follow the contents of the symlink */ 681 bzero(link, sizeof (link)); 682 if (readlink(tmp, link, sizeof (link)) == -1) { 683 pn_free2(&pn_stack, &pn_links); 684 return (NULL); 685 } 686 687 dprintf("Pzonepath following symlink '%s' -> '%s'\n", 688 zpath, link); 689 690 /* 691 * Push each path component of the symlink target onto our 692 * path components stack since we need to verify each one. 693 */ 694 while ((p = strrchr(link, '/')) != NULL) { 695 *p = '\0'; 696 if (pn_push(&pn_stack, &p[1]) != NULL) 697 continue; 698 pn_free2(&pn_stack, &pn_links); 699 return (NULL); 700 } 701 702 /* absolute or relative symlink? */ 703 if (*link == '\0') { 704 /* Absolute symlink, nuke existing zpath. */ 705 *zpath = '\0'; 706 continue; 707 } 708 709 /* 710 * Relative symlink. Push the first path component of the 711 * symlink target onto our stack for verification and then 712 * remove the current path component from zpath. 713 */ 714 if (pn_push(&pn_stack, link) == NULL) { 715 pn_free2(&pn_stack, &pn_links); 716 return (NULL); 717 } 718 p = strrchr(zpath, '/'); 719 assert(p != NULL); 720 *p = '\0'; 721 continue; 722 } 723 pn_free(&pn_links); 724 725 /* Place the final result in zpath */ 726 (void) strlcpy(tmp, zroot, sizeof (tmp)); 727 (void) strlcat(tmp, zpath, sizeof (tmp)); 728 (void) strlcpy(zpath, tmp, sizeof (zpath)); 729 730 (void) Plofspath(zpath, zpath, sizeof (zpath)); 731 dprintf("Pzonepath found zone path (3) '%s'\n", zpath); 732 733 (void) strlcpy(s, zpath, n); 734 return (s); 735 } 736 737 char * 738 Pfindobj(struct ps_prochandle *P, const char *path, char *s, size_t n) 739 { 740 int len; 741 742 dprintf("Pfindobj '%s'\n", path); 743 744 /* We only deal with absolute paths */ 745 if (path[0] != '/') 746 return (NULL); 747 748 /* First try to resolve the path to some zone */ 749 if (Pzonepath(P, path, s, n) != NULL) 750 return (s); 751 752 /* If that fails resolve any lofs links in the path */ 753 if (Plofspath(path, s, n) != NULL) 754 return (s); 755 756 /* If that fails then just see if the path exists */ 757 if ((len = resolvepath(path, s, n)) > 0) { 758 s[len] = '\0'; 759 return (s); 760 } 761 762 return (NULL); 763 } 764 765 char * 766 Pfindmap(struct ps_prochandle *P, map_info_t *mptr, char *s, size_t n) 767 { 768 file_info_t *fptr = mptr->map_file; 769 char buf[PATH_MAX]; 770 int len; 771 772 /* If it's already been explicity set return that */ 773 if ((fptr != NULL) && (fptr->file_rname != NULL)) { 774 (void) strlcpy(s, fptr->file_rname, n); 775 return (s); 776 } 777 778 /* If it's the a.out segment, defer to the magical Pexecname() */ 779 if ((P->map_exec == mptr) || 780 (strcmp(mptr->map_pmap.pr_mapname, "a.out") == 0) || 781 ((fptr != NULL) && (fptr->file_lname != NULL) && 782 (strcmp(fptr->file_lname, "a.out") == 0))) { 783 if (Pexecname(P, buf, sizeof (buf)) != NULL) { 784 (void) strlcpy(s, buf, n); 785 return (s); 786 } 787 } 788 789 /* Try /proc first to get the real object name */ 790 if ((Pstate(P) != PS_DEAD) && (mptr->map_pmap.pr_mapname[0] != '\0')) { 791 (void) snprintf(buf, sizeof (buf), "%s/%d/path/%s", 792 procfs_path, (int)P->pid, mptr->map_pmap.pr_mapname); 793 if ((len = readlink(buf, buf, sizeof (buf))) > 0) { 794 buf[len] = '\0'; 795 (void) Plofspath(buf, buf, sizeof (buf)); 796 (void) strlcpy(s, buf, n); 797 return (s); 798 } 799 } 800 801 /* 802 * If we couldn't get the name from /proc, take the lname and 803 * try to expand it on the current system to a real object path. 804 */ 805 fptr = mptr->map_file; 806 if ((fptr != NULL) && (fptr->file_lname != NULL)) { 807 (void) strlcpy(buf, fptr->file_lname, sizeof (buf)); 808 if (Pfindobj(P, buf, buf, sizeof (buf)) == NULL) 809 return (NULL); 810 (void) strlcpy(s, buf, n); 811 return (s); 812 } 813 814 return (NULL); 815 }