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