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
46struct path_node {
47	struct path_node	*pn_next;
48	char			*pn_path;
49};
50typedef struct path_node path_node_t;
51
52/*
53 * Parameters of the lofs lookup cache.
54 */
55static struct stat64 lofs_mstat; /* last stat() of MNTTAB */
56static 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;
61static mutex_t lofs_lock = DEFAULTMUTEX;	/* protects the lofs cache */
62
63static void
64rebuild_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
111static const char *
112lookup_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
125static path_node_t *
126pn_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
141static void
142pn_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
154static void
155pn_free2(path_node_t **pn1, path_node_t **pn2)
156{
157	pn_free(pn1);
158	pn_free(pn2);
159}
160
161static char *
162pn_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 */
190static int
191i_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
214char *
215Pbrandname(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 */
232char *
233Pzonename(struct ps_prochandle *P, char *s, size_t n)
234{
235	return (P->ops.pop_zonename(P, s, n, P->data));
236}
237
238char *
239Pzoneroot(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 */
310char *
311Plofspath(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 */
517char *
518Pzonepath(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
744char *
745Pfindobj(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
772char *
773Pfindmap(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		char path[PATH_MAX];
799
800		len = snprintf(path, sizeof (path), "%s/%d/path/%s",
801		    procfs_path, (int)P->pid, mptr->map_pmap.pr_mapname);
802		if (len < 0 || (size_t)len >= sizeof (path))
803			return (NULL);
804
805		if ((len = readlink(path, buf, sizeof (buf))) > 0) {
806			buf[len] = '\0';
807			(void) Plofspath(buf, buf, sizeof (buf));
808			(void) strlcpy(s, buf, n);
809			return (s);
810		}
811	}
812
813	/*
814	 * If we couldn't get the name from /proc, take the lname and
815	 * try to expand it on the current system to a real object path.
816	 */
817	fptr = mptr->map_file;
818	if ((fptr != NULL) && (fptr->file_lname != NULL)) {
819		(void) strlcpy(buf, fptr->file_lname, sizeof (buf));
820		if (Pfindobj(P, buf, buf, sizeof (buf)) == NULL)
821			return (NULL);
822		(void) strlcpy(s, buf, n);
823		return (s);
824	}
825
826	return (NULL);
827}
828