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