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