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