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