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