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 * However, we need to be careful to handle the case of 392 * a lofs mounted file under a lofs mounted file system. 393 * In this case, we just keep going. 394 */ 395 396 (void) strlcpy(tmp2, special, sizeof (tmp2) - 1); 397 (void) strlcat(tmp2, "/", sizeof (tmp2) - 1); 398 (void) strlcat(tmp2, &p[1], sizeof (tmp2) - 1); 399 if ((rv = resolvepath(tmp2, tmp2, sizeof (tmp2) - 1)) >= 400 0) { 401 tmp2[rv] = '\0'; 402 (void) strlcpy(tmp, tmp2, sizeof (tmp) - 1); 403 p = &tmp[strlen(tmp)]; 404 p[1] = '\0'; 405 continue; 406 } 407 } 408 409 /* No lofs mount found */ 410 if ((p2 = strrchr(tmp, '/')) == NULL) { 411 char tmp2[PATH_MAX]; 412 413 (void) mutex_unlock(&lofs_lock); 414 415 /* 416 * We know that tmp was an absolute path, so if we 417 * made it here we know that (p == tmp) and that 418 * (*p == '\0'). This means that we've managed 419 * to check the whole path and so we're done. 420 */ 421 assert(p == tmp); 422 assert(p[0] == '\0'); 423 424 /* Restore the leading '/' in the path */ 425 p[0] = '/'; 426 427 if (strcmp(tmp, path) == 0) { 428 /* The path didn't change */ 429 return (NULL); 430 } 431 432 /* 433 * It's possible that lofs source path we just 434 * obtained contains a symbolic link. Use 435 * resolvepath() to clean it up. 436 */ 437 (void) strlcpy(tmp2, tmp, sizeof (tmp2)); 438 if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0) 439 tmp[rv] = '\0'; 440 441 /* 442 * It's always possible that our lofs source path is 443 * actually another lofs mount. So call ourselves 444 * recursively to resolve that path. 445 */ 446 (void) Plofspath(tmp, tmp, PATH_MAX); 447 448 /* Copy out our final resolved lofs source path */ 449 (void) strlcpy(s, tmp, n); 450 dprintf("Plofspath path result '%s'\n", s); 451 return (s); 452 } 453 454 /* 455 * So the path we just checked is not a lofs mount. Next we 456 * want to check the parent path component for a lofs mount. 457 * 458 * First, restore any '/' that we replaced with a '\0' (NUL). 459 * We can determine if we should do this by looking at p[1]. 460 * If p[1] points to a '\0' (NUL) then we know that p points 461 * to the end of the string and there is no '/' to restore. 462 * if p[1] doesn't point to a '\0' (NUL) then it points to 463 * the part of the path that we've already verified so there 464 * is a '/' to restore. 465 */ 466 if (p[1] != '\0') 467 p[0] = '/'; 468 469 /* 470 * Second, replace the last '/' in the part of the path 471 * that we've already checked with a '\0' (NUL) so that 472 * when we loop around we check the parent component of the 473 * path. 474 */ 475 p2[0] = '\0'; 476 p = p2; 477 } 478 /*NOTREACHED*/ 479 } 480 481 /* 482 * Pzonepath() - Way too much code to attempt to derive the full path of 483 * an object within a zone. 484 * 485 * Pzonepath() takes a path and attempts to resolve it relative to the 486 * root associated with the current process handle. If it fails it will 487 * not update the results string. It is safe to specify the same pointer 488 * for the file string and the results string. 489 * 490 * Doing this resolution is more difficult than it initially sounds. 491 * We can't simply append the file path to the zone root, because in 492 * a root directory, '..' is treated the same as '.'. Also, symbolic 493 * links that specify an absolute path need to be interpreted relative 494 * to the zone root. 495 * 496 * It seems like perhaps we could do a chroot(<zone root>) followed by a 497 * resolvepath(). But we can't do this because chroot requires special 498 * privileges and affects the entire process. Perhaps if there was a 499 * special version of resolvepath() which took an addition root path 500 * we could use that, but this isn't ideal either. The reason is 501 * that we want to have special handling for native paths. (A native path 502 * is a path that begins with "/native/" or "/.SUNWnative/".) Native 503 * paths could be passed explicity to this function or could be embedded 504 * in a symlink that is part of the path passed into this function. 505 * These paths are always lofs mounts of global zone paths, but lofs 506 * mounts only exist when a zone is booted. So if we were to try to do 507 * a resolvepath() on a native path when the zone wasn't booted the 508 * resolvepath() would fail even though we know that the components 509 * exists in the global zone. 510 * 511 * Given all these constraints, we just implement a path walking function 512 * that resolves a file path relative to a zone root by manually inspecting 513 * each of the path components and verifying its existence. This means that 514 * we must have access to the zone and that all the components of the 515 * path must exist for this operation to succeed. 516 */ 517 char * 518 Pzonepath(struct ps_prochandle *P, const char *path, char *s, size_t n) 519 { 520 char zroot[PATH_MAX], zpath[PATH_MAX], tmp[PATH_MAX], link[PATH_MAX]; 521 path_node_t *pn_stack = NULL, *pn_links = NULL, *pn; 522 struct stat64 sb; 523 char *p; 524 int i, rv; 525 526 dprintf("Pzonepath lookup '%s'\n", path); 527 528 /* First lookup the zone root */ 529 if (Pzoneroot(P, zroot, sizeof (zroot)) == NULL) 530 return (NULL); 531 532 /* 533 * Make a temporary copy of the path specified. 534 * If it's a relative path then make it into an absolute path. 535 */ 536 tmp[0] = '\0'; 537 if (path[0] != '/') 538 (void) strlcat(tmp, "/", sizeof (tmp)); 539 (void) strlcat(tmp, path, sizeof (tmp)); 540 541 /* 542 * If the path that was passed in is the zone root, we're done. 543 * If the path that was passed in already contains the zone root 544 * then strip the zone root out and verify the rest of the path. 545 */ 546 if (strcmp(tmp, zroot) == 0) { 547 (void) Plofspath(zroot, zroot, sizeof (zroot)); 548 dprintf("Pzonepath found zone path (1) '%s'\n", zroot); 549 (void) strlcpy(s, zroot, n); 550 return (s); 551 } 552 i = strlen(zroot); 553 if ((strncmp(tmp, zroot, i) == 0) && (tmp[i] == '/')) 554 (void) memmove(tmp, tmp + i, strlen(tmp + i) + 1); 555 556 /* If no path is passed in, then it maps to the zone root */ 557 if (strlen(tmp) == 0) { 558 (void) Plofspath(zroot, zroot, sizeof (zroot)); 559 dprintf("Pzonepath found zone path (2) '%s'\n", zroot); 560 (void) strlcpy(s, zroot, n); 561 return (s); 562 } 563 564 /* 565 * Push each path component that we plan to verify onto a stack of 566 * path components, with parent components at the top of the stack. 567 * So for example, if we're going to verify the path /foo/bar/bang 568 * then our stack will look like: 569 * foo (top) 570 * bar 571 * bang (bottom) 572 */ 573 while ((p = strrchr(tmp, '/')) != NULL) { 574 *p = '\0'; 575 if (pn_push(&pn_stack, &p[1]) != NULL) 576 continue; 577 pn_free(&pn_stack); 578 return (NULL); 579 } 580 581 /* We're going to store the final zone relative path in zpath */ 582 *zpath = '\0'; 583 584 while (pn_pop(&pn_stack, tmp) != NULL) { 585 /* 586 * Drop zero length path components (which come from 587 * consecutive '/'s) and '.' path components. 588 */ 589 if ((strlen(tmp) == 0) || (strcmp(tmp, ".") == 0)) 590 continue; 591 592 /* 593 * Check the current path component for '..', if found 594 * drop any previous path component. 595 */ 596 if (strcmp(tmp, "..") == 0) { 597 if ((p = strrchr(zpath, '/')) != NULL) 598 *p = '\0'; 599 continue; 600 } 601 602 /* The path we want to verify now is zpath + / + tmp. */ 603 (void) strlcat(zpath, "/", sizeof (zpath)); 604 (void) strlcat(zpath, tmp, sizeof (zpath)); 605 606 /* 607 * Check if this is a native object. A native object is an 608 * object from the global zone that is running in a branded 609 * zone. These objects are lofs mounted into a zone. So if a 610 * branded zone is not booted then lofs mounts won't be setup 611 * so we won't be able to find these objects. Luckily, we know 612 * that they exist in the global zone with the same path sans 613 * the initial native component, so we'll just strip out the 614 * native component here. 615 */ 616 if ((strncmp(zpath, "/native", sizeof ("/native")) == 0) || 617 (strncmp(zpath, "/.SUNWnative", 618 sizeof ("/.SUNWnative")) == 0)) { 619 620 /* Free any cached symlink paths */ 621 pn_free(&pn_links); 622 623 /* Reconstruct the path from our path component stack */ 624 *zpath = '\0'; 625 while (pn_pop(&pn_stack, tmp) != NULL) { 626 (void) strlcat(zpath, "/", sizeof (zpath)); 627 (void) strlcat(zpath, tmp, sizeof (zpath)); 628 } 629 630 /* Verify that the path actually exists */ 631 rv = resolvepath(zpath, tmp, sizeof (tmp) - 1); 632 if (rv < 0) { 633 dprintf("Pzonepath invalid native path '%s'\n", 634 zpath); 635 return (NULL); 636 } 637 tmp[rv] = '\0'; 638 639 /* Return the path */ 640 dprintf("Pzonepath found native path '%s'\n", tmp); 641 (void) Plofspath(tmp, tmp, sizeof (tmp)); 642 (void) strlcpy(s, tmp, n); 643 return (s); 644 } 645 646 /* 647 * Check if the path points to a symlink. We do this 648 * explicitly since any absolute symlink needs to be 649 * interpreted relativly to the zone root and not "/". 650 */ 651 (void) strlcpy(tmp, zroot, sizeof (tmp)); 652 (void) strlcat(tmp, zpath, sizeof (tmp)); 653 if (lstat64(tmp, &sb) != 0) { 654 pn_free2(&pn_stack, &pn_links); 655 return (NULL); 656 } 657 if (!S_ISLNK(sb.st_mode)) { 658 /* 659 * Since the lstat64() above succeeded we know that 660 * zpath exists, since this is not a symlink loop 661 * around and check the next path component. 662 */ 663 continue; 664 } 665 666 /* 667 * Symlink allow for paths with loops. Make sure 668 * we're not stuck in a loop. 669 */ 670 for (pn = pn_links; pn != NULL; pn = pn->pn_next) { 671 if (strcmp(zpath, pn->pn_path) != 0) 672 continue; 673 674 /* We have a loop. Fail. */ 675 dprintf("Pzonepath symlink loop '%s'\n", zpath); 676 pn_free2(&pn_stack, &pn_links); 677 return (NULL); 678 } 679 680 /* Save this symlink path for future loop checks */ 681 if (pn_push(&pn_links, zpath) == NULL) { 682 /* Out of memory */ 683 pn_free2(&pn_stack, &pn_links); 684 return (NULL); 685 } 686 687 /* Now follow the contents of the symlink */ 688 bzero(link, sizeof (link)); 689 if (readlink(tmp, link, sizeof (link)) == -1) { 690 pn_free2(&pn_stack, &pn_links); 691 return (NULL); 692 } 693 694 dprintf("Pzonepath following symlink '%s' -> '%s'\n", 695 zpath, link); 696 697 /* 698 * Push each path component of the symlink target onto our 699 * path components stack since we need to verify each one. 700 */ 701 while ((p = strrchr(link, '/')) != NULL) { 702 *p = '\0'; 703 if (pn_push(&pn_stack, &p[1]) != NULL) 704 continue; 705 pn_free2(&pn_stack, &pn_links); 706 return (NULL); 707 } 708 709 /* absolute or relative symlink? */ 710 if (*link == '\0') { 711 /* Absolute symlink, nuke existing zpath. */ 712 *zpath = '\0'; 713 continue; 714 } 715 716 /* 717 * Relative symlink. Push the first path component of the 718 * symlink target onto our stack for verification and then 719 * remove the current path component from zpath. 720 */ 721 if (pn_push(&pn_stack, link) == NULL) { 722 pn_free2(&pn_stack, &pn_links); 723 return (NULL); 724 } 725 p = strrchr(zpath, '/'); 726 assert(p != NULL); 727 *p = '\0'; 728 continue; 729 } 730 pn_free(&pn_links); 731 732 /* Place the final result in zpath */ 733 (void) strlcpy(tmp, zroot, sizeof (tmp)); 734 (void) strlcat(tmp, zpath, sizeof (tmp)); 735 (void) strlcpy(zpath, tmp, sizeof (zpath)); 736 737 (void) Plofspath(zpath, zpath, sizeof (zpath)); 738 dprintf("Pzonepath found zone path (3) '%s'\n", zpath); 739 740 (void) strlcpy(s, zpath, n); 741 return (s); 742 } 743 744 char * 745 Pfindobj(struct ps_prochandle *P, const char *path, char *s, size_t n) 746 { 747 int len; 748 749 dprintf("Pfindobj '%s'\n", path); 750 751 /* We only deal with absolute paths */ 752 if (path[0] != '/') 753 return (NULL); 754 755 /* First try to resolve the path to some zone */ 756 if (Pzonepath(P, path, s, n) != NULL) 757 return (s); 758 759 /* If that fails resolve any lofs links in the path */ 760 if (Plofspath(path, s, n) != NULL) 761 return (s); 762 763 /* If that fails then just see if the path exists */ 764 if ((len = resolvepath(path, s, n)) > 0) { 765 s[len] = '\0'; 766 return (s); 767 } 768 769 return (NULL); 770 } 771 772 char * 773 Pfindmap(struct ps_prochandle *P, map_info_t *mptr, char *s, size_t n) 774 { 775 file_info_t *fptr = mptr->map_file; 776 char buf[PATH_MAX]; 777 int len; 778 779 /* If it's already been explicity set return that */ 780 if ((fptr != NULL) && (fptr->file_rname != NULL)) { 781 (void) strlcpy(s, fptr->file_rname, n); 782 return (s); 783 } 784 785 /* If it's the a.out segment, defer to the magical Pexecname() */ 786 if ((P->map_exec == mptr) || 787 (strcmp(mptr->map_pmap.pr_mapname, "a.out") == 0) || 788 ((fptr != NULL) && (fptr->file_lname != NULL) && 789 (strcmp(fptr->file_lname, "a.out") == 0))) { 790 if (Pexecname(P, buf, sizeof (buf)) != NULL) { 791 (void) strlcpy(s, buf, n); 792 return (s); 793 } 794 } 795 796 /* Try /proc first to get the real object name */ 797 if ((Pstate(P) != PS_DEAD) && (mptr->map_pmap.pr_mapname[0] != '\0')) { 798 (void) snprintf(buf, sizeof (buf), "%s/%d/path/%s", 799 procfs_path, (int)P->pid, mptr->map_pmap.pr_mapname); 800 if ((len = readlink(buf, buf, sizeof (buf))) > 0) { 801 buf[len] = '\0'; 802 (void) Plofspath(buf, buf, sizeof (buf)); 803 (void) strlcpy(s, buf, n); 804 return (s); 805 } 806 } 807 808 /* 809 * If we couldn't get the name from /proc, take the lname and 810 * try to expand it on the current system to a real object path. 811 */ 812 fptr = mptr->map_file; 813 if ((fptr != NULL) && (fptr->file_lname != NULL)) { 814 (void) strlcpy(buf, fptr->file_lname, sizeof (buf)); 815 if (Pfindobj(P, buf, buf, sizeof (buf)) == NULL) 816 return (NULL); 817 (void) strlcpy(s, buf, n); 818 return (s); 819 } 820 821 return (NULL); 822 } 823